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

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

Issue 2220373003: Allow botlist API call to respond to quarantined: and is_dead: (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@master
Patch Set: Fix one edge case Created 4 years, 4 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 """This module defines Swarming Server endpoints handlers.""" 5 """This module defines Swarming Server endpoints handlers."""
6 6
7 import datetime 7 import datetime
8 import logging 8 import logging
9 9
10 from google.appengine.api import datastore_errors 10 from google.appengine.api import datastore_errors
(...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after
601 message_conversion.task_result_to_rpc( 601 message_conversion.task_result_to_rpc(
602 r, request.include_performance_stats) 602 r, request.include_performance_stats)
603 for r in items 603 for r in items
604 ], 604 ],
605 now=now) 605 now=now)
606 606
607 607
608 @swarming_api.api_class(resource_name='bots', path='bots') 608 @swarming_api.api_class(resource_name='bots', path='bots')
609 class SwarmingBotsService(remote.Service): 609 class SwarmingBotsService(remote.Service):
610 """Bots-related API.""" 610 """Bots-related API."""
611
611 @gae_ts_mon.instrument_endpoint() 612 @gae_ts_mon.instrument_endpoint()
612 @auth.endpoints_method( 613 @auth.endpoints_method(
613 swarming_rpcs.BotsRequest, swarming_rpcs.BotList, 614 swarming_rpcs.BotsRequest, swarming_rpcs.BotList,
614 http_method='GET') 615 http_method='GET')
615 @auth.require(acl.is_privileged_user) 616 @auth.require(acl.is_privileged_user)
616 def list(self, request): 617 def list(self, request):
617 """Provides list of known bots. 618 """Provides list of known bots.
618 619
619 Deleted bots will not be listed. 620 Deleted bots will not be listed.
620 """ 621 """
621 logging.info('%s', request) 622 logging.info('%s', request)
622 now = utils.utcnow() 623 now = utils.utcnow()
623 q = bot_management.BotInfo.query().order(bot_management.BotInfo.key) 624 q = bot_management.BotInfo.query()
624 for d in request.dimensions: 625 try:
625 if not ':' in d: 626 q = bot_management.filter_dimensions(q, request.dimensions)
626 raise endpoints.BadRequestException('Invalid dimensions') 627 q = bot_management.filter_availability(q, request.quarantined,
M-A Ruel 2016/08/09 20:23:13 I don't like this kind of alignment, indent all ar
kjlubick 2016/08/09 20:44:44 Done.
627 parts = d.split(':', 1) 628 request.is_dead, now)
628 if len(parts) != 2 or any(i.strip() != i or not i for i in parts): 629 except ValueError as e:
629 raise endpoints.BadRequestException('Invalid dimensions') 630 raise endpoints.BadRequestException('%s' % e)
M-A Ruel 2016/08/09 20:23:13 str(e)
kjlubick 2016/08/09 20:44:44 Done.
630 q = q.filter(bot_management.BotInfo.dimensions_flat == d) 631
631 bots, cursor = datastore_utils.fetch_page(q, request.limit, request.cursor) 632 bots, cursor = datastore_utils.fetch_page(q, request.limit, request.cursor)
632 return swarming_rpcs.BotList( 633 return swarming_rpcs.BotList(
633 cursor=cursor, 634 cursor=cursor,
634 death_timeout=config.settings().bot_death_timeout_secs, 635 death_timeout=config.settings().bot_death_timeout_secs,
635 items=[message_conversion.bot_info_to_rpc(bot, now) for bot in bots], 636 items=[message_conversion.bot_info_to_rpc(bot, now) for bot in bots],
636 now=now) 637 now=now)
637 638
638 @gae_ts_mon.instrument_endpoint() 639 @gae_ts_mon.instrument_endpoint()
639 @auth.endpoints_method( 640 @auth.endpoints_method(
640 swarming_rpcs.BotsRequest, swarming_rpcs.BotsCount, 641 swarming_rpcs.BotsRequest, swarming_rpcs.BotsCount,
M-A Ruel 2016/08/09 20:23:13 BotsRequest shouldn't be used here. Only dimension
kjlubick 2016/08/09 20:44:43 What if I want to count all bots that aren't quara
M-A Ruel 2016/08/09 21:15:32 It's already part of BoutsCount.
641 http_method='GET') 642 http_method='GET')
642 @auth.require(acl.is_privileged_user) 643 @auth.require(acl.is_privileged_user)
643 def count(self, request): 644 def count(self, request):
644 """Counts number of bots with given dimensions.""" 645 """Counts number of bots with given dimensions."""
645 logging.info('%s', request) 646 logging.info('%s', request)
646 now = utils.utcnow() 647 now = utils.utcnow()
647 q = bot_management.BotInfo.query() 648 q = bot_management.BotInfo.query()
648 for d in request.dimensions: 649 try:
649 parts = d.split(':', 1) 650 q = bot_management.filter_dimensions(q, request.dimensions)
650 if len(parts) != 2 or any(i.strip() != i or not i for i in parts): 651 except ValueError as e:
651 raise endpoints.BadRequestException('Invalid dimensions: %s' % d) 652 raise endpoints.BadRequestException('%s' % e)
652 q = q.filter(bot_management.BotInfo.dimensions_flat == d) 653
653 f_count = q.count_async() 654 quarantined = swarming_rpcs.to_bool(request.quarantined)
654 dt = datetime.timedelta(seconds=config.settings().bot_death_timeout_secs) 655 is_dead = swarming_rpcs.to_bool(request.is_dead)
655 timeout = now - dt 656 if quarantined is None and is_dead is None:
656 f_dead = q.filter( 657 f_count = q.count_async()
657 bot_management.BotInfo.last_seen_ts < timeout).count_async() 658 f_dead = (bot_management.filter_availability(q, None, True, now)
658 f_quarantined = q.filter( 659 .count_async())
659 bot_management.BotInfo.quarantined == True).count_async() 660 f_quarantined = (bot_management.filter_availability(q, True, None, now)
660 f_busy = q.filter(bot_management.BotInfo.is_busy == True).count_async() 661 .count_async())
661 return swarming_rpcs.BotsCount( 662 f_busy = q.filter(bot_management.BotInfo.is_busy == True).count_async()
662 count=f_count.get_result(), 663 return swarming_rpcs.BotsCount(
663 quarantined=f_quarantined.get_result(), 664 count=f_count.get_result(),
664 dead=f_dead.get_result(), 665 quarantined=f_quarantined.get_result(),
665 busy=f_busy.get_result(), 666 dead=f_dead.get_result(),
666 now=now) 667 busy=f_busy.get_result(),
668 now=now)
669 elif quarantined or is_dead:
670 q = bot_management.filter_availability(q, quarantined, is_dead, now)
671 f_count = q.count_async()
672 f_dead = (bot_management.filter_availability(q, None, True, now)
673 .count_async())
674 f_quarantined = (bot_management.filter_availability(q, True, None, now)
675 .count_async())
676 # Dead and quarantined bots, by definition, are not busy.
677 return swarming_rpcs.BotsCount(
678 count=f_count.get_result(),
679 quarantined=f_quarantined.get_result(),
680 dead=f_dead.get_result(),
681 busy=0,
682 now=now)
683 else: # both quarantined and is_dead are false or None
684 f_count = (bot_management.filter_availability(q, quarantined, is_dead,
685 now).count_async())
686 f_busy = q.filter(bot_management.BotInfo.is_busy == True).count_async()
687 return swarming_rpcs.BotsCount(
688 count=f_count.get_result(),
689 quarantined=0,
690 dead=0,
691 busy=f_busy.get_result(),
692 now=now)
693
667 694
668 @gae_ts_mon.instrument_endpoint() 695 @gae_ts_mon.instrument_endpoint()
669 @auth.endpoints_method( 696 @auth.endpoints_method(
670 message_types.VoidMessage, swarming_rpcs.BotsDimensions, 697 message_types.VoidMessage, swarming_rpcs.BotsDimensions,
671 http_method='GET') 698 http_method='GET')
672 @auth.require(acl.is_privileged_user) 699 @auth.require(acl.is_privileged_user)
673 def dimensions(self, _request): 700 def dimensions(self, _request):
674 """Returns the cached set of dimensions currently in use in the fleet.""" 701 """Returns the cached set of dimensions currently in use in the fleet."""
675 dims = bot_management.DimensionAggregation.KEY.get() 702 dims = bot_management.DimensionAggregation.KEY.get()
676 fd = [ 703 fd = [
677 swarming_rpcs.StringListPair(key=d.dimension, value=d.values) 704 swarming_rpcs.StringListPair(key=d.dimension, value=d.values)
678 for d in dims.dimensions 705 for d in dims.dimensions
679 ] 706 ]
680 return swarming_rpcs.BotsDimensions(bots_dimensions=fd, ts=dims.ts) 707 return swarming_rpcs.BotsDimensions(bots_dimensions=fd, ts=dims.ts)
681 708
682 709
683 def get_routes(): 710 def get_routes():
684 return ( 711 return (
685 endpoints_webapp2.api_routes(SwarmingServerService) + 712 endpoints_webapp2.api_routes(SwarmingServerService) +
686 endpoints_webapp2.api_routes(SwarmingTaskService) + 713 endpoints_webapp2.api_routes(SwarmingTaskService) +
687 endpoints_webapp2.api_routes(SwarmingTasksService) + 714 endpoints_webapp2.api_routes(SwarmingTasksService) +
688 endpoints_webapp2.api_routes(SwarmingBotService) + 715 endpoints_webapp2.api_routes(SwarmingBotService) +
689 endpoints_webapp2.api_routes(SwarmingBotsService) + 716 endpoints_webapp2.api_routes(SwarmingBotsService) +
690 # components.config endpoints for validation and configuring of luci-config 717 # components.config endpoints for validation and configuring of luci-config
691 # service URL. 718 # service URL.
692 endpoints_webapp2.api_routes(config.ConfigApi)) 719 endpoints_webapp2.api_routes(config.ConfigApi))
OLDNEW
« no previous file with comments | « no previous file | appengine/swarming/handlers_endpoints_test.py » ('j') | appengine/swarming/server/bot_management.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698