| 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 """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  Loading... | 
| 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( | 
| 627       parts = d.split(':', 1) | 628           q, swarming_rpcs.to_bool(request.quarantined), | 
| 628       if len(parts) != 2 or any(i.strip() != i or not i for i in parts): | 629           swarming_rpcs.to_bool(request.is_dead), now) | 
| 629         raise endpoints.BadRequestException('Invalid dimensions') | 630     except ValueError as e: | 
| 630       q = q.filter(bot_management.BotInfo.dimensions_flat == d) | 631       raise endpoints.BadRequestException('%s' % e) | 
|  | 632 | 
| 631     bots, cursor = datastore_utils.fetch_page(q, request.limit, request.cursor) | 633     bots, cursor = datastore_utils.fetch_page(q, request.limit, request.cursor) | 
| 632     return swarming_rpcs.BotList( | 634     return swarming_rpcs.BotList( | 
| 633         cursor=cursor, | 635         cursor=cursor, | 
| 634         death_timeout=config.settings().bot_death_timeout_secs, | 636         death_timeout=config.settings().bot_death_timeout_secs, | 
| 635         items=[message_conversion.bot_info_to_rpc(bot, now) for bot in bots], | 637         items=[message_conversion.bot_info_to_rpc(bot, now) for bot in bots], | 
| 636         now=now) | 638         now=now) | 
| 637 | 639 | 
| 638   @gae_ts_mon.instrument_endpoint() | 640   @gae_ts_mon.instrument_endpoint() | 
| 639   @auth.endpoints_method( | 641   @auth.endpoints_method( | 
| 640       swarming_rpcs.BotsRequest, swarming_rpcs.BotsCount, | 642       swarming_rpcs.BotsRequest, swarming_rpcs.BotsCount, | 
| 641       http_method='GET') | 643       http_method='GET') | 
| 642   @auth.require(acl.is_privileged_user) | 644   @auth.require(acl.is_privileged_user) | 
| 643   def count(self, request): | 645   def count(self, request): | 
| 644     """Counts number of bots with given dimensions.""" | 646     """Counts number of bots with given dimensions.""" | 
| 645     logging.info('%s', request) | 647     logging.info('%s', request) | 
| 646     now = utils.utcnow() | 648     now = utils.utcnow() | 
| 647     q = bot_management.BotInfo.query() | 649     q = bot_management.BotInfo.query() | 
| 648     for d in request.dimensions: | 650     try: | 
| 649       parts = d.split(':', 1) | 651       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): | 652     except ValueError as e: | 
| 651         raise endpoints.BadRequestException('Invalid dimensions: %s' % d) | 653       raise endpoints.BadRequestException(str(e)) | 
| 652       q = q.filter(bot_management.BotInfo.dimensions_flat == d) | 654 | 
| 653     f_count = q.count_async() | 655     f_count = q.count_async() | 
| 654     dt = datetime.timedelta(seconds=config.settings().bot_death_timeout_secs) | 656     f_dead = (bot_management.filter_availability(q, None, True, now) | 
| 655     timeout = now - dt | 657         .count_async()) | 
| 656     f_dead = q.filter( | 658     f_quarantined = (bot_management.filter_availability(q, True, None, now) | 
| 657         bot_management.BotInfo.last_seen_ts < timeout).count_async() | 659         .count_async()) | 
| 658     f_quarantined = q.filter( |  | 
| 659         bot_management.BotInfo.quarantined == True).count_async() |  | 
| 660     f_busy = q.filter(bot_management.BotInfo.is_busy == True).count_async() | 660     f_busy = q.filter(bot_management.BotInfo.is_busy == True).count_async() | 
| 661     return swarming_rpcs.BotsCount( | 661     return swarming_rpcs.BotsCount( | 
| 662         count=f_count.get_result(), | 662         count=f_count.get_result(), | 
| 663         quarantined=f_quarantined.get_result(), | 663         quarantined=f_quarantined.get_result(), | 
| 664         dead=f_dead.get_result(), | 664         dead=f_dead.get_result(), | 
| 665         busy=f_busy.get_result(), | 665         busy=f_busy.get_result(), | 
| 666         now=now) | 666         now=now) | 
| 667 | 667 | 
|  | 668 | 
| 668   @gae_ts_mon.instrument_endpoint() | 669   @gae_ts_mon.instrument_endpoint() | 
| 669   @auth.endpoints_method( | 670   @auth.endpoints_method( | 
| 670       message_types.VoidMessage, swarming_rpcs.BotsDimensions, | 671       message_types.VoidMessage, swarming_rpcs.BotsDimensions, | 
| 671       http_method='GET') | 672       http_method='GET') | 
| 672   @auth.require(acl.is_privileged_user) | 673   @auth.require(acl.is_privileged_user) | 
| 673   def dimensions(self, _request): | 674   def dimensions(self, _request): | 
| 674     """Returns the cached set of dimensions currently in use in the fleet.""" | 675     """Returns the cached set of dimensions currently in use in the fleet.""" | 
| 675     dims = bot_management.DimensionAggregation.KEY.get() | 676     dims = bot_management.DimensionAggregation.KEY.get() | 
| 676     fd = [ | 677     fd = [ | 
| 677       swarming_rpcs.StringListPair(key=d.dimension, value=d.values) | 678       swarming_rpcs.StringListPair(key=d.dimension, value=d.values) | 
| 678       for d in dims.dimensions | 679       for d in dims.dimensions | 
| 679     ] | 680     ] | 
| 680     return swarming_rpcs.BotsDimensions(bots_dimensions=fd, ts=dims.ts) | 681     return swarming_rpcs.BotsDimensions(bots_dimensions=fd, ts=dims.ts) | 
| 681 | 682 | 
| 682 | 683 | 
| 683 def get_routes(): | 684 def get_routes(): | 
| 684   return ( | 685   return ( | 
| 685     endpoints_webapp2.api_routes(SwarmingServerService) + | 686     endpoints_webapp2.api_routes(SwarmingServerService) + | 
| 686     endpoints_webapp2.api_routes(SwarmingTaskService) + | 687     endpoints_webapp2.api_routes(SwarmingTaskService) + | 
| 687     endpoints_webapp2.api_routes(SwarmingTasksService) + | 688     endpoints_webapp2.api_routes(SwarmingTasksService) + | 
| 688     endpoints_webapp2.api_routes(SwarmingBotService) + | 689     endpoints_webapp2.api_routes(SwarmingBotService) + | 
| 689     endpoints_webapp2.api_routes(SwarmingBotsService) + | 690     endpoints_webapp2.api_routes(SwarmingBotsService) + | 
| 690     # components.config endpoints for validation and configuring of luci-config | 691     # components.config endpoints for validation and configuring of luci-config | 
| 691     # service URL. | 692     # service URL. | 
| 692     endpoints_webapp2.api_routes(config.ConfigApi)) | 693     endpoints_webapp2.api_routes(config.ConfigApi)) | 
| OLD | NEW | 
|---|