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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2016 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import json
6 import os
7
8 import logging
9
10 from common import cache_decorator
11 from common.http_client_appengine import HttpClientAppEngine as HttpClient
12 from waterfall import buildbot
13 from waterfall import swarming_util
14
15
16 @cache_decorator.Cached(
17 namespace='trybots', cacher=cache_decorator.CompressedMemCacher())
18 def _LoadTrybots(): # pragma: no cover.
19 """Returns the mapping of Commit Queue trybots to Waterfall buildbots."""
20 with open(os.path.join(os.path.dirname(__file__), 'trybots.json'), 'r') as f:
21 return json.load(f)
22
23
24 def _GetMatchingBuildbots(cq_master_name, cq_builder_name): # pragma: no cover.
25 """Returns a list of matching builder/tester buildbots on Waterfall."""
26 trybot_map = _LoadTrybots()
27 builders = trybot_map.get(cq_master_name, {}).get('builders', {})
28 return builders.get(cq_builder_name, {}).get('bot_ids', [])
29
30
31 def _GetMatchingWaterfallBuildStep(
32 cq_build_step, http_client): # pragma: no cover.
33 """Returns the matching Waterfall build step of the given CQ one.
34
35 Args:
36 cq_build_step (BuildStep): A build step on Commit Queue.
37 http_client (RetryHttpClient): A http client to send http requests.
38
39 Returns:
40 (master_name, builder_name, build_number, step_name)
41 or
42 None
43 """
44 no_matching_result = (None, None, None, None)
45
46 def GetTagValue(tag_name, tags):
47 """Returns the value of a tag in a Swarming task."""
48 tag_name_prefix = '%s:' % tag_name
49 for tag in tags:
50 if tag.startswith(tag_name_prefix):
51 return tag[len(tag_name_prefix):]
52 return None
53
54 # 1. Map a cq trybot to the matching waterfall buildbots.
55 buildbots = _GetMatchingBuildbots(
56 cq_build_step.master_name, cq_build_step.builder_name)
57 if not buildbots:
58 logging.info('%s/%s has no matching Waterfall buildbot',
59 cq_build_step.master_name, cq_build_step.builder_name)
60 return no_matching_result # No matching Waterfall buildbots.
61
62 # 2. Get "name" of the CQ trybot step in the tags of a Swarming task.
63 tasks = swarming_util.ListSwarmingTasksDataByTags(
64 cq_build_step.master_name, cq_build_step.builder_name,
65 cq_build_step.build_number, http_client,
66 {'stepname': cq_build_step.step_name})
67 if not tasks:
68 logging.info(
69 '%s/%s/%s is not Swarmed yet.',
70 cq_build_step.master_name, cq_build_step.builder_name,
71 cq_build_step.build_step)
72 return no_matching_result # Not on Swarm yet.
73
74 # Name of the step in the tags of a Swarming task.
75 # Can't use step name, as cq one is with "(with patch)" while waterfall one
76 # without.
77 name = GetTagValue('name', tasks[0].get('tags', []))
78 # The OS in which the test runs on. The same test binary might run on two
79 # different OS platforms.
80 os_name = GetTagValue('os', tasks[0].get('tags', []))
81 if not name or not os_name:
82 logging.error(
83 'Swarming task has no name/os tag: %s' % tasks[0].get('task_id'))
84 return no_matching_result # No name of the step.
85
86 for bot in buildbots:
87 wf_master_name = bot['mastername']
88 # Assume Swarmed gtests run on tester bot instead of the builder bot.
89 wf_builder_name = bot.get('tester') or bot.get('buildername')
90 # TODO: cache and throttle QPS to the same master.
91 # 3. Retrieve latest completed build cycle on the buildbot.
92 builds = buildbot.GetRecentCompletedBuilds(
93 wf_master_name, wf_builder_name, http_client)
94 if not builds:
95 continue # No recent builds for the buildbot.
96
97 # 4. Check whether there is matching step.
98 # TODO: we might have to check OS or dimension too.
99 tasks = swarming_util.ListSwarmingTasksDataByTags(
100 wf_master_name, wf_builder_name, builds[0], http_client,
101 {'name': name, 'os': os_name})
102 if tasks: # One matching buildbot is found.
103 wf_step_name = GetTagValue('stepname', tasks[0].get('tags', []))
104 logging.info(
105 '%s/%s/%s is mapped to %s/%s/%s',
106 cq_build_step.master_name, cq_build_step.builder_name,
107 cq_build_step.build_step, wf_master_name, wf_builder_name,
108 wf_step_name)
109 return wf_master_name, wf_builder_name, builds[0], wf_step_name
110
111 return no_matching_result
112
113
114 def FindMatchingWaterfallStep(build_step): # pragma: no cover.
115 """Finds the matching Waterfall step and checks whether it is supported.
116
117 Only Swarmed and gtest-based steps are supported at the moment.
118
119 Args:
120 build_step (BuildStep): A build step on Waterfall or Commit Queue. It
121 will be updated with the matching Waterfall step and whether it is
122 Swarmed and supported.
123 """
124 # TODO (chanli): re-implement this hack after step metadata is added.
125
126 build_step.swarmed = False
127 build_step.supported = False
128
129 wf_master_name = None
130 wf_builder_name = None
131 wf_build_number = None
132 wf_step_name = None
133
134 http_client = HttpClient()
135
136 if not build_step.master_name.startswith('tryserver.'):
137 wf_master_name = build_step.master_name
138 wf_builder_name = build_step.builder_name
139 wf_build_number = build_step.build_number
140 wf_step_name = build_step.step_name
141 else:
142 step_info = _GetMatchingWaterfallBuildStep(build_step, http_client)
143 wf_master_name, wf_builder_name, wf_build_number, wf_step_name = step_info
144
145 build_step.wf_master_name = wf_master_name
146 build_step.wf_builder_name = wf_builder_name
147 build_step.wf_build_number = wf_build_number
148 build_step.wf_step_name = wf_step_name
149
150 if not build_step.has_matching_waterfall_step:
151 return
152
153 # Query Swarming for isolated data.
154 step_isolated_data = swarming_util.GetIsolatedDataForStep(
155 build_step.master_name, build_step.builder_name, build_step.build_number,
156 build_step.step_name, http_client)
157 build_step.swarmed = len(step_isolated_data) > 0
158
159 if build_step.swarmed:
160 # Retrieve a sample output from Isolate.
161 output = swarming_util.RetrieveShardedTestResultsFromIsolatedServer(
162 step_isolated_data[:1], http_client)
163 if output:
164 # Guess from the format.
165 build_step.supported = (
166 isinstance(output, dict) and
167 isinstance(output.get('all_tests'), list) and
168 isinstance(output.get('per_iteration_data'), list) and
169 all(isinstance(i, dict) for i in output.get('per_iteration_data'))
170 )
OLDNEW
« 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