pbs_testsuite.py 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452
  1. # coding: utf-8
  2. # Copyright (C) 1994-2018 Altair Engineering, Inc.
  3. # For more information, contact Altair at www.altair.com.
  4. #
  5. # This file is part of the PBS Professional ("PBS Pro") software.
  6. #
  7. # Open Source License Information:
  8. #
  9. # PBS Pro is free software. You can redistribute it and/or modify it under the
  10. # terms of the GNU Affero General Public License as published by the Free
  11. # Software Foundation, either version 3 of the License, or (at your option) any
  12. # later version.
  13. #
  14. # PBS Pro is distributed in the hope that it will be useful, but WITHOUT ANY
  15. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16. # FOR A PARTICULAR PURPOSE.
  17. # See the GNU Affero General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU Affero General Public License
  20. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. #
  22. # Commercial License Information:
  23. #
  24. # For a copy of the commercial license terms and conditions,
  25. # go to: (http://www.pbspro.com/UserArea/agreement.html)
  26. # or contact the Altair Legal Department.
  27. #
  28. # Altair’s dual-license business model allows companies, individuals, and
  29. # organizations to create proprietary derivative works of PBS Pro and
  30. # distribute them - whether embedded or bundled with other software -
  31. # under a commercial license agreement.
  32. #
  33. # Use of Altair’s trademarks, including but not limited to "PBS™",
  34. # "PBS Professional®", and "PBS Pro™" and Altair’s logos is subject to Altair's
  35. # trademark licensing policies.
  36. import unittest
  37. import logging
  38. import subprocess
  39. import pwd
  40. import grp
  41. import os
  42. import sys
  43. import platform
  44. import socket
  45. import time
  46. import calendar
  47. import ptl
  48. from ptl.utils.pbs_logutils import PBSLogAnalyzer
  49. from ptl.utils.pbs_dshutils import DshUtils
  50. from ptl.utils.pbs_cliutils import CliUtils
  51. from ptl.utils.pbs_procutils import ProcMonitor
  52. from ptl.lib.pbs_testlib import *
  53. try:
  54. from ptl.utils.plugins.ptl_test_tags import tags
  55. except ImportError:
  56. def tags(*args, **kwargs):
  57. pass
  58. try:
  59. from nose.plugins.skip import SkipTest
  60. except ImportError:
  61. class SkipTest(Exception):
  62. pass
  63. # Test users/groups are expected to exist on the test systems
  64. # User running the tests and the test users should have passwordless sudo
  65. # access configured to avoid interrupted (queries for password) test runs
  66. # Groups
  67. TSTGRP0 = PbsGroup('tstgrp00', gid=1900)
  68. TSTGRP1 = PbsGroup('tstgrp01', gid=1901)
  69. TSTGRP2 = PbsGroup('tstgrp02', gid=1902)
  70. TSTGRP3 = PbsGroup('tstgrp03', gid=1903)
  71. TSTGRP4 = PbsGroup('tstgrp04', gid=1904)
  72. TSTGRP5 = PbsGroup('tstgrp05', gid=1905)
  73. TSTGRP6 = PbsGroup('tstgrp06', gid=1906)
  74. TSTGRP7 = PbsGroup('tstgrp07', gid=1907)
  75. GRP_PBS = PbsGroup('pbs', gid=901)
  76. GRP_AGT = PbsGroup('agt', gid=1146)
  77. ROOT_GRP = PbsGroup(grp.getgrgid(0).gr_name, gid=0)
  78. # Users
  79. # first group from group list is primary group of user
  80. TEST_USER = PbsUser('pbsuser', uid=4359, groups=[TSTGRP0])
  81. TEST_USER1 = PbsUser('pbsuser1', uid=4361, groups=[TSTGRP0, TSTGRP1, TSTGRP2])
  82. TEST_USER2 = PbsUser('pbsuser2', uid=4362, groups=[TSTGRP0, TSTGRP1, TSTGRP3])
  83. TEST_USER3 = PbsUser('pbsuser3', uid=4363, groups=[TSTGRP0, TSTGRP1, TSTGRP4])
  84. TEST_USER4 = PbsUser('pbsuser4', uid=4364, groups=[TSTGRP1, TSTGRP4, TSTGRP5])
  85. TEST_USER5 = PbsUser('pbsuser5', uid=4365, groups=[TSTGRP2, TSTGRP4, TSTGRP6])
  86. TEST_USER6 = PbsUser('pbsuser6', uid=4366, groups=[TSTGRP3, TSTGRP4, TSTGRP7])
  87. TEST_USER7 = PbsUser('pbsuser7', uid=4368, groups=[TSTGRP1])
  88. OTHER_USER = PbsUser('pbsother', uid=4358, groups=[TSTGRP0, TSTGRP2, GRP_PBS,
  89. GRP_AGT])
  90. PBSTEST_USER = PbsUser('pbstest', uid=4355, groups=[TSTGRP0, TSTGRP2, GRP_PBS,
  91. GRP_AGT])
  92. TST_USR = PbsUser('tstusr00', uid=11000, groups=[TSTGRP0])
  93. TST_USR1 = PbsUser('tstusr01', uid=11001, groups=[TSTGRP0])
  94. BUILD_USER = PbsUser('pbsbuild', uid=9000, groups=[TSTGRP0])
  95. DATA_USER = PbsUser('pbsdata', uid=4372, groups=[TSTGRP0])
  96. MGR_USER = PbsUser('pbsmgr', uid=4367, groups=[TSTGRP0])
  97. OPER_USER = PbsUser('pbsoper', uid=4356, groups=[TSTGRP0, TSTGRP2, GRP_PBS,
  98. GRP_AGT])
  99. ADMIN_USER = PbsUser('pbsadmin', uid=4357, groups=[TSTGRP0, TSTGRP2, GRP_PBS,
  100. GRP_AGT])
  101. PBSROOT_USER = PbsUser('pbsroot', uid=4371, groups=[TSTGRP0, TSTGRP2])
  102. ROOT_USER = PbsUser('root', uid=0, groups=[ROOT_GRP])
  103. PBS_USERS = (TEST_USER, TEST_USER1, TEST_USER2, TEST_USER3, TEST_USER4,
  104. TEST_USER5, TEST_USER6, TEST_USER7, OTHER_USER, PBSTEST_USER,
  105. TST_USR, TST_USR1)
  106. PBS_GROUPS = (TSTGRP0, TSTGRP1, TSTGRP2, TSTGRP3, TSTGRP4, TSTGRP5, TSTGRP6,
  107. TSTGRP7, GRP_PBS, GRP_AGT)
  108. PBS_OPER_USERS = (OPER_USER,)
  109. PBS_MGR_USERS = (MGR_USER, ADMIN_USER)
  110. PBS_DATA_USERS = (DATA_USER,)
  111. PBS_ROOT_USERS = (PBSROOT_USER, ROOT_USER)
  112. PBS_BUILD_USERS = (BUILD_USER,)
  113. SETUPLOG = 'setuplog'
  114. TEARDOWNLOG = 'teardownlog'
  115. SMOKE = 'smoke'
  116. REGRESSION = 'regression'
  117. NUMNODES = 'numnodes'
  118. TIMEOUT_KEY = '__testcase_timeout__'
  119. MINIMUM_TESTCASE_TIMEOUT = 600
  120. def skip(reason="Skipped test execution"):
  121. """
  122. Unconditionally skip a test.
  123. :param reason: Reason for the skip
  124. :type reason: str or None
  125. """
  126. skip_flag = True
  127. def wrapper(test_item):
  128. test_item.__unittest_skip__ = skip_flag
  129. test_item.__unittest_skip_why__ = reason
  130. return test_item
  131. return wrapper
  132. def timeout(val):
  133. """
  134. Decorator to set timeout value of test case
  135. """
  136. logger = logging.getLogger(__name__)
  137. old_val = None
  138. if val < MINIMUM_TESTCASE_TIMEOUT:
  139. old_val = val
  140. val = MINIMUM_TESTCASE_TIMEOUT
  141. def wrapper(obj):
  142. msg = 'for test ' + obj.func_name
  143. msg += ' minimum-testcase-timeout updated to '
  144. msg += str(val) + ' from ' + str(old_val)
  145. if old_val:
  146. logger.info(msg)
  147. setattr(obj, TIMEOUT_KEY, int(val))
  148. return obj
  149. return wrapper
  150. def checkModule(modname):
  151. """
  152. Decorator to check if named module is available on the system
  153. and if not skip the test
  154. """
  155. def decorated(function):
  156. def wrapper(self, *args, **kwargs):
  157. import imp
  158. try:
  159. imp.find_module(modname)
  160. except ImportError:
  161. self.skipTest(reason='Module unavailable ' + modname)
  162. else:
  163. function(self, *args, **kwargs)
  164. wrapper.__doc__ = function.__doc__
  165. wrapper.__name__ = function.__name__
  166. return wrapper
  167. return decorated
  168. def skipOnCray(function):
  169. """
  170. Decorator to skip a test on a ``Cray`` system
  171. """
  172. def wrapper(self, *args, **kwargs):
  173. if self.mom.is_cray():
  174. self.skipTest(reason='capability not supported on Cray')
  175. else:
  176. function(self, *args, **kwargs)
  177. wrapper.__doc__ = function.__doc__
  178. wrapper.__name__ = function.__name__
  179. return wrapper
  180. def skipOnCpuSet(function):
  181. """
  182. Decorator to skip a test on a CpuSet system
  183. """
  184. def wrapper(self, *args, **kwargs):
  185. if self.mom.is_cpuset_mom():
  186. self.skipTest(reason='capability not supported on Cpuset')
  187. else:
  188. function(self, *args, **kwargs)
  189. wrapper.__doc__ = function.__doc__
  190. wrapper.__name__ = function.__name__
  191. return wrapper
  192. class PBSServiceInstanceWrapper(dict):
  193. """
  194. A wrapper class to handle multiple service
  195. ``(i.e., mom, server, scheduler)``instances as passed along
  196. through the test harness ``(pbs_benchpress)``.Returns an
  197. ordered dictionary of PBS service instances ``(i.e., mom/server/
  198. scheduler)``
  199. Users may invoke PTL using pointers to multiple services per
  200. host, for example:
  201. ``pbs_benchpress -p moms=hostA@/etc/pbs.conf,hostB,hostA@/etc/pbs.conf3``
  202. In such cases, the moms instance variable must be able to distinguish
  203. the ``self.moms['hostA']`` instances, each instance will be mapped
  204. to a unique configuration file
  205. """
  206. def __init__(self, *args, **kwargs):
  207. super(self.__class__, self).__init__(self, *args, **kwargs)
  208. self.orderedlist = super(self.__class__, self).keys()
  209. def __setitem__(self, key, value):
  210. super(self.__class__, self).__setitem__(key, value)
  211. if key not in self.orderedlist:
  212. self.orderedlist.append(key)
  213. def __getitem__(self, key):
  214. for k, v in self.items():
  215. if k == key:
  216. return v
  217. if '@' in k:
  218. name, _ = k.split('@')
  219. if key in name:
  220. return v
  221. else:
  222. name = k
  223. # Users may have specified shortnames instead of FQDN, in order
  224. # to not enforce that PBS_SERVER match the hostname passed in as
  225. # parameter, we check if a shortname matches a FQDN entry
  226. if '.' in key and key.split('.')[0] in name:
  227. return v
  228. if '.' in name and name.split('.')[0] in key:
  229. return v
  230. return None
  231. def __contains__(self, key):
  232. if key in self.keys():
  233. return True
  234. for k in self.keys():
  235. if '@' in k:
  236. name, _ = k.split('@')
  237. if key in name:
  238. return True
  239. else:
  240. name = k
  241. # Users may have specified shortnames instead of FQDN, in order
  242. # to not enforce that PBS_SERVER match the hostname passed in as
  243. # parameter, we check if a shortname matches a FQDN entry
  244. if '.' in key and key.split('.')[0] in name:
  245. return True
  246. if '.' in name and name.split('.')[0] in key:
  247. return True
  248. return False
  249. def __iter__(self):
  250. return iter(self.orderedlist)
  251. def host_keys(self):
  252. return map(lambda h: h.split('@')[0], self.keys())
  253. def keys(self):
  254. return self.orderedlist
  255. def itervalues(self):
  256. return (self[key] for key in self.orderedlist)
  257. def values(self):
  258. return [self[key] for key in self.orderedlist]
  259. class setUpClassError(Exception):
  260. pass
  261. class tearDownClassError(Exception):
  262. pass
  263. class PBSTestSuite(unittest.TestCase):
  264. """
  265. Generic ``setup``, ``teardown``, and ``logging`` functions to
  266. be used as parent class for most tests.
  267. Class instantiates:
  268. ``server object connected to localhost``
  269. ``scheduler objected connected to localhost``
  270. ``mom object connected to localhost``
  271. Custom parameters:
  272. :param server: The hostname on which the PBS ``server/scheduler``
  273. are running
  274. :param mom: The hostname on which the PBS MoM is running
  275. :param servers: Colon-separated list of hostnames hosting a PBS server.
  276. Servers are then accessible as a dictionary in the
  277. instance variable servers.
  278. :param client: For CLI mode only, name of the host on which the PBS
  279. client commands are to be run from. Format is
  280. ``<host>@<path-to-config-file>``
  281. :param moms: Colon-separated list of hostnames hosting a PBS MoM.
  282. MoMs are made accessible as a dictionary in the instance
  283. variable moms.
  284. :param comms: Colon-separated list of hostnames hosting a PBS Comm.
  285. Comms are made accessible as a dictionary in the
  286. instance variable comms.
  287. :param nomom=<host1>\:<host2>...: expect no MoM on given set of hosts
  288. :param mode: Sets mode of operation to PBS server. Can be either
  289. ``'cli'`` or ``'api'``.Defaults to API behavior.
  290. :param conn_timeout: set a timeout in seconds after which a pbs_connect
  291. IFL call is refreshed (i.e., disconnected)
  292. :param skip-setup: Bypasses setUp of PBSTestSuite (not custom ones)
  293. :param skip-teardown: Bypasses tearDown of PBSTestSuite (not custom ones)
  294. :param procinfo: Enables process monitoring thread, logged into
  295. ptl_proc_info test metrics. The value can be set to
  296. _all_ to monitor all PBS processes,including
  297. ``pbs_server``, ``pbs_sched``, ``pbs_mom``, or a process
  298. defined by name.
  299. :param revert-to-defaults=<True|False>: if False, will not revert to
  300. defaults.True by default.
  301. :param revert-hooks=<True|False>: if False, do not revert hooks to
  302. defaults.Defaults to True.
  303. ``revert-to-defaults`` set to False
  304. overrides this setting.
  305. :param del-hooks=<True|False>: If False, do not delete hooks. Defaults
  306. to False.``revert-to-defaults`` set to
  307. False overrides this setting.
  308. :param revert-queues=<True|False>: If False, do not revert queues to
  309. defaults.Defaults to True.
  310. ``revert-to-defaults`` set to False
  311. overrides this setting.
  312. :param revert-resources=<True|False>: If False, do not revert resources
  313. to defaults. Defaults to True.
  314. ``revert-to-defaults`` set to False
  315. overrides this setting.
  316. :param del-queues=<True|False>: If False, do not delete queues. Defaults
  317. to False.``revert-to-defaults`` set to
  318. Falseoverrides this setting.
  319. :param del-vnodes=<True|False>: If False, do not delete vnodes on MoM
  320. instances.Defaults to True.
  321. :param server-revert-to-defaults=<True|False>: if False, don't revert
  322. Server to defaults
  323. :param comm-revert-to-defaults=<True|False>: if False, don't revert Comm
  324. to defaults
  325. :param mom-revert-to-defaults=<True|False>: if False, don't revert MoM
  326. to defaults
  327. :param sched-revert-to-defaults=<True|False>: if False, don't revert
  328. Scheduler to defaults
  329. :param procmon: Enables process monitoring. Multiple values must be
  330. colon separated. For example to monitor ``server``,
  331. ``sched``, and ``mom`` use
  332. ``procmon=pbs_server:pbs_sched:pbs_mom``
  333. :param procmon-freq: Sets a polling frequency for the process monitoring
  334. tool.Defaults to 10 seconds.
  335. :param test-users: colon-separated list of users to use as test users.
  336. The users specified override the default users in the
  337. order in which they appear in the ``PBS_USERS`` list.
  338. :param default-testcase-timeout: Default test case timeout value.
  339. :param data-users: colon-separated list of data users.
  340. :param oper-users: colon-separated list of operator users.
  341. :param mgr-users: colon-separated list of manager users.
  342. :param root-users: colon-separated list of root users.
  343. :param build-users: colon-separated list of build users.
  344. :param clienthost: the hostnames to set in the MoM config file
  345. """
  346. logger = logging.getLogger(__name__)
  347. metrics_data = {}
  348. measurements = []
  349. additional_data = {}
  350. conf = {}
  351. param = None
  352. du = DshUtils()
  353. _procmon = None
  354. _process_monitoring = False
  355. revert_to_defaults = True
  356. server_revert_to_defaults = True
  357. mom_revert_to_defaults = True
  358. sched_revert_to_defaults = True
  359. revert_queues = True
  360. revert_resources = True
  361. revert_hooks = True
  362. del_hooks = True
  363. del_queues = True
  364. del_scheds = True
  365. del_vnodes = True
  366. server = None
  367. scheduler = None
  368. mom = None
  369. comm = None
  370. servers = None
  371. schedulers = {}
  372. scheds = None
  373. moms = None
  374. comms = None
  375. @classmethod
  376. def setUpClass(cls):
  377. cls.log_enter_setup(True)
  378. cls._testMethodName = 'setUpClass'
  379. cls.parse_param()
  380. cls.init_param()
  381. cls.check_users_exist()
  382. cls.init_servers()
  383. cls.init_comms()
  384. cls.init_schedulers()
  385. cls.init_moms()
  386. cls.log_end_setup(True)
  387. def setUp(self):
  388. if 'skip-setup' in self.conf:
  389. return
  390. self.log_enter_setup()
  391. self.init_proc_mon()
  392. self.revert_pbsconf()
  393. self.revert_servers()
  394. self.revert_comms()
  395. self.revert_schedulers()
  396. self.revert_moms()
  397. self.log_end_setup()
  398. self.measurements = []
  399. @classmethod
  400. def log_enter_setup(cls, iscls=False):
  401. _m = ' Entered ' + cls.__name__ + ' setUp'
  402. if iscls:
  403. _m += 'Class'
  404. _m_len = len(_m)
  405. cls.logger.info('=' * _m_len)
  406. cls.logger.info(_m)
  407. cls.logger.info('=' * _m_len)
  408. @classmethod
  409. def log_end_setup(cls, iscls=False):
  410. _m = 'Completed ' + cls.__name__ + ' setUp'
  411. if iscls:
  412. _m += 'Class'
  413. _m_len = len(_m)
  414. cls.logger.info('=' * _m_len)
  415. cls.logger.info(_m)
  416. cls.logger.info('=' * _m_len)
  417. @classmethod
  418. def _validate_param(cls, pname):
  419. """
  420. Check if parameter was enabled at the ``command-line``
  421. :param pname: parameter name
  422. :type pname: str
  423. :param pvar: class variable to set according to command-line setting
  424. """
  425. if pname not in cls.conf:
  426. return
  427. if cls.conf[pname] in PTL_TRUE:
  428. setattr(cls, pname.replace('-', '_'), True)
  429. else:
  430. setattr(cls, pname.replace('-', '_'), False)
  431. @classmethod
  432. def _set_user(cls, name, user_list):
  433. if name in cls.conf:
  434. for idx, u in enumerate(cls.conf[name].split(':')):
  435. user_list[idx].__init__(u)
  436. @classmethod
  437. def check_users_exist(cls):
  438. """
  439. Check whether the user is exist or not
  440. """
  441. testusersexist = True
  442. for u in [TEST_USER, TEST_USER1, TEST_USER2, TEST_USER3]:
  443. rv = cls.du.check_user_exists(str(u))
  444. if not rv:
  445. _msg = 'User ' + str(u) + ' does not exist!'
  446. raise setUpClassError(_msg)
  447. return testusersexist
  448. @classmethod
  449. def kicksched_action(cls, server, obj_type, *args, **kwargs):
  450. """
  451. custom scheduler action to kick a scheduling cycle when expectig
  452. a job state change
  453. """
  454. if server is None:
  455. cls.logger.error('no server defined for custom action')
  456. return
  457. if obj_type == JOB:
  458. if (('scheduling' in server.attributes) and
  459. (server.attributes['scheduling'] != 'False')):
  460. server.manager(MGR_CMD_SET, MGR_OBJ_SERVER,
  461. {'scheduling': 'True'},
  462. level=logging.DEBUG)
  463. @classmethod
  464. def parse_param(cls):
  465. """
  466. get test configuration parameters as a ``comma-separated``
  467. list of attributes.
  468. Attributes may be ``'='`` separated key value pairs or standalone
  469. entries.
  470. ``Multi-property`` attributes are colon-delimited.
  471. """
  472. if cls.param is None:
  473. return
  474. for h in cls.param.split(','):
  475. if '=' in h:
  476. k, v = h.split('=')
  477. cls.conf[k.strip()] = v.strip()
  478. else:
  479. cls.conf[h.strip()] = ''
  480. if (('clienthost' in cls.conf) and
  481. not isinstance(cls.conf['clienthost'], list)):
  482. cls.conf['clienthost'] = cls.conf['clienthost'].split(':')
  483. users_map = [('test-users', PBS_USERS),
  484. ('oper-users', PBS_OPER_USERS),
  485. ('mgr-users', PBS_MGR_USERS),
  486. ('data-users', PBS_DATA_USERS),
  487. ('root-users', PBS_ROOT_USERS),
  488. ('build-users', PBS_BUILD_USERS)]
  489. for k, v in users_map:
  490. cls._set_user(k, v)
  491. @classmethod
  492. def init_param(cls):
  493. cls._validate_param('revert-to-defaults')
  494. cls._validate_param('server-revert-to-defaults')
  495. cls._validate_param('comm-revert-to-defaults')
  496. cls._validate_param('mom-revert-to-defaults')
  497. cls._validate_param('sched-revert-to-defaults')
  498. cls._validate_param('del-hooks')
  499. cls._validate_param('revert-hooks')
  500. cls._validate_param('del-queues')
  501. cls._validate_param('del-vnodes')
  502. cls._validate_param('revert-queues')
  503. cls._validate_param('revert-resources')
  504. if 'default-testcase-timeout' not in cls.conf.keys():
  505. cls.conf['default_testcase_timeout'] = MINIMUM_TESTCASE_TIMEOUT
  506. else:
  507. cls.conf['default_testcase_timeout'] = int(
  508. cls.conf['default-testcase-timeout'])
  509. @classmethod
  510. def is_server_licensed(cls, server):
  511. """
  512. Check if server is licensed or not
  513. """
  514. for i in range(0, 10, 1):
  515. lic = server.status(SERVER, 'license_count', level=logging.INFOCLI)
  516. if lic and 'license_count' in lic[0]:
  517. lic = PbsTypeLicenseCount(lic[0]['license_count'])
  518. if ('Avail_Nodes' in lic) and (int(lic['Avail_Nodes']) > 0):
  519. return True
  520. elif (('Avail_Sockets' in lic) and
  521. (int(lic['Avail_Sockets']) > 0)):
  522. return True
  523. elif (('Avail_Global' in lic) and
  524. (int(lic['Avail_Global']) > 0)):
  525. return True
  526. elif ('Avail_Local' in lic) and (int(lic['Avail_Local']) > 0):
  527. return True
  528. time.sleep(i)
  529. return False
  530. @classmethod
  531. def init_from_conf(cls, conf, single=None, multiple=None, skip=None,
  532. func=None):
  533. """
  534. Helper method to parse test parameters for`` mom/server/scheduler``
  535. instances.
  536. The supported format of each service request is:
  537. ``hostname@configuration/path``
  538. For example:
  539. ``pbs_benchpress -p server=remote@/etc/pbs.conf.12.0``
  540. initializes a remote server instance that is configured according to
  541. the remote file ``/etc/pbs.conf.12.0``
  542. """
  543. endpoints = []
  544. if ((multiple in conf) and (conf[multiple] is not None)):
  545. __objs = conf[multiple].split(':')
  546. for _m in __objs:
  547. tmp = _m.split('@')
  548. if len(tmp) == 2:
  549. endpoints.append(tuple(tmp))
  550. elif len(tmp) == 1:
  551. endpoints.append((tmp[0], None))
  552. elif ((single in conf) and (conf[single] is not None)):
  553. tmp = conf[single].split('@')
  554. if len(tmp) == 2:
  555. endpoints.append(tuple(tmp))
  556. elif len(tmp) == 1:
  557. endpoints.append((tmp[0], None))
  558. else:
  559. endpoints = [(socket.gethostname(), None)]
  560. objs = PBSServiceInstanceWrapper()
  561. for name, objconf in endpoints:
  562. if ((skip is not None) and (skip in conf) and
  563. ((name in conf[skip]) or (conf[skip] in name))):
  564. continue
  565. if objconf is not None:
  566. n = name + '@' + objconf
  567. else:
  568. n = name
  569. if getattr(cls, "server", None) is not None:
  570. objs[n] = func(name, pbsconf_file=objconf,
  571. server=cls.server.hostname)
  572. else:
  573. objs[n] = func(name, pbsconf_file=objconf)
  574. if objs[n] is None:
  575. _msg = 'Failed %s(%s, %s)' % (func.__name__, name, objconf)
  576. raise setUpClassError(_msg)
  577. objs[n].initialise_service()
  578. return objs
  579. @classmethod
  580. def init_servers(cls, init_server_func=None, skip=None):
  581. """
  582. Initialize servers
  583. """
  584. if init_server_func is None:
  585. init_server_func = cls.init_server
  586. if 'servers' in cls.conf:
  587. if 'comms' not in cls.conf:
  588. cls.conf['comms'] = cls.conf['servers']
  589. if 'schedulers' not in cls.conf:
  590. cls.conf['schedulers'] = cls.conf['servers']
  591. if 'moms' not in cls.conf:
  592. cls.conf['moms'] = cls.conf['servers']
  593. if 'server' in cls.conf:
  594. if 'comm' not in cls.conf:
  595. cls.conf['comm'] = cls.conf['server']
  596. if 'scheduler' not in cls.conf:
  597. cls.conf['scheduler'] = cls.conf['server']
  598. if 'mom' not in cls.conf:
  599. cls.conf['mom'] = cls.conf['server']
  600. cls.servers = cls.init_from_conf(conf=cls.conf, single='server',
  601. multiple='servers', skip=skip,
  602. func=init_server_func)
  603. if cls.servers:
  604. cls.server = cls.servers.values()[0]
  605. @classmethod
  606. def init_comms(cls, init_comm_func=None, skip=None):
  607. """
  608. Initialize comms
  609. """
  610. if init_comm_func is None:
  611. init_comm_func = cls.init_comm
  612. cls.comms = cls.init_from_conf(conf=cls.conf,
  613. single='comm',
  614. multiple='comms', skip=skip,
  615. func=init_comm_func)
  616. if cls.comms:
  617. cls.comm = cls.comms.values()[0]
  618. @classmethod
  619. def init_schedulers(cls, init_sched_func=None, skip=None):
  620. """
  621. Initialize schedulers
  622. """
  623. if init_sched_func is None:
  624. init_sched_func = cls.init_scheduler
  625. cls.scheds = cls.init_from_conf(conf=cls.conf,
  626. single='scheduler',
  627. multiple='schedulers', skip=skip,
  628. func=init_sched_func)
  629. for sched in cls.scheds.values():
  630. if sched.server.name in cls.schedulers:
  631. continue
  632. else:
  633. cls.schedulers[sched.server.name] = sched.server.schedulers
  634. # creating a short hand for current host server.schedulers
  635. cls.scheds = cls.server.schedulers
  636. cls.scheduler = cls.scheds['default']
  637. @classmethod
  638. def init_moms(cls, init_mom_func=None, skip='nomom'):
  639. """
  640. Initialize moms
  641. """
  642. if init_mom_func is None:
  643. init_mom_func = cls.init_mom
  644. cls.moms = cls.init_from_conf(conf=cls.conf, single='mom',
  645. multiple='moms', skip=skip,
  646. func=init_mom_func)
  647. if cls.moms:
  648. cls.mom = cls.moms.values()[0]
  649. cls.server.moms = cls.moms
  650. @classmethod
  651. def init_server(cls, hostname, pbsconf_file=None):
  652. """
  653. Initialize a server instance
  654. Define custom expect action to trigger a scheduling cycle when job
  655. is not in running state
  656. :returns: The server instance on success and None on failure
  657. """
  658. client = hostname
  659. client_conf = None
  660. if 'client' in cls.conf:
  661. _cl = cls.conf['client'].split('@')
  662. client = _cl[0]
  663. if len(_cl) > 1:
  664. client_conf = _cl[1]
  665. server = Server(hostname, pbsconf_file=pbsconf_file, client=client,
  666. client_pbsconf_file=client_conf)
  667. server._conn_timeout = 0
  668. if cls.conf is not None:
  669. if 'mode' in cls.conf:
  670. if cls.conf['mode'] == 'cli':
  671. server.set_op_mode(PTL_CLI)
  672. if 'conn_timeout' in cls.conf:
  673. conn_timeout = int(cls.conf['conn_timeout'])
  674. server.set_connect_timeout(conn_timeout)
  675. sched_action = ExpectAction('kicksched', True, JOB,
  676. cls.kicksched_action)
  677. server.add_expect_action(action=sched_action)
  678. return server
  679. @classmethod
  680. def init_comm(cls, hostname, pbsconf_file=None, server=None):
  681. """
  682. Initialize a Comm instance associated to the given hostname.
  683. This method must be called after init_server
  684. :param hostname: The host on which the Comm is running
  685. :type hostname: str
  686. :param pbsconf_file: Optional path to an alternate pbs config file
  687. :type pbsconf_file: str or None
  688. :returns: The instantiated Comm upon success and None on failure.
  689. :param server: The server name associated to the Comm
  690. :type server: str
  691. Return the instantiated Comm upon success and None on failure.
  692. """
  693. try:
  694. server = cls.servers[server]
  695. except:
  696. server = None
  697. return Comm(hostname, pbsconf_file=pbsconf_file, server=server)
  698. @classmethod
  699. def init_scheduler(cls, hostname, pbsconf_file=None, server=None):
  700. """
  701. Initialize a Scheduler instance associated to the given server.
  702. This method must be called after ``init_server``
  703. :param server: The server name associated to the scheduler
  704. :type server: str
  705. :param pbsconf_file: Optional path to an alternate config file
  706. :type pbsconf_file: str or None
  707. :param hostname: The host on which Sched is running
  708. :type hostname: str
  709. :returns: The instantiated scheduler upon success and None on failure
  710. """
  711. try:
  712. server = cls.servers[server]
  713. except:
  714. server = None
  715. return Scheduler(hostname=hostname, server=server,
  716. pbsconf_file=pbsconf_file)
  717. @classmethod
  718. def init_mom(cls, hostname, pbsconf_file=None, server=None):
  719. """
  720. Initialize a ``MoM`` instance associated to the given hostname.
  721. This method must be called after ``init_server``
  722. :param hostname: The host on which the MoM is running
  723. :type hostname: str
  724. :param pbsconf_file: Optional path to an alternate pbs config file
  725. :type pbsconf_file: str or None
  726. :returns: The instantiated MoM upon success and None on failure.
  727. """
  728. try:
  729. server = cls.servers[server]
  730. except:
  731. server = None
  732. return MoM(hostname, pbsconf_file=pbsconf_file, server=server)
  733. def init_proc_mon(self):
  734. """
  735. Initialize process monitoring when requested
  736. """
  737. if 'procmon' in self.conf:
  738. _proc_mon = []
  739. for p in self.conf['procmon'].split(':'):
  740. _proc_mon += ['.*' + p + '.*']
  741. if _proc_mon:
  742. if 'procmon-freq' in self.conf:
  743. freq = int(self.conf['procmon-freq'])
  744. else:
  745. freq = 10
  746. self.start_proc_monitor(name='|'.join(_proc_mon), regexp=True,
  747. frequency=freq)
  748. self._process_monitoring = True
  749. def _get_dflt_pbsconfval(self, conf, svr_hostname, hosttype, hostobj):
  750. """
  751. Helper function to revert_pbsconf, tries to determine and return
  752. default value for the pbs.conf variable given
  753. :param conf: the pbs.conf variable
  754. :type conf: str
  755. :param svr_hostname: hostname of the server host
  756. :type svr_hostname: str
  757. :param hosttype: type of host being reverted
  758. :type hosttype: str
  759. :param hostobj: PTL object associated with the host
  760. :type hostobj: PBSService
  761. :return default value of the pbs.conf variable if it can be determined
  762. as a string, otherwise None
  763. """
  764. if conf == "PBS_SERVER":
  765. return svr_hostname
  766. elif conf == "PBS_START_SCHED":
  767. if hosttype == "server":
  768. return "1"
  769. else:
  770. return "0"
  771. elif conf == "PBS_START_COMM":
  772. if hosttype == "comm":
  773. return "1"
  774. else:
  775. return "0"
  776. elif conf == "PBS_START_SERVER":
  777. if hosttype == "server":
  778. return "1"
  779. else:
  780. return "0"
  781. elif conf == "PBS_START_MOM":
  782. if hosttype == "mom":
  783. return "1"
  784. else:
  785. return "0"
  786. elif conf == "PBS_CORE_LIMIT":
  787. return "unlimited"
  788. elif conf == "PBS_SCP":
  789. scppath = self.du.which(hostobj.hostname, "scp")
  790. if scppath != "scp":
  791. return scppath
  792. return None
  793. def _revert_pbsconf_comm(self, primary_server, vals_to_set):
  794. """
  795. Helper function to revert_pbsconf to revert all comm daemons' pbs.conf
  796. :param primary_server: object of the primary PBS server
  797. :type primary_server: PBSService
  798. :param vals_to_set: dict of pbs.conf values to set
  799. :type vals_to_set: dict
  800. """
  801. svr_hostnames = [svr.hostname for svr in self.servers.values()]
  802. for comm in self.comms.values():
  803. if comm.hostname in svr_hostnames:
  804. continue
  805. new_pbsconf = dict(vals_to_set)
  806. restart_comm = False
  807. pbs_conf_val = self.du.parse_pbs_config(comm.hostname)
  808. if not pbs_conf_val:
  809. raise ValueError("Could not parse pbs.conf on host %s" %
  810. (comm.hostname))
  811. # to start with, set all keys in new_pbsconf with values from the
  812. # existing pbs.conf
  813. keys_to_delete = []
  814. for conf in new_pbsconf:
  815. if conf in pbs_conf_val:
  816. new_pbsconf[conf] = pbs_conf_val[conf]
  817. else:
  818. # existing pbs.conf doesn't have a default variable set
  819. # Try to determine the default
  820. val = self._get_dflt_pbsconfval(conf,
  821. primary_server.hostname,
  822. "comm", comm)
  823. if val is None:
  824. self.logger.error("Couldn't revert %s in pbs.conf"
  825. " to its default value" %
  826. (conf))
  827. keys_to_delete.append(conf)
  828. else:
  829. new_pbsconf[conf] = val
  830. for key in keys_to_delete:
  831. del(new_pbsconf[key])
  832. # Set the comm start bit to 1
  833. if new_pbsconf["PBS_START_COMM"] != "1":
  834. new_pbsconf["PBS_START_COMM"] = "1"
  835. restart_comm = True
  836. # Set PBS_CORE_LIMIT, PBS_SCP and PBS_SERVER
  837. if new_pbsconf["PBS_CORE_LIMIT"] != "unlimited":
  838. new_pbsconf["PBS_CORE_LIMIT"] = "unlimited"
  839. restart_comm = True
  840. if new_pbsconf["PBS_SERVER"] != primary_server.hostname:
  841. new_pbsconf["PBS_SERVER"] = primary_server.hostname
  842. restart_comm = True
  843. if "PBS_SCP" not in new_pbsconf:
  844. scppath = self.du.which(comm.hostname, "scp")
  845. if scppath != "scp":
  846. new_pbsconf["PBS_SCP"] = scppath
  847. restart_comm = True
  848. # Check if existing pbs.conf has more/less entries than the
  849. # default list
  850. if len(pbs_conf_val) != len(new_pbsconf):
  851. restart_comm = True
  852. if restart_comm:
  853. self.du.set_pbs_config(comm.hostname, confs=new_pbsconf)
  854. comm.pbs_conf = new_pbsconf
  855. comm.pi.initd(comm.hostname, "restart", daemon="comm")
  856. def _revert_pbsconf_mom(self, primary_server, vals_to_set):
  857. """
  858. Helper function to revert_pbsconf to revert all mom daemons' pbs.conf
  859. :param primary_server: object of the primary PBS server
  860. :type primary_server: PBSService
  861. :param vals_to_set: dict of pbs.conf values to set
  862. :type vals_to_set: dict
  863. """
  864. svr_hostnames = [svr.hostname for svr in self.servers.values()]
  865. for mom in self.moms.values():
  866. if mom.hostname in svr_hostnames:
  867. continue
  868. new_pbsconf = dict(vals_to_set)
  869. restart_mom = False
  870. pbs_conf_val = self.du.parse_pbs_config(mom.hostname)
  871. if not pbs_conf_val:
  872. raise ValueError("Could not parse pbs.conf on host %s" %
  873. (mom.hostname))
  874. # to start with, set all keys in new_pbsconf with values from the
  875. # existing pbs.conf
  876. keys_to_delete = []
  877. for conf in new_pbsconf:
  878. if conf in pbs_conf_val:
  879. new_pbsconf[conf] = pbs_conf_val[conf]
  880. else:
  881. # existing pbs.conf doesn't have a default variable set
  882. # Try to determine the default
  883. val = self._get_dflt_pbsconfval(conf,
  884. primary_server.hostname,
  885. "mom", mom)
  886. if val is None:
  887. self.logger.error("Couldn't revert %s in pbs.conf"
  888. " to its default value" %
  889. (conf))
  890. keys_to_delete.append(conf)
  891. else:
  892. new_pbsconf[conf] = val
  893. for key in keys_to_delete:
  894. del(new_pbsconf[key])
  895. # Set the mom start bit to 1
  896. if (new_pbsconf["PBS_START_MOM"] != "1"):
  897. new_pbsconf["PBS_START_MOM"] = "1"
  898. restart_mom = True
  899. # Set PBS_CORE_LIMIT, PBS_SCP and PBS_SERVER
  900. if new_pbsconf["PBS_CORE_LIMIT"] != "unlimited":
  901. new_pbsconf["PBS_CORE_LIMIT"] = "unlimited"
  902. restart_mom = True
  903. if new_pbsconf["PBS_SERVER"] != primary_server.hostname:
  904. new_pbsconf["PBS_SERVER"] = primary_server.hostname
  905. restart_mom = True
  906. if "PBS_SCP" not in new_pbsconf:
  907. scppath = self.du.which(mom.hostname, "scp")
  908. if scppath != "scp":
  909. new_pbsconf["PBS_SCP"] = scppath
  910. restart_mom = True
  911. # Check if existing pbs.conf has more/less entries than the
  912. # default list
  913. if len(pbs_conf_val) != len(new_pbsconf):
  914. restart_mom = True
  915. if restart_mom:
  916. self.du.set_pbs_config(mom.hostname, confs=new_pbsconf,
  917. append=False)
  918. mom.pbs_conf = new_pbsconf
  919. mom.pi.initd(mom.hostname, "restart", daemon="mom")
  920. def _revert_pbsconf_server(self, vals_to_set):
  921. """
  922. Helper function to revert_pbsconf to revert all servers' pbs.conf
  923. :param vals_to_set: dict of pbs.conf values to set
  924. :type vals_to_set: dict
  925. """
  926. for server in self.servers.values():
  927. new_pbsconf = dict(vals_to_set)
  928. cmds_to_exec = []
  929. dmns_to_restart = 0
  930. restart_pbs = False
  931. pbs_conf_val = self.du.parse_pbs_config(server.hostname)
  932. if not pbs_conf_val:
  933. raise ValueError("Could not parse pbs.conf on host %s" %
  934. (server.hostname))
  935. # to start with, set all keys in new_pbsconf with values from the
  936. # existing pbs.conf
  937. keys_to_delete = []
  938. for conf in new_pbsconf:
  939. if conf in pbs_conf_val:
  940. new_pbsconf[conf] = pbs_conf_val[conf]
  941. else:
  942. # existing pbs.conf doesn't have a default variable set
  943. # Try to determine the default
  944. val = self._get_dflt_pbsconfval(conf,
  945. server.hostname,
  946. "server", server)
  947. if val is None:
  948. self.logger.error("Couldn't revert %s in pbs.conf"
  949. " to its default value" %
  950. (conf))
  951. keys_to_delete.append(conf)
  952. else:
  953. new_pbsconf[conf] = val
  954. for key in keys_to_delete:
  955. del(new_pbsconf[key])
  956. # Set all start bits
  957. if (new_pbsconf["PBS_START_SERVER"] != "1"):
  958. new_pbsconf["PBS_START_SERVER"] = "1"
  959. dmns_to_restart += 1
  960. cmds_to_exec.append(["server", "start"])
  961. if (new_pbsconf["PBS_START_SCHED"] != "1"):
  962. new_pbsconf["PBS_START_SCHED"] = "1"
  963. cmds_to_exec.append(["sched", "start"])
  964. dmns_to_restart += 1
  965. if self.moms and server.hostname not in self.moms:
  966. if new_pbsconf["PBS_START_MOM"] != "0":
  967. new_pbsconf["PBS_START_MOM"] = "0"
  968. cmds_to_exec.append(["mom", "stop"])
  969. dmns_to_restart += 1
  970. else:
  971. if (new_pbsconf["PBS_START_MOM"] != "1"):
  972. new_pbsconf["PBS_START_MOM"] = "1"
  973. cmds_to_exec.append(["mom", "start"])
  974. dmns_to_restart += 1
  975. if self.comms and server.hostname not in self.comms:
  976. if new_pbsconf["PBS_START_COMM"] != "0":
  977. new_pbsconf["PBS_START_COMM"] = "0"
  978. cmds_to_exec.append(["comm", "stop"])
  979. else:
  980. if (new_pbsconf["PBS_START_COMM"] != "1"):
  981. new_pbsconf["PBS_START_COMM"] = "1"
  982. cmds_to_exec.append(["comm", "start"])
  983. dmns_to_restart += 1
  984. if dmns_to_restart == 4:
  985. # If all daemons need to be started again, just restart PBS
  986. # instead of making PTL start each of them one at a time
  987. restart_pbs = True
  988. # Set PBS_CORE_LIMIT, PBS_SCP and PBS_SERVER
  989. if new_pbsconf["PBS_CORE_LIMIT"] != "unlimited":
  990. new_pbsconf["PBS_CORE_LIMIT"] = "unlimited"
  991. restart_pbs = True
  992. if new_pbsconf["PBS_SERVER"] != server.shortname:
  993. new_pbsconf["PBS_SERVER"] = server.shortname
  994. restart_pbs = True
  995. if "PBS_SCP" not in new_pbsconf:
  996. scppath = self.du.which(server.hostname, "scp")
  997. if scppath != "scp":
  998. new_pbsconf["PBS_SCP"] = scppath
  999. restart_pbs = True
  1000. # Check if existing pbs.conf has more/less entries than the
  1001. # default list
  1002. if len(pbs_conf_val) != len(new_pbsconf):
  1003. restart_pbs = True
  1004. if restart_pbs or dmns_to_restart > 0:
  1005. # Write out the new pbs.conf file
  1006. self.du.set_pbs_config(server.hostname, confs=new_pbsconf,
  1007. append=False)
  1008. server.pbs_conf = new_pbsconf
  1009. if restart_pbs:
  1010. # Restart all
  1011. server.pi.restart(server.hostname)
  1012. else:
  1013. for initcmd in cmds_to_exec:
  1014. # start/stop the particular daemon
  1015. server.pi.initd(server.hostname, initcmd[1],
  1016. daemon=initcmd[0])
  1017. def revert_pbsconf(self):
  1018. """
  1019. Revert contents of the pbs.conf file
  1020. Also start/stop the appropriate daemons
  1021. """
  1022. primary_server = self.server
  1023. vals_to_set = {
  1024. "PBS_HOME": None,
  1025. "PBS_EXEC": None,
  1026. "PBS_SERVER": None,
  1027. "PBS_START_SCHED": None,
  1028. "PBS_START_COMM": None,
  1029. "PBS_START_SERVER": None,
  1030. "PBS_START_MOM": None,
  1031. "PBS_CORE_LIMIT": None,
  1032. "PBS_SCP": None
  1033. }
  1034. self._revert_pbsconf_server(vals_to_set)
  1035. self._revert_pbsconf_mom(primary_server, vals_to_set)
  1036. self._revert_pbsconf_comm(primary_server, vals_to_set)
  1037. def revert_servers(self, force=False):
  1038. """
  1039. Revert the values set for servers
  1040. """
  1041. for server in self.servers.values():
  1042. self.revert_server(server, force)
  1043. def revert_comms(self, force=False):
  1044. """
  1045. Revert the values set for comms
  1046. """
  1047. for comm in self.comms.values():
  1048. self.revert_comm(comm, force)
  1049. def revert_schedulers(self, force=False):
  1050. """
  1051. Revert the values set for schedulers
  1052. """
  1053. for scheds in self.schedulers.values():
  1054. if 'default' in scheds:
  1055. self.revert_scheduler(scheds['default'], force)
  1056. def revert_moms(self, force=False):
  1057. """
  1058. Revert the values set for moms
  1059. """
  1060. self.del_all_nodes = True
  1061. for mom in self.moms.values():
  1062. self.revert_mom(mom, force)
  1063. def revert_server(self, server, force=False):
  1064. """
  1065. Revert the values set for server
  1066. """
  1067. rv = server.isUp()
  1068. if not rv:
  1069. self.logger.error('server ' + server.hostname + ' is down')
  1070. server.start()
  1071. msg = 'Failed to restart server ' + server.hostname
  1072. self.assertTrue(server.isUp(), msg)
  1073. server_stat = server.status(SERVER)[0]
  1074. current_user = pwd.getpwuid(os.getuid())[0]
  1075. try:
  1076. # Unset managers list
  1077. server.manager(MGR_CMD_UNSET, SERVER, 'managers', sudo=True,
  1078. expect=True)
  1079. except PbsManagerError as e:
  1080. self.logger.error(e.msg)
  1081. a = {ATTR_managers: (INCR, current_user + '@*')}
  1082. server.manager(MGR_CMD_SET, SERVER, a, sudo=True)
  1083. if ((self.revert_to_defaults and self.server_revert_to_defaults) or
  1084. force):
  1085. server.revert_to_defaults(reverthooks=self.revert_hooks,
  1086. delhooks=self.del_hooks,
  1087. revertqueues=self.revert_queues,
  1088. delqueues=self.del_queues,
  1089. delscheds=self.del_scheds,
  1090. revertresources=self.revert_resources,
  1091. server_stat=server_stat)
  1092. rv = self.is_server_licensed(server)
  1093. _msg = 'No license found on server %s' % (server.shortname)
  1094. self.assertTrue(rv, _msg)
  1095. self.logger.info('server: %s licensed', server.hostname)
  1096. def revert_comm(self, comm, force=False):
  1097. """
  1098. Revert the values set for comm
  1099. """
  1100. rv = comm.isUp()
  1101. if not rv:
  1102. self.logger.error('comm ' + comm.hostname + ' is down')
  1103. comm.start()
  1104. msg = 'Failed to restart comm ' + comm.hostname
  1105. self.assertTrue(comm.isUp(), msg)
  1106. def revert_scheduler(self, scheduler, force=False):
  1107. """
  1108. Revert the values set for scheduler
  1109. """
  1110. rv = scheduler.isUp()
  1111. if not rv:
  1112. self.logger.error('scheduler ' + scheduler.hostname + ' is down')
  1113. scheduler.start()
  1114. msg = 'Failed to restart scheduler ' + scheduler.hostname
  1115. self.assertTrue(scheduler.isUp(), msg)
  1116. if ((self.revert_to_defaults and self.sched_revert_to_defaults) or
  1117. force):
  1118. rv = scheduler.revert_to_defaults()
  1119. _msg = 'Failed to revert sched %s' % (scheduler.hostname)
  1120. self.assertTrue(rv, _msg)
  1121. def revert_mom(self, mom, force=False):
  1122. """
  1123. Revert the values set for mom
  1124. :param mom: the MoM object whose values are to be reverted
  1125. :type mom: MoM object
  1126. :param force: Option to reverse forcibly
  1127. :type force: bool
  1128. """
  1129. rv = mom.isUp()
  1130. if not rv:
  1131. self.logger.error('mom ' + mom.hostname + ' is down')
  1132. mom.start()
  1133. msg = 'Failed to restart mom ' + mom.hostname
  1134. self.assertTrue(mom.isUp(), msg)
  1135. mom.pbs_version()
  1136. if ((self.revert_to_defaults and self.mom_revert_to_defaults) or
  1137. force):
  1138. rv = mom.revert_to_defaults(delvnodedefs=self.del_vnodes)
  1139. _msg = 'Failed to revert mom %s' % (mom.hostname)
  1140. self.assertTrue(rv, _msg)
  1141. if 'clienthost' in self.conf:
  1142. mom.add_config({'$clienthost': self.conf['clienthost']})
  1143. a = {'state': 'free', 'resources_available.ncpus': (GE, 1)}
  1144. nodes = self.server.counter(NODE, a, attrop=PTL_AND,
  1145. level=logging.DEBUG)
  1146. if not nodes:
  1147. try:
  1148. self.server.manager(MGR_CMD_DELETE, NODE, None, '')
  1149. except:
  1150. pass
  1151. mom.delete_vnode_defs()
  1152. mom.delete_vnodes()
  1153. mom.restart()
  1154. self.logger.info('server: no nodes defined, creating one')
  1155. self.server.manager(MGR_CMD_CREATE, NODE, None, mom.shortname)
  1156. name = mom.shortname
  1157. if mom.platform == 'cray' or mom.platform == 'craysim':
  1158. # delete all nodes(@default) on first call of revert_mom
  1159. # and create all nodes specified by self.moms one by one
  1160. try:
  1161. if self.del_all_nodes:
  1162. self.server.manager(MGR_CMD_DELETE, NODE, None, '')
  1163. self.del_all_nodes = False
  1164. except:
  1165. pass
  1166. self.server.manager(MGR_CMD_CREATE, NODE, None, name)
  1167. else:
  1168. try:
  1169. self.server.status(NODE, id=name)
  1170. except PbsStatusError:
  1171. # server doesn't have node with shortname
  1172. # check with hostname
  1173. name = mom.hostname
  1174. try:
  1175. self.server.status(NODE, id=name)
  1176. except PbsStatusError:
  1177. # server doesn't have node for this mom yet
  1178. # so create with shortname
  1179. name = mom.shortname
  1180. self.server.manager(MGR_CMD_CREATE, NODE, None,
  1181. mom.shortname)
  1182. self.server.expect(NODE, {ATTR_NODE_state: 'free'}, id=name,
  1183. interval=1)
  1184. return mom
  1185. def analyze_logs(self):
  1186. """
  1187. analyze accounting and scheduler logs from time test was started
  1188. until it finished
  1189. """
  1190. pla = PBSLogAnalyzer()
  1191. self.metrics_data = pla.analyze_logs(serverlog=self.server.logfile,
  1192. schedlog=self.scheduler.logfile,
  1193. momlog=self.mom.logfile,
  1194. acctlog=self.server.acctlogfile,
  1195. start=self.server.ctime,
  1196. end=int(time.time()))
  1197. def set_test_measurements(self, mdic=None):
  1198. """
  1199. set dictionary of analytical results of the test
  1200. in order to include it in test report
  1201. :param mdic: dictionary with analytical data
  1202. :type mdic: dict
  1203. :returns: True on successful append or False on failure
  1204. """
  1205. if not (mdic and isinstance(mdic, dict)):
  1206. return False
  1207. self.measurements.append(mdic)
  1208. return True
  1209. def add_additional_data_to_report(self, datadic=None):
  1210. """
  1211. set dictionary that will be merged with the test report
  1212. for the overall test run
  1213. :param datadic: dictionary with analytical data
  1214. :type datadic: dict
  1215. :returns: True on succssful update or False on failure
  1216. """
  1217. if not (datadic and isinstance(datadic, dict)):
  1218. return False
  1219. self.additional_data.update(datadic)
  1220. return True
  1221. def start_proc_monitor(self, name=None, regexp=False, frequency=60):
  1222. """
  1223. Start the process monitoring
  1224. :param name: Process name
  1225. :type name: str or None
  1226. :param regexp: Regular expression to match
  1227. :type regexp: bool
  1228. :param frequency: Frequency of monitoring
  1229. :type frequency: int
  1230. """
  1231. if self._procmon is not None:
  1232. self.logger.info('A process monitor is already instantiated')
  1233. return
  1234. self.logger.info('starting process monitoring of ' + name +
  1235. ' every ' + str(frequency) + 'seconds')
  1236. self._procmon = ProcMonitor(name=name, regexp=regexp,
  1237. frequency=frequency)
  1238. self._procmon.start()
  1239. def stop_proc_monitor(self):
  1240. """
  1241. Stop the process monitoring
  1242. """
  1243. if not self._process_monitoring:
  1244. return
  1245. self.logger.info('stopping process monitoring')
  1246. self._procmon.stop()
  1247. self.metrics_data['procs'] = self._procmon.db_proc_info
  1248. self._process_monitoring = False
  1249. def skipTest(self, reason=None):
  1250. """
  1251. Skip Test
  1252. :param reason: message to indicate why test is skipped
  1253. :type reason: str or None
  1254. """
  1255. if reason:
  1256. self.logger.warning('test skipped: ' + reason)
  1257. else:
  1258. reason = 'unknown'
  1259. raise SkipTest(reason)
  1260. skip_test = skipTest
  1261. @classmethod
  1262. def log_enter_teardown(cls, iscls=False):
  1263. _m = ' Entered ' + cls.__name__ + ' tearDown'
  1264. if iscls:
  1265. _m += 'Class'
  1266. _m_len = len(_m)
  1267. cls.logger.info('=' * _m_len)
  1268. cls.logger.info(_m)
  1269. cls.logger.info('=' * _m_len)
  1270. @classmethod
  1271. def log_end_teardown(cls, iscls=False):
  1272. _m = 'Completed ' + cls.__name__ + ' tearDown'
  1273. if iscls:
  1274. _m += 'Class'
  1275. _m_len = len(_m)
  1276. cls.logger.info('=' * _m_len)
  1277. cls.logger.info(_m)
  1278. cls.logger.info('=' * _m_len)
  1279. def tearDown(self):
  1280. """
  1281. verify that ``server`` and ``scheduler`` are up
  1282. clean up jobs and reservations
  1283. """
  1284. if 'skip-teardown' in self.conf:
  1285. return
  1286. self.log_enter_teardown()
  1287. self.stop_proc_monitor()
  1288. self.log_end_teardown()
  1289. @classmethod
  1290. def tearDownClass(cls):
  1291. cls._testMethodName = 'tearDownClass'