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

Unified Diff: appengine/findit/waterfall/flake/step_mapper.py

Issue 2394013002: [Findit] Hacky solution to map a CQ trybot step to a Waterfall buildbot step. (Closed)
Patch Set: Fix nit. Created 4 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 side-by-side diff with in-line comments
Download patch
Index: appengine/findit/waterfall/flake/step_mapper.py
diff --git a/appengine/findit/waterfall/flake/step_mapper.py b/appengine/findit/waterfall/flake/step_mapper.py
new file mode 100644
index 0000000000000000000000000000000000000000..38e49c52a34492642e4c4622bc0a62b2b8f11f91
--- /dev/null
+++ b/appengine/findit/waterfall/flake/step_mapper.py
@@ -0,0 +1,170 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import os
+
+import logging
+
+from common import cache_decorator
+from common.http_client_appengine import HttpClientAppEngine as HttpClient
+from waterfall import buildbot
+from waterfall import swarming_util
+
+
+@cache_decorator.Cached(
+ namespace='trybots', cacher=cache_decorator.CompressedMemCacher())
+def _LoadTrybots(): # pragma: no cover.
+ """Returns the mapping of Commit Queue trybots to Waterfall buildbots."""
+ with open(os.path.join(os.path.dirname(__file__), 'trybots.json'), 'r') as f:
+ return json.load(f)
+
+
+def _GetMatchingBuildbots(cq_master_name, cq_builder_name): # pragma: no cover.
+ """Returns a list of matching builder/tester buildbots on Waterfall."""
+ trybot_map = _LoadTrybots()
+ builders = trybot_map.get(cq_master_name, {}).get('builders', {})
+ return builders.get(cq_builder_name, {}).get('bot_ids', [])
+
+
+def _GetMatchingWaterfallBuildStep(
+ cq_build_step, http_client): # pragma: no cover.
+ """Returns the matching Waterfall build step of the given CQ one.
+
+ Args:
+ cq_build_step (BuildStep): A build step on Commit Queue.
+ http_client (RetryHttpClient): A http client to send http requests.
+
+ Returns:
+ (master_name, builder_name, build_number, step_name)
+ or
+ None
+ """
+ no_matching_result = (None, None, None, None)
+
+ def GetTagValue(tag_name, tags):
+ """Returns the value of a tag in a Swarming task."""
+ tag_name_prefix = '%s:' % tag_name
+ for tag in tags:
+ if tag.startswith(tag_name_prefix):
+ return tag[len(tag_name_prefix):]
+ return None
+
+ # 1. Map a cq trybot to the matching waterfall buildbots.
+ buildbots = _GetMatchingBuildbots(
+ cq_build_step.master_name, cq_build_step.builder_name)
+ if not buildbots:
+ logging.info('%s/%s has no matching Waterfall buildbot',
+ cq_build_step.master_name, cq_build_step.builder_name)
+ return no_matching_result # No matching Waterfall buildbots.
+
+ # 2. Get "name" of the CQ trybot step in the tags of a Swarming task.
+ tasks = swarming_util.ListSwarmingTasksDataByTags(
+ cq_build_step.master_name, cq_build_step.builder_name,
+ cq_build_step.build_number, http_client,
+ {'stepname': cq_build_step.step_name})
+ if not tasks:
+ logging.info(
+ '%s/%s/%s is not Swarmed yet.',
+ cq_build_step.master_name, cq_build_step.builder_name,
+ cq_build_step.build_step)
+ return no_matching_result # Not on Swarm yet.
+
+ # Name of the step in the tags of a Swarming task.
+ # Can't use step name, as cq one is with "(with patch)" while waterfall one
+ # without.
+ name = GetTagValue('name', tasks[0].get('tags', []))
+ # The OS in which the test runs on. The same test binary might run on two
+ # different OS platforms.
+ os_name = GetTagValue('os', tasks[0].get('tags', []))
+ if not name or not os_name:
+ logging.error(
+ 'Swarming task has no name/os tag: %s' % tasks[0].get('task_id'))
+ return no_matching_result # No name of the step.
+
+ for bot in buildbots:
+ wf_master_name = bot['mastername']
+ # Assume Swarmed gtests run on tester bot instead of the builder bot.
+ wf_builder_name = bot.get('tester') or bot.get('buildername')
+ # TODO: cache and throttle QPS to the same master.
+ # 3. Retrieve latest completed build cycle on the buildbot.
+ builds = buildbot.GetRecentCompletedBuilds(
+ wf_master_name, wf_builder_name, http_client)
+ if not builds:
+ continue # No recent builds for the buildbot.
+
+ # 4. Check whether there is matching step.
+ # TODO: we might have to check OS or dimension too.
+ tasks = swarming_util.ListSwarmingTasksDataByTags(
+ wf_master_name, wf_builder_name, builds[0], http_client,
+ {'name': name, 'os': os_name})
+ if tasks: # One matching buildbot is found.
+ wf_step_name = GetTagValue('stepname', tasks[0].get('tags', []))
+ logging.info(
+ '%s/%s/%s is mapped to %s/%s/%s',
+ cq_build_step.master_name, cq_build_step.builder_name,
+ cq_build_step.build_step, wf_master_name, wf_builder_name,
+ wf_step_name)
+ return wf_master_name, wf_builder_name, builds[0], wf_step_name
+
+ return no_matching_result
+
+
+def FindMatchingWaterfallStep(build_step): # pragma: no cover.
+ """Finds the matching Waterfall step and checks whether it is supported.
+
+ Only Swarmed and gtest-based steps are supported at the moment.
+
+ Args:
+ build_step (BuildStep): A build step on Waterfall or Commit Queue. It
+ will be updated with the matching Waterfall step and whether it is
+ Swarmed and supported.
+ """
+ # TODO (chanli): re-implement this hack after step metadata is added.
+
+ build_step.swarmed = False
+ build_step.supported = False
+
+ wf_master_name = None
+ wf_builder_name = None
+ wf_build_number = None
+ wf_step_name = None
+
+ http_client = HttpClient()
+
+ if not build_step.master_name.startswith('tryserver.'):
+ wf_master_name = build_step.master_name
+ wf_builder_name = build_step.builder_name
+ wf_build_number = build_step.build_number
+ wf_step_name = build_step.step_name
+ else:
+ step_info = _GetMatchingWaterfallBuildStep(build_step, http_client)
+ wf_master_name, wf_builder_name, wf_build_number, wf_step_name = step_info
+
+ build_step.wf_master_name = wf_master_name
+ build_step.wf_builder_name = wf_builder_name
+ build_step.wf_build_number = wf_build_number
+ build_step.wf_step_name = wf_step_name
+
+ if not build_step.has_matching_waterfall_step:
+ return
+
+ # Query Swarming for isolated data.
+ step_isolated_data = swarming_util.GetIsolatedDataForStep(
+ build_step.master_name, build_step.builder_name, build_step.build_number,
+ build_step.step_name, http_client)
+ build_step.swarmed = len(step_isolated_data) > 0
+
+ if build_step.swarmed:
+ # Retrieve a sample output from Isolate.
+ output = swarming_util.RetrieveShardedTestResultsFromIsolatedServer(
+ step_isolated_data[:1], http_client)
+ if output:
+ # Guess from the format.
+ build_step.supported = (
+ isinstance(output, dict) and
+ isinstance(output.get('all_tests'), list) and
+ isinstance(output.get('per_iteration_data'), list) and
+ all(isinstance(i, dict) for i in output.get('per_iteration_data'))
+ )
« no previous file with comments | « appengine/findit/model/flake/test/flake_analysis_request_test.py ('k') | appengine/findit/waterfall/flake/trybots.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698