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

Side by Side Diff: swarming.py

Issue 51383003: Report all swarming and isolate fatal errors in a consistent way. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/swarm_client
Patch Set: make isolate_smoke_test less strict regarding exact contents of stderr Created 7 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « run_isolated.py ('k') | tests/isolate_smoke_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2013 The Chromium Authors. All rights reserved. 2 # Copyright 2013 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 """Client tool to trigger tasks or retrieve results from a Swarming server.""" 6 """Client tool to trigger tasks or retrieve results from a Swarming server."""
7 7
8 __version__ = '0.1' 8 __version__ = '0.1'
9 9
10 import hashlib 10 import hashlib
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 start_time = time.time() 126 start_time = time.time()
127 self._isolate_item = isolateserver.BufferItem( 127 self._isolate_item = isolateserver.BufferItem(
128 self.bundle.zip_into_buffer(), self._algo, is_isolated=True) 128 self.bundle.zip_into_buffer(), self._algo, is_isolated=True)
129 print 'Zipping completed, time elapsed: %f' % (time.time() - start_time) 129 print 'Zipping completed, time elapsed: %f' % (time.time() - start_time)
130 130
131 try: 131 try:
132 start_time = time.time() 132 start_time = time.time()
133 uploaded = self.storage.upload_items([self._isolate_item]) 133 uploaded = self.storage.upload_items([self._isolate_item])
134 elapsed = time.time() - start_time 134 elapsed = time.time() - start_time
135 except (IOError, OSError) as exc: 135 except (IOError, OSError) as exc:
136 print >> sys.stderr, 'Failed to upload the zip file: %s' % exc 136 tools.report_error('Failed to upload the zip file: %s' % exc)
137 return False 137 return False
138 138
139 if self._isolate_item in uploaded: 139 if self._isolate_item in uploaded:
140 print 'Upload complete, time elapsed: %f' % elapsed 140 print 'Upload complete, time elapsed: %f' % elapsed
141 else: 141 else:
142 print 'Zip file already on server, time elapsed: %f' % elapsed 142 print 'Zip file already on server, time elapsed: %f' % elapsed
143 143
144 return True 144 return True
145 145
146 def to_json(self): 146 def to_json(self):
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 file_hash_or_isolated, test_name, shards, test_filter, slave_os, 340 file_hash_or_isolated, test_name, shards, test_filter, slave_os,
341 working_dir, isolate_server, swarming, verbose, profile, priority, algo): 341 working_dir, isolate_server, swarming, verbose, profile, priority, algo):
342 """Process the manifest file and send off the swarm test request. 342 """Process the manifest file and send off the swarm test request.
343 343
344 Optionally archives an .isolated file. 344 Optionally archives an .isolated file.
345 """ 345 """
346 if file_hash_or_isolated.endswith('.isolated'): 346 if file_hash_or_isolated.endswith('.isolated'):
347 file_hash = archive( 347 file_hash = archive(
348 file_hash_or_isolated, isolate_server, slave_os, algo, verbose) 348 file_hash_or_isolated, isolate_server, slave_os, algo, verbose)
349 if not file_hash: 349 if not file_hash:
350 print >> sys.stderr, 'Archival failure %s' % file_hash_or_isolated 350 tools.report_error('Archival failure %s' % file_hash_or_isolated)
351 return 1 351 return 1
352 elif isolateserver.is_valid_hash(file_hash_or_isolated, algo): 352 elif isolateserver.is_valid_hash(file_hash_or_isolated, algo):
353 file_hash = file_hash_or_isolated 353 file_hash = file_hash_or_isolated
354 else: 354 else:
355 print >> sys.stderr, 'Invalid hash %s' % file_hash_or_isolated 355 tools.report_error('Invalid hash %s' % file_hash_or_isolated)
356 return 1 356 return 1
357 357
358 try: 358 try:
359 manifest = Manifest( 359 manifest = Manifest(
360 file_hash, 360 file_hash,
361 test_name, 361 test_name,
362 shards, 362 shards,
363 test_filter, 363 test_filter,
364 PLATFORM_MAPPING_SWARMING[slave_os], 364 PLATFORM_MAPPING_SWARMING[slave_os],
365 working_dir, 365 working_dir,
366 isolate_server, 366 isolate_server,
367 verbose, 367 verbose,
368 profile, 368 profile,
369 priority, 369 priority,
370 algo) 370 algo)
371 except ValueError as e: 371 except ValueError as e:
372 print >> sys.stderr, 'Unable to process %s: %s' % (test_name, e) 372 tools.report_error('Unable to process %s: %s' % (test_name, e))
373 return 1 373 return 1
374 374
375 chromium_setup(manifest) 375 chromium_setup(manifest)
376 376
377 # Zip up relevant files. 377 # Zip up relevant files.
378 print('Zipping up files...') 378 print('Zipping up files...')
379 if not manifest.zip_and_upload(): 379 if not manifest.zip_and_upload():
380 return 1 380 return 1
381 381
382 # Send test requests off to swarm. 382 # Send test requests off to swarm.
383 print('Sending test requests to swarm.') 383 print('Sending test requests to swarm.')
384 print('Server: %s' % swarming) 384 print('Server: %s' % swarming)
385 print('Job name: %s' % test_name) 385 print('Job name: %s' % test_name)
386 test_url = swarming + '/test' 386 test_url = swarming + '/test'
387 manifest_text = manifest.to_json() 387 manifest_text = manifest.to_json()
388 result = net.url_read(test_url, data={'request': manifest_text}) 388 result = net.url_read(test_url, data={'request': manifest_text})
389 if not result: 389 if not result:
390 print >> sys.stderr, 'Failed to send test for %s\n%s' % ( 390 tools.report_error(
391 test_name, test_url) 391 'Failed to send test for %s\n%s' % (test_name, test_url))
392 return 1 392 return 1
393 try: 393 try:
394 json.loads(result) 394 json.loads(result)
395 except (ValueError, TypeError) as e: 395 except (ValueError, TypeError) as e:
396 print >> sys.stderr, 'Failed to send test for %s' % test_name 396 msg = '\n'.join((
397 print >> sys.stderr, 'Manifest: %s' % manifest_text 397 'Failed to send test for %s' % test_name,
398 print >> sys.stderr, 'Bad response: %s' % result 398 'Manifest: %s' % manifest_text,
399 print >> sys.stderr, str(e) 399 'Bad response: %s' % result,
400 str(e)))
401 tools.report_error(msg)
400 return 1 402 return 1
401 return 0 403 return 0
402 404
403 405
404 def trigger( 406 def trigger(
405 slave_os, 407 slave_os,
406 tasks, 408 tasks,
407 task_prefix, 409 task_prefix,
408 working_dir, 410 working_dir,
409 isolate_server, 411 isolate_server,
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 add_collect_options(parser) 533 add_collect_options(parser)
532 (options, args) = parser.parse_args(args) 534 (options, args) = parser.parse_args(args)
533 if not args: 535 if not args:
534 parser.error('Must specify one test name.') 536 parser.error('Must specify one test name.')
535 elif len(args) > 1: 537 elif len(args) > 1:
536 parser.error('Must specify only one test name.') 538 parser.error('Must specify only one test name.')
537 539
538 try: 540 try:
539 return collect(options.swarming, args[0], options.timeout, options.decorate) 541 return collect(options.swarming, args[0], options.timeout, options.decorate)
540 except Failure as e: 542 except Failure as e:
541 parser.error(e.args[0]) 543 tools.report_error(e)
544 return 1
542 545
543 546
544 @subcommand.usage('[hash|isolated ...]') 547 @subcommand.usage('[hash|isolated ...]')
545 def CMDrun(parser, args): 548 def CMDrun(parser, args):
546 """Triggers a job and wait for the results. 549 """Triggers a job and wait for the results.
547 550
548 Basically, does everything to run command(s) remotely. 551 Basically, does everything to run command(s) remotely.
549 """ 552 """
550 add_trigger_options(parser) 553 add_trigger_options(parser)
551 add_collect_options(parser) 554 add_collect_options(parser)
(...skipping 13 matching lines...) Expand all
565 options.task_prefix, 568 options.task_prefix,
566 options.working_dir, 569 options.working_dir,
567 options.isolate_server, 570 options.isolate_server,
568 options.swarming, 571 options.swarming,
569 options.verbose, 572 options.verbose,
570 options.profile, 573 options.profile,
571 options.priority) 574 options.priority)
572 except Failure as e: 575 except Failure as e:
573 result = e.args[0] 576 result = e.args[0]
574 if result: 577 if result:
575 print >> sys.stderr, 'Failed to trigger %s: %s' % (arg, result) 578 tools.report_error('Failed to trigger %s: %s' % (arg, result))
576 else: 579 else:
577 success.append(os.path.basename(arg)) 580 success.append(os.path.basename(arg))
578 581
579 if not success: 582 if not success:
580 print >> sys.stderr, 'Failed to trigger any job.' 583 tools.report_error('Failed to trigger any job.')
581 return result 584 return result
582 585
583 code = 0 586 code = 0
584 for arg in success: 587 for arg in success:
585 logging.info('Collecting %s', arg) 588 logging.info('Collecting %s', arg)
586 try: 589 try:
587 new_code = collect( 590 new_code = collect(
588 options.swarming, 591 options.swarming,
589 options.task_prefix + arg, 592 options.task_prefix + arg,
590 options.timeout, 593 options.timeout,
591 options.decorate) 594 options.decorate)
592 code = max(code, new_code) 595 code = max(code, new_code)
593 except Failure as e: 596 except Failure as e:
594 code = max(code, 1) 597 code = max(code, 1)
595 print >> sys.stderr, e.args[0] 598 tools.report_error(e)
596 return code 599 return code
597 600
598 601
599 def CMDtrigger(parser, args): 602 def CMDtrigger(parser, args):
600 """Triggers Swarm request(s). 603 """Triggers Swarm request(s).
601 604
602 Accepts one or multiple --task requests, with either the hash (sha1) of a 605 Accepts one or multiple --task requests, with either the hash (sha1) of a
603 .isolated file already uploaded or the path to an .isolated file to archive, 606 .isolated file already uploaded or the path to an .isolated file to archive,
604 packages it if needed and sends a Swarm manifest file to the Swarm server. 607 packages it if needed and sends a Swarm manifest file to the Swarm server.
605 """ 608 """
(...skipping 17 matching lines...) Expand all
623 options.os, 626 options.os,
624 options.tasks, 627 options.tasks,
625 options.task_prefix, 628 options.task_prefix,
626 options.working_dir, 629 options.working_dir,
627 options.isolate_server, 630 options.isolate_server,
628 options.swarming, 631 options.swarming,
629 options.verbose, 632 options.verbose,
630 options.profile, 633 options.profile,
631 options.priority) 634 options.priority)
632 except Failure as e: 635 except Failure as e:
633 parser.error(e.args[0]) 636 tools.report_error(e)
637 return 1
634 638
635 639
636 class OptionParserSwarming(tools.OptionParserWithLogging): 640 class OptionParserSwarming(tools.OptionParserWithLogging):
637 def __init__(self, **kwargs): 641 def __init__(self, **kwargs):
638 tools.OptionParserWithLogging.__init__( 642 tools.OptionParserWithLogging.__init__(
639 self, prog='swarming.py', **kwargs) 643 self, prog='swarming.py', **kwargs)
640 self.add_option( 644 self.add_option(
641 '-S', '--swarming', 645 '-S', '--swarming',
642 metavar='URL', default='', 646 metavar='URL', default='',
643 help='Swarming server to use') 647 help='Swarming server to use')
644 648
645 def parse_args(self, *args, **kwargs): 649 def parse_args(self, *args, **kwargs):
646 options, args = tools.OptionParserWithLogging.parse_args( 650 options, args = tools.OptionParserWithLogging.parse_args(
647 self, *args, **kwargs) 651 self, *args, **kwargs)
648 options.swarming = options.swarming.rstrip('/') 652 options.swarming = options.swarming.rstrip('/')
649 if not options.swarming: 653 if not options.swarming:
650 self.error('--swarming is required.') 654 self.error('--swarming is required.')
651 return options, args 655 return options, args
652 656
653 657
654 def main(args): 658 def main(args):
655 dispatcher = subcommand.CommandDispatcher(__name__) 659 dispatcher = subcommand.CommandDispatcher(__name__)
656 try: 660 try:
657 return dispatcher.execute(OptionParserSwarming(version=__version__), args) 661 return dispatcher.execute(OptionParserSwarming(version=__version__), args)
658 except Failure as e: 662 except Exception as e:
659 sys.stderr.write('\nError: ') 663 tools.report_error(e)
660 sys.stderr.write(str(e))
661 sys.stderr.write('\n')
662 return 1 664 return 1
663 665
664 666
665 if __name__ == '__main__': 667 if __name__ == '__main__':
666 fix_encoding.fix_encoding() 668 fix_encoding.fix_encoding()
667 tools.disable_buffering() 669 tools.disable_buffering()
668 colorama.init() 670 colorama.init()
669 sys.exit(main(sys.argv[1:])) 671 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « run_isolated.py ('k') | tests/isolate_smoke_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698