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

Side by Side Diff: appengine/swarming/handlers_bot.py

Issue 2043853002: Complete CIPD integration (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@run-isolated-cipd
Patch Set: rebased and nit Created 4 years, 6 months 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
OLDNEW
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 514 matching lines...) Expand 10 before | Expand all | Expand 10 after
525 self.send_response({}) 525 self.send_response({})
526 526
527 527
528 class BotTaskUpdateHandler(_BotApiHandler): 528 class BotTaskUpdateHandler(_BotApiHandler):
529 """Receives updates from a Bot for a task. 529 """Receives updates from a Bot for a task.
530 530
531 The handler verifies packets are processed in order and will refuse 531 The handler verifies packets are processed in order and will refuse
532 out-of-order packets. 532 out-of-order packets.
533 """ 533 """
534 ACCEPTED_KEYS = { 534 ACCEPTED_KEYS = {
535 u'bot_overhead', u'cost_usd', u'duration', u'exit_code', 535 u'bot_overhead', u'cipd_stats', u'cost_usd', u'duration', u'exit_code',
536 u'hard_timeout', u'id', u'io_timeout', u'isolated_stats', u'output', 536 u'hard_timeout', u'id', u'io_timeout', u'isolated_stats', u'output',
537 u'output_chunk_start', u'outputs_ref', u'task_id', 537 u'output_chunk_start', u'outputs_ref', u'task_id',
538 } 538 }
539 REQUIRED_KEYS = {u'id', u'task_id'} 539 REQUIRED_KEYS = {u'id', u'task_id'}
540 540
541 @auth.require(acl.is_bot) 541 @auth.require(acl.is_bot)
542 def post(self, task_id=None): 542 def post(self, task_id=None):
543 # Unlike handshake and poll, we do not accept invalid keys here. This code 543 # Unlike handshake and poll, we do not accept invalid keys here. This code
544 # path is much more strict. 544 # path is much more strict.
545 request = self.parse_body() 545 request = self.parse_body()
546 msg = log_unexpected_subset_keys( 546 msg = log_unexpected_subset_keys(
547 self.ACCEPTED_KEYS, self.REQUIRED_KEYS, request, self.request, 'bot', 547 self.ACCEPTED_KEYS, self.REQUIRED_KEYS, request, self.request, 'bot',
548 'keys') 548 'keys')
549 if msg: 549 if msg:
550 self.abort_with_error(400, error=msg) 550 self.abort_with_error(400, error=msg)
551 551
552 bot_id = request['id'] 552 bot_id = request['id']
553 cost_usd = request['cost_usd'] 553 cost_usd = request['cost_usd']
554 task_id = request['task_id'] 554 task_id = request['task_id']
555 555
556 # Make sure bot self-reported ID matches the authentication token. 556 # Make sure bot self-reported ID matches the authentication token.
557 bot_auth.validate_bot_id(bot_id) 557 bot_auth.validate_bot_id(bot_id)
558 558
559 bot_overhead = request.get('bot_overhead') 559 bot_overhead = request.get('bot_overhead')
560 duration = request.get('duration') 560 duration = request.get('duration')
561 exit_code = request.get('exit_code') 561 exit_code = request.get('exit_code')
562 hard_timeout = request.get('hard_timeout') 562 hard_timeout = request.get('hard_timeout')
563 io_timeout = request.get('io_timeout') 563 io_timeout = request.get('io_timeout')
564 isolated_stats = request.get('isolated_stats') 564 isolated_stats = request.get('isolated_stats')
565 cipd_stats = request.get('cipd_stats')
565 output = request.get('output') 566 output = request.get('output')
566 output_chunk_start = request.get('output_chunk_start') 567 output_chunk_start = request.get('output_chunk_start')
567 outputs_ref = request.get('outputs_ref') 568 outputs_ref = request.get('outputs_ref')
568 569
569 if isolated_stats and bot_overhead is None: 570 if (isolated_stats or cipd_stats) and bot_overhead is None:
570 ereporter2.log_request( 571 ereporter2.log_request(
571 request=self.request, 572 request=self.request,
572 source='server', 573 source='server',
573 category='task_failure', 574 category='task_failure',
574 message='Failed to update task: %s' % task_id) 575 message='Failed to update task: %s' % task_id)
575 self.abort_with_error( 576 self.abort_with_error(
576 400, 577 400,
577 error='isolated_stats requires bot_overhead to be set' 578 error='isolated_stats and cipd_stats require bot_overhead to be set'
578 '\nbot_overhead: %s\nisolated_stats: %s' % 579 '\nbot_overhead: %s\nisolate_stats: %s' %
579 (bot_overhead, isolated_stats)) 580 (bot_overhead, isolated_stats))
580 581
581 run_result_key = task_pack.unpack_run_result_key(task_id) 582 run_result_key = task_pack.unpack_run_result_key(task_id)
582 performance_stats = None 583 performance_stats = None
583 if bot_overhead: 584 if bot_overhead:
584 performance_stats = task_result.PerformanceStats( 585 performance_stats = task_result.PerformanceStats(
585 bot_overhead=bot_overhead) 586 bot_overhead=bot_overhead)
586 if isolated_stats: 587 if isolated_stats:
587 download = isolated_stats.get('download') or {} 588 download = isolated_stats.get('download') or {}
588 upload = isolated_stats.get('upload') or {} 589 upload = isolated_stats.get('upload') or {}
589 def unpack_base64(d, k): 590 def unpack_base64(d, k):
590 x = d.get(k) 591 x = d.get(k)
591 if x: 592 if x:
592 return base64.b64decode(x) 593 return base64.b64decode(x)
593 performance_stats.isolated_download = task_result.OperationStats( 594 performance_stats.isolated_download = task_result.OperationStats(
594 duration=download.get('duration'), 595 duration=download.get('duration'),
595 initial_number_items=download.get('initial_number_items'), 596 initial_number_items=download.get('initial_number_items'),
596 initial_size=download.get('initial_size'), 597 initial_size=download.get('initial_size'),
597 items_cold=unpack_base64(download, 'items_cold'), 598 items_cold=unpack_base64(download, 'items_cold'),
598 items_hot=unpack_base64(download, 'items_hot')) 599 items_hot=unpack_base64(download, 'items_hot'))
599 performance_stats.isolated_upload = task_result.OperationStats( 600 performance_stats.isolated_upload = task_result.OperationStats(
600 duration=upload.get('duration'), 601 duration=upload.get('duration'),
601 items_cold=unpack_base64(upload, 'items_cold'), 602 items_cold=unpack_base64(upload, 'items_cold'),
602 items_hot=unpack_base64(upload, 'items_hot')) 603 items_hot=unpack_base64(upload, 'items_hot'))
604 if cipd_stats:
605 performance_stats.package_installation = task_result.OperationStats(
606 duration=cipd_stats.get('duration'))
M-A Ruel 2016/06/10 02:06:42 and client?
nodir 2016/06/10 15:46:32 so OperationStats does not have a place to put get
603 607
604 if output is not None: 608 if output is not None:
605 try: 609 try:
606 output = base64.b64decode(output) 610 output = base64.b64decode(output)
607 except UnicodeEncodeError as e: 611 except UnicodeEncodeError as e:
608 logging.error('Failed to decode output\n%s\n%r', e, output) 612 logging.error('Failed to decode output\n%s\n%r', e, output)
609 output = output.encode('ascii', 'replace') 613 output = output.encode('ascii', 'replace')
610 except TypeError as e: 614 except TypeError as e:
611 # Save the output as-is instead. The error will be logged in ereporter2 615 # Save the output as-is instead. The error will be logged in ereporter2
612 # and returning a HTTP 500 would only force the bot to stay in a retry 616 # and returning a HTTP 500 would only force the bot to stay in a retry
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
733 ('/swarming/api/v1/bot/poll', BotPollHandler), 737 ('/swarming/api/v1/bot/poll', BotPollHandler),
734 ('/swarming/api/v1/bot/server_ping', ServerPingHandler), 738 ('/swarming/api/v1/bot/server_ping', ServerPingHandler),
735 ('/swarming/api/v1/bot/task_update', BotTaskUpdateHandler), 739 ('/swarming/api/v1/bot/task_update', BotTaskUpdateHandler),
736 ('/swarming/api/v1/bot/task_update/<task_id:[a-f0-9]+>', 740 ('/swarming/api/v1/bot/task_update/<task_id:[a-f0-9]+>',
737 BotTaskUpdateHandler), 741 BotTaskUpdateHandler),
738 ('/swarming/api/v1/bot/task_error', BotTaskErrorHandler), 742 ('/swarming/api/v1/bot/task_error', BotTaskErrorHandler),
739 ('/swarming/api/v1/bot/task_error/<task_id:[a-f0-9]+>', 743 ('/swarming/api/v1/bot/task_error/<task_id:[a-f0-9]+>',
740 BotTaskErrorHandler), 744 BotTaskErrorHandler),
741 ] 745 ]
742 return [webapp2.Route(*i) for i in routes] 746 return [webapp2.Route(*i) for i in routes]
OLDNEW
« no previous file with comments | « no previous file | appengine/swarming/server/task_request.py » ('j') | appengine/swarming/swarming_bot/bot_code/task_runner.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698