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

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: Refactor to hardcode known results 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
612 def _filter_dimensions(self, q, request):
M-A Ruel 2016/08/09 18:05:27 maybe worth passing request.dimensions as an argum
kjlubick 2016/08/09 19:25:03 Done.
613 """Filters a ndb.Query for BotInfo based on dimensions in the request."""
614 for d in request.dimensions:
615 parts = d.split(':', 1)
616 if len(parts) != 2 or any(i.strip() != i or not i for i in parts):
617 raise endpoints.BadRequestException('Invalid dimensions')
618 q = q.filter(bot_management.BotInfo.dimensions_flat == d)
619 return q
620
621 def _filter_availability(self, q, request, now):
M-A Ruel 2016/08/09 18:05:27 same here def _filter_availability(self, q, is_bus
kjlubick 2016/08/09 19:25:03 Done.
622 """Filters a ndb.Query for BotInfo based on quarantined/is_dead."""
623 val = swarming_rpcs.to_bool(request.quarantined)
624 if val is not None:
625 q = q.filter(bot_management.BotInfo.quarantined == val)
626
627 dt = datetime.timedelta(seconds=config.settings().bot_death_timeout_secs)
628 timeout = now - dt
629 if request.is_dead == swarming_rpcs.ThreeStateBool.TRUE:
630 q = q.filter(bot_management.BotInfo.last_seen_ts < timeout)
631 elif request.is_dead == swarming_rpcs.ThreeStateBool.FALSE:
632 q = q.filter(bot_management.BotInfo.last_seen_ts > timeout)
633 return q
634
611 @gae_ts_mon.instrument_endpoint() 635 @gae_ts_mon.instrument_endpoint()
612 @auth.endpoints_method( 636 @auth.endpoints_method(
613 swarming_rpcs.BotsRequest, swarming_rpcs.BotList, 637 swarming_rpcs.BotsRequest, swarming_rpcs.BotList,
614 http_method='GET') 638 http_method='GET')
615 @auth.require(acl.is_privileged_user) 639 @auth.require(acl.is_privileged_user)
616 def list(self, request): 640 def list(self, request):
617 """Provides list of known bots. 641 """Provides list of known bots.
618 642
619 Deleted bots will not be listed. 643 Deleted bots will not be listed.
620 """ 644 """
621 logging.info('%s', request) 645 logging.info('%s', request)
622 now = utils.utcnow() 646 now = utils.utcnow()
623 q = bot_management.BotInfo.query().order(bot_management.BotInfo.key) 647 q = bot_management.BotInfo.query()
624 for d in request.dimensions: 648 q = self._filter_dimensions(q, request)
625 if not ':' in d: 649 q = self._filter_availability(q, request, now)
626 raise endpoints.BadRequestException('Invalid dimensions') 650
627 parts = d.split(':', 1)
628 if len(parts) != 2 or any(i.strip() != i or not i for i in parts):
629 raise endpoints.BadRequestException('Invalid dimensions')
630 q = q.filter(bot_management.BotInfo.dimensions_flat == d)
631 bots, cursor = datastore_utils.fetch_page(q, request.limit, request.cursor) 651 bots, cursor = datastore_utils.fetch_page(q, request.limit, request.cursor)
632 return swarming_rpcs.BotList( 652 return swarming_rpcs.BotList(
633 cursor=cursor, 653 cursor=cursor,
634 death_timeout=config.settings().bot_death_timeout_secs, 654 death_timeout=config.settings().bot_death_timeout_secs,
635 items=[message_conversion.bot_info_to_rpc(bot, now) for bot in bots], 655 items=[message_conversion.bot_info_to_rpc(bot, now) for bot in bots],
636 now=now) 656 now=now)
637 657
638 @gae_ts_mon.instrument_endpoint() 658 @gae_ts_mon.instrument_endpoint()
639 @auth.endpoints_method( 659 @auth.endpoints_method(
640 swarming_rpcs.BotsRequest, swarming_rpcs.BotsCount, 660 swarming_rpcs.BotsRequest, swarming_rpcs.BotsCount,
641 http_method='GET') 661 http_method='GET')
642 @auth.require(acl.is_privileged_user) 662 @auth.require(acl.is_privileged_user)
643 def count(self, request): 663 def count(self, request):
644 """Counts number of bots with given dimensions.""" 664 """Counts number of bots with given dimensions."""
645 logging.info('%s', request) 665 logging.info('%s', request)
646 now = utils.utcnow() 666 now = utils.utcnow()
647 q = bot_management.BotInfo.query() 667 q = bot_management.BotInfo.query()
M-A Ruel 2016/08/09 18:05:26 you can probably inline lines 667 and 668, and sam
kjlubick 2016/08/09 19:25:03 Cannot, it is too long
648 for d in request.dimensions: 668 q = self._filter_dimensions(q, request)
649 parts = d.split(':', 1) 669
650 if len(parts) != 2 or any(i.strip() != i or not i for i in parts): 670 quarantined = swarming_rpcs.to_bool(request.quarantined)
651 raise endpoints.BadRequestException('Invalid dimensions: %s' % d) 671 is_dead = swarming_rpcs.to_bool(request.is_dead)
652 q = q.filter(bot_management.BotInfo.dimensions_flat == d)
653 f_count = q.count_async()
654 dt = datetime.timedelta(seconds=config.settings().bot_death_timeout_secs) 672 dt = datetime.timedelta(seconds=config.settings().bot_death_timeout_secs)
655 timeout = now - dt 673 timeout = now - dt
656 f_dead = q.filter( 674
657 bot_management.BotInfo.last_seen_ts < timeout).count_async() 675 if quarantined is None and is_dead is None:
658 f_quarantined = q.filter( 676 f_count = q.count_async()
659 bot_management.BotInfo.quarantined == True).count_async() 677 f_dead = q.filter(
M-A Ruel 2016/08/09 18:05:26 you can do: f_dead = self._filter_availability(q,
kjlubick 2016/08/09 19:25:03 Done.
660 f_busy = q.filter(bot_management.BotInfo.is_busy == True).count_async() 678 bot_management.BotInfo.last_seen_ts < timeout).count_async()
661 return swarming_rpcs.BotsCount( 679 f_quarantined = q.filter(
M-A Ruel 2016/08/09 18:05:27 same here
kjlubick 2016/08/09 19:25:03 Done.
662 count=f_count.get_result(), 680 bot_management.BotInfo.quarantined == True).count_async()
663 quarantined=f_quarantined.get_result(), 681 f_busy = q.filter(bot_management.BotInfo.is_busy == True).count_async()
664 dead=f_dead.get_result(), 682 return swarming_rpcs.BotsCount(
665 busy=f_busy.get_result(), 683 count=f_count.get_result(),
666 now=now) 684 quarantined=f_quarantined.get_result(),
685 dead=f_dead.get_result(),
686 busy=f_busy.get_result(),
687 now=now)
688 elif is_dead is not None:
689 if is_dead:
690 q = q.filter(bot_management.BotInfo.last_seen_ts < timeout)
691 else:
692 q = q.filter(bot_management.BotInfo.last_seen_ts > timeout)
693 count = q.count()
694 # Dead bots, by definition, are not quarantined, nor are they busy.
695 return swarming_rpcs.BotsCount(
696 count=count,
697 quarantined=0,
698 dead=count,
699 busy=0,
700 now=now)
701 else:
702 # Quarantined bots, by definition, are not dead, nor are they busy.
703 q = q.filter(bot_management.BotInfo.quarantined == quarantined)
704 count = q.count()
705 return swarming_rpcs.BotsCount(
706 count=count,
707 quarantined=count,
708 dead=0,
709 busy=0,
710 now=now)
711
667 712
668 @gae_ts_mon.instrument_endpoint() 713 @gae_ts_mon.instrument_endpoint()
669 @auth.endpoints_method( 714 @auth.endpoints_method(
670 message_types.VoidMessage, swarming_rpcs.BotsDimensions, 715 message_types.VoidMessage, swarming_rpcs.BotsDimensions,
671 http_method='GET') 716 http_method='GET')
672 @auth.require(acl.is_privileged_user) 717 @auth.require(acl.is_privileged_user)
673 def dimensions(self, _request): 718 def dimensions(self, _request):
674 """Returns the cached set of dimensions currently in use in the fleet.""" 719 """Returns the cached set of dimensions currently in use in the fleet."""
675 dims = bot_management.DimensionAggregation.KEY.get() 720 dims = bot_management.DimensionAggregation.KEY.get()
676 fd = [ 721 fd = [
677 swarming_rpcs.StringListPair(key=d.dimension, value=d.values) 722 swarming_rpcs.StringListPair(key=d.dimension, value=d.values)
678 for d in dims.dimensions 723 for d in dims.dimensions
679 ] 724 ]
680 return swarming_rpcs.BotsDimensions(bots_dimensions=fd, ts=dims.ts) 725 return swarming_rpcs.BotsDimensions(bots_dimensions=fd, ts=dims.ts)
681 726
682 727
683 def get_routes(): 728 def get_routes():
684 return ( 729 return (
685 endpoints_webapp2.api_routes(SwarmingServerService) + 730 endpoints_webapp2.api_routes(SwarmingServerService) +
686 endpoints_webapp2.api_routes(SwarmingTaskService) + 731 endpoints_webapp2.api_routes(SwarmingTaskService) +
687 endpoints_webapp2.api_routes(SwarmingTasksService) + 732 endpoints_webapp2.api_routes(SwarmingTasksService) +
688 endpoints_webapp2.api_routes(SwarmingBotService) + 733 endpoints_webapp2.api_routes(SwarmingBotService) +
689 endpoints_webapp2.api_routes(SwarmingBotsService) + 734 endpoints_webapp2.api_routes(SwarmingBotsService) +
690 # components.config endpoints for validation and configuring of luci-config 735 # components.config endpoints for validation and configuring of luci-config
691 # service URL. 736 # service URL.
692 endpoints_webapp2.api_routes(config.ConfigApi)) 737 endpoints_webapp2.api_routes(config.ConfigApi))
OLDNEW
« no previous file with comments | « no previous file | appengine/swarming/handlers_endpoints_test.py » ('j') | appengine/swarming/swarming_rpcs.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698