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

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

Issue 2069903003: swarming: custom cipd package paths (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-py@cipd-win
Patch Set: test "." and None custom path Created 4 years, 6 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 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 28 matching lines...) Expand all
39 +---------------------+ 39 +---------------------+
40 ^ 40 ^
41 | 41 |
42 <See task_to_run.py and task_result.py> 42 <See task_to_run.py and task_result.py>
43 43
44 TaskProperties is embedded in TaskRequest. TaskProperties is still declared as a 44 TaskProperties is embedded in TaskRequest. TaskProperties is still declared as a
45 separate entity to clearly declare the boundary for task request deduplication. 45 separate entity to clearly declare the boundary for task request deduplication.
46 """ 46 """
47 47
48 48
49 import collections
49 import datetime 50 import datetime
50 import hashlib 51 import hashlib
51 import random 52 import random
52 import re 53 import re
53 import urlparse 54 import urlparse
54 55
55 from google.appengine.api import datastore_errors 56 from google.appengine.api import datastore_errors
56 from google.appengine.ext import ndb 57 from google.appengine.ext import ndb
57 58
58 from components import auth 59 from components import auth
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
252 A part of TaskProperties. 253 A part of TaskProperties.
253 """ 254 """
254 # Package name template. May use cipd.ALL_PARAMS. 255 # Package name template. May use cipd.ALL_PARAMS.
255 # Most users will specify ${platform} parameter. 256 # Most users will specify ${platform} parameter.
256 package_name = ndb.StringProperty( 257 package_name = ndb.StringProperty(
257 indexed=False, validator=_validate_package_name_template) 258 indexed=False, validator=_validate_package_name_template)
258 # Package version that is valid for all packages matched by package_name. 259 # Package version that is valid for all packages matched by package_name.
259 # Most users will specify tags. 260 # Most users will specify tags.
260 version = ndb.StringProperty( 261 version = ndb.StringProperty(
261 indexed=False, validator=_validate_package_version) 262 indexed=False, validator=_validate_package_version)
263 # Path to dir, relative to the run dir, where to install the package.
264 # If empty, the package will be installed in run dir.
265 path = ndb.StringProperty(indexed=False)
262 266
263 def __str__(self): 267 def __str__(self):
264 return '%s:%s' % (self.package_name, self.version) 268 return '%s:%s' % (self.package_name, self.version)
265 269
266 def _pre_put_hook(self): 270 def _pre_put_hook(self):
267 super(CipdPackage, self)._pre_put_hook() 271 super(CipdPackage, self)._pre_put_hook()
268 if not self.package_name: 272 if not self.package_name:
269 raise datastore_errors.BadValueError('CIPD package name is required') 273 raise datastore_errors.BadValueError('CIPD package name is required')
270 if not self.version: 274 if not self.version:
271 raise datastore_errors.BadValueError('CIPD package version is required') 275 raise datastore_errors.BadValueError('CIPD package version is required')
272 276
277 if self.path:
M-A Ruel 2016/06/15 17:28:27 Use a validator instead.
nodir 2016/06/15 17:53:42 Done.
278 if '\\' in self.path:
279 raise datastore_errors.BadValueError(
280 'CIPD package path cannot contain \\. On Windows forward-slashes '
281 'will be replaced with back-slashes.')
282 if '..' in self.path.split('/'):
283 raise datastore_errors.BadValueError(
284 'CIPD package path cannot contain "..".')
285 if self.path.startswith('/'):
286 raise datastore_errors.BadValueError(
287 'CIPD package path cannot start with "/".')
288
273 289
274 class CipdInput(ndb.Model): 290 class CipdInput(ndb.Model):
275 """Specifies which CIPD client and packages to install, from which server. 291 """Specifies which CIPD client and packages to install, from which server.
276 292
277 A part of TaskProperties. 293 A part of TaskProperties.
278 """ 294 """
279 # URL of the CIPD server. Must start with "https://" or "http://". 295 # URL of the CIPD server. Must start with "https://" or "http://".
280 server = ndb.StringProperty(indexed=False, validator=_validate_url) 296 server = ndb.StringProperty(indexed=False, validator=_validate_url)
281 297
282 # CIPD package of CIPD client to use. 298 # CIPD package of CIPD client to use.
283 # client_package.version is required. 299 # client_package.version is required.
300 # client_package.path must be None.
284 client_package = ndb.LocalStructuredProperty(CipdPackage) 301 client_package = ndb.LocalStructuredProperty(CipdPackage)
285 302
286 # List of packages to install in $CIPD_PATH prior task execution. 303 # List of packages to install in $CIPD_PATH prior task execution.
287 packages = ndb.LocalStructuredProperty(CipdPackage, repeated=True) 304 packages = ndb.LocalStructuredProperty(CipdPackage, repeated=True)
288 305
289 def _pre_put_hook(self): 306 def _pre_put_hook(self):
290 if not self.server: 307 if not self.server:
291 raise datastore_errors.BadValueError('cipd server is required') 308 raise datastore_errors.BadValueError('cipd server is required')
292 if not self.client_package: 309 if not self.client_package:
293 raise datastore_errors.BadValueError('client_package is required') 310 raise datastore_errors.BadValueError('client_package is required')
311 if self.client_package.path:
312 raise datastore_errors.BadValueError('client_package.path must be unset')
294 self.client_package._pre_put_hook() 313 self.client_package._pre_put_hook()
295 314
296 if not self.packages: 315 if not self.packages:
297 raise datastore_errors.BadValueError( 316 raise datastore_errors.BadValueError(
298 'cipd_input cannot have an empty package list') 317 'cipd_input cannot have an empty package list')
299 318
300 package_names = set() 319 package_names = set()
301 for p in self.packages: 320 for p in self.packages:
302 p._pre_put_hook() 321 p._pre_put_hook()
303 if p.package_name in package_names: 322 if p.package_name in package_names:
304 raise datastore_errors.BadValueError( 323 raise datastore_errors.BadValueError(
305 'package %s is specified more than once' % p.package_name) 324 'package %s is specified more than once' % p.package_name)
306 package_names.add(p.package_name) 325 package_names.add(p.package_name)
307 self.packages.sort(key=lambda p: p.package_name) 326 self.packages.sort(key=lambda p: p.package_name)
308 327
328 def packages_grouped_by_path(self):
329 """Returns sorted [(path), [package]) list. Used by user_task.html."""
330 packages = collections.defaultdict(list)
331 for p in self.packages:
332 packages[p.path or '.'].append(p)
M-A Ruel 2016/06/15 17:28:27 I don't like that path=None and path='.' have the
nodir 2016/06/15 17:53:41 Good point, done.
333 for pkgs in packages.values():
M-A Ruel 2016/06/15 17:28:27 itervalues()
nodir 2016/06/15 17:53:42 Done.
334 pkgs.sort()
335 return sorted(packages.iteritems())
309 336
M-A Ruel 2016/06/15 17:28:27 2 lines
nodir 2016/06/15 17:53:42 Done.
310 class TaskProperties(ndb.Model): 337 class TaskProperties(ndb.Model):
311 """Defines all the properties of a task to be run on the Swarming 338 """Defines all the properties of a task to be run on the Swarming
312 infrastructure. 339 infrastructure.
313 340
314 This entity is not saved in the DB as a standalone entity, instead it is 341 This entity is not saved in the DB as a standalone entity, instead it is
315 embedded in a TaskRequest. 342 embedded in a TaskRequest.
316 343
317 This model is immutable. 344 This model is immutable.
318 345
319 New-style TaskProperties supports invocation of run_isolated. When this 346 New-style TaskProperties supports invocation of run_isolated. When this
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 _put_request(request) 796 _put_request(request)
770 return request 797 return request
771 798
772 799
773 def validate_priority(priority): 800 def validate_priority(priority):
774 """Throws ValueError if priority is not a valid value.""" 801 """Throws ValueError if priority is not a valid value."""
775 if 0 > priority or MAXIMUM_PRIORITY < priority: 802 if 0 > priority or MAXIMUM_PRIORITY < priority:
776 raise datastore_errors.BadValueError( 803 raise datastore_errors.BadValueError(
777 'priority (%d) must be between 0 and %d (inclusive)' % 804 'priority (%d) must be between 0 and %d (inclusive)' %
778 (priority, MAXIMUM_PRIORITY)) 805 (priority, MAXIMUM_PRIORITY))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698