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 295 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 | 367 # 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 | 368 # reentrantly creates other Swarming tasks. Note that the task_id is to a |
368 # TaskResultSummary. | 369 # TaskResultSummary. |
369 children_task_ids = ndb.StringProperty( | 370 children_task_ids = ndb.StringProperty( |
370 validator=_validate_task_summary_id, repeated=True) | 371 validator=_validate_task_summary_id, repeated=True) |
371 | 372 |
372 # File outputs of the task. Only set if TaskRequest.properties.sources_ref is | 373 # File outputs of the task. Only set if TaskRequest.properties.sources_ref is |
373 # set. The isolateserver and namespace should match. | 374 # set. The isolateserver and namespace should match. |
374 outputs_ref = ndb.LocalStructuredProperty(task_request.FilesRef) | 375 outputs_ref = ndb.LocalStructuredProperty(task_request.FilesRef) |
375 | 376 |
| 377 # The pinned versions of all the cipd packages that were specified as inputs |
| 378 # to the task. So if the task inputs included `package/${platform}@latest`, |
| 379 # the pinned version might be `package/windows@deadbeef`, where 'windows' is |
| 380 # the expanded template parameter, and `deadbeef` is the resolved version of |
| 381 # the package that the task actually used. |
| 382 cipd_pins = ndb.LocalStructuredProperty(task_request.CipdPackage, |
| 383 repeated=True) |
| 384 |
376 @property | 385 @property |
377 def can_be_canceled(self): | 386 def can_be_canceled(self): |
378 """Returns True if the task is in a state that can be canceled.""" | 387 """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: | 388 # 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 | 389 # task_scheduler.cancel_task() must be strictly a transaction relative to |
381 # task_scheduler.bot_kill_task() and task_scheduler.bot_update_task(). | 390 # task_scheduler.bot_kill_task() and task_scheduler.bot_update_task(). |
382 # | 391 # |
383 # The tricky part is to keep this code performant. On the other hand, all | 392 # The tricky part is to keep this code performant. On the other hand, all |
384 # the entities under the transaction (TaskToRun, TaskResultSummary and | 393 # the entities under the transaction (TaskToRun, TaskResultSummary and |
385 # TaskRunResult) are under the same entity root, so it's definitely | 394 # TaskRunResult) are under the same entity root, so it's definitely |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
775 return None | 784 return None |
776 return task_pack.result_summary_key_to_run_result_key( | 785 return task_pack.result_summary_key_to_run_result_key( |
777 self.key, self.try_number) | 786 self.key, self.try_number) |
778 | 787 |
779 @property | 788 @property |
780 def task_id(self): | 789 def task_id(self): |
781 return task_pack.pack_result_summary_key(self.key) | 790 return task_pack.pack_result_summary_key(self.key) |
782 | 791 |
783 def reset_to_pending(self): | 792 def reset_to_pending(self): |
784 """Resets this entity to pending state.""" | 793 """Resets this entity to pending state.""" |
| 794 self.cipd_pins = None |
785 self.duration = None | 795 self.duration = None |
786 self.exit_code = None | 796 self.exit_code = None |
787 self.internal_failure = False | 797 self.internal_failure = False |
788 self.outputs_ref = None | 798 self.outputs_ref = None |
789 self.started_ts = None | 799 self.started_ts = None |
790 self.state = State.PENDING | 800 self.state = State.PENDING |
791 | 801 |
792 def set_from_run_result(self, run_result, request): | 802 def set_from_run_result(self, run_result, request): |
793 """Copies all the relevant properties from a TaskRunResult into this | 803 """Copies all the relevant properties from a TaskRunResult into this |
794 TaskResultSummary. | 804 TaskResultSummary. |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1161 if tags: | 1171 if tags: |
1162 # Add TaskResultSummary indexes if desired. | 1172 # Add TaskResultSummary indexes if desired. |
1163 if sort != 'created_ts': | 1173 if sort != 'created_ts': |
1164 raise ValueError( | 1174 raise ValueError( |
1165 'Add needed indexes for sort:%s and tags if desired' % sort) | 1175 'Add needed indexes for sort:%s and tags if desired' % sort) |
1166 tags_filter = TaskResultSummary.tags == tags[0] | 1176 tags_filter = TaskResultSummary.tags == tags[0] |
1167 for tag in tags[1:]: | 1177 for tag in tags[1:]: |
1168 tags_filter = ndb.AND(tags_filter, TaskResultSummary.tags == tag) | 1178 tags_filter = ndb.AND(tags_filter, TaskResultSummary.tags == tag) |
1169 query = query.filter(tags_filter) | 1179 query = query.filter(tags_filter) |
1170 return _filter_query(TaskResultSummary, query, start, end, sort, state) | 1180 return _filter_query(TaskResultSummary, query, start, end, sort, state) |
OLD | NEW |