Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2015 The LUCI Authors. All rights reserved. | 1 # Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 # Use of this source code is governed under the Apache License, Version 2.0 | 2 # Use of this source code is governed under the Apache License, Version 2.0 |
| 3 # that can be found in the LICENSE file. | 3 # that can be found in the LICENSE file. |
| 4 | 4 |
| 5 """Internal bot API handlers.""" | 5 """Internal bot API handlers.""" |
| 6 | 6 |
| 7 import base64 | 7 import base64 |
| 8 import json | 8 import json |
| 9 import logging | 9 import logging |
| 10 import re | 10 import re |
| (...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 568 | 568 |
| 569 class BotTaskUpdateHandler(_BotApiHandler): | 569 class BotTaskUpdateHandler(_BotApiHandler): |
| 570 """Receives updates from a Bot for a task. | 570 """Receives updates from a Bot for a task. |
| 571 | 571 |
| 572 The handler verifies packets are processed in order and will refuse | 572 The handler verifies packets are processed in order and will refuse |
| 573 out-of-order packets. | 573 out-of-order packets. |
| 574 """ | 574 """ |
| 575 ACCEPTED_KEYS = { | 575 ACCEPTED_KEYS = { |
| 576 u'bot_overhead', u'cipd_stats', u'cost_usd', u'duration', u'exit_code', | 576 u'bot_overhead', u'cipd_stats', u'cost_usd', u'duration', u'exit_code', |
| 577 u'hard_timeout', u'id', u'io_timeout', u'isolated_stats', u'output', | 577 u'hard_timeout', u'id', u'io_timeout', u'isolated_stats', u'output', |
| 578 u'output_chunk_start', u'outputs_ref', u'task_id', | 578 u'output_chunk_start', u'outputs_ref', u'cipd_pins', u'task_id', |
|
M-A Ruel
2016/08/24 02:13:44
keep ordered lists ordered
iannucci
2016/08/24 02:31:57
Done.
| |
| 579 } | 579 } |
| 580 REQUIRED_KEYS = {u'id', u'task_id'} | 580 REQUIRED_KEYS = {u'id', u'task_id'} |
| 581 | 581 |
| 582 @auth.public # auth happens in bot_auth.validate_bot_id_and_fetch_config() | 582 @auth.public # auth happens in bot_auth.validate_bot_id_and_fetch_config() |
| 583 def post(self, task_id=None): | 583 def post(self, task_id=None): |
| 584 # Unlike handshake and poll, we do not accept invalid keys here. This code | 584 # Unlike handshake and poll, we do not accept invalid keys here. This code |
| 585 # path is much more strict. | 585 # path is much more strict. |
| 586 request = self.parse_body() | 586 request = self.parse_body() |
| 587 msg = log_unexpected_subset_keys( | 587 msg = log_unexpected_subset_keys( |
| 588 self.ACCEPTED_KEYS, self.REQUIRED_KEYS, request, self.request, 'bot', | 588 self.ACCEPTED_KEYS, self.REQUIRED_KEYS, request, self.request, 'bot', |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 601 cost_usd = request.get('cost_usd', 0) | 601 cost_usd = request.get('cost_usd', 0) |
| 602 duration = request.get('duration') | 602 duration = request.get('duration') |
| 603 exit_code = request.get('exit_code') | 603 exit_code = request.get('exit_code') |
| 604 hard_timeout = request.get('hard_timeout') | 604 hard_timeout = request.get('hard_timeout') |
| 605 io_timeout = request.get('io_timeout') | 605 io_timeout = request.get('io_timeout') |
| 606 isolated_stats = request.get('isolated_stats') | 606 isolated_stats = request.get('isolated_stats') |
| 607 cipd_stats = request.get('cipd_stats') | 607 cipd_stats = request.get('cipd_stats') |
| 608 output = request.get('output') | 608 output = request.get('output') |
| 609 output_chunk_start = request.get('output_chunk_start') | 609 output_chunk_start = request.get('output_chunk_start') |
| 610 outputs_ref = request.get('outputs_ref') | 610 outputs_ref = request.get('outputs_ref') |
| 611 cipd_pins = request.get('cipd_pins') | |
| 611 | 612 |
| 612 if (isolated_stats or cipd_stats) and bot_overhead is None: | 613 if (isolated_stats or cipd_stats) and bot_overhead is None: |
| 613 ereporter2.log_request( | 614 ereporter2.log_request( |
| 614 request=self.request, | 615 request=self.request, |
| 615 source='server', | 616 source='server', |
| 616 category='task_failure', | 617 category='task_failure', |
| 617 message='Failed to update task: %s' % task_id) | 618 message='Failed to update task: %s' % task_id) |
| 618 self.abort_with_error( | 619 self.abort_with_error( |
| 619 400, | 620 400, |
| 620 error='isolated_stats and cipd_stats require bot_overhead to be set' | 621 error='isolated_stats and cipd_stats require bot_overhead to be set' |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 654 logging.error('Failed to decode output\n%s\n%r', e, output) | 655 logging.error('Failed to decode output\n%s\n%r', e, output) |
| 655 output = output.encode('ascii', 'replace') | 656 output = output.encode('ascii', 'replace') |
| 656 except TypeError as e: | 657 except TypeError as e: |
| 657 # Save the output as-is instead. The error will be logged in ereporter2 | 658 # Save the output as-is instead. The error will be logged in ereporter2 |
| 658 # and returning a HTTP 500 would only force the bot to stay in a retry | 659 # and returning a HTTP 500 would only force the bot to stay in a retry |
| 659 # loop. | 660 # loop. |
| 660 logging.error('Failed to decode output\n%s\n%r', e, output) | 661 logging.error('Failed to decode output\n%s\n%r', e, output) |
| 661 if outputs_ref: | 662 if outputs_ref: |
| 662 outputs_ref = task_request.FilesRef(**outputs_ref) | 663 outputs_ref = task_request.FilesRef(**outputs_ref) |
| 663 | 664 |
| 665 if cipd_pins: | |
| 666 cipd_pins = [task_request.CipdPackage(**pin) for pin in cipd_pins] | |
| 667 | |
| 664 try: | 668 try: |
| 665 state = task_scheduler.bot_update_task( | 669 state = task_scheduler.bot_update_task( |
| 666 run_result_key=run_result_key, | 670 run_result_key=run_result_key, |
| 667 bot_id=bot_id, | 671 bot_id=bot_id, |
| 668 output=output, | 672 output=output, |
| 669 output_chunk_start=output_chunk_start, | 673 output_chunk_start=output_chunk_start, |
| 670 exit_code=exit_code, | 674 exit_code=exit_code, |
| 671 duration=duration, | 675 duration=duration, |
| 672 hard_timeout=hard_timeout, | 676 hard_timeout=hard_timeout, |
| 673 io_timeout=io_timeout, | 677 io_timeout=io_timeout, |
| 674 cost_usd=cost_usd, | 678 cost_usd=cost_usd, |
| 675 outputs_ref=outputs_ref, | 679 outputs_ref=outputs_ref, |
| 680 cipd_pins=cipd_pins, | |
| 676 performance_stats=performance_stats) | 681 performance_stats=performance_stats) |
| 677 if not state: | 682 if not state: |
| 678 logging.info('Failed to update, please retry') | 683 logging.info('Failed to update, please retry') |
| 679 self.abort_with_error(500, error='Failed to update, please retry') | 684 self.abort_with_error(500, error='Failed to update, please retry') |
| 680 | 685 |
| 681 if state in (task_result.State.COMPLETED, task_result.State.TIMED_OUT): | 686 if state in (task_result.State.COMPLETED, task_result.State.TIMED_OUT): |
| 682 action = 'task_completed' | 687 action = 'task_completed' |
| 683 elif state == task_result.State.CANCELED: | 688 elif state == task_result.State.CANCELED: |
| 684 action = 'task_canceled' | 689 action = 'task_canceled' |
| 685 else: | 690 else: |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 781 ('/swarming/api/v1/bot/poll', BotPollHandler), | 786 ('/swarming/api/v1/bot/poll', BotPollHandler), |
| 782 ('/swarming/api/v1/bot/server_ping', ServerPingHandler), | 787 ('/swarming/api/v1/bot/server_ping', ServerPingHandler), |
| 783 ('/swarming/api/v1/bot/task_update', BotTaskUpdateHandler), | 788 ('/swarming/api/v1/bot/task_update', BotTaskUpdateHandler), |
| 784 ('/swarming/api/v1/bot/task_update/<task_id:[a-f0-9]+>', | 789 ('/swarming/api/v1/bot/task_update/<task_id:[a-f0-9]+>', |
| 785 BotTaskUpdateHandler), | 790 BotTaskUpdateHandler), |
| 786 ('/swarming/api/v1/bot/task_error', BotTaskErrorHandler), | 791 ('/swarming/api/v1/bot/task_error', BotTaskErrorHandler), |
| 787 ('/swarming/api/v1/bot/task_error/<task_id:[a-f0-9]+>', | 792 ('/swarming/api/v1/bot/task_error/<task_id:[a-f0-9]+>', |
| 788 BotTaskErrorHandler), | 793 BotTaskErrorHandler), |
| 789 ] | 794 ] |
| 790 return [webapp2.Route(*i) for i in routes] | 795 return [webapp2.Route(*i) for i in routes] |
| OLD | NEW |