Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 """Provides API wrapper for FindIt""" | |
| 6 | |
| 7 import httplib2 | |
| 8 import logging | |
| 9 import time | |
| 10 | |
| 11 from apiclient import discovery | |
| 12 from apiclient.errors import HttpError | |
| 13 from oauth2client.appengine import AppAssertionCredentials | |
| 14 | |
| 15 | |
| 16 # TODO(akuegel): Do we want to use a different timeout? Do we want to use a | |
| 17 # cache? See documentation here: | |
| 18 # https://github.com/jcgregorio/httplib2/blob/master/python2/httplib2/__init__.p y#L1142 | |
| 19 def _createHttpObject(scope): | |
| 20 credentials = AppAssertionCredentials(scope=scope) | |
| 21 return credentials.authorize(httplib2.Http()) | |
| 22 | |
| 23 | |
| 24 def _buildClient(api_name, api_version, http, discovery_url): | |
| 25 # This occassionally hits a 503 "Backend Error". Hopefully a simple retry | |
| 26 # can recover. | |
| 27 tries_left = 5 | |
| 28 tries_wait = 10 | |
| 29 while tries_left: | |
| 30 tries_left -= 1 | |
| 31 try: | |
| 32 client = discovery.build( | |
| 33 api_name, api_version, | |
| 34 discoveryServiceUrl=discovery_url, | |
| 35 http=http) | |
| 36 break | |
| 37 except HttpError as e: | |
| 38 if tries_left: | |
| 39 logging.error( | |
| 40 'apiclient.discovery.build() failed for %s: %s', api_name, e) | |
| 41 logging.error( | |
| 42 'Retrying apiclient.discovery.build() in %s seconds.', tries_wait) | |
| 43 time.sleep(tries_wait) | |
| 44 else: | |
| 45 logging.exception( | |
| 46 'apiclient.discovery.build() failed for %s too many times.', | |
| 47 api_name) | |
| 48 raise e | |
| 49 return client | |
| 50 | |
| 51 | |
| 52 class FindItAPI(object): | |
| 53 """A wrapper around the FindIt api.""" | |
| 54 def __init__(self): | |
| 55 self.client = _buildClient( | |
| 56 'findit', 'v1', | |
| 57 _createHttpObject('https://www.googleapis.com/auth/userinfo.email'), | |
| 58 'https://findit-for-me.appspot.com/_ah/api/discovery/v1/apis/{api}/' | |
| 59 '{apiVersion}/rest') | |
| 60 | |
| 61 def _retry_api_call(self, request, num_retries=5): | |
| 62 retries = 0 | |
| 63 while True: | |
| 64 try: | |
| 65 return request.execute() | |
| 66 except HttpError as e: | |
| 67 # This retries internal server (500, 503) and quota (403) errors. | |
| 68 if retries == num_retries or e.resp.status not in [403, 500, 503]: | |
| 69 raise | |
| 70 time.sleep(2**retries) | |
| 71 retries += 1 | |
| 72 | |
| 73 def flake(self, flake, flaky_runs): | |
| 74 body = {} | |
| 75 body['name'] = flake.name | |
| 76 body['is_step'] = flake.is_step | |
| 77 body['bug_id'] = flake.issue_id | |
| 78 body['build_steps'] = [] | |
| 79 for flaky_run in flaky_runs: | |
| 80 failure_run = flaky_run.failure_run.get() | |
| 81 patchset_build_run = failure_run.parent.get() | |
| 82 for occurrence in flaky_run.flakes: | |
| 83 body['build_steps'].append({ | |
| 84 'master_name': patchset_build_run.master, | |
| 85 'builder_name': patchset_build_run.builder, | |
| 86 'build_number': failure_run.buildnumber, | |
| 87 'step_name': occurrence.name | |
|
stgao
2016/10/03 19:24:35
To double check:
is it the original step name as s
Sergiy Byelozyorov
2016/10/04 08:58:22
This is original step name. The normalized step na
stgao
2016/10/05 00:28:47
Acknowledged.
| |
| 88 }) | |
| 89 self._retry_api_call(self.client.flake(body=body)) | |
| OLD | NEW |