Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1111)

Side by Side Diff: appengine/swarming/server/task_request.py

Issue 1910713002: swarming: add support for cipd on the server side (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@master
Patch Set: swarming: add cipd packages on the server side Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 by the Apache v2.0 license that can be 3 # Use of this source code is governed by the Apache v2.0 license that can be
4 # found in the LICENSE file. 4 # 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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 import urlparse 54 import urlparse
55 55
56 from google.appengine.api import datastore_errors 56 from google.appengine.api import datastore_errors
57 from google.appengine.ext import ndb 57 from google.appengine.ext import ndb
58 58
59 from components import auth 59 from components import auth
60 from components import datastore_utils 60 from components import datastore_utils
61 from components import pubsub 61 from components import pubsub
62 from components import utils 62 from components import utils
63 from server import task_pack 63 from server import task_pack
64 import cipd
64 65
65 66
66 # Maximum acceptable priority value, which is effectively the lowest priority. 67 # Maximum acceptable priority value, which is effectively the lowest priority.
67 MAXIMUM_PRIORITY = 255 68 MAXIMUM_PRIORITY = 255
68 69
69 70
70 # Enforced on both task request and bots. 71 # Enforced on both task request and bots.
71 DIMENSION_KEY_RE = ur'^[a-zA-Z\-\_\.]+$' 72 DIMENSION_KEY_RE = ur'^[a-zA-Z\-\_\.]+$'
72 73
73 74
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 # Namespace on the isolate server. 217 # Namespace on the isolate server.
217 namespace = ndb.StringProperty(validator=_validate_namespace, indexed=False) 218 namespace = ndb.StringProperty(validator=_validate_namespace, indexed=False)
218 219
219 def _pre_put_hook(self): 220 def _pre_put_hook(self):
220 super(FilesRef, self)._pre_put_hook() 221 super(FilesRef, self)._pre_put_hook()
221 if not self.isolated or not self.isolatedserver or not self.namespace: 222 if not self.isolated or not self.isolatedserver or not self.namespace:
222 raise datastore_errors.BadValueError( 223 raise datastore_errors.BadValueError(
223 'isolated requires server and namespace') 224 'isolated requires server and namespace')
224 225
225 226
227 class CipdPackage(ndb.Model):
228 """A CIPD package to install in $CIPD_PATH and $PATH before task execution.
229
230 A part of TaskProperties.
231 """
232 package_name = ndb.StringProperty(indexed=False)
233 version = ndb.StringProperty(indexed=False)
234
235 def _pre_put_hook(self):
236 super(CipdPackage, self)._pre_put_hook()
237 if not self.package_name:
238 raise datastore_errors.BadValueError('CIPD package name is required')
239 if not cipd.is_valid_package_name(self.package_name):
M-A Ruel 2016/04/25 19:09:45 Could you use validator=wrapper_function instead?
nodir 2016/04/25 20:27:16 Done.
240 raise datastore_errors.BadValueError(
241 'malformed package name "%s"' % self.package_name)
242 if not self.version:
243 raise datastore_errors.BadValueError('CIPD package version is required')
244 if not cipd.is_valid_version(self.version):
M-A Ruel 2016/04/25 19:09:45 Same
nodir 2016/04/25 20:27:15 Done.
245 raise datastore_errors.BadValueError(
246 'malformed package version "%s"' % self.version)
247
248
226 class TaskProperties(ndb.Model): 249 class TaskProperties(ndb.Model):
227 """Defines all the properties of a task to be run on the Swarming 250 """Defines all the properties of a task to be run on the Swarming
228 infrastructure. 251 infrastructure.
229 252
230 This entity is not saved in the DB as a standalone entity, instead it is 253 This entity is not saved in the DB as a standalone entity, instead it is
231 embedded in a TaskRequest. 254 embedded in a TaskRequest.
232 255
233 This model is immutable. 256 This model is immutable.
234 257
235 New-style TaskProperties supports invocation of run_isolated. When this 258 New-style TaskProperties supports invocation of run_isolated. When this
236 behavior is desired, the member .inputs_ref must be suppled. .extra_args can 259 behavior is desired, the member .inputs_ref must be suppled. .extra_args can
237 be supplied to pass extraneous arguments. 260 be supplied to pass extraneous arguments.
238 """ 261 """
239 # Hashing algorithm used to hash TaskProperties to create its key. 262 # Hashing algorithm used to hash TaskProperties to create its key.
240 HASHING_ALGO = hashlib.sha1 263 HASHING_ALGO = hashlib.sha1
241 264
242 # Commands to run. It is a list of 1 item, the command to run. 265 # Commands to run. It is a list of 1 item, the command to run.
243 # TODO(maruel): Remove after 2016-06-01. 266 # TODO(maruel): Remove after 2016-06-01.
244 commands = datastore_utils.DeterministicJsonProperty( 267 commands = datastore_utils.DeterministicJsonProperty(
245 json_type=list, indexed=False) 268 json_type=list, indexed=False)
246 # Command to run. This is only relevant when self._inputs_ref is None. This is 269 # Command to run. This is only relevant when self._inputs_ref is None. This is
247 # what is called 'raw commands', in the sense that no inputs files are 270 # what is called 'raw commands', in the sense that no inputs files are
248 # declared. 271 # declared.
249 command = ndb.StringProperty(repeated=True, indexed=False) 272 command = ndb.StringProperty(repeated=True, indexed=False)
250 273
251 # File inputs of the task. Only inputs_ref or command&data can be specified. 274 # File inputs of the task. Only inputs_ref or command&data can be specified.
252 inputs_ref = ndb.LocalStructuredProperty(FilesRef) 275 inputs_ref = ndb.LocalStructuredProperty(FilesRef)
253 276
277 # A list of CIPD packages to install $CIPD_PATH and $PATH before task
278 # execution.
279 packages = ndb.LocalStructuredProperty(CipdPackage, repeated=True)
280
254 # Filter to use to determine the required properties on the bot to run on. For 281 # Filter to use to determine the required properties on the bot to run on. For
255 # example, Windows or hostname. Encoded as json. Optional but highly 282 # example, Windows or hostname. Encoded as json. Optional but highly
256 # recommended. 283 # recommended.
257 dimensions = datastore_utils.DeterministicJsonProperty( 284 dimensions = datastore_utils.DeterministicJsonProperty(
258 validator=_validate_dimensions, json_type=dict, indexed=False) 285 validator=_validate_dimensions, json_type=dict, indexed=False)
259 286
260 # Environment variables. Encoded as json. Optional. 287 # Environment variables. Encoded as json. Optional.
261 env = datastore_utils.DeterministicJsonProperty( 288 env = datastore_utils.DeterministicJsonProperty(
262 validator=_validate_dict_of_strings, json_type=dict, indexed=False) 289 validator=_validate_dict_of_strings, json_type=dict, indexed=False)
263 290
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 if self.commands: 352 if self.commands:
326 raise datastore_errors.BadValueError( 353 raise datastore_errors.BadValueError(
327 'commands is not supported anymore') 354 'commands is not supported anymore')
328 if not self.is_terminate: 355 if not self.is_terminate:
329 if bool(self.command) == bool(self.inputs_ref): 356 if bool(self.command) == bool(self.inputs_ref):
330 raise datastore_errors.BadValueError('use one of command or inputs_ref') 357 raise datastore_errors.BadValueError('use one of command or inputs_ref')
331 if self.extra_args and not self.inputs_ref: 358 if self.extra_args and not self.inputs_ref:
332 raise datastore_errors.BadValueError('extra_args require inputs_ref') 359 raise datastore_errors.BadValueError('extra_args require inputs_ref')
333 if self.inputs_ref: 360 if self.inputs_ref:
334 self.inputs_ref._pre_put_hook() 361 self.inputs_ref._pre_put_hook()
362 for p in self.packages:
M-A Ruel 2016/04/25 19:09:45 Can you also sort it? It's important that listing
nodir 2016/04/25 20:27:16 good point, done also add a check that only one ve
363 p._pre_put_hook()
364 if self.idempotent:
365 pinned = lambda p: cipd.is_pinned_version(p.version)
366 if self.packages and any(not pinned(p) for p in self.packages):
367 raise datastore_errors.BadValueError(
368 'an idempotent task cannot have unpinned packages; '
369 'use instance IDs or tags as package versions')
370
335 371
336 372
337 class TaskRequest(ndb.Model): 373 class TaskRequest(ndb.Model):
338 """Contains a user request. 374 """Contains a user request.
339 375
340 Key id is a decreasing integer based on time since utils.EPOCH plus some 376 Key id is a decreasing integer based on time since utils.EPOCH plus some
341 randomness on lower order bits. See _new_request_key() for the complete gory 377 randomness on lower order bits. See _new_request_key() for the complete gory
342 details. 378 details.
343 379
344 There is also "old style keys" which inherit from a fake root entity 380 There is also "old style keys" which inherit from a fake root entity
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 root_entity_shard_id)) 594 root_entity_shard_id))
559 595
560 596
561 def make_request(request, is_bot_or_admin): 597 def make_request(request, is_bot_or_admin):
562 """Registers the request in the DB. 598 """Registers the request in the DB.
563 599
564 Fills up some values. 600 Fills up some values.
565 601
566 If parent_task_id is set, properties for the parent are used: 602 If parent_task_id is set, properties for the parent are used:
567 - priority: defaults to parent.priority - 1 603 - priority: defaults to parent.priority - 1
568 - user: overriden by parent.user 604 - user: overridden by parent.user
569 605
570 """ 606 """
571 assert request.__class__ is TaskRequest 607 assert request.__class__ is TaskRequest
572 if request.parent_task_id: 608 if request.parent_task_id:
573 run_result_key = task_pack.unpack_run_result_key(request.parent_task_id) 609 run_result_key = task_pack.unpack_run_result_key(request.parent_task_id)
574 result_summary_key = task_pack.run_result_key_to_result_summary_key( 610 result_summary_key = task_pack.run_result_key_to_result_summary_key(
575 run_result_key) 611 run_result_key)
576 request_key = task_pack.result_summary_key_to_request_key( 612 request_key = task_pack.result_summary_key_to_request_key(
577 result_summary_key) 613 result_summary_key)
578 parent = request_key.get() 614 parent = request_key.get()
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 _put_request(request) 684 _put_request(request)
649 return request 685 return request
650 686
651 687
652 def validate_priority(priority): 688 def validate_priority(priority):
653 """Throws ValueError if priority is not a valid value.""" 689 """Throws ValueError if priority is not a valid value."""
654 if 0 > priority or MAXIMUM_PRIORITY < priority: 690 if 0 > priority or MAXIMUM_PRIORITY < priority:
655 raise datastore_errors.BadValueError( 691 raise datastore_errors.BadValueError(
656 'priority (%d) must be between 0 and %d (inclusive)' % 692 'priority (%d) must be between 0 and %d (inclusive)' %
657 (priority, MAXIMUM_PRIORITY)) 693 (priority, MAXIMUM_PRIORITY))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698