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

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: removing blank line Created 5 years, 3 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 api = self.api
464 name = 'Waiting for revision ' + revision_list[0].revision_string 464
465 if len(revision_list) > 1: 465 revision_mapping = {}
466 name += ' and %d other revision(s).' % (len(revision_list) - 1) 466 gs_jobs = []
467 script = self.api.resource('wait_for_any.py') 467 buildbot_jobs = []
468 args_list = [gsutil_path] 468
469 url_mapping = {r.get_next_url(): r for r in revision_list} 469 for revision in revision_list:
470 bb_locator_mapping = {r.get_buildbot_locator(): r for r in revision_list} 470 url = revision.get_next_url()
471 bb_locator_list = bb_locator_mapping.keys() 471 buildbot_job = revision.get_buildbot_locator()
472 url_list = url_mapping.keys() 472 if url:
473 args_list += [url for url in url_list if url and url is not None] 473 gs_jobs.append({'type': 'gs', 'location': url})
474 args_list += [entry for entry in bb_locator_list 474 revision_mapping[url] = revision
475 if entry and entry is not None] 475 if buildbot_job:
476 args_list.append( 476 buildbot_jobs.append(buildbot_job)
477 '--timeout=%d' % ( 477 revision_mapping[buildbot_job['job_name']] = revision
478 self.get_build_timeout_minutes() * 60)) 478
479 jobs_config = {'jobs': buildbot_jobs + gs_jobs}
480
481 script = api.resource('wait_for_any.py')
482 args_list = [api.m.gsutil.get_gsutil_path()] if gs_jobs else []
483
479 try: 484 try:
480 step_result = self.api.m.python( 485 step_name = 'Waiting for revision ' + revision_list[0].revision_string
481 str(name), 486 if len(revision_list) > 1:
487 step_name += ' and %d other revision(s).' % (len(revision_list) - 1)
488 step_result = api.m.python(
489 str(step_name),
482 script, 490 script,
483 args_list, 491 args_list,
484 stdout=self.api.m.raw_io.output()) 492 stdout=api.m.json.output(),
485 except self.api.m.step.StepFailure: # pragma: no cover 493 stdin=api.m.json.input(jobs_config),
486 # StepFailure is interpreted as a timeout. 494 ok_ret={0,1})
487 for revision in revision_list: 495 except api.m.step.StepFailure as sf: # pragma: no cover
488 revision.status = revision_state.RevisionState.FAILED 496 if sf.retcode == 2: # 6 days and no builds finished.
497 for revision in revision_list:
498 revision.status = revision_state.RevisionState.FAILED
499 return None # All builds are failed, no point in returning one.
500 else: # Something else went wrong.
501 raise
502
503 step_results = api.m.step.active_result.stdout
504 build_failed = api.m.step.active_result.retcode
505
506 if build_failed: # Explicitly making the step red
507 api.m.step.active_result.presentation.status = api.m.step.FAILURE
508
509 if not step_results: # For most recipe_simulation_test cases.
489 return None 510 return None
490 step_output = step_result.stdout or 'Build finished: Unknown' 511
491 for line in step_output.splitlines(): 512 failed_jobs = step_results.get('failed', [])
492 if line.startswith('Build finished: '): 513 completed_jobs = step_results.get('completed', [])
493 finished_url = line[len('Build finished: '):].strip() 514 assert failed_jobs or completed_jobs
494 return url_mapping.get(finished_url) 515 # Marked all failed builds as failed
495 if line.startswith('Failed build url: '): # pragma: no cover 516 for job in failed_jobs:
496 url = line[len('Failed build url: '):].strip() 517 last_failed_revision = revision_mapping[str(job.get(
497 step_result.presentation.links['Failed build'] = url 518 'location', job.get('job_name')))]
498 if line.startswith('Build failed: '): # pragma: no cover 519 if 'job_url' in job:
499 failed_build_locator = line[len('Build failed: '):].strip() 520 url = job['job_url']
500 failed_build = bb_locator_mapping.get(failed_build_locator) 521 api.m.step.active_result.presentation.links['Failed build'] = url
501 failed_build.status = revision_state.RevisionState.FAILED 522 last_failed_revision.status = revision_state.RevisionState.FAILED
502 return failed_build 523
524 # Return a completed job if availavle
525 for job in completed_jobs:
526 if 'job_url' in job: # pragma: no cover
527 url = job['job_url']
528 api.m.step.active_result.presentation.links['Completed build'] = url
529 return revision_mapping[str(job.get(
530 'location', job.get('job_name')))]
531
532 # Or return any of the failed revisions
533 return last_failed_revision
503 534
504 def wait_for_any(self, revision_list): 535 def wait_for_any(self, revision_list):
505 """Waits for any of the revisions in the list to finish its job(s).""" 536 """Waits for any of the revisions in the list to finish its job(s)."""
506 while True: 537 while True:
507 if not revision_list or any(r.status == revision_state.RevisionState.NEW 538 if not revision_list or any(r.status == revision_state.RevisionState.NEW
508 for r in revision_list): # pragma: no cover 539 for r in revision_list): # pragma: no cover
509 # We want to avoid waiting forever for revisions that are not started, 540 # We want to avoid waiting forever for revisions that are not started,
510 # or for an empty list. Hence we fail fast. 541 # or for an empty list. Hence we fail fast.
511 assert False 542 assert False
512 543
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 recipe_tester_name = self.bisect_config.get('recipe_tester_name') 590 recipe_tester_name = self.bisect_config.get('recipe_tester_name')
560 original_bot_name = self.bisect_config.get('original_bot_name', '') 591 original_bot_name = self.bisect_config.get('original_bot_name', '')
561 if recipe_tester_name: 592 if recipe_tester_name:
562 return recipe_tester_name 593 return recipe_tester_name
563 elif 'win' in original_bot_name: # pragma: no cover 594 elif 'win' in original_bot_name: # pragma: no cover
564 return 'win64_nv_tester' 595 return 'win64_nv_tester'
565 else: # pragma: no cover 596 else: # pragma: no cover
566 # Reasonable fallback 597 # Reasonable fallback
567 return 'linux_perf_tester' 598 return 'linux_perf_tester'
568 599
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): 600 def get_builder_bot_for_this_platform(self):
575 # TODO(prasadv): We should refactor these codes to remove hard coded values. 601 # TODO(prasadv): We should refactor these codes to remove hard coded values.
576 bot_name = self.get_perf_tester_name() 602 bot_name = self.get_perf_tester_name()
577 if 'win' in bot_name: 603 if 'win' in bot_name:
578 if any(b in bot_name for b in ['x64', 'gpu']): 604 if any(b in bot_name for b in ['x64', 'gpu']):
579 return 'winx64_bisect_builder' 605 return 'winx64_bisect_builder'
580 return 'win_perf_bisect_builder' 606 return 'win_perf_bisect_builder'
581 607
582 if 'android' in bot_name: 608 if 'android' in bot_name:
583 if 'nexus9' in bot_name: 609 if 'nexus9' in bot_name:
(...skipping 28 matching lines...) Expand all
612 638
613 We have seen on several occasions that the local master branch gets reset 639 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 640 to previous revisions and also detached head states. Running this should
615 take care of either situation. 641 take care of either situation.
616 """ 642 """
617 # TODO(robertocn): Investigate what causes the states mentioned in the 643 # TODO(robertocn): Investigate what causes the states mentioned in the
618 # docstring in the first place. 644 # docstring in the first place.
619 self.api.m.git('update-ref', 'refs/heads/master', 645 self.api.m.git('update-ref', 'refs/heads/master',
620 'refs/remotes/origin/master') 646 'refs/remotes/origin/master')
621 self.api.m.git('checkout', 'master', cwd=self.api.m.path['checkout']) 647 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