| OLD | NEW |
| 1 # Copyright 2013 The LUCI Authors. All rights reserved. | 1 # Copyright 2013 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 service. | 5 """Main entry point for Swarming service. |
| 6 | 6 |
| 7 This file contains the URL handlers for all the Swarming service URLs, | 7 This file contains the URL handlers for all the Swarming service URLs, |
| 8 implemented using the webapp2 framework. | 8 implemented using the webapp2 framework. |
| 9 """ | 9 """ |
| 10 | 10 |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 version = bot_code.get_bot_version(self.request.host_url) | 238 version = bot_code.get_bot_version(self.request.host_url) |
| 239 bots, cursor, more = fetch_future.get_result() | 239 bots, cursor, more = fetch_future.get_result() |
| 240 # Prefetch the tasks. We don't actually use the value here, it'll be | 240 # Prefetch the tasks. We don't actually use the value here, it'll be |
| 241 # implicitly used by ndb local's cache when refetched by the html template. | 241 # implicitly used by ndb local's cache when refetched by the html template. |
| 242 tasks = filter(None, (b.task for b in bots)) | 242 tasks = filter(None, (b.task for b in bots)) |
| 243 ndb.get_multi(tasks) | 243 ndb.get_multi(tasks) |
| 244 num_bots_busy = num_bots_busy_future.get_result() | 244 num_bots_busy = num_bots_busy_future.get_result() |
| 245 num_bots_dead = num_bots_dead_future.get_result() | 245 num_bots_dead = num_bots_dead_future.get_result() |
| 246 num_bots_quarantined = num_bots_quarantined_future.get_result() | 246 num_bots_quarantined = num_bots_quarantined_future.get_result() |
| 247 num_bots_total = num_bots_total_future.get_result() | 247 num_bots_total = num_bots_total_future.get_result() |
| 248 try_link = '/newui/botlist?l=%d' % limit |
| 249 if dimensions: |
| 250 try_link += '&f=' + '&f='.join(dimensions) |
| 248 params = { | 251 params = { |
| 249 'bots': bots, | 252 'bots': bots, |
| 250 'current_version': version, | 253 'current_version': version, |
| 251 'cursor': cursor.urlsafe() if cursor and more else '', | 254 'cursor': cursor.urlsafe() if cursor and more else '', |
| 252 'dimensions': '\n'.join(dimensions), | 255 'dimensions': '\n'.join(dimensions), |
| 253 'is_admin': acl.is_admin(), | 256 'is_admin': acl.is_admin(), |
| 254 'is_privileged_user': acl.is_privileged_user(), | 257 'is_privileged_user': acl.is_privileged_user(), |
| 255 'limit': limit, | 258 'limit': limit, |
| 256 'now': now, | 259 'now': now, |
| 257 'num_bots_alive': num_bots_total - num_bots_dead, | 260 'num_bots_alive': num_bots_total - num_bots_dead, |
| 258 'num_bots_busy': num_bots_busy, | 261 'num_bots_busy': num_bots_busy, |
| 259 'num_bots_dead': num_bots_dead, | 262 'num_bots_dead': num_bots_dead, |
| 260 'num_bots_quarantined': num_bots_quarantined, | 263 'num_bots_quarantined': num_bots_quarantined, |
| 264 'try_link': try_link, |
| 261 'sort_by': sort_by, | 265 'sort_by': sort_by, |
| 262 'sort_options': self.SORT_OPTIONS, | 266 'sort_options': self.SORT_OPTIONS, |
| 263 'xsrf_token': self.generate_xsrf_token(), | 267 'xsrf_token': self.generate_xsrf_token(), |
| 264 } | 268 } |
| 265 self.response.write( | 269 self.response.write( |
| 266 template.render('swarming/restricted_botslist.html', params)) | 270 template.render('swarming/restricted_botslist.html', params)) |
| 267 | 271 |
| 268 | 272 |
| 269 class BotHandler(auth.AuthenticatingHandler): | 273 class BotHandler(auth.AuthenticatingHandler): |
| 270 """Returns data about the bot, including last tasks and events.""" | 274 """Returns data about the bot, including last tasks and events.""" |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 'bot_id': bot_id, | 340 'bot_id': bot_id, |
| 337 'current_version': bot_code.get_bot_version(self.request.host_url), | 341 'current_version': bot_code.get_bot_version(self.request.host_url), |
| 338 'cursor': cursor.urlsafe() if cursor and more else None, | 342 'cursor': cursor.urlsafe() if cursor and more else None, |
| 339 'events': events, | 343 'events': events, |
| 340 'idle_time': idle_time, | 344 'idle_time': idle_time, |
| 341 'is_admin': acl.is_admin(), | 345 'is_admin': acl.is_admin(), |
| 342 'limit': limit, | 346 'limit': limit, |
| 343 'now': now, | 347 'now': now, |
| 344 'run_results': run_results, | 348 'run_results': run_results, |
| 345 'run_time': run_time, | 349 'run_time': run_time, |
| 350 'try_link': '/newui/bot?id=%s' % bot_id, |
| 346 'xsrf_token': self.generate_xsrf_token(), | 351 'xsrf_token': self.generate_xsrf_token(), |
| 347 } | 352 } |
| 348 self.response.write( | 353 self.response.write( |
| 349 template.render('swarming/restricted_bot.html', params)) | 354 template.render('swarming/restricted_bot.html', params)) |
| 350 | 355 |
| 351 | 356 |
| 352 class BotDeleteHandler(auth.AuthenticatingHandler): | 357 class BotDeleteHandler(auth.AuthenticatingHandler): |
| 353 """Deletes a known bot. | 358 """Deletes a known bot. |
| 354 | 359 |
| 355 This only deletes the BotInfo, not BotRoot, BotEvent's nor BotSettings. | 360 This only deletes the BotInfo, not BotRoot, BotEvent's nor BotSettings. |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 513 # overhead saved. | 518 # overhead saved. |
| 514 # In theory, t.duration_as_seen_by_server should always be set when | 519 # In theory, t.duration_as_seen_by_server should always be set when |
| 515 # t.deduped_from is set but there has some broken entities in the datastore. | 520 # t.deduped_from is set but there has some broken entities in the datastore. |
| 516 total_saved = safe_sum( | 521 total_saved = safe_sum( |
| 517 t.duration_as_seen_by_server for t in tasks | 522 t.duration_as_seen_by_server for t in tasks |
| 518 if t.deduped_from and t.duration_as_seen_by_server) | 523 if t.deduped_from and t.duration_as_seen_by_server) |
| 519 duration_sum = safe_sum(durations) | 524 duration_sum = safe_sum(durations) |
| 520 total_saved_percent = ( | 525 total_saved_percent = ( |
| 521 (100. * total_saved.total_seconds() / duration_sum.total_seconds()) | 526 (100. * total_saved.total_seconds() / duration_sum.total_seconds()) |
| 522 if duration_sum else 0.) | 527 if duration_sum else 0.) |
| 528 |
| 529 try_link = '/newui/tasklist?l=%d' % limit |
| 530 if task_tags: |
| 531 try_link += '&f=' + '&f='.join(task_tags) |
| 523 params = { | 532 params = { |
| 524 'cursor': cursor_str, | 533 'cursor': cursor_str, |
| 525 'duration_average': avg(durations), | 534 'duration_average': avg(durations), |
| 526 'duration_median': median(durations), | 535 'duration_median': median(durations), |
| 527 'duration_sum': duration_sum, | 536 'duration_sum': duration_sum, |
| 528 'has_pending': any(t.is_pending for t in tasks), | 537 'has_pending': any(t.is_pending for t in tasks), |
| 529 'has_running': any(t.is_running for t in tasks), | 538 'has_running': any(t.is_running for t in tasks), |
| 530 'is_admin': acl.is_admin(), | 539 'is_admin': acl.is_admin(), |
| 531 'is_privileged_user': acl.is_privileged_user(), | 540 'is_privileged_user': acl.is_privileged_user(), |
| 532 'limit': limit, | 541 'limit': limit, |
| 533 'now': now, | 542 'now': now, |
| 534 'pending_average': avg(pendings), | 543 'pending_average': avg(pendings), |
| 535 'pending_median': median(pendings), | 544 'pending_median': median(pendings), |
| 536 'pending_sum': safe_sum(pendings), | 545 'pending_sum': safe_sum(pendings), |
| 537 'show_footer': bool(pendings or durations), | 546 'show_footer': bool(pendings or durations), |
| 538 'sort': sort, | 547 'sort': sort, |
| 539 'sort_choices': self.SORT_CHOICES, | 548 'sort_choices': self.SORT_CHOICES, |
| 540 'state': state, | 549 'state': state, |
| 541 'state_choices': state_choices, | 550 'state_choices': state_choices, |
| 542 'task_tag': '\n'.join(task_tags), | 551 'task_tag': '\n'.join(task_tags), |
| 543 'tasks': tasks, | 552 'tasks': tasks, |
| 544 'total_cost_usd': total_cost_usd, | 553 'total_cost_usd': total_cost_usd, |
| 545 'total_cost_saved_usd': total_cost_saved_usd, | 554 'total_cost_saved_usd': total_cost_saved_usd, |
| 546 'total_saved': total_saved, | 555 'total_saved': total_saved, |
| 547 'total_saved_percent': total_saved_percent, | 556 'total_saved_percent': total_saved_percent, |
| 557 'try_link': try_link, |
| 548 'xsrf_token': self.generate_xsrf_token(), | 558 'xsrf_token': self.generate_xsrf_token(), |
| 549 } | 559 } |
| 550 # TODO(maruel): If admin or if the user is task's .user, show the Cancel | 560 # TODO(maruel): If admin or if the user is task's .user, show the Cancel |
| 551 # button. Do not show otherwise. | 561 # button. Do not show otherwise. |
| 552 self.response.write(template.render('swarming/user_tasks.html', params)) | 562 self.response.write(template.render('swarming/user_tasks.html', params)) |
| 553 | 563 |
| 554 # Do not let dangling futures linger around. | 564 # Do not let dangling futures linger around. |
| 555 ndb.Future.wait_all(futures) | 565 ndb.Future.wait_all(futures) |
| 556 | 566 |
| 557 def _get_counts_future(self, now): | 567 def _get_counts_future(self, now): |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 'is_gae_admin': users.is_current_user_admin(), | 709 'is_gae_admin': users.is_current_user_admin(), |
| 700 'is_privileged_user': acl.is_privileged_user(), | 710 'is_privileged_user': acl.is_privileged_user(), |
| 701 'following_task': following_task, | 711 'following_task': following_task, |
| 702 'full_appid': os.environ['APPLICATION_ID'], | 712 'full_appid': os.environ['APPLICATION_ID'], |
| 703 'host_url': self.request.host_url, | 713 'host_url': self.request.host_url, |
| 704 'is_running': result.state == task_result.State.RUNNING, | 714 'is_running': result.state == task_result.State.RUNNING, |
| 705 'parent_task': parent_task, | 715 'parent_task': parent_task, |
| 706 'previous_task': previous_task, | 716 'previous_task': previous_task, |
| 707 'request': request, | 717 'request': request, |
| 708 'task': result, | 718 'task': result, |
| 719 'try_link': '/newui/task?id=%s' % task_id, |
| 709 'xsrf_token': self.generate_xsrf_token(), | 720 'xsrf_token': self.generate_xsrf_token(), |
| 710 } | 721 } |
| 711 self.response.write(template.render('swarming/user_task.html', params)) | 722 self.response.write(template.render('swarming/user_task.html', params)) |
| 712 | 723 |
| 713 | 724 |
| 714 class TaskCancelHandler(BaseTaskHandler): | 725 class TaskCancelHandler(BaseTaskHandler): |
| 715 """Cancel a task.""" | 726 """Cancel a task.""" |
| 716 | 727 |
| 717 @auth.require(acl.is_user) | 728 @auth.require(acl.is_user) |
| 718 def post(self, task_id): | 729 def post(self, task_id): |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 845 | 856 |
| 846 # If running on a local dev server, allow bots to connect without prior | 857 # If running on a local dev server, allow bots to connect without prior |
| 847 # groups configuration. Useful when running smoke test. | 858 # groups configuration. Useful when running smoke test. |
| 848 if utils.is_local_dev_server(): | 859 if utils.is_local_dev_server(): |
| 849 acl.bootstrap_dev_server_acls() | 860 acl.bootstrap_dev_server_acls() |
| 850 | 861 |
| 851 routes.extend(handlers_backend.get_routes()) | 862 routes.extend(handlers_backend.get_routes()) |
| 852 routes.extend(handlers_bot.get_routes()) | 863 routes.extend(handlers_bot.get_routes()) |
| 853 routes.extend(handlers_endpoints.get_routes()) | 864 routes.extend(handlers_endpoints.get_routes()) |
| 854 return webapp2.WSGIApplication(routes, debug=debug) | 865 return webapp2.WSGIApplication(routes, debug=debug) |
| OLD | NEW |