OLD | NEW |
1 # coding: utf-8 | 1 # coding: utf-8 |
2 # Copyright 2014 The LUCI Authors. All rights reserved. | 2 # Copyright 2014 The LUCI Authors. All rights reserved. |
3 # Use of this source code is governed under the Apache License, Version 2.0 | 3 # Use of this source code is governed under the Apache License, Version 2.0 |
4 # that can be found in the LICENSE file. | 4 # that can be found in the LICENSE file. |
5 | 5 |
6 """Tasks definition. | 6 """Tasks definition. |
7 | 7 |
8 Each user request creates a new TaskRequest. The TaskRequest instance saves the | 8 Each user request creates a new TaskRequest. The TaskRequest instance saves the |
9 metadata of the request, e.g. who requested it, when why, etc. It links to the | 9 metadata of the request, e.g. who requested it, when why, etc. It links to the |
10 actual data of the request in a TaskProperties. The TaskProperties represents | 10 actual data of the request in a TaskProperties. The TaskProperties represents |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 # pylint: disable=W0212 | 155 # pylint: disable=W0212 |
156 if not value: | 156 if not value: |
157 raise datastore_errors.BadValueError(u'%s must be specified' % prop._name) | 157 raise datastore_errors.BadValueError(u'%s must be specified' % prop._name) |
158 _validate_dict_of_strings(prop, value) | 158 _validate_dict_of_strings(prop, value) |
159 for key, val in value.iteritems(): | 159 for key, val in value.iteritems(): |
160 if not config.validate_dimension_key(key): | 160 if not config.validate_dimension_key(key): |
161 raise datastore_errors.BadValueError(u'dimension %r isn\'t valid' % key) | 161 raise datastore_errors.BadValueError(u'dimension %r isn\'t valid' % key) |
162 if not config.validate_dimension_value(val): | 162 if not config.validate_dimension_value(val): |
163 raise datastore_errors.BadValueError( | 163 raise datastore_errors.BadValueError( |
164 u'dimension %r:%r isn\'t valid' % (key, val)) | 164 u'dimension %r:%r isn\'t valid' % (key, val)) |
165 if u'pool' not in value and u'id' not in value: | |
166 raise datastore_errors.BadValueError( | |
167 u'At least one of \'id\' or \'pool\' must be used as %s' % prop._name) | |
168 if len(value) > 64: | 165 if len(value) > 64: |
169 raise datastore_errors.BadValueError( | 166 raise datastore_errors.BadValueError( |
170 '%s can have up to 64 keys' % prop._name) | 167 '%s can have up to 64 keys' % prop._name) |
171 | 168 |
172 | 169 |
173 def _validate_env(prop, value): | 170 def _validate_env(prop, value): |
174 _validate_dict_of_strings(prop, value) | 171 _validate_dict_of_strings(prop, value) |
175 maxlen = 1024 | 172 maxlen = 1024 |
176 for k, v in value.iteritems(): | 173 for k, v in value.iteritems(): |
177 if not k: | 174 if not k: |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 # May be non-None even if task input is not isolated. | 479 # May be non-None even if task input is not isolated. |
483 # | 480 # |
484 # Only inputs_ref.isolated or command can be specified. | 481 # Only inputs_ref.isolated or command can be specified. |
485 inputs_ref = ndb.LocalStructuredProperty(FilesRef) | 482 inputs_ref = ndb.LocalStructuredProperty(FilesRef) |
486 | 483 |
487 # CIPD packages to install. | 484 # CIPD packages to install. |
488 cipd_input = ndb.LocalStructuredProperty(CipdInput) | 485 cipd_input = ndb.LocalStructuredProperty(CipdInput) |
489 | 486 |
490 # Filter to use to determine the required properties on the bot to run on. For | 487 # Filter to use to determine the required properties on the bot to run on. For |
491 # example, Windows or hostname. Encoded as json. Either 'pool' or 'id' | 488 # example, Windows or hostname. Encoded as json. Either 'pool' or 'id' |
492 # dimension are required (see _validate_dimensions). | 489 # dimension are required (see _validate_dimensions and _pre_put_hook). |
493 dimensions = datastore_utils.DeterministicJsonProperty( | 490 dimensions = datastore_utils.DeterministicJsonProperty( |
494 validator=_validate_dimensions, json_type=dict, indexed=False) | 491 validator=_validate_dimensions, json_type=dict, indexed=False) |
495 | 492 |
496 # Environment variables. Encoded as json. Optional. | 493 # Environment variables. Encoded as json. Optional. |
497 env = datastore_utils.DeterministicJsonProperty( | 494 env = datastore_utils.DeterministicJsonProperty( |
498 validator=_validate_env, json_type=dict, indexed=False) | 495 validator=_validate_env, json_type=dict, indexed=False) |
499 | 496 |
500 # Maximum duration the bot can take to run this task. It's named hard_timeout | 497 # Maximum duration the bot can take to run this task. It's named hard_timeout |
501 # in the bot. | 498 # in the bot. |
502 execution_timeout_secs = ndb.IntegerProperty( | 499 execution_timeout_secs = ndb.IntegerProperty( |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
547 not self.grace_period_secs and | 544 not self.grace_period_secs and |
548 not self.io_timeout_secs and | 545 not self.io_timeout_secs and |
549 not self.idempotent and | 546 not self.idempotent and |
550 not self.outputs and | 547 not self.outputs and |
551 not self.has_secret_bytes) | 548 not self.has_secret_bytes) |
552 | 549 |
553 def _pre_put_hook(self): | 550 def _pre_put_hook(self): |
554 super(TaskProperties, self)._pre_put_hook() | 551 super(TaskProperties, self)._pre_put_hook() |
555 if self.is_terminate: | 552 if self.is_terminate: |
556 # Most values are not valid with a terminate task. self.is_terminate | 553 # Most values are not valid with a terminate task. self.is_terminate |
557 # already check those. | 554 # already check those. Terminate task can only use 'id'. |
558 return | 555 return |
559 | 556 |
| 557 if u'pool' not in self.dimensions: |
| 558 # Only terminate task may no use 'pool'. Others must specify one. |
| 559 raise datastore_errors.BadValueError( |
| 560 u'\'pool\' must be used as dimensions') |
| 561 |
560 isolated_input = self.inputs_ref and self.inputs_ref.isolated | 562 isolated_input = self.inputs_ref and self.inputs_ref.isolated |
561 if not self.command and not isolated_input: | 563 if not self.command and not isolated_input: |
562 raise datastore_errors.BadValueError( | 564 raise datastore_errors.BadValueError( |
563 'use at least one of command or inputs_ref.isolated') | 565 'use at least one of command or inputs_ref.isolated') |
564 if self.command and self.extra_args: | 566 if self.command and self.extra_args: |
565 raise datastore_errors.BadValueError( | 567 raise datastore_errors.BadValueError( |
566 'can\'t use both command and extra_args') | 568 'can\'t use both command and extra_args') |
567 if self.extra_args and not isolated_input: | 569 if self.extra_args and not isolated_input: |
568 raise datastore_errors.BadValueError( | 570 raise datastore_errors.BadValueError( |
569 'extra_args require inputs_ref.isolated') | 571 'extra_args require inputs_ref.isolated') |
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1014 init_new_request(request, allow_high_priority, original_secret_bytes) | 1016 init_new_request(request, allow_high_priority, original_secret_bytes) |
1015 return request | 1017 return request |
1016 | 1018 |
1017 | 1019 |
1018 def validate_priority(priority): | 1020 def validate_priority(priority): |
1019 """Throws ValueError if priority is not a valid value.""" | 1021 """Throws ValueError if priority is not a valid value.""" |
1020 if 0 > priority or MAXIMUM_PRIORITY < priority: | 1022 if 0 > priority or MAXIMUM_PRIORITY < priority: |
1021 raise datastore_errors.BadValueError( | 1023 raise datastore_errors.BadValueError( |
1022 'priority (%d) must be between 0 and %d (inclusive)' % | 1024 'priority (%d) must be between 0 and %d (inclusive)' % |
1023 (priority, MAXIMUM_PRIORITY)) | 1025 (priority, MAXIMUM_PRIORITY)) |
OLD | NEW |