| OLD | NEW |
| 1 # Copyright 2014 The LUCI Authors. All rights reserved. | 1 # Copyright 2014 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 """Main entry point for Swarming backend handlers.""" | 5 """Main entry point for Swarming backend handlers.""" |
| 6 | 6 |
| 7 import datetime | 7 import datetime |
| 8 import json | 8 import json |
| 9 import logging | 9 import logging |
| 10 | 10 |
| 11 import webapp2 | 11 import webapp2 |
| 12 from google.appengine.api import datastore_errors | 12 from google.appengine.api import datastore_errors |
| 13 from google.appengine.ext import ndb | 13 from google.appengine.ext import ndb |
| 14 | 14 |
| 15 from components import utils | 15 from components import utils |
| 16 | 16 |
| 17 import mapreduce_jobs | 17 import mapreduce_jobs |
| 18 from components import decorators | 18 from components import decorators |
| 19 from components import datastore_utils | 19 from components import datastore_utils |
| 20 from components import machine_provider | 20 from components import machine_provider |
| 21 from server import bot_management | 21 from server import bot_management |
| 22 from server import config | 22 from server import config |
| 23 from server import lease_management | 23 from server import lease_management |
| 24 from server import stats | 24 from server import stats |
| 25 from server import task_pack | 25 from server import task_pack |
| 26 from server import task_queues |
| 26 from server import task_result | 27 from server import task_result |
| 27 from server import task_scheduler | 28 from server import task_scheduler |
| 28 import ts_mon_metrics | 29 import ts_mon_metrics |
| 29 | 30 |
| 30 | 31 |
| 31 class CronBotDiedHandler(webapp2.RequestHandler): | 32 class CronBotDiedHandler(webapp2.RequestHandler): |
| 32 @decorators.require_cronjob | 33 @decorators.require_cronjob |
| 33 def get(self): | 34 def get(self): |
| 34 try: | 35 try: |
| 35 task_scheduler.cron_handle_bot_died(self.request.host_url) | 36 task_scheduler.cron_handle_bot_died(self.request.host_url) |
| 36 except datastore_errors.NeedIndexError as e: | 37 except datastore_errors.NeedIndexError as e: |
| 37 # When a fresh new instance is deployed, it takes a few minutes for the | 38 # When a fresh new instance is deployed, it takes a few minutes for the |
| 38 # composite indexes to be created even if they are empty. Ignore the case | 39 # composite indexes to be created even if they are empty. Ignore the case |
| 39 # where the index is defined but still being created by AppEngine. | 40 # where the index is defined but still being created by AppEngine. |
| 40 if not str(e).startswith( | 41 if not str(e).startswith( |
| 41 'NeedIndexError: The index for this query is not ready to serve.'): | 42 'NeedIndexError: The index for this query is not ready to serve.'): |
| 42 raise | 43 raise |
| 43 self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' | 44 self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' |
| 44 self.response.out.write('Success.') | 45 self.response.out.write('Success.') |
| 45 | 46 |
| 46 | 47 |
| 47 class CronAbortExpiredShardToRunHandler(webapp2.RequestHandler): | 48 class CronAbortExpiredShardToRunHandler(webapp2.RequestHandler): |
| 48 @decorators.require_cronjob | 49 @decorators.require_cronjob |
| 49 def get(self): | 50 def get(self): |
| 50 task_scheduler.cron_abort_expired_task_to_run(self.request.host_url) | 51 task_scheduler.cron_abort_expired_task_to_run(self.request.host_url) |
| 51 self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' | 52 self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' |
| 52 self.response.out.write('Success.') | 53 self.response.out.write('Success.') |
| 53 | 54 |
| 54 | 55 |
| 56 class CronTaskQueues(webapp2.RequestHandler): |
| 57 @decorators.require_cronjob |
| 58 def get(self): |
| 59 task_queues.tidy_stale() |
| 60 self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' |
| 61 self.response.out.write('Success.') |
| 62 |
| 63 |
| 55 class CronMachineProviderBotsUtilizationHandler(webapp2.RequestHandler): | 64 class CronMachineProviderBotsUtilizationHandler(webapp2.RequestHandler): |
| 56 """Determines Machine Provider bot utilization.""" | 65 """Determines Machine Provider bot utilization.""" |
| 57 | 66 |
| 58 @decorators.require_cronjob | 67 @decorators.require_cronjob |
| 59 def get(self): | 68 def get(self): |
| 60 if not config.settings().mp.enabled: | 69 if not config.settings().mp.enabled: |
| 61 logging.info('MP support is disabled') | 70 logging.info('MP support is disabled') |
| 62 return | 71 return |
| 63 | 72 |
| 64 lease_management.compute_utilization() | 73 lease_management.compute_utilization() |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 continue | 185 continue |
| 177 request_obj = request_key.get() | 186 request_obj = request_key.get() |
| 178 if not request_obj: | 187 if not request_obj: |
| 179 logging.error('Request for %s was not found.', request_key.id()) | 188 logging.error('Request for %s was not found.', request_key.id()) |
| 180 continue | 189 continue |
| 181 ok, was_running = task_scheduler.cancel_task(request_obj, result_key) | 190 ok, was_running = task_scheduler.cancel_task(request_obj, result_key) |
| 182 logging.info('task %s canceled: %s was running: %s', | 191 logging.info('task %s canceled: %s was running: %s', |
| 183 task_id, ok, was_running) | 192 task_id, ok, was_running) |
| 184 | 193 |
| 185 | 194 |
| 195 class TaskDimensionsHandler(webapp2.RequestHandler): |
| 196 @decorators.require_taskqueue('task-dimensions') |
| 197 def post(self): |
| 198 self.tidy_stale(self.request.body) |
| 199 self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' |
| 200 self.response.out.write('Success.') |
| 201 |
| 202 @staticmethod |
| 203 def tidy_stale(body): |
| 204 payload = body.split('\n') |
| 205 dimensions_hash = int(payload[0]) |
| 206 dimensions_flat = payload[1:] |
| 207 task_queues.rebuild_task_cache(dimensions_hash, dimensions_flat) |
| 208 |
| 209 |
| 186 class TaskSendPubSubMessage(webapp2.RequestHandler): | 210 class TaskSendPubSubMessage(webapp2.RequestHandler): |
| 187 """Sends PubSub notification about task completion.""" | 211 """Sends PubSub notification about task completion.""" |
| 188 | 212 |
| 189 # Add task_id to the URL for better visibility in request logs. | 213 # Add task_id to the URL for better visibility in request logs. |
| 190 @decorators.require_taskqueue('pubsub') | 214 @decorators.require_taskqueue('pubsub') |
| 191 def post(self, task_id): # pylint: disable=unused-argument | 215 def post(self, task_id): # pylint: disable=unused-argument |
| 192 task_scheduler.task_handle_pubsub_task(json.loads(self.request.body)) | 216 task_scheduler.task_handle_pubsub_task(json.loads(self.request.body)) |
| 193 self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' | 217 self.response.headers['Content-Type'] = 'text/plain; charset=utf-8' |
| 194 self.response.out.write('Success.') | 218 self.response.out.write('Success.') |
| 195 | 219 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 mapreduce_jobs.launch_job(job_id) | 252 mapreduce_jobs.launch_job(job_id) |
| 229 | 253 |
| 230 | 254 |
| 231 ### | 255 ### |
| 232 | 256 |
| 233 | 257 |
| 234 def get_routes(): | 258 def get_routes(): |
| 235 """Returns internal urls that should only be accessible via the backend.""" | 259 """Returns internal urls that should only be accessible via the backend.""" |
| 236 routes = [ | 260 routes = [ |
| 237 # Cron jobs. | 261 # Cron jobs. |
| 238 # TODO(maruel): Rename cron.yaml job url. Doing so is a bit annoying since | |
| 239 # the app version has to be running an already compatible version already. | |
| 240 ('/internal/cron/abort_bot_died', CronBotDiedHandler), | 262 ('/internal/cron/abort_bot_died', CronBotDiedHandler), |
| 241 ('/internal/cron/handle_bot_died', CronBotDiedHandler), | 263 ('/internal/cron/handle_bot_died', CronBotDiedHandler), |
| 242 ('/internal/cron/abort_expired_task_to_run', | 264 ('/internal/cron/abort_expired_task_to_run', |
| 243 CronAbortExpiredShardToRunHandler), | 265 CronAbortExpiredShardToRunHandler), |
| 266 ('/internal/cron/task_queues_tidy', CronTaskQueues), |
| 244 | 267 |
| 245 ('/internal/cron/stats/update', stats.InternalStatsUpdateHandler), | 268 ('/internal/cron/stats/update', stats.InternalStatsUpdateHandler), |
| 246 ('/internal/cron/aggregate_bots_dimensions', | 269 ('/internal/cron/aggregate_bots_dimensions', |
| 247 CronBotsDimensionAggregationHandler), | 270 CronBotsDimensionAggregationHandler), |
| 248 ('/internal/cron/aggregate_tasks_tags', | 271 ('/internal/cron/aggregate_tasks_tags', |
| 249 CronTasksTagsAggregationHandler), | 272 CronTasksTagsAggregationHandler), |
| 250 | 273 |
| 251 # Machine Provider. | 274 # Machine Provider. |
| 252 ('/internal/cron/machine_provider_bot_usage', | 275 ('/internal/cron/machine_provider_bot_usage', |
| 253 CronMachineProviderBotsUtilizationHandler), | 276 CronMachineProviderBotsUtilizationHandler), |
| 254 ('/internal/cron/machine_provider_config', | 277 ('/internal/cron/machine_provider_config', |
| 255 CronMachineProviderConfigHandler), | 278 CronMachineProviderConfigHandler), |
| 256 ('/internal/cron/machine_provider_manage', | 279 ('/internal/cron/machine_provider_manage', |
| 257 CronMachineProviderManagementHandler), | 280 CronMachineProviderManagementHandler), |
| 258 | 281 |
| 259 # Task queues. | 282 # Task queues. |
| 260 ('/internal/taskqueue/cancel-tasks', CancelTasksHandler), | 283 ('/internal/taskqueue/cancel-tasks', CancelTasksHandler), |
| 284 ('/internal/taskqueue/task-dimensions', TaskDimensionsHandler), |
| 261 (r'/internal/taskqueue/pubsub/<task_id:[0-9a-f]+>', TaskSendPubSubMessage), | 285 (r'/internal/taskqueue/pubsub/<task_id:[0-9a-f]+>', TaskSendPubSubMessage), |
| 262 ('/internal/taskqueue/machine-provider-manage', | 286 ('/internal/taskqueue/machine-provider-manage', |
| 263 TaskMachineProviderManagementHandler), | 287 TaskMachineProviderManagementHandler), |
| 264 (r'/internal/taskqueue/tsmon/<kind:[0-9A-Za-z_]+>', TaskGlobalMetrics), | 288 (r'/internal/taskqueue/tsmon/<kind:[0-9A-Za-z_]+>', TaskGlobalMetrics), |
| 265 | 289 |
| 266 # Mapreduce related urls. | 290 # Mapreduce related urls. |
| 267 (r'/internal/taskqueue/mapreduce/launch/<job_id:[^\/]+>', | 291 (r'/internal/taskqueue/mapreduce/launch/<job_id:[^\/]+>', |
| 268 InternalLaunchMapReduceJobWorkerHandler), | 292 InternalLaunchMapReduceJobWorkerHandler), |
| 269 ] | 293 ] |
| 270 return [webapp2.Route(*a) for a in routes] | 294 return [webapp2.Route(*a) for a in routes] |
| 271 | 295 |
| 272 | 296 |
| 273 def create_application(debug): | 297 def create_application(debug): |
| 274 return webapp2.WSGIApplication(get_routes(), debug=debug) | 298 return webapp2.WSGIApplication(get_routes(), debug=debug) |
| OLD | NEW |