corotests.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. __copyright__='''
  2. Copyright (c) 2010 Red Hat, Inc.
  3. '''
  4. # All rights reserved.
  5. #
  6. # Author: Angus Salkeld <asalkeld@redhat.com>
  7. #
  8. # This software licensed under BSD license, the text of which follows:
  9. #
  10. # Redistribution and use in source and binary forms, with or without
  11. # modification, are permitted provided that the following conditions are met:
  12. #
  13. # - Redistributions of source code must retain the above copyright notice,
  14. # this list of conditions and the following disclaimer.
  15. # - Redistributions in binary form must reproduce the above copyright notice,
  16. # this list of conditions and the following disclaimer in the documentation
  17. # and/or other materials provided with the distribution.
  18. # - Neither the name of the MontaVista Software, Inc. nor the names of its
  19. # contributors may be used to endorse or promote products derived from this
  20. # software without specific prior written permission.
  21. #
  22. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  32. # THE POSSIBILITY OF SUCH DAMAGE.
  33. from cts.CTStests import *
  34. ###################################################################
  35. class CoroTest(CTSTest):
  36. '''
  37. basic class to make sure that new configuration is applied
  38. and old configuration is removed.
  39. '''
  40. def __init__(self, cm):
  41. CTSTest.__init__(self,cm)
  42. self.start = StartTest(cm)
  43. self.stop = StopTest(cm)
  44. self.config = {}
  45. self.need_all_up = True
  46. def setup(self, node):
  47. ret = CTSTest.setup(self, node)
  48. # setup the authkey
  49. localauthkey = '/tmp/authkey'
  50. if not os.path.exists(localauthkey):
  51. self.CM.rsh(node, 'corosync-keygen')
  52. self.CM.rsh.cp("%s:%s" % (node, "/etc/corosync/authkey"), localauthkey)
  53. for n in self.CM.Env["nodes"]:
  54. if n is not node:
  55. #copy key onto other nodes
  56. self.CM.rsh.cp(localauthkey, "%s:%s" % (n, "/etc/corosync/authkey"))
  57. # copy over any new config
  58. for c in self.config:
  59. self.CM.new_config[c] = self.config[c]
  60. # apply the config
  61. self.CM.apply_new_config()
  62. # start/stop all corosyncs'
  63. for n in self.CM.Env["nodes"]:
  64. if self.need_all_up and not self.CM.StataCM(n):
  65. self.incr("started")
  66. self.start(n)
  67. if not self.need_all_up and self.CM.StataCM(n):
  68. self.incr("stopped")
  69. self.stop(n)
  70. return ret
  71. def teardown(self, node):
  72. self.CM.apply_default_config()
  73. return CTSTest.teardown(self, node)
  74. ###################################################################
  75. class CpgConfigChangeBase(CoroTest):
  76. '''
  77. join a cpg group on each node, and test that the following
  78. causes a leave event:
  79. - a call to cpg_leave()
  80. - app exit
  81. - node leave
  82. - node leave (with large token timeout)
  83. '''
  84. def setup(self, node):
  85. ret = CoroTest.setup(self, node)
  86. self.listener = None
  87. self.wobbly = None
  88. for n in self.CM.Env["nodes"]:
  89. self.CM.cpg_agent[n].clean_start()
  90. self.CM.cpg_agent[n].cpg_join(self.name)
  91. if self.listener is None:
  92. self.listener = n
  93. elif self.wobbly is None:
  94. self.wobbly = n
  95. self.wobbly_id = self.CM.cpg_agent[self.wobbly].cpg_local_get()
  96. self.CM.cpg_agent[self.listener].record_config_events(truncate=True)
  97. return ret
  98. def wait_for_config_change(self):
  99. found = False
  100. max_timeout = 5 * 60
  101. waited = 0
  102. printit = 0
  103. self.CM.log("Waiting for config change on " + self.listener)
  104. while not found:
  105. try:
  106. event = self.CM.cpg_agent[self.listener].read_config_event()
  107. except:
  108. return self.failure('connection to test cpg_agent failed.')
  109. if not event == None:
  110. self.CM.debug("RECEIVED: " + str(event))
  111. if event == None:
  112. if waited >= max_timeout:
  113. return self.failure("timedout(" + str(waited) + " sec) == no event!")
  114. else:
  115. time.sleep(1)
  116. waited = waited + 1
  117. printit = printit + 1
  118. if printit is 60:
  119. print 'waited 60 seconds'
  120. printit = 0
  121. elif str(event.node_id) in str(self.wobbly_id) and not event.is_member:
  122. self.CM.log("Got the config change in " + str(waited) + " seconds")
  123. found = True
  124. else:
  125. self.CM.debug("No match")
  126. self.CM.debug("wobbly nodeid:" + str(self.wobbly_id))
  127. self.CM.debug("event nodeid:" + str(event.node_id))
  128. self.CM.debug("event.is_member:" + str(event.is_member))
  129. if found:
  130. return self.success()
  131. ###################################################################
  132. class CpgCfgChgOnGroupLeave(CpgConfigChangeBase):
  133. def __init__(self, cm):
  134. CpgConfigChangeBase.__init__(self,cm)
  135. self.name="CpgCfgChgOnGroupLeave"
  136. def failure_action(self):
  137. self.CM.log("calling cpg_leave() on " + self.wobbly)
  138. self.CM.cpg_agent[self.wobbly].cpg_leave(self.name)
  139. def __call__(self, node):
  140. self.incr("calls")
  141. self.failure_action()
  142. return self.wait_for_config_change()
  143. ###################################################################
  144. class CpgCfgChgOnNodeLeave(CpgConfigChangeBase):
  145. def __init__(self, cm):
  146. CpgConfigChangeBase.__init__(self,cm)
  147. self.name="CpgCfgChgOnNodeLeave"
  148. def failure_action(self):
  149. self.CM.log("stopping corosync on " + self.wobbly)
  150. self.stop(self.wobbly)
  151. def __call__(self, node):
  152. self.incr("calls")
  153. self.failure_action()
  154. return self.wait_for_config_change()
  155. ###################################################################
  156. class CpgCfgChgOnLowestNodeJoin(CTSTest):
  157. '''
  158. 1) stop all nodes
  159. 2) start all but the node with the smallest ip address
  160. 3) start recording events
  161. 4) start the last node
  162. '''
  163. def __init__(self, cm):
  164. CTSTest.__init__(self, cm)
  165. self.name="CpgCfgChgOnLowestNodeJoin"
  166. self.start = StartTest(cm)
  167. self.stop = StopTest(cm)
  168. self.config = {}
  169. self.need_all_up = False
  170. self.config['compatibility'] = 'none'
  171. def lowest_ip_set(self):
  172. self.lowest = None
  173. for n in self.CM.Env["nodes"]:
  174. if self.lowest is None:
  175. self.lowest = n
  176. self.CM.log("lowest node is " + self.lowest)
  177. def setup(self, node):
  178. # stop all nodes
  179. for n in self.CM.Env["nodes"]:
  180. self.CM.StopaCM(n)
  181. self.lowest_ip_set()
  182. # copy over any new config
  183. for c in self.config:
  184. self.CM.new_config[c] = self.config[c]
  185. # install the config
  186. self.CM.install_all_config()
  187. # start all but lowest
  188. self.listener = None
  189. for n in self.CM.Env["nodes"]:
  190. if n is not self.lowest:
  191. if self.listener is None:
  192. self.listener = n
  193. self.incr("started")
  194. self.CM.log("starting " + n)
  195. self.start(n)
  196. self.CM.cpg_agent[n].clean_start()
  197. self.CM.cpg_agent[n].cpg_join(self.name)
  198. # start recording events
  199. pats = []
  200. pats.append("%s .*sync: node joined.*" % self.listener)
  201. pats.append("%s .*sync: activate correctly.*" % self.listener)
  202. self.sync_log = self.create_watch(pats, 60)
  203. self.sync_log.setwatch()
  204. self.CM.log("setup done")
  205. return CTSTest.setup(self, node)
  206. def __call__(self, node):
  207. self.incr("calls")
  208. self.start(self.lowest)
  209. self.CM.cpg_agent[self.lowest].clean_start()
  210. self.CM.cpg_agent[self.lowest].cpg_join(self.name)
  211. self.wobbly_id = self.CM.cpg_agent[self.lowest].cpg_local_get()
  212. self.CM.log("waiting for sync events")
  213. if not self.sync_log.lookforall():
  214. return self.failure("Patterns not found: " + repr(self.sync_log.unmatched))
  215. else:
  216. return self.success()
  217. ###################################################################
  218. class CpgCfgChgOnExecCrash(CpgConfigChangeBase):
  219. def __init__(self, cm):
  220. CpgConfigChangeBase.__init__(self,cm)
  221. self.name="CpgCfgChgOnExecCrash"
  222. def failure_action(self):
  223. self.CM.log("sending KILL to corosync on " + self.wobbly)
  224. self.CM.rsh(self.wobbly, "killall -9 corosync")
  225. self.CM.rsh(self.wobbly, "rm -f /var/run/corosync.pid")
  226. self.CM.ShouldBeStatus[self.wobbly] = "down"
  227. def __call__(self, node):
  228. self.incr("calls")
  229. self.failure_action()
  230. return self.wait_for_config_change()
  231. ###################################################################
  232. class CpgCfgChgOnNodeIsolate(CpgConfigChangeBase):
  233. def __init__(self, cm):
  234. CpgConfigChangeBase.__init__(self,cm)
  235. self.name="CpgCfgChgOnNodeIsolate"
  236. def failure_action(self):
  237. self.CM.log("isolating node " + self.wobbly)
  238. self.CM.isolate_node(self.wobbly)
  239. def __call__(self, node):
  240. self.incr("calls")
  241. self.failure_action()
  242. return self.wait_for_config_change()
  243. def teardown(self, node):
  244. self.CM.unisolate_node (self.wobbly)
  245. return CpgConfigChangeBase.teardown(self, node)
  246. ###################################################################
  247. class CpgMsgOrderBase(CoroTest):
  248. def __init__(self, cm):
  249. CoroTest.__init__(self,cm)
  250. self.num_msgs_per_node = 0
  251. self.total_num_msgs = 0
  252. def setup(self, node):
  253. ret = CoroTest.setup(self, node)
  254. for n in self.CM.Env["nodes"]:
  255. self.total_num_msgs = self.total_num_msgs + self.num_msgs_per_node
  256. self.CM.cpg_agent[n].clean_start()
  257. self.CM.cpg_agent[n].cpg_join(self.name)
  258. self.CM.cpg_agent[n].record_messages()
  259. time.sleep(1)
  260. return ret
  261. def cpg_msg_blaster(self):
  262. for n in self.CM.Env["nodes"]:
  263. self.CM.cpg_agent[n].msg_blaster(self.num_msgs_per_node)
  264. def wait_and_validate_order(self):
  265. msgs = {}
  266. for n in self.CM.Env["nodes"]:
  267. msgs[n] = []
  268. stopped = False
  269. waited = 0
  270. while len(msgs[n]) < self.total_num_msgs and waited < 360:
  271. msg = self.CM.cpg_agent[n].read_messages(50)
  272. if not msg == None:
  273. msgl = msg.split(";")
  274. # remove empty entries
  275. not_done=True
  276. while not_done:
  277. try:
  278. msgl.remove('')
  279. except:
  280. not_done = False
  281. msgs[n].extend(msgl)
  282. elif msg == None:
  283. time.sleep(2)
  284. waited = waited + 2
  285. if len(msgs[n]) < self.total_num_msgs:
  286. return self.failure("expected %d messages from %s got %d" % (self.total_num_msgs, n, len(msgs[n])))
  287. fail = False
  288. error_message = ''
  289. for i in range(0, self.total_num_msgs):
  290. first = None
  291. for n in self.CM.Env["nodes"]:
  292. # first test for errors
  293. params = msgs[n][i].split(":")
  294. if not 'OK' in params[3]:
  295. fail = True
  296. error_message = 'error: ' + params[3] + ' in received message'
  297. self.CM.log(str(params))
  298. # then look for out of order messages
  299. if first == None:
  300. first = n
  301. else:
  302. if not msgs[first][i] == msgs[n][i]:
  303. # message order not the same!
  304. fail = True
  305. error_message = 'message out of order'
  306. self.CM.log(msgs[first][i] + " != " + msgs[n][i])
  307. if fail:
  308. return self.failure(error_message)
  309. else:
  310. return self.success()
  311. ###################################################################
  312. class CpgMsgOrderBasic(CpgMsgOrderBase):
  313. '''
  314. each sends & logs lots of messages
  315. '''
  316. def __init__(self, cm):
  317. CpgMsgOrderBase.__init__(self,cm)
  318. self.name="CpgMsgOrderBasic"
  319. self.num_msgs_per_node = 9000
  320. def __call__(self, node):
  321. self.incr("calls")
  322. for n in self.CM.Env["nodes"]:
  323. self.CM.cpg_agent[n].msg_blaster(self.num_msgs_per_node)
  324. return self.wait_and_validate_order()
  325. ###################################################################
  326. class CpgMsgOrderZcb(CpgMsgOrderBase):
  327. '''
  328. each sends & logs lots of messages
  329. '''
  330. def __init__(self, cm):
  331. CpgMsgOrderBase.__init__(self,cm)
  332. self.name="CpgMsgOrderZcb"
  333. self.num_msgs_per_node = 9000
  334. def __call__(self, node):
  335. self.incr("calls")
  336. for n in self.CM.Env["nodes"]:
  337. self.CM.cpg_agent[n].msg_blaster_zcb(self.num_msgs_per_node)
  338. return self.wait_and_validate_order()
  339. ###################################################################
  340. class MemLeakObject(CoroTest):
  341. '''
  342. run mem_leak_test.sh -1
  343. '''
  344. def __init__(self, cm):
  345. CoroTest.__init__(self,cm)
  346. self.name="MemLeakObject"
  347. def __call__(self, node):
  348. self.incr("calls")
  349. mem_leaked = self.CM.rsh(node, "/usr/share/corosync/tests/mem_leak_test.sh -1")
  350. if mem_leaked is 0:
  351. return self.success()
  352. else:
  353. return self.failure(str(mem_leaked) + 'kB memory leaked.')
  354. ###################################################################
  355. class MemLeakSession(CoroTest):
  356. '''
  357. run mem_leak_test.sh -2
  358. '''
  359. def __init__(self, cm):
  360. CoroTest.__init__(self,cm)
  361. self.name="MemLeakSession"
  362. def __call__(self, node):
  363. self.incr("calls")
  364. mem_leaked = self.CM.rsh(node, "/usr/share/corosync/tests/mem_leak_test.sh -2")
  365. if mem_leaked is 0:
  366. return self.success()
  367. else:
  368. return self.failure(str(mem_leaked) + 'kB memory leaked.')
  369. ###################################################################
  370. class ServiceLoadTest(CoroTest):
  371. '''
  372. Test loading and unloading of service engines
  373. '''
  374. def __init__(self, cm):
  375. CoroTest.__init__(self, cm)
  376. self.name="ServiceLoadTest"
  377. def is_loaded(self, node):
  378. check = 'corosync-objctl runtime.services. | grep evs'
  379. (res, out) = self.CM.rsh(node, check, stdout=2)
  380. if res is 0:
  381. return True
  382. else:
  383. return False
  384. def service_unload(self, node):
  385. # unload evs
  386. pats = []
  387. pats.append("%s .*Service engine unloaded: corosync extended.*" % node)
  388. unloaded = self.create_watch(pats, 60)
  389. unloaded.setwatch()
  390. self.CM.rsh(node, 'corosync-cfgtool -u corosync_evs')
  391. if not unloaded.lookforall():
  392. self.CM.log("Patterns not found: " + repr(unloaded.unmatched))
  393. self.error_message = "evs service not unloaded"
  394. return False
  395. if self.is_loaded(node):
  396. self.error_message = "evs has been unload, why are it's session objects are still there?"
  397. return False
  398. return True
  399. def service_load(self, node):
  400. # now reload it.
  401. pats = []
  402. pats.append("%s .*Service engine loaded.*" % node)
  403. loaded = self.create_watch(pats, 60)
  404. loaded.setwatch()
  405. self.CM.rsh(node, 'corosync-cfgtool -l corosync_evs')
  406. if not loaded.lookforall():
  407. self.CM.log("Patterns not found: " + repr(loaded.unmatched))
  408. self.error_message = "evs service not unloaded"
  409. return False
  410. return True
  411. def __call__(self, node):
  412. self.incr("calls")
  413. should_be_loaded = True
  414. if self.is_loaded(node):
  415. ret = self.service_unload(node)
  416. should_be_loaded = False
  417. else:
  418. ret = self.service_load(node)
  419. should_be_loaded = True
  420. if not ret:
  421. return self.failure(self.error_message)
  422. if self.is_loaded(node):
  423. ret = self.service_unload(node)
  424. else:
  425. ret = self.service_load(node)
  426. if not ret:
  427. return self.failure(self.error_message)
  428. return self.success()
  429. ###################################################################
  430. class ConfdbReplaceTest(CoroTest):
  431. def __init__(self, cm):
  432. CoroTest.__init__(self, cm)
  433. self.name="ConfdbReplaceTest"
  434. def __call__(self, node):
  435. self.incr("calls")
  436. res = self.CM.confdb_agent[node].set_get_test()
  437. if 'OK' in res:
  438. return self.success()
  439. else:
  440. return self.failure('set_get_test failed')
  441. ###################################################################
  442. class ConfdbIncrementTest(CoroTest):
  443. def __init__(self, cm):
  444. CoroTest.__init__(self, cm)
  445. self.name="ConfdbIncrementTest"
  446. def __call__(self, node):
  447. self.incr("calls")
  448. res = self.CM.confdb_agent[node].increment_decrement_test()
  449. if 'OK' in res:
  450. return self.success()
  451. else:
  452. return self.failure('increment_decrement_test failed')
  453. ###################################################################
  454. class ConfdbObjectFindTest(CoroTest):
  455. def __init__(self, cm):
  456. CoroTest.__init__(self, cm)
  457. self.name="ConfdbObjectFindTest"
  458. def __call__(self, node):
  459. self.incr("calls")
  460. res = self.CM.confdb_agent[node].object_find_test()
  461. if 'OK' in res:
  462. return self.success()
  463. else:
  464. return self.failure('object_find_test failed')
  465. ###################################################################
  466. class ConfdbNotificationTest(CoroTest):
  467. def __init__(self, cm):
  468. CoroTest.__init__(self, cm)
  469. self.name="ConfdbNotificationTest"
  470. def __call__(self, node):
  471. self.incr("calls")
  472. res = self.CM.confdb_agent[node].notification_test()
  473. if 'OK' in res:
  474. return self.success()
  475. else:
  476. return self.failure('notification_test failed')
  477. ###################################################################
  478. class SamTest1(CoroTest):
  479. def __init__(self, cm):
  480. CoroTest.__init__(self, cm)
  481. self.name="SamTest1"
  482. def __call__(self, node):
  483. self.incr("calls")
  484. res = self.CM.sam_agent[node].test1()
  485. if 'OK' in res:
  486. return self.success()
  487. else:
  488. return self.failure('sam test 1 failed')
  489. ###################################################################
  490. class SamTest2(CoroTest):
  491. def __init__(self, cm):
  492. CoroTest.__init__(self, cm)
  493. self.name="SamTest2"
  494. def __call__(self, node):
  495. self.incr("calls")
  496. res = self.CM.sam_agent[node].test2()
  497. if 'OK' in res:
  498. return self.success()
  499. else:
  500. return self.failure('sam test 2 failed')
  501. ###################################################################
  502. class SamTest3(CoroTest):
  503. def __init__(self, cm):
  504. CoroTest.__init__(self, cm)
  505. self.name="SamTest3"
  506. def __call__(self, node):
  507. self.incr("calls")
  508. res = self.CM.sam_agent[node].test3()
  509. if 'OK' in res:
  510. return self.success()
  511. else:
  512. return self.failure('sam test 3 failed')
  513. ###################################################################
  514. class SamTest4(CoroTest):
  515. def __init__(self, cm):
  516. CoroTest.__init__(self, cm)
  517. self.name="SamTest4"
  518. def __call__(self, node):
  519. self.incr("calls")
  520. res = self.CM.sam_agent[node].test4()
  521. if 'OK' in res:
  522. return self.success()
  523. else:
  524. return self.failure('sam test 4 failed')
  525. class QuorumState(object):
  526. def __init__(self, cm, node):
  527. self.node = node
  528. self.CM = cm
  529. def refresh(self):
  530. info = self.CM.votequorum_agent[self.node].votequorum_getinfo()
  531. assert(info != 'FAIL')
  532. assert(info != 'NOT_SUPPORTED')
  533. #self.CM.log('refresh: ' + info)
  534. params = info.split(':')
  535. self.node_votes = int(params[0])
  536. self.expected_votes = int(params[1])
  537. self.highest_expected = int(params[2])
  538. self.total_votes = int(params[3])
  539. self.quorum = int(params[4])
  540. self.quorate = self.CM.votequorum_agent[self.node].quorum_getquorate()
  541. assert(self.quorate != 'FAIL')
  542. assert(self.quorate != 'NOT_SUPPORTED')
  543. #self.CM.log('quorate: ' + str(self.quorate))
  544. ###################################################################
  545. class VoteQuorumBase(CoroTest):
  546. '''
  547. '''
  548. def setup(self, node):
  549. ret = CoroTest.setup(self, node)
  550. self.id_map = {}
  551. self.listener = None
  552. for n in self.CM.Env["nodes"]:
  553. if self.listener is None:
  554. self.listener = n
  555. if self.need_all_up:
  556. self.CM.cpg_agent[n].clean_start()
  557. self.CM.cpg_agent[n].cpg_join(self.name)
  558. self.id_map[n] = self.CM.cpg_agent[n].cpg_local_get()
  559. #self.CM.votequorum_agent[self.listener].record_events()
  560. return ret
  561. def wait_for_quorum_change(self):
  562. found = False
  563. max_timeout = 5 * 60
  564. waited = 0
  565. printit = 0
  566. self.CM.log("Waiting for quorum event on " + self.listener)
  567. while not found:
  568. try:
  569. event = self.CM.votequorum_agent[self.listener].read_event()
  570. except:
  571. return self.failure('connection to test agent failed.')
  572. if not event == None:
  573. self.CM.debug("RECEIVED: " + str(event))
  574. if event == None:
  575. if waited >= max_timeout:
  576. return self.failure("timedout(" + str(waited) + " sec) == no event!")
  577. else:
  578. time.sleep(1)
  579. waited = waited + 1
  580. printit = printit + 1
  581. if printit is 60:
  582. print 'waited 60 seconds'
  583. printit = 0
  584. elif str(event.node_id) in str(self.wobbly_id) and not event.is_member:
  585. self.CM.log("Got the config change in " + str(waited) + " seconds")
  586. found = True
  587. else:
  588. self.CM.debug("No match")
  589. self.CM.debug("wobbly nodeid:" + str(self.wobbly_id))
  590. self.CM.debug("event nodeid:" + str(event.node_id))
  591. self.CM.debug("event.is_member:" + str(event.is_member))
  592. if found:
  593. return self.success()
  594. # repeat below with equal and uneven votes
  595. ###################################################################
  596. class VoteQuorumGoDown(VoteQuorumBase):
  597. # all up
  598. # calc min expected votes to get Q
  599. # bring nodes down one-by-one
  600. # confirm cluster looses Q when V < EV
  601. #
  602. def __init__(self, cm):
  603. VoteQuorumBase.__init__(self, cm)
  604. self.name="VoteQuorumGoDown"
  605. self.victims = []
  606. self.expected = len(self.CM.Env["nodes"])
  607. self.config['quorum/provider'] = 'corosync_votequorum'
  608. self.config['quorum/expected_votes'] = self.expected
  609. #self.CM.log('set expected to %d' % (self.expected))
  610. def __call__(self, node):
  611. self.incr("calls")
  612. state = QuorumState(self.CM, self.listener)
  613. for n in self.CM.Env["nodes"]:
  614. if n is self.listener:
  615. continue
  616. self.victims.append(n)
  617. self.CM.StopaCM(n)
  618. nodes_alive = len(self.CM.Env["nodes"]) - len(self.victims)
  619. state.refresh()
  620. #self.expected = self.expected - 1
  621. if state.node_votes != 1:
  622. self.failure('unexpected number of node_votes')
  623. if state.expected_votes != self.expected:
  624. self.CM.log('nev: %d != exp %d' % (state.expected_votes, self.expected))
  625. self.failure('unexpected number of expected_votes')
  626. if state.total_votes != nodes_alive:
  627. self.failure('unexpected number of total votes')
  628. min = ((len(self.CM.Env["nodes"]) + 2) / 2)
  629. if min != state.quorum:
  630. self.failure('we should have %d (not %d) as quorum' % (min, state.quorum))
  631. if nodes_alive < state.quorum:
  632. if state.quorate == 1:
  633. self.failure('we should NOT have quorum(%d) %d > %d' % (state.quorate, state.quorum, nodes_alive))
  634. else:
  635. if state.quorate == 0:
  636. self.failure('we should have quorum(%d) %d <= %d' % (state.quorate, state.quorum, nodes_alive))
  637. return self.success()
  638. # all down
  639. # calc min expected votes to get Q
  640. # bring nodes up one-by-one
  641. # confirm cluster gains Q when V >= EV
  642. #
  643. ###################################################################
  644. class VoteQuorumGoUp(VoteQuorumBase):
  645. # all up
  646. # calc min expected votes to get Q
  647. # bring nodes down one-by-one
  648. # confirm cluster looses Q when V < EV
  649. #
  650. def __init__(self, cm):
  651. VoteQuorumBase.__init__(self, cm)
  652. self.name="VoteQuorumGoUp"
  653. self.need_all_up = False
  654. self.expected = len(self.CM.Env["nodes"])
  655. self.config['quorum/provider'] = 'corosync_votequorum'
  656. self.config['quorum/expected_votes'] = self.expected
  657. #self.CM.log('set expected to %d' % (self.expected))
  658. def __call__(self, node):
  659. self.incr("calls")
  660. self.CM.StartaCM(self.listener)
  661. nodes_alive = 1
  662. state = QuorumState(self.CM, self.listener)
  663. state.refresh()
  664. for n in self.CM.Env["nodes"]:
  665. if n is self.listener:
  666. continue
  667. if state.node_votes != 1:
  668. self.failure('unexpected number of node_votes')
  669. if state.expected_votes != self.expected:
  670. self.CM.log('nev: %d != exp %d' % (state.expected_votes, self.expected))
  671. self.failure('unexpected number of expected_votes')
  672. if state.total_votes != nodes_alive:
  673. self.failure('unexpected number of total votes')
  674. min = ((len(self.CM.Env["nodes"]) + 2) / 2)
  675. if min != state.quorum:
  676. self.failure('we should have %d (not %d) as quorum' % (min, state.quorum))
  677. if nodes_alive < state.quorum:
  678. if state.quorate == 1:
  679. self.failure('we should NOT have quorum(%d) %d > %d' % (state.quorate, state.quorum, nodes_alive))
  680. else:
  681. if state.quorate == 0:
  682. self.failure('we should have quorum(%d) %d <= %d' % (state.quorate, state.quorum, nodes_alive))
  683. self.CM.StartaCM(n)
  684. nodes_alive = nodes_alive + 1
  685. state.refresh()
  686. return self.success()
  687. GenTestClasses = []
  688. GenTestClasses.append(CpgMsgOrderBasic)
  689. GenTestClasses.append(CpgMsgOrderZcb)
  690. GenTestClasses.append(CpgCfgChgOnExecCrash)
  691. GenTestClasses.append(CpgCfgChgOnGroupLeave)
  692. GenTestClasses.append(CpgCfgChgOnNodeLeave)
  693. GenTestClasses.append(CpgCfgChgOnNodeIsolate)
  694. GenTestClasses.append(CpgCfgChgOnLowestNodeJoin)
  695. GenTestClasses.append(VoteQuorumGoDown)
  696. GenTestClasses.append(VoteQuorumGoUp)
  697. AllTestClasses = []
  698. AllTestClasses.append(ConfdbReplaceTest)
  699. AllTestClasses.append(ConfdbIncrementTest)
  700. AllTestClasses.append(ConfdbObjectFindTest)
  701. AllTestClasses.append(ConfdbNotificationTest)
  702. AllTestClasses.append(SamTest1)
  703. AllTestClasses.append(SamTest2)
  704. AllTestClasses.append(SamTest3)
  705. AllTestClasses.append(SamTest4)
  706. AllTestClasses.append(ServiceLoadTest)
  707. AllTestClasses.append(MemLeakObject)
  708. AllTestClasses.append(MemLeakSession)
  709. AllTestClasses.append(FlipTest)
  710. AllTestClasses.append(RestartTest)
  711. AllTestClasses.append(StartOnebyOne)
  712. AllTestClasses.append(SimulStart)
  713. AllTestClasses.append(StopOnebyOne)
  714. AllTestClasses.append(SimulStop)
  715. AllTestClasses.append(RestartOnebyOne)
  716. def CoroTestList(cm, audits):
  717. result = []
  718. configs = []
  719. for testclass in AllTestClasses:
  720. bound_test = testclass(cm)
  721. if bound_test.is_applicable():
  722. bound_test.Audits = audits
  723. result.append(bound_test)
  724. default = {}
  725. default['logging/function_name'] = 'off'
  726. default['logging/logfile_priority'] = 'info'
  727. default['logging/syslog_priority'] = 'info'
  728. default['logging/syslog_facility'] = 'daemon'
  729. default['uidgid/uid'] = '0'
  730. default['uidgid/gid'] = '0'
  731. configs.append(default)
  732. a = {}
  733. a['compatibility'] = 'none'
  734. a['totem/token'] = 10000
  735. configs.append(a)
  736. b = {}
  737. b['compatibility'] = 'whitetank'
  738. b['totem/token'] = 10000
  739. configs.append(b)
  740. c = {}
  741. c['totem/secauth'] = 'on'
  742. c['totem/crypto_accept'] = 'new'
  743. c['totem/crypto_type'] = 'nss'
  744. configs.append(c)
  745. d = {}
  746. d['totem/secauth'] = 'on'
  747. d['totem/crypto_type'] = 'sober'
  748. configs.append(d)
  749. e = {}
  750. e['totem/threads'] = 4
  751. configs.append(e)
  752. #quorum/provider=
  753. #f = {}
  754. #f['quorum/provider'] = 'corosync_quorum_ykd'
  755. #configs.append(f)
  756. g = {}
  757. g['totem/rrp_mode'] = 'passive'
  758. g['totem/interface[2]/ringnumber'] = '1'
  759. g['totem/interface[2]/bindnetaddr'] = '192.168.200.0'
  760. g['totem/interface[2]/mcastaddr'] = '226.94.1.2'
  761. g['totem/interface[2]/mcastport'] = '5405'
  762. configs.append(g)
  763. h = {}
  764. h['totem/rrp_mode'] = 'active'
  765. h['totem/interface[2]/ringnumber'] = '1'
  766. h['totem/interface[2]/bindnetaddr'] = '192.168.200.0'
  767. h['totem/interface[2]/mcastaddr'] = '226.94.1.2'
  768. h['totem/interface[2]/mcastport'] = '5405'
  769. configs.append(h)
  770. num=1
  771. for cfg in configs:
  772. for testclass in GenTestClasses:
  773. bound_test = testclass(cm)
  774. if bound_test.is_applicable():
  775. bound_test.Audits = audits
  776. for c in cfg:
  777. bound_test.config[c] = cfg[c]
  778. bound_test.name = bound_test.name + '_' + str(num)
  779. result.append(bound_test)
  780. num = num + 1
  781. return result