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 |