| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 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 from datetime import datetime | 5 from datetime import datetime |
| 6 import logging | 6 import logging |
| 7 | 7 |
| 8 from google.appengine.ext import ndb | 8 from google.appengine.ext import ndb |
| 9 | 9 |
| 10 from common import appengine_util | 10 from common import appengine_util |
| 11 from common import constants |
| 11 from model.wf_analysis import WfAnalysis | 12 from model.wf_analysis import WfAnalysis |
| 12 from model import wf_analysis_status | 13 from model import analysis_status |
| 13 from waterfall import analyze_build_failure_pipeline | 14 from waterfall import analyze_build_failure_pipeline |
| 14 | 15 |
| 15 @ndb.transactional | 16 @ndb.transactional |
| 16 def NeedANewAnalysis( | 17 def NeedANewAnalysis( |
| 17 master_name, builder_name, build_number, failed_steps, | 18 master_name, builder_name, build_number, failed_steps, |
| 18 build_completed, force): | 19 build_completed, force): |
| 19 """Checks status of analysis for the build and decides if a new one is needed. | 20 """Checks status of analysis for the build and decides if a new one is needed. |
| 20 | 21 |
| 21 A WfAnalysis entity for the given build will be created if none exists. | 22 A WfAnalysis entity for the given build will be created if none exists. |
| 22 When a new analysis is needed, this function will create and save a WfAnalysis | 23 When a new analysis is needed, this function will create and save a WfAnalysis |
| 23 entity to the datastore, or it will reset the existing one but still keep the | 24 entity to the datastore, or it will reset the existing one but still keep the |
| 24 result of last analysis. | 25 result of last analysis. |
| 25 | 26 |
| 26 Returns: | 27 Returns: |
| 27 True if an analysis is needed, otherwise False. | 28 True if an analysis is needed, otherwise False. |
| 28 """ | 29 """ |
| 29 analysis = WfAnalysis.Get(master_name, builder_name, build_number) | 30 analysis = WfAnalysis.Get(master_name, builder_name, build_number) |
| 30 | 31 |
| 31 if not analysis: | 32 if not analysis: |
| 32 # The build failure is not analyzed yet. | 33 # The build failure is not analyzed yet. |
| 33 analysis = WfAnalysis.Create(master_name, builder_name, build_number) | 34 analysis = WfAnalysis.Create(master_name, builder_name, build_number) |
| 34 analysis.status = wf_analysis_status.PENDING | 35 analysis.status = analysis_status.PENDING |
| 35 analysis.request_time = datetime.utcnow() | 36 analysis.request_time = datetime.utcnow() |
| 36 analysis.put() | 37 analysis.put() |
| 37 return True | 38 return True |
| 38 elif force: | 39 elif force: |
| 39 # A new analysis could be forced if last analysis was completed. | 40 # A new analysis could be forced if last analysis was completed. |
| 40 if not analysis.completed: | 41 if not analysis.completed: |
| 41 # TODO: start a new analysis if the last one has started running but it | 42 # TODO: start a new analysis if the last one has started running but it |
| 42 # has no update for a considerable amount of time, eg. 10 minutes. | 43 # has no update for a considerable amount of time, eg. 10 minutes. |
| 43 return False | 44 return False |
| 44 | 45 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 67 # TODO: support following cases | 68 # TODO: support following cases |
| 68 # * Automatically retry if last analysis failed with errors. | 69 # * Automatically retry if last analysis failed with errors. |
| 69 # * Analysis is not complete and no update in the last 5 minutes. | 70 # * Analysis is not complete and no update in the last 5 minutes. |
| 70 return False | 71 return False |
| 71 | 72 |
| 72 | 73 |
| 73 def ScheduleAnalysisIfNeeded(master_name, builder_name, build_number, | 74 def ScheduleAnalysisIfNeeded(master_name, builder_name, build_number, |
| 74 failed_steps=None, | 75 failed_steps=None, |
| 75 build_completed=False, | 76 build_completed=False, |
| 76 force=False, | 77 force=False, |
| 77 queue_name='default'): | 78 queue_name=constants.DEFAULT_QUEUE): |
| 78 """Schedules an analysis if needed and returns the build analysis. | 79 """Schedules an analysis if needed and returns the build analysis. |
| 79 | 80 |
| 80 When the build failure was already analyzed and a new analysis is scheduled, | 81 When the build failure was already analyzed and a new analysis is scheduled, |
| 81 the returned WfAnalysis will still have the result of last completed analysis. | 82 the returned WfAnalysis will still have the result of last completed analysis. |
| 82 | 83 |
| 83 Args: | 84 Args: |
| 84 master_name (str): The master name of the failed build. | 85 master_name (str): The master name of the failed build. |
| 85 builder_name (str): The builder name of the failed build. | 86 builder_name (str): The builder name of the failed build. |
| 86 build_number (int): The build number of the failed build. | 87 build_number (int): The build number of the failed build. |
| 87 failed_steps (list): The names of all failed steps reported for the build. | 88 failed_steps (list): The names of all failed steps reported for the build. |
| 88 build_completed (bool): Indicate whether the build is completed. | 89 build_completed (bool): Indicate whether the build is completed. |
| 89 force (bool): If True, a fresh new analysis will be triggered even when an | 90 force (bool): If True, a fresh new analysis will be triggered even when an |
| 90 old one was completed already; otherwise bail out. | 91 old one was completed already; otherwise bail out. |
| 91 queue_name (str): The task queue to be used for pipeline tasks. | 92 queue_name (str): The task queue to be used for pipeline tasks. |
| 92 | 93 |
| 93 Returns: | 94 Returns: |
| 94 A WfAnalysis instance. | 95 A WfAnalysis instance. |
| 95 """ | 96 """ |
| 96 if NeedANewAnalysis( | 97 if NeedANewAnalysis( |
| 97 master_name, builder_name, build_number, failed_steps, | 98 master_name, builder_name, build_number, failed_steps, |
| 98 build_completed, force): | 99 build_completed, force): |
| 99 pipeline_job = analyze_build_failure_pipeline.AnalyzeBuildFailurePipeline( | 100 pipeline_job = analyze_build_failure_pipeline.AnalyzeBuildFailurePipeline( |
| 100 master_name, builder_name, build_number, build_completed) | 101 master_name, builder_name, build_number, build_completed) |
| 101 # Explicitly run analysis in the backend module "build-failure-analysis". | 102 # Explicitly run analysis in the backend module "waterfall-backend". |
| 102 # Note: Just setting the target in queue.yaml does NOT work for pipeline | 103 # Note: Just setting the target in queue.yaml does NOT work for pipeline |
| 103 # when deployed to App Engine, but it does work in dev-server locally. | 104 # when deployed to App Engine, but it does work in dev-server locally. |
| 104 # A possible reason is that pipeline will pick a default target if none is | 105 # A possible reason is that pipeline will pick a default target if none is |
| 105 # specified explicitly, and the default target is used rather than the one | 106 # specified explicitly, and the default target is used rather than the one |
| 106 # in the queue.yaml file, but this contradicts the documentation in | 107 # in the queue.yaml file, but this contradicts the documentation in |
| 107 # https://cloud.google.com/appengine/docs/python/taskqueue/tasks#Task. | 108 # https://cloud.google.com/appengine/docs/python/taskqueue/tasks#Task. |
| 108 pipeline_job.target = appengine_util.GetTargetNameForModule( | 109 pipeline_job.target = appengine_util.GetTargetNameForModule( |
| 109 'build-failure-analysis') | 110 constants.WATERFALL_BACKEND) |
| 110 pipeline_job.start(queue_name=queue_name) | 111 pipeline_job.start(queue_name=queue_name) |
| 111 | 112 |
| 112 logging.info('An analysis was scheduled for build %s, %s, %s: %s', | 113 logging.info('An analysis was scheduled for build %s, %s, %s: %s', |
| 113 master_name, builder_name, build_number, | 114 master_name, builder_name, build_number, |
| 114 pipeline_job.pipeline_status_path()) | 115 pipeline_job.pipeline_status_path()) |
| 115 | 116 |
| 116 return WfAnalysis.Get(master_name, builder_name, build_number) | 117 return WfAnalysis.Get(master_name, builder_name, build_number) |
| OLD | NEW |