Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(224)

Side by Side Diff: scripts/slave/recipe_modules/auto_bisect/bisector.py

Issue 1339613005: Refactoring scripts that wait for buildbot jobs to complete. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@hax
Patch Set: Addressed all issues stemming from local test. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | scripts/slave/recipe_modules/auto_bisect/example.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import json 5 import json
6 import re 6 import re
7 7
8 from . import bisect_results 8 from . import bisect_results
9 from . import depot_config 9 from . import depot_config
10 from . import revision_state 10 from . import revision_state
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 """Waits for all revisions in list to finish.""" 453 """Waits for all revisions in list to finish."""
454 while any([r.in_progress for r in revision_list]): 454 while any([r.in_progress for r in revision_list]):
455 revision_list.remove(self.wait_for_any(revision_list)) 455 revision_list.remove(self.wait_for_any(revision_list))
456 456
457 def sleep_until_next_revision_ready(self, revision_list): 457 def sleep_until_next_revision_ready(self, revision_list):
458 """Produces a single step that sleeps until any revision makes progress. 458 """Produces a single step that sleeps until any revision makes progress.
459 459
460 A revision is considered to make progress when a build file is uploaded to 460 A revision is considered to make progress when a build file is uploaded to
461 the appropriate bucket, or when buildbot test job is complete. 461 the appropriate bucket, or when buildbot test job is complete.
462 """ 462 """
463 gsutil_path = self.api.m.gsutil.get_gsutil_path() 463
prasadv 2015/09/22 23:00:15 Delete this blank line.
RobertoCN 2015/09/23 00:01:35 Done.
464 name = 'Waiting for revision ' + revision_list[0].revision_string 464 api = self.api
465 if len(revision_list) > 1: 465
466 name += ' and %d other revision(s).' % (len(revision_list) - 1) 466 revision_mapping = {}
467 script = self.api.resource('wait_for_any.py') 467 gs_jobs = []
468 args_list = [gsutil_path] 468 buildbot_jobs = []
469 url_mapping = {r.get_next_url(): r for r in revision_list} 469
470 bb_locator_mapping = {r.get_buildbot_locator(): r for r in revision_list} 470 for revision in revision_list:
471 bb_locator_list = bb_locator_mapping.keys() 471 url = revision.get_next_url()
472 url_list = url_mapping.keys() 472 buildbot_job = revision.get_buildbot_locator()
473 args_list += [url for url in url_list if url and url is not None] 473 if url:
474 args_list += [entry for entry in bb_locator_list 474 gs_jobs.append({'type': 'gs', 'location': url})
475 if entry and entry is not None] 475 revision_mapping[url] = revision
476 args_list.append( 476 if buildbot_job:
477 '--timeout=%d' % ( 477 buildbot_jobs.append(buildbot_job)
478 self.get_build_timeout_minutes() * 60)) 478 revision_mapping[buildbot_job['job_name']] = revision
479
480 jobs_config = {'jobs': buildbot_jobs + gs_jobs}
481
482 script = api.resource('wait_for_any.py')
483 args_list = [api.m.gsutil.get_gsutil_path()] if gs_jobs else []
484
479 try: 485 try:
480 step_result = self.api.m.python( 486 step_name = 'Waiting for revision ' + revision_list[0].revision_string
481 str(name), 487 if len(revision_list) > 1:
488 step_name += ' and %d other revision(s).' % (len(revision_list) - 1)
489 step_result = api.m.python(
490 str(step_name),
482 script, 491 script,
483 args_list, 492 args_list,
484 stdout=self.api.m.raw_io.output()) 493 stdout=api.m.json.output(),
485 except self.api.m.step.StepFailure: # pragma: no cover 494 stdin=api.m.json.input(jobs_config),
486 # StepFailure is interpreted as a timeout. 495 ok_ret={0,1})
487 for revision in revision_list: 496 except api.m.step.StepFailure as sf: # pragma: no cover
488 revision.status = revision_state.RevisionState.FAILED 497 if sf.retcode == 2: # 6 days and no builds finished.
498 for revision in revision_list:
499 revision.status = revision_state.RevisionState.FAILED
500 return None # All builds are failed, no point in returning one.
501 else: # Something else went wrong.
502 raise
503
504 step_results = api.m.step.active_result.stdout
505 build_failed = api.m.step.active_result.retcode
506
507 if build_failed: # Explicitly making the step red
508 api.m.step.active_result.presentation.status = api.m.step.FAILURE
509
510 if not step_results: # For most recipe_simulation_test cases.
489 return None 511 return None
490 step_output = step_result.stdout or 'Build finished: Unknown' 512
491 for line in step_output.splitlines(): 513 failed_jobs = step_results.get('failed', [])
492 if line.startswith('Build finished: '): 514 completed_jobs = step_results.get('completed', [])
493 finished_url = line[len('Build finished: '):].strip() 515 assert failed_jobs or completed_jobs
494 return url_mapping.get(finished_url) 516 # Marked all failed builds as failed
495 if line.startswith('Failed build url: '): # pragma: no cover 517 for job in failed_jobs:
496 url = line[len('Failed build url: '):].strip() 518 last_failed_revision = revision_mapping[str(job.get(
497 step_result.presentation.links['Failed build'] = url 519 'location', job.get('job_name')))]
498 if line.startswith('Build failed: '): # pragma: no cover 520 if 'job_url' in job:
499 failed_build_locator = line[len('Build failed: '):].strip() 521 url = job['job_url']
500 failed_build = bb_locator_mapping.get(failed_build_locator) 522 api.m.step.active_result.presentation.links['Failed build'] = url
501 failed_build.status = revision_state.RevisionState.FAILED 523 last_failed_revision.status = revision_state.RevisionState.FAILED
502 return failed_build 524
525 # Return a completed job if availavle
526 for job in completed_jobs:
527 if 'job_url' in job: # pragma: no cover
528 url = job['job_url']
529 api.m.step.active_result.presentation.links['Completed build'] = url
530 return revision_mapping[str(job.get(
531 'location', job.get('job_name')))]
532
533 # Or return any of the failed revisions
534 return last_failed_revision
503 535
504 def wait_for_any(self, revision_list): 536 def wait_for_any(self, revision_list):
505 """Waits for any of the revisions in the list to finish its job(s).""" 537 """Waits for any of the revisions in the list to finish its job(s)."""
506 while True: 538 while True:
507 if not revision_list or any(r.status == revision_state.RevisionState.NEW 539 if not revision_list or any(r.status == revision_state.RevisionState.NEW
508 for r in revision_list): # pragma: no cover 540 for r in revision_list): # pragma: no cover
509 # We want to avoid waiting forever for revisions that are not started, 541 # We want to avoid waiting forever for revisions that are not started,
510 # or for an empty list. Hence we fail fast. 542 # or for an empty list. Hence we fail fast.
511 assert False 543 assert False
512 544
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 recipe_tester_name = self.bisect_config.get('recipe_tester_name') 591 recipe_tester_name = self.bisect_config.get('recipe_tester_name')
560 original_bot_name = self.bisect_config.get('original_bot_name', '') 592 original_bot_name = self.bisect_config.get('original_bot_name', '')
561 if recipe_tester_name: 593 if recipe_tester_name:
562 return recipe_tester_name 594 return recipe_tester_name
563 elif 'win' in original_bot_name: # pragma: no cover 595 elif 'win' in original_bot_name: # pragma: no cover
564 return 'win64_nv_tester' 596 return 'win64_nv_tester'
565 else: # pragma: no cover 597 else: # pragma: no cover
566 # Reasonable fallback 598 # Reasonable fallback
567 return 'linux_perf_tester' 599 return 'linux_perf_tester'
568 600
569 def get_build_timeout_minutes(self):
570 if 'win' in self.get_perf_tester_name():
571 return 4 * 60
572 return 2 * 60
573
574 def get_builder_bot_for_this_platform(self): 601 def get_builder_bot_for_this_platform(self):
575 # TODO(prasadv): We should refactor these codes to remove hard coded values. 602 # TODO(prasadv): We should refactor these codes to remove hard coded values.
576 bot_name = self.get_perf_tester_name() 603 bot_name = self.get_perf_tester_name()
577 if 'win' in bot_name: 604 if 'win' in bot_name:
578 if any(b in bot_name for b in ['x64', 'gpu']): 605 if any(b in bot_name for b in ['x64', 'gpu']):
579 return 'winx64_bisect_builder' 606 return 'winx64_bisect_builder'
580 return 'win_perf_bisect_builder' 607 return 'win_perf_bisect_builder'
581 608
582 if 'android' in bot_name: 609 if 'android' in bot_name:
583 if 'nexus9' in bot_name: 610 if 'nexus9' in bot_name:
(...skipping 28 matching lines...) Expand all
612 639
613 We have seen on several occasions that the local master branch gets reset 640 We have seen on several occasions that the local master branch gets reset
614 to previous revisions and also detached head states. Running this should 641 to previous revisions and also detached head states. Running this should
615 take care of either situation. 642 take care of either situation.
616 """ 643 """
617 # TODO(robertocn): Investigate what causes the states mentioned in the 644 # TODO(robertocn): Investigate what causes the states mentioned in the
618 # docstring in the first place. 645 # docstring in the first place.
619 self.api.m.git('update-ref', 'refs/heads/master', 646 self.api.m.git('update-ref', 'refs/heads/master',
620 'refs/remotes/origin/master') 647 'refs/remotes/origin/master')
621 self.api.m.git('checkout', 'master', cwd=self.api.m.path['checkout']) 648 self.api.m.git('checkout', 'master', cwd=self.api.m.path['checkout'])
OLDNEW
« no previous file with comments | « no previous file | scripts/slave/recipe_modules/auto_bisect/example.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698