| 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 |