Chromium Code Reviews| 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 """Task execution result models. | 5 """Task execution result models. |
| 6 | 6 |
| 7 This module doesn't do the scheduling itself. It only describes the entities to | 7 This module doesn't do the scheduling itself. It only describes the entities to |
| 8 store tasks results. | 8 store tasks results. |
| 9 | 9 |
| 10 - TaskResultSummary represents the overall result for the TaskRequest taking in | 10 - TaskResultSummary represents the overall result for the TaskRequest taking in |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 51 |id=1 (not stored)| |id=1 | | 51 |id=1 (not stored)| |id=1 | |
| 52 +-----------------+ +----------------+ | 52 +-----------------+ +----------------+ |
| 53 ^ ^ | 53 ^ ^ |
| 54 | | | 54 | | |
| 55 +---------------+ +---------------+ | 55 +---------------+ +---------------+ |
| 56 |TaskOutputChunk| |TaskOutputChunk| ... | 56 |TaskOutputChunk| |TaskOutputChunk| ... |
| 57 |id=1 | |id=2 | | 57 |id=1 | |id=2 | |
| 58 +---------------+ +---------------+ | 58 +---------------+ +---------------+ |
| 59 """ | 59 """ |
| 60 | 60 |
| 61 import collections | |
| 61 import datetime | 62 import datetime |
| 62 import logging | 63 import logging |
| 63 import random | 64 import random |
| 64 | 65 |
| 65 from google.appengine.api import datastore_errors | 66 from google.appengine.api import datastore_errors |
| 66 from google.appengine.datastore import datastore_query | 67 from google.appengine.datastore import datastore_query |
| 67 from google.appengine.ext import ndb | 68 from google.appengine.ext import ndb |
| 68 | 69 |
| 69 from components import datastore_utils | 70 from components import datastore_utils |
| 70 from components import utils | 71 from components import utils |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 299 @property | 300 @property |
| 300 def is_valid(self): | 301 def is_valid(self): |
| 301 return self.bot_overhead is not None | 302 return self.bot_overhead is not None |
| 302 | 303 |
| 303 def _pre_put_hook(self): | 304 def _pre_put_hook(self): |
| 304 if self.bot_overhead is None: | 305 if self.bot_overhead is None: |
| 305 raise datastore_errors.BadValueError( | 306 raise datastore_errors.BadValueError( |
| 306 'PerformanceStats.bot_overhead is required') | 307 'PerformanceStats.bot_overhead is required') |
| 307 | 308 |
| 308 | 309 |
| 310 class CipdPins(ndb.Model): | |
| 311 """Specifies which CIPD client and packages were actually installed. | |
| 312 | |
| 313 A part of TaskRunResult. | |
|
M-A Ruel
2016/08/26 23:19:51
This is misleading, since this is in TaskResultSum
iannucci
2016/08/29 22:08:40
erp, sorry.
| |
| 314 """ | |
| 315 # CIPD package of CIPD client to use. | |
| 316 # client_package.package_name and version are provided. | |
| 317 # client_package.path will be None. | |
| 318 client_package = ndb.LocalStructuredProperty(task_request.CipdPackage) | |
| 319 | |
| 320 # List of packages to install in $CIPD_PATH prior task execution. | |
| 321 packages = ndb.LocalStructuredProperty(task_request.CipdPackage, | |
|
M-A Ruel
2016/08/26 23:19:51
I'd like the entities to be sorted the same way th
iannucci
2016/08/29 22:08:40
yep, absolutely true, don't know what I was thinki
M-A Ruel
2016/08/30 02:18:07
Yes, so the check will have to be done in a valida
| |
| 322 repeated=True) | |
| 323 | |
| 324 | |
| 309 class _TaskResultCommon(ndb.Model): | 325 class _TaskResultCommon(ndb.Model): |
| 310 """Contains properties that is common to both TaskRunResult and | 326 """Contains properties that is common to both TaskRunResult and |
| 311 TaskResultSummary. | 327 TaskResultSummary. |
| 312 | 328 |
| 313 It is not meant to be instantiated on its own. | 329 It is not meant to be instantiated on its own. |
| 314 | 330 |
| 315 TODO(maruel): Overhaul this entity: | 331 TODO(maruel): Overhaul this entity: |
| 316 - Get rid of TaskOutput as it is not needed anymore (?) | 332 - Get rid of TaskOutput as it is not needed anymore (?) |
| 317 """ | 333 """ |
| 318 # Bot that ran this task. | 334 # Bot that ran this task. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 366 # Children tasks that were triggered by this task. This is set when the task | 382 # Children tasks that were triggered by this task. This is set when the task |
| 367 # reentrantly creates other Swarming tasks. Note that the task_id is to a | 383 # reentrantly creates other Swarming tasks. Note that the task_id is to a |
| 368 # TaskResultSummary. | 384 # TaskResultSummary. |
| 369 children_task_ids = ndb.StringProperty( | 385 children_task_ids = ndb.StringProperty( |
| 370 validator=_validate_task_summary_id, repeated=True) | 386 validator=_validate_task_summary_id, repeated=True) |
| 371 | 387 |
| 372 # File outputs of the task. Only set if TaskRequest.properties.sources_ref is | 388 # File outputs of the task. Only set if TaskRequest.properties.sources_ref is |
| 373 # set. The isolateserver and namespace should match. | 389 # set. The isolateserver and namespace should match. |
| 374 outputs_ref = ndb.LocalStructuredProperty(task_request.FilesRef) | 390 outputs_ref = ndb.LocalStructuredProperty(task_request.FilesRef) |
| 375 | 391 |
| 392 # The pinned versions of all the CIPD packages used in the task. | |
| 393 cipd_pins = ndb.LocalStructuredProperty(CipdPins) | |
| 394 | |
| 376 @property | 395 @property |
| 377 def can_be_canceled(self): | 396 def can_be_canceled(self): |
| 378 """Returns True if the task is in a state that can be canceled.""" | 397 """Returns True if the task is in a state that can be canceled.""" |
| 379 # TOOD(maruel): To be able to add State.RUNNING, the following must be done: | 398 # TOOD(maruel): To be able to add State.RUNNING, the following must be done: |
| 380 # task_scheduler.cancel_task() must be strictly a transaction relative to | 399 # task_scheduler.cancel_task() must be strictly a transaction relative to |
| 381 # task_scheduler.bot_kill_task() and task_scheduler.bot_update_task(). | 400 # task_scheduler.bot_kill_task() and task_scheduler.bot_update_task(). |
| 382 # | 401 # |
| 383 # The tricky part is to keep this code performant. On the other hand, all | 402 # The tricky part is to keep this code performant. On the other hand, all |
| 384 # the entities under the transaction (TaskToRun, TaskResultSummary and | 403 # the entities under the transaction (TaskToRun, TaskResultSummary and |
| 385 # TaskRunResult) are under the same entity root, so it's definitely | 404 # TaskRunResult) are under the same entity root, so it's definitely |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 596 if self.deduped_from: | 615 if self.deduped_from: |
| 597 if self.state != State.COMPLETED: | 616 if self.state != State.COMPLETED: |
| 598 raise datastore_errors.BadValueError( | 617 raise datastore_errors.BadValueError( |
| 599 'state must be COMPLETED on deduped task') | 618 'state must be COMPLETED on deduped task') |
| 600 if self.failure: | 619 if self.failure: |
| 601 raise datastore_errors.BadValueError( | 620 raise datastore_errors.BadValueError( |
| 602 'failure can\'t be True on deduped task') | 621 'failure can\'t be True on deduped task') |
| 603 | 622 |
| 604 self.children_task_ids = sorted( | 623 self.children_task_ids = sorted( |
| 605 set(self.children_task_ids), key=lambda x: int(x, 16)) | 624 set(self.children_task_ids), key=lambda x: int(x, 16)) |
| 606 | 625 |
|
M-A Ruel
2016/08/26 23:19:51
It should explicitly:
if self.cipd_pins:
self.ci
| |
| 607 @classmethod | 626 @classmethod |
| 608 def _properties_fixed(cls): | 627 def _properties_fixed(cls): |
| 609 """Returns all properties with their member name, excluding computed | 628 """Returns all properties with their member name, excluding computed |
| 610 properties. | 629 properties. |
| 611 """ | 630 """ |
| 612 return [ | 631 return [ |
| 613 prop._code_name for prop in cls._properties.itervalues() | 632 prop._code_name for prop in cls._properties.itervalues() |
| 614 if not isinstance(prop, ndb.ComputedProperty) | 633 if not isinstance(prop, ndb.ComputedProperty) |
| 615 ] | 634 ] |
| 616 | 635 |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 775 return None | 794 return None |
| 776 return task_pack.result_summary_key_to_run_result_key( | 795 return task_pack.result_summary_key_to_run_result_key( |
| 777 self.key, self.try_number) | 796 self.key, self.try_number) |
| 778 | 797 |
| 779 @property | 798 @property |
| 780 def task_id(self): | 799 def task_id(self): |
| 781 return task_pack.pack_result_summary_key(self.key) | 800 return task_pack.pack_result_summary_key(self.key) |
| 782 | 801 |
| 783 def reset_to_pending(self): | 802 def reset_to_pending(self): |
| 784 """Resets this entity to pending state.""" | 803 """Resets this entity to pending state.""" |
| 804 self.cipd_pins = None | |
| 785 self.duration = None | 805 self.duration = None |
| 786 self.exit_code = None | 806 self.exit_code = None |
| 787 self.internal_failure = False | 807 self.internal_failure = False |
| 788 self.outputs_ref = None | 808 self.outputs_ref = None |
| 789 self.started_ts = None | 809 self.started_ts = None |
| 790 self.state = State.PENDING | 810 self.state = State.PENDING |
| 791 | 811 |
| 792 def set_from_run_result(self, run_result, request): | 812 def set_from_run_result(self, run_result, request): |
| 793 """Copies all the relevant properties from a TaskRunResult into this | 813 """Copies all the relevant properties from a TaskRunResult into this |
| 794 TaskResultSummary. | 814 TaskResultSummary. |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1161 if tags: | 1181 if tags: |
| 1162 # Add TaskResultSummary indexes if desired. | 1182 # Add TaskResultSummary indexes if desired. |
| 1163 if sort != 'created_ts': | 1183 if sort != 'created_ts': |
| 1164 raise ValueError( | 1184 raise ValueError( |
| 1165 'Add needed indexes for sort:%s and tags if desired' % sort) | 1185 'Add needed indexes for sort:%s and tags if desired' % sort) |
| 1166 tags_filter = TaskResultSummary.tags == tags[0] | 1186 tags_filter = TaskResultSummary.tags == tags[0] |
| 1167 for tag in tags[1:]: | 1187 for tag in tags[1:]: |
| 1168 tags_filter = ndb.AND(tags_filter, TaskResultSummary.tags == tag) | 1188 tags_filter = ndb.AND(tags_filter, TaskResultSummary.tags == tag) |
| 1169 query = query.filter(tags_filter) | 1189 query = query.filter(tags_filter) |
| 1170 return _filter_query(TaskResultSummary, query, start, end, sort, state) | 1190 return _filter_query(TaskResultSummary, query, start, end, sort, state) |
| OLD | NEW |