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

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

Issue 1939343002: swarming: change meaning of inputs_ref (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@master
Patch Set: fix templates Created 4 years, 7 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
« no previous file with comments | « appengine/swarming/handlers_bot_test.py ('k') | appengine/swarming/server/task_request_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 if not cipd.is_valid_version(value): 216 if not cipd.is_valid_version(value):
217 raise datastore_errors.BadValueError( 217 raise datastore_errors.BadValueError(
218 '%s must be a valid package version "%s"' % (prop._name, value)) 218 '%s must be a valid package version "%s"' % (prop._name, value))
219 219
220 220
221 ### Models. 221 ### Models.
222 222
223 223
224 class FilesRef(ndb.Model): 224 class FilesRef(ndb.Model):
225 """Defines a data tree reference, normally a reference to a .isolated file.""" 225 """Defines a data tree reference, normally a reference to a .isolated file."""
226
227 # TODO(maruel): make this class have one responsibility. Currently it is used
228 # in two modes:
229 # - a reference to a tree, as class docstring says.
230 # - input/output settings in TaskProperties.
231
226 # The hash of an isolated archive. 232 # The hash of an isolated archive.
227 isolated = ndb.StringProperty(validator=_validate_isolated, indexed=False) 233 isolated = ndb.StringProperty(validator=_validate_isolated, indexed=False)
228 # The hostname of the isolated server to use. 234 # The hostname of the isolated server to use.
229 isolatedserver = ndb.StringProperty( 235 isolatedserver = ndb.StringProperty(
230 validator=_validate_hostname, indexed=False) 236 validator=_validate_hostname, indexed=False)
231 # Namespace on the isolate server. 237 # Namespace on the isolate server.
232 namespace = ndb.StringProperty(validator=_validate_namespace, indexed=False) 238 namespace = ndb.StringProperty(validator=_validate_namespace, indexed=False)
233 239
234 def _pre_put_hook(self): 240 def _pre_put_hook(self):
235 super(FilesRef, self)._pre_put_hook() 241 super(FilesRef, self)._pre_put_hook()
236 if not self.isolated or not self.isolatedserver or not self.namespace: 242 if not self.isolatedserver or not self.namespace:
237 raise datastore_errors.BadValueError( 243 raise datastore_errors.BadValueError(
238 'isolated requires server and namespace') 244 'isolate server and namespace are required')
239 245
240 246
241 class CipdPackage(ndb.Model): 247 class CipdPackage(ndb.Model):
242 """A CIPD package to install in $CIPD_PATH and $PATH before task execution. 248 """A CIPD package to install in $CIPD_PATH and $PATH before task execution.
243 249
244 A part of TaskProperties. 250 A part of TaskProperties.
245 """ 251 """
246 package_name = ndb.StringProperty( 252 package_name = ndb.StringProperty(
247 indexed=False, validator=_validate_package_name) 253 indexed=False, validator=_validate_package_name)
248 version = ndb.StringProperty( 254 version = ndb.StringProperty(
(...skipping 10 matching lines...) Expand all
259 class TaskProperties(ndb.Model): 265 class TaskProperties(ndb.Model):
260 """Defines all the properties of a task to be run on the Swarming 266 """Defines all the properties of a task to be run on the Swarming
261 infrastructure. 267 infrastructure.
262 268
263 This entity is not saved in the DB as a standalone entity, instead it is 269 This entity is not saved in the DB as a standalone entity, instead it is
264 embedded in a TaskRequest. 270 embedded in a TaskRequest.
265 271
266 This model is immutable. 272 This model is immutable.
267 273
268 New-style TaskProperties supports invocation of run_isolated. When this 274 New-style TaskProperties supports invocation of run_isolated. When this
269 behavior is desired, the member .inputs_ref must be suppled. .extra_args can 275 behavior is desired, the member .inputs_ref with an .isolated field value must
270 be supplied to pass extraneous arguments. 276 be supplied. .extra_args can be supplied to pass extraneous arguments.
271 """ 277 """
278
279 # TODO(maruel): convert inputs_ref and _TaskResultCommon.outputs_ref as:
280 # - input = String which is the isolated input, if any
281 # - isolated_server = <server, metadata e.g. namespace> which is a
282 # simplified version of FilesRef
283 # - _TaskResultCommon.output = String which is isolated output, if any.
284
272 # Hashing algorithm used to hash TaskProperties to create its key. 285 # Hashing algorithm used to hash TaskProperties to create its key.
273 HASHING_ALGO = hashlib.sha1 286 HASHING_ALGO = hashlib.sha1
274 287
275 # Commands to run. It is a list of 1 item, the command to run. 288 # Commands to run. It is a list of 1 item, the command to run.
276 # TODO(maruel): Remove after 2016-06-01. 289 # TODO(maruel): Remove after 2016-06-01.
277 commands = datastore_utils.DeterministicJsonProperty( 290 commands = datastore_utils.DeterministicJsonProperty(
278 json_type=list, indexed=False) 291 json_type=list, indexed=False)
279 # Command to run. This is only relevant when self._inputs_ref is None. This is 292 # Command to run. This is only relevant when self.inputs_ref.isolated is None.
280 # what is called 'raw commands', in the sense that no inputs files are 293 # This is what is called 'raw commands', in the sense that no inputs files are
281 # declared. 294 # declared.
282 command = ndb.StringProperty(repeated=True, indexed=False) 295 command = ndb.StringProperty(repeated=True, indexed=False)
283 296
284 # File inputs of the task. Only inputs_ref or command&data can be specified. 297 # Isolate server, namespace and input isolate hash.
298 #
299 # Despite its name, contains isolate server URL and namespace for isolated
300 # output too. See TODO at the top of this class.
301 # May be non-None even if task input is not isolated.
302 #
303 # Only inputs_ref.isolated or command can be specified.
285 inputs_ref = ndb.LocalStructuredProperty(FilesRef) 304 inputs_ref = ndb.LocalStructuredProperty(FilesRef)
286 305
287 # A list of CIPD packages to install $CIPD_PATH and $PATH before task 306 # A list of CIPD packages to install $CIPD_PATH and $PATH before task
288 # execution. 307 # execution.
289 packages = ndb.LocalStructuredProperty(CipdPackage, repeated=True) 308 packages = ndb.LocalStructuredProperty(CipdPackage, repeated=True)
290 309
291 # Filter to use to determine the required properties on the bot to run on. For 310 # Filter to use to determine the required properties on the bot to run on. For
292 # example, Windows or hostname. Encoded as json. Optional but highly 311 # example, Windows or hostname. Encoded as json. Optional but highly
293 # recommended. 312 # recommended.
294 dimensions = datastore_utils.DeterministicJsonProperty( 313 dimensions = datastore_utils.DeterministicJsonProperty(
295 validator=_validate_dimensions, json_type=dict, indexed=False) 314 validator=_validate_dimensions, json_type=dict, indexed=False)
296 315
297 # Environment variables. Encoded as json. Optional. 316 # Environment variables. Encoded as json. Optional.
298 env = datastore_utils.DeterministicJsonProperty( 317 env = datastore_utils.DeterministicJsonProperty(
299 validator=_validate_dict_of_strings, json_type=dict, indexed=False) 318 validator=_validate_dict_of_strings, json_type=dict, indexed=False)
300 319
301 # Maximum duration the bot can take to run this task. It's named hard_timeout 320 # Maximum duration the bot can take to run this task. It's named hard_timeout
302 # in the bot. 321 # in the bot.
303 execution_timeout_secs = ndb.IntegerProperty( 322 execution_timeout_secs = ndb.IntegerProperty(
304 validator=_validate_timeout, required=True, indexed=False) 323 validator=_validate_timeout, required=True, indexed=False)
305 324
306 # Extra arguments to supply to the command `python run_isolated ...`. Can only 325 # Extra arguments to supply to the command `python run_isolated ...`. Can only
307 # be set if inputs_ref is set. 326 # be set if inputs_ref.isolated is set.
308 extra_args = ndb.StringProperty(repeated=True, indexed=False) 327 extra_args = ndb.StringProperty(repeated=True, indexed=False)
309 328
310 # Grace period is the time between signaling the task it timed out and killing 329 # Grace period is the time between signaling the task it timed out and killing
311 # the process. During this time the process should clean up itself as quickly 330 # the process. During this time the process should clean up itself as quickly
312 # as possible, potentially uploading partial results back. 331 # as possible, potentially uploading partial results back.
313 grace_period_secs = ndb.IntegerProperty( 332 grace_period_secs = ndb.IntegerProperty(
314 validator=_validate_grace, default=30, indexed=False) 333 validator=_validate_grace, default=30, indexed=False)
315 334
316 # Bot controlled timeout for new bytes from the subprocess. If a subprocess 335 # Bot controlled timeout for new bytes from the subprocess. If a subprocess
317 # doesn't output new data to stdout for .io_timeout_secs, consider the command 336 # doesn't output new data to stdout for .io_timeout_secs, consider the command
318 # timed out. Optional. 337 # timed out. Optional.
319 io_timeout_secs = ndb.IntegerProperty( 338 io_timeout_secs = ndb.IntegerProperty(
320 validator=_validate_timeout, indexed=False) 339 validator=_validate_timeout, indexed=False)
321 340
322 # If True, the task can safely be served results from a previously succeeded 341 # If True, the task can safely be served results from a previously succeeded
323 # task. 342 # task.
324 idempotent = ndb.BooleanProperty(default=False, indexed=False) 343 idempotent = ndb.BooleanProperty(default=False, indexed=False)
325 344
326 @property 345 @property
327 def is_terminate(self): 346 def is_terminate(self):
328 """If True, it is a terminate request.""" 347 """If True, it is a terminate request."""
329 return ( 348 return (
330 not self.commands and 349 not self.commands and
331 not self.command and 350 not self.command and
332 self.dimensions.keys() == [u'id'] and 351 self.dimensions.keys() == [u'id'] and
333 not self.inputs_ref and 352 not (self.inputs_ref and self.inputs_ref.isolated) and
334 not self.env and 353 not self.env and
335 not self.execution_timeout_secs and 354 not self.execution_timeout_secs and
336 not self.extra_args and 355 not self.extra_args and
337 not self.grace_period_secs and 356 not self.grace_period_secs and
338 not self.io_timeout_secs and 357 not self.io_timeout_secs and
339 not self.idempotent) 358 not self.idempotent)
340 359
341 @property 360 @property
342 def properties_hash(self): 361 def properties_hash(self):
343 """Calculates the hash for this entity IFF the task is idempotent. 362 """Calculates the hash for this entity IFF the task is idempotent.
(...skipping 12 matching lines...) Expand all
356 out = super(TaskProperties, self).to_dict(exclude=['commands']) 375 out = super(TaskProperties, self).to_dict(exclude=['commands'])
357 out['command'] = self.commands[0] if self.commands else self.command 376 out['command'] = self.commands[0] if self.commands else self.command
358 return out 377 return out
359 378
360 def _pre_put_hook(self): 379 def _pre_put_hook(self):
361 super(TaskProperties, self)._pre_put_hook() 380 super(TaskProperties, self)._pre_put_hook()
362 if self.commands: 381 if self.commands:
363 raise datastore_errors.BadValueError( 382 raise datastore_errors.BadValueError(
364 'commands is not supported anymore') 383 'commands is not supported anymore')
365 if not self.is_terminate: 384 if not self.is_terminate:
366 if bool(self.command) == bool(self.inputs_ref): 385 isolated_input = self.inputs_ref and self.inputs_ref.isolated
367 raise datastore_errors.BadValueError('use one of command or inputs_ref') 386 if bool(self.command) == bool(isolated_input):
368 if self.extra_args and not self.inputs_ref: 387 raise datastore_errors.BadValueError(
369 raise datastore_errors.BadValueError('extra_args require inputs_ref') 388 'use one of command or inputs_ref.isolated')
389 if self.extra_args and not isolated_input:
390 raise datastore_errors.BadValueError(
391 'extra_args require inputs_ref.isolated')
370 if self.inputs_ref: 392 if self.inputs_ref:
371 self.inputs_ref._pre_put_hook() 393 self.inputs_ref._pre_put_hook()
372 394
373 package_names = set() 395 package_names = set()
374 for p in self.packages: 396 for p in self.packages:
375 p._pre_put_hook() 397 p._pre_put_hook()
376 if p.package_name in package_names: 398 if p.package_name in package_names:
377 raise datastore_errors.BadValueError( 399 raise datastore_errors.BadValueError(
378 'package %s is specified more than once' % p.package_name) 400 'package %s is specified more than once' % p.package_name)
379 package_names.add(p.package_name) 401 package_names.add(p.package_name)
380 self.packages.sort(key=lambda p: p.package_name) 402 self.packages.sort(key=lambda p: p.package_name)
381 403
382 if self.idempotent: 404 if self.idempotent:
383 pinned = lambda p: cipd.is_pinned_version(p.version) 405 pinned = lambda p: cipd.is_pinned_version(p.version)
384 if self.packages and any(not pinned(p) for p in self.packages): 406 if self.packages and any(not pinned(p) for p in self.packages):
385 raise datastore_errors.BadValueError( 407 raise datastore_errors.BadValueError(
386 'an idempotent task cannot have unpinned packages; ' 408 'an idempotent task cannot have unpinned packages; '
387 'use instance IDs or tags as package versions') 409 'use instance IDs or tags as package versions')
388 410
389 411
390
391 class TaskRequest(ndb.Model): 412 class TaskRequest(ndb.Model):
392 """Contains a user request. 413 """Contains a user request.
393 414
394 Key id is a decreasing integer based on time since utils.EPOCH plus some 415 Key id is a decreasing integer based on time since utils.EPOCH plus some
395 randomness on lower order bits. See _new_request_key() for the complete gory 416 randomness on lower order bits. See _new_request_key() for the complete gory
396 details. 417 details.
397 418
398 There is also "old style keys" which inherit from a fake root entity 419 There is also "old style keys" which inherit from a fake root entity
399 TaskRequestShard. 420 TaskRequestShard.
400 TODO(maruel): Remove support 2015-10-01 once entities are deleted. 421 TODO(maruel): Remove support 2015-10-01 once entities are deleted.
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
702 _put_request(request) 723 _put_request(request)
703 return request 724 return request
704 725
705 726
706 def validate_priority(priority): 727 def validate_priority(priority):
707 """Throws ValueError if priority is not a valid value.""" 728 """Throws ValueError if priority is not a valid value."""
708 if 0 > priority or MAXIMUM_PRIORITY < priority: 729 if 0 > priority or MAXIMUM_PRIORITY < priority:
709 raise datastore_errors.BadValueError( 730 raise datastore_errors.BadValueError(
710 'priority (%d) must be between 0 and %d (inclusive)' % 731 'priority (%d) must be between 0 and %d (inclusive)' %
711 (priority, MAXIMUM_PRIORITY)) 732 (priority, MAXIMUM_PRIORITY))
OLDNEW
« no previous file with comments | « appengine/swarming/handlers_bot_test.py ('k') | appengine/swarming/server/task_request_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698