blob: 25a7f69a6ac690f0b7f99dd55c6e7bb5e45b4e45 [file] [log] [blame]
cmtice46093e52014-12-09 14:59:16 -08001#!/usr/bin/python
2
3# Copyright 2014 Google Inc. All Rights Reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import os
8import time
9import urllib2
10
11from utils import command_executer
12from utils import logger
13from utils import buildbot_json
14
15SLEEP_TIME = 600 # 10 minutes; time between polling of buildbot.
16TIME_OUT = 18000 # Decide the build is dead or will never finish
17 # after this time (5 hours).
18
19"""Utilities for launching and accessing ChromeOS buildbots."""
20
21def ParseReportLog (url, build):
22 """
23 Scrape the trybot image name off the Reports log page.
24
25 This takes the URL for a trybot Reports Stage web page,
26 and a trybot build type, such as 'daisy-release'. It
27 opens the web page and parses it looking for the trybot
28 artifact name (e.g. something like
29 'trybot-daisy-release/R40-6394.0.0-b1389'). It returns the
30 artifact name, if found.
31 """
32 trybot_image = ""
33 url += "/text"
34 newurl = url.replace ("uberchromegw", "chromegw")
35 webpage = urllib2.urlopen(newurl)
36 data = webpage.read()
37 lines = data.split('\n')
38 for l in lines:
cmtice1047b072015-02-10 09:33:21 -080039 if l.find("Artifacts") > 0 and l.find("trybot") > 0:
cmtice46093e52014-12-09 14:59:16 -080040 trybot_name = "trybot-%s" % build
41 start_pos = l.find(trybot_name)
42 end_pos = l.find("@https://storage")
43 trybot_image = l[start_pos:end_pos]
44
45 return trybot_image
46
cmtice46093e52014-12-09 14:59:16 -080047def GetBuildData (buildbot_queue, build_id):
48 """
49 Find the Reports stage web page for a trybot build.
50
51 This takes the name of a buildbot_queue, such as 'daisy-release'
52 and a build id (the build number), and uses the json buildbot api to
53 find the Reports stage web page for that build, if it exists.
54 """
55 builder = buildbot_json.Buildbot(
56 "http://chromegw/p/tryserver.chromiumos/").builders[buildbot_queue]
57 build_data = builder.builds[build_id].data
58 logs = build_data["logs"]
59 for l in logs:
60 fname = l[1]
61 if "steps/Report/" in fname:
62 return fname
63
64 return ""
65
66
67def FindBuildRecordFromLog(description, log_info):
68 """
69 Find the right build record in the build logs.
70
71 Get the first build record from build log with a reason field
72 that matches 'description'. ('description' is a special tag we
73 created when we launched the buildbot, so we could find it at this
74 point.)
75 """
76
77 current_line = 1
78 while current_line < len(log_info):
79 my_dict = {}
80 # Read all the lines from one "Build" to the next into my_dict
81 while True:
82 key = log_info[current_line].split(":")[0].strip()
83 value = log_info[current_line].split(":", 1)[1].strip()
84 my_dict[key] = value
85 current_line += 1
86 if "Build" in key or current_line == len(log_info):
87 break
88 try:
89 # Check to see of the build record is the right one.
90 if str(description) in my_dict["reason"]:
91 # We found a match; we're done.
92 return my_dict
93 except:
94 print "reason is not in dictionary: '%s'" % repr(my_dict)
95 else:
96 # Keep going.
97 continue
98
99 # We hit the bottom of the log without a match.
100 return {}
101
102
cmtice717bd4a2015-06-25 09:11:52 -0700103def GetBuildInfo(file_dir, builder):
cmtice46093e52014-12-09 14:59:16 -0800104 """
105 Get all the build records for the trybot builds.
106
107 file_dir is the toolchain_utils directory.
108 """
109 ce = command_executer.GetCommandExecuter()
110 commands = ("{0}/utils/buildbot_json.py builds "
Han Shen3931b8b2015-04-28 13:17:26 -0700111 "http://chromegw/i/tryserver.chromiumos/"
cmtice46093e52014-12-09 14:59:16 -0800112 .format(file_dir))
113
cmtice717bd4a2015-06-25 09:11:52 -0700114 if builder:
Rahul Chaudhrydac5f562015-08-05 11:22:20 -0700115 # For release builds, get logs from the 'release' builder.
116 if builder.endswith('-release'):
117 commands += " -b release"
118 else:
119 commands += " -b %s" % builder
cmtice46093e52014-12-09 14:59:16 -0800120 _, buildinfo, _ = ce.RunCommand(commands, return_output=True,
121 print_to_console=False)
122 build_log = buildinfo.splitlines()
123 return build_log
124
125
cmtice1047b072015-02-10 09:33:21 -0800126def FindArchiveImage(chromeos_root, build, build_id):
127 """
128 Given a build_id, search Google Storage for a trybot artifact
129 for the correct board with the correct build_id. Return the
130 name of the artifact, if found.
131 """
132 ce = command_executer.GetCommandExecuter()
133 command = ("gsutil ls gs://chromeos-image-archive/trybot-%s/*b%s"
134 "/chromiumos_test_image.tar.xz" % (build, build_id))
cmtice717bd4a2015-06-25 09:11:52 -0700135 retval, out, err = ce.ChrootRunCommand(chromeos_root, command,
136 return_output=True,
cmtice1047b072015-02-10 09:33:21 -0800137 print_to_console=False)
138
139 trybot_image = ""
140 trybot_name = "trybot-%s" % build
141 if out and out.find(trybot_name) > 0:
142 start_pos = out.find(trybot_name)
143 end_pos = out.find("/chromiumos_test_image")
144 trybot_image = out[start_pos:end_pos]
145
146 return trybot_image
147
Luis Lozano8a68b2d2015-04-23 14:37:09 -0700148def GetTrybotImage(chromeos_root, buildbot_name, patch_list, build_tag,
149 build_toolchain=False):
cmtice46093e52014-12-09 14:59:16 -0800150 """
151 Launch buildbot and get resulting trybot artifact name.
152
153 This function launches a buildbot with the appropriate flags to
154 build the test ChromeOS image, with the current ToT mobile compiler. It
155 checks every 10 minutes to see if the trybot has finished. When the trybot
156 has finished, it parses the resulting report logs to find the trybot
157 artifact (if one was created), and returns that artifact name.
158
159 chromeos_root is the path to the ChromeOS root, needed for finding chromite
160 and launching the buildbot.
161
162 buildbot_name is the name of the buildbot queue, such as lumpy-release or
163 daisy-paladin.
164
165 patch_list a python list of the patches, if any, for the buildbot to use.
166
167 build_tag is a (unique) string to be used to look up the buildbot results
168 from among all the build records.
169 """
170 ce = command_executer.GetCommandExecuter()
171 cbuildbot_path = os.path.join(chromeos_root, "chromite/cbuildbot")
172 base_dir = os.getcwd()
173 patch_arg = ""
174 if patch_list:
175 patch_arg = "-g "
176 for p in patch_list:
177 patch_arg = patch_arg + " " + repr(p)
Luis Lozano8a68b2d2015-04-23 14:37:09 -0700178 toolchain_flags=""
179 if build_toolchain:
Luis Lozanod7d50842015-04-24 10:03:26 -0700180 toolchain_flags += "--latest-toolchain"
cmtice46093e52014-12-09 14:59:16 -0800181 branch = "master"
182 os.chdir(cbuildbot_path)
183
184 # Launch buildbot with appropriate flags.
185 build = buildbot_name
186 description = build_tag
Luis Lozano8a68b2d2015-04-23 14:37:09 -0700187 command = ("./cbuildbot --remote --nochromesdk --notests"
188 " --remote-description=%s %s %s %s"
189 % (description, toolchain_flags, patch_arg, build))
cmticeaea53412015-06-19 09:44:43 -0700190 _, out, _ = ce.RunCommand(command, return_output=True)
191 if "Tryjob submitted!" not in out:
192 logger.GetLogger().LogFatal("Error occurred while launching trybot job: "
193 "%s" % command)
cmtice46093e52014-12-09 14:59:16 -0800194 os.chdir(base_dir)
195
196 build_id = 0
cmticed54f9802015-02-05 11:04:11 -0800197 build_status = None
cmticea63ffc02015-04-21 11:38:55 -0700198 # Wait for buildbot to finish running (check every 10 minutes). Wait
199 # 10 minutes before the first check to give the buildbot time to launch
200 # (so we don't start looking for build data before it's out there).
201 time.sleep(SLEEP_TIME)
cmtice46093e52014-12-09 14:59:16 -0800202 done = False
cmticeaea53412015-06-19 09:44:43 -0700203 pending = True
204 # pending_time is the time between when we submit the job and when the
205 # buildbot actually launches the build. running_time is the time between
206 # when the buildbot job launches and when it finishes. The job is
207 # considered 'pending' until we can find an entry for it in the buildbot
208 # logs.
cmticea63ffc02015-04-21 11:38:55 -0700209 pending_time = SLEEP_TIME
cmticeaea53412015-06-19 09:44:43 -0700210 running_time = 0
cmtice46093e52014-12-09 14:59:16 -0800211 while not done:
212 done = True
cmtice717bd4a2015-06-25 09:11:52 -0700213 build_info = GetBuildInfo(base_dir, build)
cmtice46093e52014-12-09 14:59:16 -0800214 if not build_info:
cmticece5ffa42015-02-12 15:18:43 -0800215 if pending_time > TIME_OUT:
cmticeaea53412015-06-19 09:44:43 -0700216 logger.GetLogger().LogFatal("Unable to get build logs for target %s."
217 % build)
cmticece5ffa42015-02-12 15:18:43 -0800218 else:
cmticeaea53412015-06-19 09:44:43 -0700219 pending_message = "Unable to find build log; job may be pending."
cmticece5ffa42015-02-12 15:18:43 -0800220 done = False
cmtice46093e52014-12-09 14:59:16 -0800221
cmticeaea53412015-06-19 09:44:43 -0700222 if done:
223 data_dict = FindBuildRecordFromLog(description, build_info)
224 if not data_dict:
225 # Trybot job may be pending (not actually launched yet).
226 if pending_time > TIME_OUT:
227 logger.GetLogger().LogFatal("Unable to find build record for trybot"
228 " %s." % description)
229 else:
230 pending_message = "Unable to find build record; job may be pending."
231 done = False
232
cmticece5ffa42015-02-12 15:18:43 -0800233 else:
cmticeaea53412015-06-19 09:44:43 -0700234 # Now that we have actually found the entry for the build
235 # job in the build log, we know the job is actually
236 # runnning, not pending, so we flip the 'pending' flag. We
237 # still have to wait for the buildbot job to finish running
238 # however.
239 pending = False
240 if "True" in data_dict["completed"]:
241 build_id = data_dict["number"]
242 build_status = int(data_dict["result"])
243 else:
244 done = False
cmtice46093e52014-12-09 14:59:16 -0800245
Rahul Chaudhryc7a9ac52015-08-05 11:13:35 -0700246 if not done:
247 if pending:
248 logger.GetLogger().LogOutput(pending_message)
249 logger.GetLogger().LogOutput("Current pending time: %d minutes." %
250 (pending_time / 60))
251 pending_time += SLEEP_TIME
252 else:
253 logger.GetLogger().LogOutput("{0} minutes passed.".format(
254 running_time / 60))
255 logger.GetLogger().LogOutput("Sleeping {0} seconds.".format(
256 SLEEP_TIME))
257 running_time += SLEEP_TIME
cmticeaea53412015-06-19 09:44:43 -0700258
Rahul Chaudhryc7a9ac52015-08-05 11:13:35 -0700259 time.sleep(SLEEP_TIME)
260 if running_time > TIME_OUT:
261 done = True
cmtice46093e52014-12-09 14:59:16 -0800262
cmtice1047b072015-02-10 09:33:21 -0800263 trybot_image = FindArchiveImage(chromeos_root, build, build_id)
264 if not trybot_image:
265 logger.GetLogger().LogError("Trybot job %s failed with status %d;"
266 " no trybot image generated."
267 % (description, build_status))
cmtice46093e52014-12-09 14:59:16 -0800268
cmtice1047b072015-02-10 09:33:21 -0800269 logger.GetLogger().LogOutput("trybot_image is '%s'" % trybot_image)
cmticeaea53412015-06-19 09:44:43 -0700270 logger.GetLogger().LogOutput("build_status is %d" % build_status)
cmtice1047b072015-02-10 09:33:21 -0800271 return trybot_image