PageRenderTime 59ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/py/jprobe.py

https://github.com/dbfree/h2o
Python | 523 lines | 321 code | 91 blank | 111 comment | 64 complexity | f2c3a87a5090eca629d49cfa5f799036 MD5 | raw file
Possible License(s): Apache-2.0
  1. #!/usr/bin/python
  2. import random, jenkinsapi, getpass, re, os, argparse, shutil, json, logging, sys
  3. import string
  4. from jenkinsapi.jenkins import Jenkins
  5. # only used when we wanted to see what objects were available (below)
  6. from see import see
  7. DO_LAST_GOOD = False
  8. # using the env variables to force jenkinsapi to use proxy..but after to clear to avoid
  9. # problems in other python stuff that uses requests!
  10. def clear_env():
  11. # need to set environment variables for proxy server if going to sm box
  12. # or clear them if not!
  13. if os.environ.get('HTTPS_PROXY'):
  14. print "removing HTTPS_PROXY os env variable so requests won't use it"
  15. del os.environ['HTTPS_PROXY']
  16. if os.environ.get('HTTP_PROXY'):
  17. print "removing HTTP_PROXY os env variable so requests won't use it"
  18. del os.environ['HTTP_PROXY']
  19. import sys
  20. def my_hook(type, value, traceback):
  21. print 'hooked the exception so we can clear env variables'
  22. clear_env()
  23. print 'Type:', type
  24. print 'Value:', value
  25. print 'Traceback:', traceback
  26. raise Exception
  27. sys.excepthook = my_hook
  28. parse = argparse.ArgumentParser()
  29. group = parse.add_mutually_exclusive_group()
  30. group.add_argument('-e', help="job number from a list of ec2 known jobs", type=int, action='store', default=None)
  31. group.add_argument('-x', help="job number from a list of 164 known jobs", type=int, action='store', default=None)
  32. group.add_argument('-s', help="job number from a list of sm known jobs", type=int, action='store', default=None)
  33. group.add_argument('-j', '--jobname', help="jobname. Correct url is found", action='store', default=None)
  34. parse.add_argument('-l', '--logging', help="turn on logging.DEBUG msgs to see allUrls used", action='store_true')
  35. parse.add_argument('-v', '--verbose', help="dump the last N stdout from the failed jobs", action='store_true')
  36. group.add_argument('-c', help="do a hardwired special job copy between jenkins", type=int, action='store', default=None)
  37. args = parse.parse_args()
  38. print "creates jsandbox (cleaned), and puts aTxt.txt and aConsole.txt in there, along with artifacts"
  39. print " also creates fails* and regress* in there"
  40. # can refer to this by zero-based index with -n 0 or -n 1 etc
  41. # or by job name with -j h2o_master_test
  42. allowedJobsX = [
  43. 'h2o_master_test',
  44. 'h2o_release_tests',
  45. 'h2o_release_tests2',
  46. 'h2o_release_tests_164',
  47. 'h2o_release_tests_c10_only',
  48. 'h2o_perf_test',
  49. 'h2o_release_Runit',
  50. ]
  51. allowedJobsE = [
  52. 'h2o.tests.single.jvm',
  53. 'h2o.tests.single.jvm.fvec',
  54. 'h2o.multi.vm.temporary',
  55. 'h2o.tests.ec2.multi.jvm',
  56. 'h2o.tests.ec2.multi.jvm.fvec',
  57. 'h2o.tests.ec2.hosts',
  58. ]
  59. allowedJobsS = [
  60. 'sm_testdir_single_jvm',
  61. 'sm_testdir_single_jvm_fvec',
  62. 'sm_testdir_multi_jvm',
  63. 'sm_testdir_hosts',
  64. 'sm_test_NN2_mnist',
  65. ]
  66. allUrls = {
  67. 'ec2': 'http://test.0xdata.com',
  68. '164': 'http://192.168.1.164:8080',
  69. 'sm': 'http://10.71.0.163:8080',
  70. }
  71. all164Jobs = ['do all', 'h2o_master_test', 'h2o_master_test2', 'h2o_perf_test', 'h2o_private_json_vers_Runit', 'h2o_release_Runit', 'h2o_release_tests', 'h2o_release_tests2', 'h2o_release_tests_164', 'h2o_release_tests_c10_only', 'h2o_release_tests_cdh3', 'h2o_release_tests_cdh4', 'h2o_release_tests_cdh4_yarn', 'h2o_release_tests_cdh5', 'h2o_release_tests_cdh5_yarn', 'h2o_release_tests_hdp1.3', 'h2o_release_tests_hdp2.0.6', 'h2o_release_tests_mapr', 'selenium12']
  72. allEc2Jobs = ['generic.h2o.build.branch', 'h2o.branch.api-dev', 'h2o.branch.cliffc-drf', 'h2o.branch.hilbert', 'h2o.branch.jobs', 'h2o.branch.jobs1', 'h2o.branch.json_versioning', 'h2o.branch.rel-ito', 'h2o.build', 'h2o.build.api-dev', 'h2o.build.gauss', 'h2o.build.godel', 'h2o.build.h2oscala', 'h2o.build.hilbert', 'h2o.build.jobs', 'h2o.build.master', 'h2o.build.rel-ito', 'h2o.build.rel-ivory', 'h2o.build.rel-iwasawa', 'h2o.build.rel-jacobi', 'h2o.build.rel-jordan', 'h2o.build.rest_api_versioning', 'h2o.build.ux-client', 'h2o.build.va_defaults_renamed', 'h2o.clone', 'h2o.datasets', 'h2o.download.latest', 'h2o.ec2.start', 'h2o.ec2.stop', 'h2o.findbugs', 'h2o.multi.vm.temporary', 'h2o.multi.vm.temporary.cliffc-no-limits', 'h2o.nightly', 'h2o.nightly.1', 'h2o.nightly.cliffc-lock', 'h2o.nightly.ec2', 'h2o.nightly.ec2.cliffc-no-limits', 'h2o.nightly.ec2.erdos', 'h2o.nightly.ec2.hilbert', 'h2o.nightly.ec2.rel-ito', 'h2o.nightly.ec2.rel-jacobi', 'h2o.nightly.ec2.rel-jordan', 'h2o.nightly.fourier', 'h2o.nightly.godel', 'h2o.nightly.multi.vm', 'h2o.nightly.rel-ivory', 'h2o.nightly.rel-iwasawa', 'h2o.nightly.rel-jacobi', 'h2o.nightly.rel-jordan', 'h2o.nightly.va_defaults_renamed', 'h2o.post.push', 'h2o.private.nightly', 'h2o.tests.ec2', 'h2o.tests.ec2.hosts', 'h2o.tests.ec2.multi.jvm', 'h2o.tests.ec2.multi.jvm.fvec', 'h2o.tests.golden', 'h2o.tests.junit', 'h2o.tests.multi.jvm', 'h2o.tests.multi.jvm.fvec', 'h2o.tests.single.jvm', 'h2o.tests.single.jvm.fvec', 'h2o.tests.test']
  73. allSmJobs = [
  74. 'sm_testdir_single_jvm',
  75. 'sm_testdir_single_jvm_fvec',
  76. 'sm_testdir_multi_jvm',
  77. 'sm_testdir_hosts',
  78. 'sm_test_NN2_mnist',
  79. ]
  80. # jenkinsapi:
  81. # This library wraps up that interface as more
  82. # conventional python objects in order to make many
  83. # Jenkins oriented tasks easier to automate.
  84. # http://pythonhosted.org//jenkinsapi
  85. # https://pypi.python.org/pypi/jenkinsapi
  86. # Project source code: github: https://github.com/salimfadhley/jenkinsapi
  87. # Project documentation: https://jenkinsapi.readthedocs.org/en/latest/
  88. #************************************************
  89. if args.logging:
  90. logging.basicConfig(level=logging.DEBUG)
  91. if args.jobname and (args.e or args.x or args.s):
  92. raise Exception("Don't use both -j and -x or -e or -s args")
  93. # default ec2 0
  94. jobname = None
  95. if args.e is not None:
  96. if args.e<0 or args.e>(len(allowedJobsE)-1):
  97. raise Exception("ec2 job number %s is outside allowed range: 0-%s" % \
  98. (args.e, len(allowedJobsE)-1))
  99. jobname = allowedJobsE[args.e]
  100. if args.x is not None:
  101. if args.x<0 or args.x>(len(allowedJobsX)-1):
  102. raise Exception("0xdata job number %s is outside allowed range: 0-%s" % \
  103. (args.x, len(allowedJobsX)-1))
  104. jobname = allowedJobsX[args.x]
  105. if args.s is not None:
  106. if args.s<0 or args.s>(len(allowedJobsS)-1):
  107. raise Exception("sm job number %s is outside allowed range: 0-%s" % \
  108. (args.s, len(allowedJobsS)-1))
  109. jobname = allowedJobsS[args.s]
  110. if args.jobname:
  111. if args.jobname not in allowedJobs:
  112. raise Exception("%s not in list of legal jobs" % args.jobname)
  113. jobname = args.jobname
  114. if not (args.jobname or args.x or args.e or args.s):
  115. # prompt the user
  116. subtract = 0
  117. prefix = "-e"
  118. eDone = False
  119. xDone = False
  120. while not jobname:
  121. allAllowedJobs = allowedJobsE + allowedJobsX + allowedJobsS
  122. for j, job in enumerate(allAllowedJobs):
  123. # first boundary
  124. if not eDone and j==(subtract + len(allowedJobsE)):
  125. subtract += len(allowedJobsE)
  126. prefix = "-x"
  127. eDone = True
  128. # second boundary
  129. if not xDone and j==(subtract + len(allowedJobsX)):
  130. subtract += len(allowedJobsX)
  131. prefix = "-s"
  132. xDone = True
  133. print prefix, j-subtract, " [%s]: %s" % (j, job)
  134. userInput = int(raw_input("Enter number (0 to %s): " % (len(allAllowedJobs)-1) ))
  135. if userInput >=0 and userInput <= len(allAllowedJobs):
  136. jobname = allAllowedJobs[userInput]
  137. # defaults
  138. if jobname in allEc2Jobs:
  139. machine = 'ec2'
  140. elif jobname in all164Jobs:
  141. machine = '164'
  142. elif jobname in allSmJobs:
  143. machine = 'sm'
  144. print "Setting up proxy server for sm"
  145. os.environ['HTTP_PROXY'] = 'http://172.16.0.3:8888'
  146. os.environ['HTTPS_PROXY'] = 'https://172.16.0.3:8888'
  147. else:
  148. raise Exception("%s not in lists of known jobs" % jobname)
  149. if machine not in allUrls:
  150. raise Exception("%s not in allUrls dict" % machine)
  151. jenkins_url = allUrls[machine]
  152. print "machine:", machine
  153. #************************************************
  154. def clean_sandbox(LOG_DIR="sandbox"):
  155. if os.path.exists(LOG_DIR):
  156. shutil.rmtree(LOG_DIR)
  157. # it should have been removed, but on error it might still be there
  158. if not os.path.exists(LOG_DIR):
  159. os.mkdir(LOG_DIR)
  160. return LOG_DIR
  161. #************************************************
  162. # get the username/pswd from files in the user's .ec2 dir (don't want cleartext here)
  163. # prompt if doesn't exist
  164. def login(machine='164'):
  165. def getit(k):
  166. if not os.path.isfile(k):
  167. print "you probably should create this file to avoid typing %s" % k
  168. return None
  169. else:
  170. with open(k) as f:
  171. lines = f.read().splitlines()
  172. return lines[0]
  173. home = os.path.expanduser("~")
  174. username = getit(home + '/.ec2/jenkins_user_' + machine)
  175. pswd = getit(home + '/.ec2/jenkins_pswd_' + machine)
  176. if not username:
  177. username = raw_input("Username [%s]: " % getpass.getuser())
  178. if not pswd:
  179. pswd = getpass.getpass()
  180. return username, pswd
  181. #************************************************8
  182. username, password = login(machine)
  183. LOG_DIR = clean_sandbox("sandbox")
  184. def dump_json(j):
  185. return json.dumps(j, sort_keys=True, indent=2)
  186. #************************************************8
  187. J = Jenkins(jenkins_url, username, password)
  188. print "\nCurrent jobs available at %s" % jenkins_url
  189. print J.keys()
  190. print "\nChecking this job:", J[jobname]
  191. job = J[jobname]
  192. print "\nGetting %s job config" % jobname
  193. print job.get_config
  194. print "\nlast good build:"
  195. lgb = job.get_last_good_build()
  196. print "\nlast good build revision:"
  197. print lgb.get_revision()
  198. from jenkinsapi.api import get_latest_complete_build
  199. from jenkinsapi.api import get_latest_test_results
  200. # print "************************HELLO****************************"
  201. # print get_latest_complete_build(jenkins_url, jobname, username=username, password=password)
  202. # print "************************HELLO****************************"
  203. # get_latest_test_results(jenkinsurl, jobname, username=None, password=None)[source]
  204. # search_artifact_by_regexp.py
  205. if 1==0:
  206. expr = "commands.log"
  207. print("testing search_artifact_by_regexp with expression %s") % expr
  208. from jenkinsapi.api import search_artifact_by_regexp
  209. artifact_regexp = re.compile(expr) # A file name I want.
  210. result = search_artifact_by_regexp(jenkins_url, jobname, artifact_regexp)
  211. print("tested search_artifact_by_regexp", (repr(result)))
  212. # print "last_stable_buildnumber", job.get_last_stable_buildnumber()
  213. print "last_good_buildnumber", job.get_last_good_buildnumber()
  214. # print "last_failed_buildnumber", job.get_last_failed_buildnumber()
  215. print "last_buildnumber", job.get_last_buildnumber()
  216. if DO_LAST_GOOD:
  217. print "Using last_good_buildnumber %s for result set" % job.get_last_good_buildnumber()
  218. build = job.get_build(job.get_last_good_buildnumber())
  219. else:
  220. print "Using last_buildnumber %s for result set" % job.get_last_buildnumber()
  221. build = job.get_build(job.get_last_buildnumber())
  222. af = build.get_artifacts()
  223. dict_af = build.get_artifact_dict()
  224. # for looking at object in json
  225. # import h2o_util
  226. # s = h2o_util.json_repr(dict_af, curr_depth=0, max_depth=12)
  227. # print dump_json(s)
  228. buildstatus = build.get_status()
  229. print "build get_status", buildstatus
  230. buildname = build.name
  231. print "build name", buildname
  232. buildnumber = build.get_number()
  233. print "build number", buildnumber
  234. buildrevision = build.get_revision()
  235. print "build revision", buildrevision
  236. buildbranch = build.get_revision_branch()
  237. print "build revision branch", buildbranch
  238. buildduration = build.get_duration()
  239. print "build duration", buildduration
  240. buildupstream = build.get_upstream_job_name()
  241. print "build upstream job name", buildupstream
  242. buildgood = build.is_good()
  243. print "build is_good", buildgood
  244. buildtimestamp = build.get_timestamp()
  245. print "build timestamp", buildtimestamp
  246. consoleTxt = open(LOG_DIR + '/console.txt', "a")
  247. print "getting build console (how to buffer this write?)"
  248. print "probably better to figure how to save it as file"
  249. c = build.get_console()
  250. consoleTxt.write(c)
  251. consoleTxt.close()
  252. print "build has result set", build.has_resultset()
  253. print "build get result set"
  254. rs = build.get_resultset()
  255. print "build result set name", rs.name
  256. # print "build result set items", rs.items()
  257. print #****************************************
  258. # print dump_json(item)
  259. # print "build result set keys", rs.keys()
  260. aTxt = open(LOG_DIR + '/artifacts.txt', "a")
  261. # have just a json string in the result set?
  262. # rs.items is a generator?
  263. #****************************************************************************
  264. PRINTALL = False
  265. # keep count of status counts
  266. # 2014-03-19 07:26:15+00:00
  267. # buildtimestampe is a datetime object
  268. see(buildtimestamp)
  269. t = buildtimestamp
  270. # hour minute
  271. hm = "%s_%s" % (t.hour, t.minute)
  272. # hour minute second
  273. hms = "%s_%s" % (hm, t.second)
  274. failName = "%s_%s_%s_%s%s" % ("fail", jobname, buildnumber, hm, ".txt")
  275. print "failName:", failName
  276. regressName = "%s_%s_%s_%s%s" % ("regress", jobname, buildnumber, hm, ".txt")
  277. print "regressName:", regressName
  278. fixedName = "%s_%s_%s_%s%s" % ("fixed", jobname, buildnumber, hm, ".txt")
  279. print "fixedName:", fixedName
  280. stats = {}
  281. def fprint (*args):
  282. # emulate printing each as string, then join with spaces
  283. s = ["%s" % a for a in args]
  284. line = " ".join(s)
  285. fTxt.write(line + "\n")
  286. print line
  287. def printStuff():
  288. e1 = "\n******************************************************************************"
  289. e2 = "%s %s %s" % (i, jobname, v)
  290. fprint(e1)
  291. fprint(e2)
  292. # print "\n", k, "\n"
  293. # print "\n", v, "\n"
  294. # to see what you can get
  295. # print see(v)
  296. # print dir(v)
  297. # print vars(v)
  298. # .age .className .duration .errorDetails .errorStackTrace .failedSince
  299. # .identifier() .name .skipped .skippedMessage .status .stderr .stdout
  300. fprint (i, "v.duration", v.duration)
  301. fprint (i, "v.errorStackTrace", v.errorStackTrace)
  302. fprint (i, "v.failedSince", v.failedSince)
  303. if args.verbose:
  304. fprint (i, "v.stderr", v.stderr)
  305. # lines = v.stdout.splitlines()
  306. # keep newlines in the list elements
  307. if not v.stdout:
  308. fprint ("v.stdout is empty")
  309. else:
  310. fprint ("len(v.stdout):", len(v.stdout))
  311. # have to fix the \n and \tat in the strings
  312. stdout = v.stdout
  313. # json string has the actual '\' and 'n' or 'tat' chars
  314. stdout = string.replace(stdout,'\\n', '\n');
  315. stdout = string.replace(stdout,'\\tat', '\t');
  316. # don't need double newlines
  317. stdout = string.replace(stdout,'\n\n', '\n');
  318. lineList = stdout.splitlines()
  319. fprint ("len(lineList):", len(lineList))
  320. num = min(20, len(lineList))
  321. if num!=0:
  322. # print i, "Last %s lineList of stdout %s" % (num, "\n".join(lineList[-num]))
  323. fprint (i, "Last %s lineList of stdout\n" % num)
  324. fprint ("\n".join(lineList[-num:]))
  325. else:
  326. fprint ("v.stdout is empty")
  327. #******************************************************
  328. for i, (k, v) in enumerate(rs.items()):
  329. if v.status in stats:
  330. stats[v.status] += 1
  331. else:
  332. stats[v.status] = 1
  333. # print rs.name
  334. e1 = "\n******************************************************************************"
  335. e2 = "%s %s %s" % (i, jobname, v)
  336. aTxt.write(e1+"\n")
  337. aTxt.write(e2+"\n")
  338. # only if not PASSED
  339. if v.status == 'FAILED':
  340. fTxt = open(LOG_DIR + "/" + failName, "a")
  341. printStuff()
  342. fTxt.close()
  343. if v.status == 'REGRESSION':
  344. fTxt = open(LOG_DIR + "/" + regressName, "a")
  345. printStuff()
  346. fTxt.close()
  347. if v.status == 'FIXED':
  348. fTxt = open(LOG_DIR + "/" + fixedName, "a")
  349. printStuff()
  350. fTxt.close()
  351. if PRINTALL:
  352. fprint (i, "k", k)
  353. fprint (i, "v", v)
  354. fprint (i, "v.errorDetails", v.errorDetails)
  355. fprint (i, "v.age", v.age)
  356. fprint (i, "v.className", v.className)
  357. fprint (i, "v.identifier()", v.identifier())
  358. fprint (i, "v.name", v.name)
  359. fprint (i, "v.skipped", v.age)
  360. fprint (i, "v.skippedMessage", v.skippedMessage)
  361. fprint (i, "v.status", v.status)
  362. fprint (i, "v.stdout", v.stdout)
  363. #****************************************************************************
  364. # print "dict_af", dict_af
  365. if 1==1:
  366. for a in af:
  367. # print "a.keys():", a.keys()
  368. # txt = a.get_data()
  369. e = "%s %s %s %s\n" % ("#", a.filename, a.url, "########### artifact saved ####################")
  370. # print e,
  371. aTxt.write(e+"\n")
  372. # get the h2o output from the runit runs
  373. # a.save_to_dir(LOG_DIR)
  374. consoleTxt.close()
  375. # print txt
  376. # a.save_to_dir('./sandbox')
  377. # print txt[0]
  378. aTxt.close()
  379. print "#***********************************************"
  380. print "Build:", buildname
  381. print buildtimestamp
  382. print "Status:", buildstatus
  383. if buildgood:
  384. print "Build is good"
  385. else:
  386. print "Build is bad"
  387. print "Build number", buildnumber
  388. # print buildrevision
  389. print buildbranch
  390. print "Duration", buildduration
  391. print "Upstream job", buildupstream
  392. print "Test summary"
  393. for s in stats:
  394. print s, stats[s]
  395. # rename the sandbox
  396. dirname = "%s_%s_%s_%s" % ("sandbox", jobname, buildnumber, hm)
  397. if os.path.exists(dirname):
  398. shutil.rmtree(dirname)
  399. os.rename(LOG_DIR, dirname)
  400. print "Results are in", dirname
  401. print "#***********************************************"
  402. clear_env()
  403. # from jenkins.py, we can copy jobs?
  404. # def jobs(self):
  405. # def get_jobs(self):
  406. # def get_jobs_info(self):
  407. # def get_job(self, jobname):
  408. # def has_job(self, jobname):
  409. # def create_job(self, jobname, config_):
  410. # Create a job
  411. # :param jobname: name of new job, str
  412. # :param config: configuration of new job, xml
  413. # :return: new Job obj
  414. # def copy_job(self, jobname, newjobname):
  415. # def build_job(self, jobname, params=None):
  416. # Invoke a build by job name
  417. # :param jobname: name of exist job, str
  418. # :param params: the job params, dict
  419. # :return: none
  420. # def delete_job(self, jobname):
  421. # def rename_job(self, jobname, newjobname):
  422. # load config calls get_config?
  423. # def load_config(self):
  424. # def get_config(self):
  425. # '''Returns the config.xml from the job'''
  426. # def get_config_xml_url(self):
  427. # def update_config(self, config):
  428. # def create(self, job_name, config):
  429. # Create a job
  430. # :param jobname: name of new job, str
  431. # :param config: configuration of new job, xml
  432. # :return: new Job obj