diff options
author | Ravi Mistry <rmistry@google.com> | 2018-01-31 16:08:24 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-01-31 21:19:00 +0000 |
commit | 17823764300ff33ce5969113a818eb8de7cef3fc (patch) | |
tree | 81853056671dd2f1b84dc85d8c1da87ebc351251 /infra/bots/android_compile/trigger_wait_ac_task.py | |
parent | d5f9cdd4b3a6ab0e49bb1a56f2e52e2f40edd0fa (diff) |
Add script that registers an Android compile task and waits for it to complete
It will be called from a new recipe.
This script follows the same pattern that the trigger_wait_ct_task.py used to
(https://codereview.chromium.org/1370523002).
NoTry: true
Bug: skia:7469
Change-Id: I450e415b004e7f481ca1b377d350eb64e5fa8250
Reviewed-on: https://skia-review.googlesource.com/102340
Commit-Queue: Ravi Mistry <rmistry@google.com>
Reviewed-by: Eric Boren <borenet@google.com>
Diffstat (limited to 'infra/bots/android_compile/trigger_wait_ac_task.py')
-rw-r--r-- | infra/bots/android_compile/trigger_wait_ac_task.py | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/infra/bots/android_compile/trigger_wait_ac_task.py b/infra/bots/android_compile/trigger_wait_ac_task.py new file mode 100644 index 0000000000..dcbde3ec9c --- /dev/null +++ b/infra/bots/android_compile/trigger_wait_ac_task.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python +# Copyright (c) 2018 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. + +"""Script that triggers and waits for tasks on android-compile.skia.org""" + +import base64 +import hashlib +import json +import optparse +import requests +import sys +import time + + +ANDROID_COMPILE_HOST = "https://android-compile.skia.org" +ANDROID_COMPILE_REGISTER_POST_URI = ANDROID_COMPILE_HOST + "/_/register" +ANDROID_COMPILE_TASK_STATUS_URI = ANDROID_COMPILE_HOST + "/get_task_status" +GCE_WEBHOOK_SALT_METADATA_URI = ( + "http://metadata/computeMetadata/v1/project/attributes/" + "ac_webhook_request_salt") + + +POLLING_FREQUENCY_SECS = 60 # 1 minute. +DEADLINE_SECS = 30 * 60 # 30 minutes. + + +class AndroidCompileException(Exception): + pass + + +def _CreateTaskJSON(options): + """Creates a JSON representation of the requested task.""" + params = {} + params["issue"] = options.issue + params["patchset"] = options.patchset + params["hash"] = options.hash + return json.dumps(params) + + +def _GetWebhookSaltFromMetadata(): + """Gets webhook_request_salt from GCE's metadata server.""" + headers = {"Metadata-Flavor": "Google"} + resp = requests.get(GCE_WEBHOOK_SALT_METADATA_URI, headers=headers) + if resp.status_code != 200: + raise AndroidCompileException( + 'Return code from %s was %s' % (GCE_WEBHOOK_SALT_METADATA_URI, + resp.status_code)) + return resp.text + + +def _GetAuthHeaders(data, options): + m = hashlib.sha512() + if data: + m.update(data) + m.update('notverysecret' if options.local else _GetWebhookSaltFromMetadata()) + encoded = base64.standard_b64encode(m.digest()) + return { + "Content-type": "application/x-www-form-urlencoded", + "Accept": "application/json", + "X-Webhook-Auth-Hash": encoded} + + +def _TriggerTask(options): + """Triggers the task on Android Compile and returns the new task's ID.""" + task = _CreateTaskJSON(options) + headers = _GetAuthHeaders(task, options) + resp = requests.post(ANDROID_COMPILE_REGISTER_POST_URI, task, headers=headers) + + if resp.status_code != 200: + raise AndroidCompileException( + 'Return code from %s was %s' % (ANDROID_COMPILE_REGISTER_POST_URI, + resp.status_code)) + try: + ret = json.loads(resp.text) + except ValueError, e: + raise AndroidCompileException( + 'Did not get a JSON response from %s: %s' % ( + ANDROID_COMPILE_REGISTER_POST_URI, e)) + return ret["taskID"] + + +def TriggerAndWait(options): + task_id = _TriggerTask(options) + task_str = '[id: %d, issue: %d, patchset: %d, hash: %s]' % ( + task_id, options.issue, options.patchset, options.hash) + + print + print 'Task %s has been successfully scheduled on %s.' % ( + task_str, ANDROID_COMPILE_HOST) + print + print 'The server will be polled every %d seconds.' % POLLING_FREQUENCY_SECS + print + + headers = _GetAuthHeaders('', options) + # Now poll the server till the task completes or till deadline is hit. + time_started_polling = time.time() + while True: + if (time.time() - time_started_polling) > DEADLINE_SECS: + raise AndroidCompileException( + 'Task did not complete in the deadline of %s seconds.' % ( + DEADLINE_SECS)) + + # Get the status of the task the trybot added. + get_url = '%s?task=%s' % (ANDROID_COMPILE_TASK_STATUS_URI, task_id) + resp = requests.get(get_url, headers=headers) + if resp.status_code != 200: + raise AndroidCompileException( + 'Return code from %s was %s' % (ANDROID_COMPILE_TASK_STATUS_URI, + resp.status_code)) + try: + ret = json.loads(resp.text) + except ValueError, e: + raise AndroidCompileException( + 'Did not get a JSON response from %s: %s' % (get_url, e)) + + if ret["infra_failure"]: + raise AndroidCompileException( + 'Your run failed due to infra failures. It could be due to needing ' + 'to rebase or something else.') + + if ret["done"]: + print + if ret["withpatch_success"]: + print 'Your run was successfully completed.' + print 'With patch logs are here: %s' % ret["withpatch_log"] + print + return 0 + elif ret["nopatch_success"]: + raise AndroidCompileException('The build with the patch failed and the ' + 'build without the patch succeeded. This means that the patch ' + 'causes Android to fail compilation.\n' + 'With patch logs are here: %s\n' + 'No patch logs are here: %s' % ( + ret["withpatch_log"], ret["nopatch_log"])) + else: + print ('Both with patch and no patch builds failed. This means that the' + ' Android tree is currently broken. Marking this bot as ' + 'successful') + print 'With patch logs are here: %s' % ret["WithPatchLog"] + print 'No patch logs are here: %s' % ret["NoPatchLog"] + return 0 + + sys.stdout.write('.') + sys.stdout.flush() + time.sleep(POLLING_FREQUENCY_SECS) + + +def main(): + option_parser = optparse.OptionParser() + option_parser.add_option( + '', '--issue', type=int, default=0, + help='The Gerrit change number to get the patch from.') + option_parser.add_option( + '', '--patchset', type=int, default=0, + help='The Gerrit change patchset to use.') + option_parser.add_option( + '', '--hash', type=str, default='', + help='The Skia repo hash to compile against.') + option_parser.add_option( + '', '--local', default=False, action='store_true', + help='Uses a dummy metadata salt if this flag is true else it tries to ' + 'get the salt from GCE metadata.') + options, _ = option_parser.parse_args() + sys.exit(TriggerAndWait(options)) + + +if __name__ == '__main__': + main() |