corolab.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. #!/usr/bin/python
  2. '''CTS: Cluster Testing System: Lab environment module
  3. '''
  4. __copyright__='''
  5. Copyright (c) 2010 Red Hat, Inc.
  6. '''
  7. # All rights reserved.
  8. #
  9. # Author: Angus Salkeld <asalkeld@redhat.com>
  10. #
  11. # This software licensed under BSD license, the text of which follows:
  12. #
  13. # Redistribution and use in source and binary forms, with or without
  14. # modification, are permitted provided that the following conditions are met:
  15. #
  16. # - Redistributions of source code must retain the above copyright notice,
  17. # this list of conditions and the following disclaimer.
  18. # - Redistributions in binary form must reproduce the above copyright notice,
  19. # this list of conditions and the following disclaimer in the documentation
  20. # and/or other materials provided with the distribution.
  21. # - Neither the name of the MontaVista Software, Inc. nor the names of its
  22. # contributors may be used to endorse or promote products derived from this
  23. # software without specific prior written permission.
  24. #
  25. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  26. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28. # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  29. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  30. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  31. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  32. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  33. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  34. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  35. # THE POSSIBILITY OF SUCH DAMAGE.
  36. import sys
  37. from cts.CTSaudits import AuditList
  38. from cts.CTS import Scenario, InitClusterManager
  39. from corotests import CoroTestList, AllTests
  40. from corosync import *
  41. sys.path.append("/usr/share/pacemaker/tests/cts") # So that things work from the source directory
  42. try:
  43. from CTSlab import *
  44. except ImportError:
  45. sys.stderr.write("abort: couldn't find CTSLab in [%s]\n" %
  46. ' '.join(sys.path))
  47. sys.stderr.write("(check your install and PYTHONPATH)\n")
  48. sys.exit(-1)
  49. tests = None
  50. cm = None
  51. old_handler = None
  52. DefaultFacility = "daemon"
  53. def usage(arg):
  54. print "Illegal argument " + arg
  55. print "usage: " + sys.argv[0] +" [options] number-of-iterations"
  56. print "\nCommon options: "
  57. print "\t [--at-boot (1|0)], does the cluster software start at boot time"
  58. print "\t [--nodes 'node list'], list of cluster nodes separated by whitespace"
  59. print "\t [--limit-nodes max], only use the first 'max' cluster nodes supplied with --nodes"
  60. print "\t [--logfile path], where should the test software look for logs from cluster nodes"
  61. print "\t [--outputfile path], optional location for the test software to write logs to"
  62. print "\t [--syslog-facility name], which syslog facility should the test software log to"
  63. print "\t [--choose testcase-name], run only the named test"
  64. print "\t [--list-tests], list the valid tests"
  65. print "\t [--benchmark], add the timing information"
  66. print "\t "
  67. print "Additional (less common) options: "
  68. print "\t [--trunc (truncate logfile before starting)]"
  69. print "\t [--xmit-loss lost-rate(0.0-1.0)]"
  70. print "\t [--recv-loss lost-rate(0.0-1.0)]"
  71. print "\t [--standby (1 | 0 | yes | no)]"
  72. print "\t [--fencing (1 | 0 | yes | no)]"
  73. print "\t [--once], run all valid tests once"
  74. print "\t [--no-loop-tests], dont run looping/time-based tests"
  75. print "\t [--no-unsafe-tests], dont run tests that are unsafe for use with ocfs2/drbd"
  76. print "\t [--valgrind-tests], include tests using valgrind"
  77. print "\t [--experimental-tests], include experimental tests"
  78. print "\t [--oprofile 'node list'], list of cluster nodes to run oprofile on]"
  79. print "\t [--qarsh] Use the QARSH backdoor to access nodes instead of SSH"
  80. print "\t [--seed random_seed]"
  81. print "\t [--set option=value]"
  82. sys.exit(1)
  83. #
  84. # Main entry into the test system.
  85. #
  86. if __name__ == '__main__':
  87. Environment = CtsLab()
  88. NumIter = 0
  89. Version = 1
  90. LimitNodes = 0
  91. TestCase = None
  92. TruncateLog = 0
  93. ListTests = 0
  94. HaveSeed = 0
  95. node_list = ''
  96. #
  97. # The values of the rest of the parameters are now properly derived from
  98. # the configuration files.
  99. #
  100. # Set the signal handler
  101. signal.signal(15, sig_handler)
  102. signal.signal(10, sig_handler)
  103. # Process arguments...
  104. skipthis=None
  105. args=sys.argv[1:]
  106. for i in range(0, len(args)):
  107. if skipthis:
  108. skipthis=None
  109. continue
  110. elif args[i] == "-l" or args[i] == "--limit-nodes":
  111. skipthis=1
  112. LimitNodes = int(args[i+1])
  113. elif args[i] == "-L" or args[i] == "--logfile":
  114. skipthis=1
  115. Environment["LogFileName"] = args[i+1]
  116. elif args[i] == "--outputfile":
  117. skipthis=1
  118. Environment["OutputFile"] = args[i+1]
  119. elif args[i] == "--oprofile":
  120. skipthis=1
  121. Environment["oprofile"] = args[i+1].split(' ')
  122. elif args[i] == "--trunc":
  123. Environment["TruncateLog"]=1
  124. elif args[i] == "--list-tests":
  125. Environment["ListTests"]=1
  126. elif args[i] == "--benchmark":
  127. Environment["benchmark"]=1
  128. elif args[i] == "--qarsh":
  129. Environment.rsh.enable_qarsh()
  130. elif args[i] == "--fencing":
  131. skipthis=1
  132. if args[i+1] == "1" or args[i+1] == "yes":
  133. Environment["DoFencing"] = 1
  134. elif args[i+1] == "0" or args[i+1] == "no":
  135. Environment["DoFencing"] = 0
  136. else:
  137. usage(args[i+1])
  138. elif args[i] == "--xmit-loss":
  139. try:
  140. float(args[i+1])
  141. except ValueError:
  142. print ("--xmit-loss parameter should be float")
  143. usage(args[i+1])
  144. skipthis=1
  145. Environment["XmitLoss"] = args[i+1]
  146. elif args[i] == "--recv-loss":
  147. try:
  148. float(args[i+1])
  149. except ValueError:
  150. print ("--recv-loss parameter should be float")
  151. usage(args[i+1])
  152. skipthis=1
  153. Environment["RecvLoss"] = args[i+1]
  154. elif args[i] == "--choose":
  155. skipthis=1
  156. TestCase = args[i+1]
  157. elif args[i] == "--nodes":
  158. skipthis=1
  159. node_list = args[i+1].split(' ')
  160. elif args[i] == "--at-boot" or args[i] == "--cluster-starts-at-boot":
  161. skipthis=1
  162. if args[i+1] == "1" or args[i+1] == "yes":
  163. Environment["at-boot"] = 1
  164. elif args[i+1] == "0" or args[i+1] == "no":
  165. Environment["at-boot"] = 0
  166. else:
  167. usage(args[i+1])
  168. elif args[i] == "--set":
  169. skipthis=1
  170. (name, value) = args[i+1].split('=')
  171. Environment[name] = value
  172. else:
  173. try:
  174. NumIter=int(args[i])
  175. except ValueError:
  176. usage(args[i])
  177. Environment["remote_logwatch"] = True
  178. Environment["SyslogFacility"] = DefaultFacility
  179. Environment["loop-minutes"] = int(Environment["loop-minutes"])
  180. Environment["Stack"] = "corosync (flatiron)"
  181. Environment['CMclass'] = corosync_flatiron
  182. Environment["use_logd"] = 0
  183. if Environment["OutputFile"]:
  184. Environment["logger"].append(FileLog(Environment, Environment["OutputFile"]))
  185. if len(node_list) < 1:
  186. print "No nodes specified!"
  187. sys.exit(1)
  188. if LimitNodes > 0:
  189. if len(node_list) > LimitNodes:
  190. print("Limiting the number of nodes configured=%d (max=%d)"
  191. %(len(node_list), LimitNodes))
  192. while len(node_list) > LimitNodes:
  193. node_list.pop(len(node_list)-1)
  194. Environment["nodes"] = node_list
  195. # Create the Cluster Manager object
  196. cm = Environment['CMclass'](Environment)
  197. Audits = AuditList(cm)
  198. Tests = []
  199. # Your basic start up the world type of test scenario...
  200. # Scenario selection
  201. scenario = Scenario(
  202. [ InitClusterManager(Environment), TestAgentComponent(Environment)])
  203. if Environment["ListTests"] == 1 :
  204. Tests = CoroTestList(cm, Audits)
  205. cm.log("Total %d tests"%len(Tests))
  206. for test in Tests :
  207. cm.log(str(test.name));
  208. sys.exit(0)
  209. if TruncateLog:
  210. cm.log("Truncating %s" % LogFile)
  211. lf = open(LogFile, "w");
  212. if lf != None:
  213. lf.truncate(0)
  214. lf.close()
  215. keys = []
  216. for key in Environment.keys():
  217. keys.append(key)
  218. keys.sort()
  219. for key in keys:
  220. cm.debug("Environment["+key+"]:\t"+str(Environment[key]))
  221. cm.log(">>>>>>>>>>>>>>>> BEGINNING " + repr(NumIter) + " TESTS ")
  222. cm.log("System log files: %s" % Environment["LogFileName"])
  223. cm.ns.WaitForAllNodesToComeUp(Environment["nodes"])
  224. cm.log("Cluster nodes: ")
  225. for node in Environment["nodes"]:
  226. cm.log(" * %s" % (node))
  227. if TestCase != None:
  228. for test in CoroTestList(cm, Audits):
  229. if test.name == TestCase:
  230. Tests.append(test)
  231. if Tests == []:
  232. usage("--choose: No applicable/valid tests chosen")
  233. else:
  234. Tests = CoroTestList(cm, Audits)
  235. if Environment["benchmark"]:
  236. Environment.ScenarioTests = BenchTests(scenario, cm, Tests, Audits)
  237. elif Environment["all-once"] or NumIter == 0:
  238. Environment.ScenarioTests = AllTests(scenario, cm, Tests, Audits)
  239. else:
  240. Environment.ScenarioTests = RandomTests(scenario, cm, Tests, Audits)
  241. try :
  242. overall, detailed = Environment.ScenarioTests.run(NumIter)
  243. except :
  244. cm.Env.log("Exception by %s" % sys.exc_info()[0])
  245. for logmethod in Environment["logger"]:
  246. traceback.print_exc(50, logmethod)
  247. Environment.ScenarioTests.summarize()
  248. if Environment.ScenarioTests.Stats["failure"] > 0:
  249. sys.exit(Environment.ScenarioTests.Stats["failure"])
  250. elif Environment.ScenarioTests.Stats["success"] != NumIter:
  251. cm.Env.log("No failure count but success != requested iterations")
  252. sys.exit(1)