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

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: 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 486 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 self.send_response({}) 497 self.send_response({})
498 498
499 499
500 class BotTaskUpdateHandler(_BotApiHandler): 500 class BotTaskUpdateHandler(_BotApiHandler):
501 """Receives updates from a Bot for a task. 501 """Receives updates from a Bot for a task.
502 502
503 The handler verifies packets are processed in order and will refuse 503 The handler verifies packets are processed in order and will refuse
504 out-of-order packets. 504 out-of-order packets.
505 """ 505 """
506 ACCEPTED_KEYS = { 506 ACCEPTED_KEYS = {
507 u'bot_overhead', u'cost_usd', u'duration', u'exit_code', 507 u'bot_overhead', u'cipd_stats', u'cost_usd', u'duration', u'exit_code',
508 u'hard_timeout', u'id', u'io_timeout', u'isolated_stats', u'output', 508 u'hard_timeout', u'id', u'io_timeout', u'isolated_stats', u'output',
509 u'output_chunk_start', u'outputs_ref', u'task_id', 509 u'output_chunk_start', u'outputs_ref', u'task_id',
510 } 510 }
511 REQUIRED_KEYS = {u'id', u'task_id'} 511 REQUIRED_KEYS = {u'id', u'task_id'}
512 512
513 @auth.require(acl.is_bot) 513 @auth.require(acl.is_bot)
514 def post(self, task_id=None): 514 def post(self, task_id=None):
515 # Unlike handshake and poll, we do not accept invalid keys here. This code 515 # Unlike handshake and poll, we do not accept invalid keys here. This code
516 # path is much more strict. 516 # path is much more strict.
517 request = self.parse_body() 517 request = self.parse_body()
518 msg = log_unexpected_subset_keys( 518 msg = log_unexpected_subset_keys(
519 self.ACCEPTED_KEYS, self.REQUIRED_KEYS, request, self.request, 'bot', 519 self.ACCEPTED_KEYS, self.REQUIRED_KEYS, request, self.request, 'bot',
520 'keys') 520 'keys')
521 if msg: 521 if msg:
522 self.abort_with_error(400, error=msg) 522 self.abort_with_error(400, error=msg)
523 523
524 bot_id = request['id'] 524 bot_id = request['id']
525 cost_usd = request['cost_usd'] 525 cost_usd = request['cost_usd']
526 task_id = request['task_id'] 526 task_id = request['task_id']
527 527
528 # Make sure bot self-reported ID matches the authentication token. 528 # Make sure bot self-reported ID matches the authentication token.
529 bot_auth.validate_bot_id(bot_id) 529 bot_auth.validate_bot_id(bot_id)
530 530
531 bot_overhead = request.get('bot_overhead') 531 bot_overhead = request.get('bot_overhead')
532 duration = request.get('duration') 532 duration = request.get('duration')
533 exit_code = request.get('exit_code') 533 exit_code = request.get('exit_code')
534 hard_timeout = request.get('hard_timeout') 534 hard_timeout = request.get('hard_timeout')
535 io_timeout = request.get('io_timeout') 535 io_timeout = request.get('io_timeout')
536 isolated_stats = request.get('isolated_stats') 536 isolated_stats = request.get('isolated_stats')
537 cipd_stats = request.get('cipd_stats')
537 output = request.get('output') 538 output = request.get('output')
538 output_chunk_start = request.get('output_chunk_start') 539 output_chunk_start = request.get('output_chunk_start')
539 outputs_ref = request.get('outputs_ref') 540 outputs_ref = request.get('outputs_ref')
540 541
541 if isolated_stats and bot_overhead is None: 542 if (isolated_stats or cipd_stats) and bot_overhead is None:
542 ereporter2.log_request( 543 ereporter2.log_request(
543 request=self.request, 544 request=self.request,
544 source='server', 545 source='server',
545 category='task_failure', 546 category='task_failure',
546 message='Failed to update task: %s' % task_id) 547 message='Failed to update task: %s' % task_id)
547 self.abort_with_error( 548 self.abort_with_error(
548 400, 549 400,
549 error='isolated_stats requires bot_overhead to be set' 550 error='isolated_stats and cipd_stats require bot_overhead to be set'
550 '\nbot_overhead: %s\nisolated_stats: %s' % 551 '\nbot_overhead: %s\nisolate_stats: %s' %
551 (bot_overhead, isolated_stats)) 552 (bot_overhead, isolated_stats))
552 553
553 run_result_key = task_pack.unpack_run_result_key(task_id) 554 run_result_key = task_pack.unpack_run_result_key(task_id)
554 performance_stats = None 555 performance_stats = None
555 if bot_overhead: 556 if bot_overhead:
556 performance_stats = task_result.PerformanceStats( 557 performance_stats = task_result.PerformanceStats(
557 bot_overhead=bot_overhead) 558 bot_overhead=bot_overhead)
558 if isolated_stats: 559 if isolated_stats:
559 download = isolated_stats.get('download') or {} 560 download = isolated_stats.get('download') or {}
560 upload = isolated_stats.get('upload') or {} 561 upload = isolated_stats.get('upload') or {}
561 def unpack_base64(d, k): 562 def unpack_base64(d, k):
562 x = d.get(k) 563 x = d.get(k)
563 if x: 564 if x:
564 return base64.b64decode(x) 565 return base64.b64decode(x)
565 performance_stats.isolated_download = task_result.OperationStats( 566 performance_stats.isolated_download = task_result.OperationStats(
566 duration=download.get('duration'), 567 duration=download.get('duration'),
567 initial_number_items=download.get('initial_number_items'), 568 initial_number_items=download.get('initial_number_items'),
568 initial_size=download.get('initial_size'), 569 initial_size=download.get('initial_size'),
569 items_cold=unpack_base64(download, 'items_cold'), 570 items_cold=unpack_base64(download, 'items_cold'),
570 items_hot=unpack_base64(download, 'items_hot')) 571 items_hot=unpack_base64(download, 'items_hot'))
571 performance_stats.isolated_upload = task_result.OperationStats( 572 performance_stats.isolated_upload = task_result.OperationStats(
572 duration=upload.get('duration'), 573 duration=upload.get('duration'),
573 items_cold=unpack_base64(upload, 'items_cold'), 574 items_cold=unpack_base64(upload, 'items_cold'),
574 items_hot=unpack_base64(upload, 'items_hot')) 575 items_hot=unpack_base64(upload, 'items_hot'))
576 if cipd_stats:
577 performance_stats.package_installation = task_result.OperationStats(
578 duration=cipd_stats.get('duration'))
575 579
576 if output is not None: 580 if output is not None:
577 try: 581 try:
578 output = base64.b64decode(output) 582 output = base64.b64decode(output)
579 except UnicodeEncodeError as e: 583 except UnicodeEncodeError as e:
580 logging.error('Failed to decode output\n%s\n%r', e, output) 584 logging.error('Failed to decode output\n%s\n%r', e, output)
581 output = output.encode('ascii', 'replace') 585 output = output.encode('ascii', 'replace')
582 except TypeError as e: 586 except TypeError as e:
583 # Save the output as-is instead. The error will be logged in ereporter2 587 # Save the output as-is instead. The error will be logged in ereporter2
584 # and returning a HTTP 500 would only force the bot to stay in a retry 588 # 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
705 ('/swarming/api/v1/bot/poll', BotPollHandler), 709 ('/swarming/api/v1/bot/poll', BotPollHandler),
706 ('/swarming/api/v1/bot/server_ping', ServerPingHandler), 710 ('/swarming/api/v1/bot/server_ping', ServerPingHandler),
707 ('/swarming/api/v1/bot/task_update', BotTaskUpdateHandler), 711 ('/swarming/api/v1/bot/task_update', BotTaskUpdateHandler),
708 ('/swarming/api/v1/bot/task_update/<task_id:[a-f0-9]+>', 712 ('/swarming/api/v1/bot/task_update/<task_id:[a-f0-9]+>',
709 BotTaskUpdateHandler), 713 BotTaskUpdateHandler),
710 ('/swarming/api/v1/bot/task_error', BotTaskErrorHandler), 714 ('/swarming/api/v1/bot/task_error', BotTaskErrorHandler),
711 ('/swarming/api/v1/bot/task_error/<task_id:[a-f0-9]+>', 715 ('/swarming/api/v1/bot/task_error/<task_id:[a-f0-9]+>',
712 BotTaskErrorHandler), 716 BotTaskErrorHandler),
713 ] 717 ]
714 return [webapp2.Route(*i) for i in routes] 718 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