Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 import argparse | 6 import argparse |
| 7 import contextlib | 7 import contextlib |
| 8 import cStringIO | 8 import cStringIO |
| 9 import datetime | 9 import datetime |
| 10 import gzip | 10 import gzip |
| 11 import json | 11 import json |
| 12 import logging | 12 import logging |
| 13 import multiprocessing | 13 import multiprocessing |
| 14 import os | 14 import os |
| 15 import sys | 15 import sys |
| 16 import threading | |
| 16 import traceback | 17 import traceback |
| 17 | 18 |
| 18 import requests | 19 import requests |
| 19 import requests_cache | 20 import requests_cache |
| 20 | 21 |
| 21 from infra_libs import logs | 22 from infra_libs import logs |
| 22 from infra_libs import ts_mon | 23 from infra_libs import ts_mon |
| 23 from infra.libs.service_utils import outer_loop | 24 from infra.libs.service_utils import outer_loop |
| 24 | 25 |
| 25 from infra.services.builder_alerts import alert_builder | 26 from infra.services.builder_alerts import alert_builder |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 53 class SubProcess(object): | 54 class SubProcess(object): |
| 54 | 55 |
| 55 def __init__(self, cache, old_alerts, builder_filter, jobs): | 56 def __init__(self, cache, old_alerts, builder_filter, jobs): |
| 56 super(SubProcess, self).__init__() | 57 super(SubProcess, self).__init__() |
| 57 self._cache = cache | 58 self._cache = cache |
| 58 self._old_alerts = old_alerts | 59 self._old_alerts = old_alerts |
| 59 self._builder_filter = builder_filter | 60 self._builder_filter = builder_filter |
| 60 self._jobs = jobs | 61 self._jobs = jobs |
| 61 | 62 |
| 62 def __call__(self, master_url): | 63 def __call__(self, master_url): |
| 64 logging.debug('Thread for master %s has started', master_url) | |
| 63 try: | 65 try: |
| 64 master_json = buildbot.fetch_master_json(master_url) | 66 master_json = buildbot.fetch_master_json(master_url) |
| 65 if not master_json: | 67 if not master_json: |
| 66 return (None, None, None, master_url) | 68 return (None, None, None, master_url) |
| 67 | 69 |
| 68 master_alerts, stale_master_alert = alert_builder.alerts_for_master( | 70 master_alerts, stale_master_alert = alert_builder.alerts_for_master( |
| 69 self._cache, master_url, master_json, self._old_alerts, | 71 self._cache, master_url, master_json, self._old_alerts, |
| 70 self._builder_filter, self._jobs) | 72 self._builder_filter, self._jobs) |
| 71 | 73 |
| 72 # FIXME: The builder info doesn't really belong here. The builder | 74 # FIXME: The builder info doesn't really belong here. The builder |
| 73 # revisions tool uses this and we happen to have the builder json cached | 75 # revisions tool uses this and we happen to have the builder json cached |
| 74 # at this point so it's cheap to compute, but it should be moved | 76 # at this point so it's cheap to compute, but it should be moved |
| 75 # to a different feed. | 77 # to a different feed. |
| 76 data, stale_builder_alerts = ( | 78 data, stale_builder_alerts = ( |
| 77 buildbot.latest_builder_info_and_alerts_for_master( | 79 buildbot.latest_builder_info_and_alerts_for_master( |
| 78 self._cache, master_url, master_json)) | 80 self._cache, master_url, master_json)) |
| 79 if stale_master_alert: | 81 if stale_master_alert: |
| 80 stale_builder_alerts.append(stale_master_alert) | 82 stale_builder_alerts.append(stale_master_alert) |
| 81 return (master_alerts, data, stale_builder_alerts, master_url) | 83 return (master_alerts, data, stale_builder_alerts, master_url) |
| 82 except: | 84 except: |
| 83 # Put all exception text into an exception and raise that so it doesn't | 85 # Put all exception text into an exception and raise that so it doesn't |
| 84 # get eaten by the multiprocessing code. | 86 # get eaten by the multiprocessing code. |
| 85 msg = '%s for master url %s' % ( | 87 msg = '%s for master url %s' % ( |
| 86 ''.join(traceback.format_exception(*sys.exc_info())), | 88 ''.join(traceback.format_exception(*sys.exc_info())), |
| 87 master_url, | 89 master_url, |
| 88 ) | 90 ) |
| 89 raise Exception(msg) | 91 raise Exception(msg) |
| 92 finally: | |
| 93 logging.debug('Thread for master %s has finished', master_url) | |
| 90 | 94 |
| 91 | 95 |
| 92 def query_findit(findit_api_url, alerts): | 96 def query_findit(findit_api_url, alerts): |
| 93 """Get analysis results from Findit for failures in the given alerts. | 97 """Get analysis results from Findit for failures in the given alerts. |
| 94 | 98 |
| 95 Args: | 99 Args: |
| 96 findit_api_url (str): The URL to findit's api for build failure analysis. | 100 findit_api_url (str): The URL to findit's api for build failure analysis. |
| 97 alerts (list): A non-empty list of failure alerts. | 101 alerts (list): A non-empty list of failure alerts. |
| 98 | 102 |
| 99 Returns: | 103 Returns: |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 182 | 186 |
| 183 | 187 |
| 184 def gzipped(data): | 188 def gzipped(data): |
| 185 s = cStringIO.StringIO() | 189 s = cStringIO.StringIO() |
| 186 with contextlib.closing(gzip.GzipFile(fileobj=s, mode='w')) as g: | 190 with contextlib.closing(gzip.GzipFile(fileobj=s, mode='w')) as g: |
| 187 g.write(data) | 191 g.write(data) |
| 188 return s.getvalue() | 192 return s.getvalue() |
| 189 | 193 |
| 190 | 194 |
| 191 def inner_loop(args): | 195 def inner_loop(args): |
| 196 logging.debug('Starting inner loop') | |
| 192 old_api_endpoint = string_helpers.slash_join(args.api_endpoint_prefix, | 197 old_api_endpoint = string_helpers.slash_join(args.api_endpoint_prefix, |
| 193 args.old_api_path) if args.old_api_path else None | 198 args.old_api_path) if args.old_api_path else None |
| 194 if not old_api_endpoint: | 199 if not old_api_endpoint: |
| 195 logging.warn( | 200 logging.warn( |
| 196 'No /data url passed, will write to builder_alerts.json. JSON posted ' | 201 'No /data url passed, will write to builder_alerts.json. JSON posted ' |
| 197 'to new API endpoints will be written to builder_alerts_<tree>.json ' | 202 'to new API endpoints will be written to builder_alerts_<tree>.json ' |
| 198 'files.') | 203 'files.') |
| 199 | 204 |
| 200 if args.use_cache: | 205 if args.use_cache: |
| 201 requests_cache.install_cache('failure_stats') | 206 requests_cache.install_cache('failure_stats') |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 242 ' %s' % (master, builder, step, reason)) | 247 ' %s' % (master, builder, step, reason)) |
| 243 | 248 |
| 244 old_alerts[alert_key] = alert | 249 old_alerts[alert_key] = alert |
| 245 | 250 |
| 246 latest_builder_info = {} | 251 latest_builder_info = {} |
| 247 stale_builder_alerts = [] | 252 stale_builder_alerts = [] |
| 248 missing_masters = [] | 253 missing_masters = [] |
| 249 alerts = [] | 254 alerts = [] |
| 250 suspected_cls = [] | 255 suspected_cls = [] |
| 251 | 256 |
| 257 logging.debug('Processing all masters via process pool') | |
| 252 pool = multiprocessing.Pool(processes=args.processes) | 258 pool = multiprocessing.Pool(processes=args.processes) |
| 253 master_datas = pool.map(SubProcess(cache, old_alerts, args.builder_filter, | 259 master_datas = pool.map(SubProcess(cache, old_alerts, args.builder_filter, |
| 254 args.jobs), master_urls) | 260 args.jobs), master_urls) |
| 261 logging.debug('Closing all threads in master process pool') | |
| 255 pool.close() | 262 pool.close() |
| 256 pool.join() | 263 pool.join() |
| 264 logging.debug('Joined all threads in master process pool') | |
| 257 | 265 |
| 258 for data in master_datas: | 266 for data in master_datas: |
| 259 # TODO(ojan): We should put an alert in the JSON for this master so | 267 # TODO(ojan): We should put an alert in the JSON for this master so |
| 260 # we can show that the master is down in the sheriff-o-matic UI. | 268 # we can show that the master is down in the sheriff-o-matic UI. |
| 261 if not data[0]: | 269 if not data[0]: |
| 262 missing_masters.extend([data[3]]) | 270 missing_masters.extend([data[3]]) |
| 263 continue | 271 continue |
| 264 alerts.extend(data[0]) | 272 alerts.extend(data[0]) |
| 265 latest_builder_info.update(data[1]) | 273 latest_builder_info.update(data[1]) |
| 266 stale_builder_alerts.extend(data[2]) | 274 stale_builder_alerts.extend(data[2]) |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 337 resp.status_code, resp.reason, resp.content) | 345 resp.status_code, resp.reason, resp.content) |
| 338 ret = False | 346 ret = False |
| 339 else: | 347 else: |
| 340 with open('builder_alerts_%s.json' % tree, 'w') as f: | 348 with open('builder_alerts_%s.json' % tree, 'w') as f: |
| 341 f.write(json.dumps(json_data, indent=1)) | 349 f.write(json.dumps(json_data, indent=1)) |
| 342 else: | 350 else: |
| 343 logging.error( | 351 logging.error( |
| 344 '--crbug-service-account was not specified, can not get crbug issues') | 352 '--crbug-service-account was not specified, can not get crbug issues') |
| 345 ret = False | 353 ret = False |
| 346 | 354 |
| 355 logging.debug('Returning from inner loop') | |
| 347 return ret | 356 return ret |
| 348 | 357 |
| 349 | 358 |
| 350 def main(args): | 359 def main(args): |
| 351 parser = argparse.ArgumentParser(prog='run.py %s' % __package__) | 360 parser = argparse.ArgumentParser(prog='run.py %s' % __package__) |
| 352 parser.add_argument('data_url', action='store', nargs='*') # Deprecated | 361 parser.add_argument('data_url', action='store', nargs='*') # Deprecated |
| 353 parser.add_argument('--use-cache', action='store_true') | 362 parser.add_argument('--use-cache', action='store_true') |
| 354 parser.add_argument('--master-filter', action='store') | 363 parser.add_argument('--master-filter', action='store') |
| 355 parser.add_argument('--builder-filter', action='store') | 364 parser.add_argument('--builder-filter', action='store') |
| 356 parser.add_argument('--processes', default=PARALLEL_TASKS, action='store', | 365 parser.add_argument('--processes', default=PARALLEL_TASKS, action='store', |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 421 def filter(record): | 430 def filter(record): |
| 422 if record.levelno == logging.INFO: | 431 if record.levelno == logging.INFO: |
| 423 return False | 432 return False |
| 424 return True | 433 return True |
| 425 logging.getLogger('requests.packages.urllib3.connectionpool').addFilter( | 434 logging.getLogger('requests.packages.urllib3.connectionpool').addFilter( |
| 426 _ConnectionpoolFilter()) | 435 _ConnectionpoolFilter()) |
| 427 | 436 |
| 428 def outer_loop_iteration(): | 437 def outer_loop_iteration(): |
| 429 return inner_loop(args) | 438 return inner_loop(args) |
| 430 | 439 |
| 440 logging.debug('Starting outer loop') | |
| 431 loop_results = outer_loop.loop( | 441 loop_results = outer_loop.loop( |
| 432 task=outer_loop_iteration, | 442 task=outer_loop_iteration, |
| 433 sleep_timeout=lambda: 5, | 443 sleep_timeout=lambda: 5, |
| 434 **loop_args) | 444 **loop_args) |
| 445 logging.debug('Finished outer loop') | |
| 435 | 446 |
| 436 logging.debug('Flushing ts_mon starting') | 447 logging.debug('Flushing ts_mon starting') |
| 437 ts_mon.flush() | 448 ts_mon.flush() |
| 438 logging.debug('Flushing ts_mon completed') | 449 logging.debug('Flushing ts_mon completed') |
| 439 return 0 if loop_results.success else 1 | 450 return 0 if loop_results.success else 1 |
| 440 | 451 |
| 441 | 452 |
| 442 if __name__ == '__main__': | 453 if __name__ == '__main__': |
| 454 logging.debug('Started main') | |
| 443 sys.exit(main(sys.argv[1:])) | 455 sys.exit(main(sys.argv[1:])) |
| 456 current_thread_descriptions = [t.name + (' (daemon)' if t.isDaemon() else '') | |
|
tandrii(chromium)
2016/07/26 09:56:35
this will never be executed. sys.exit raises Syste
| |
| 457 for t in threading.enumerate()] | |
| 458 logging.debug( | |
| 459 'Leaving main. Threads: %s', ', '.join(current_thread_descriptions)) | |
| OLD | NEW |