Chromium Code Reviews

Side by Side Diff: appengine/cr-buildbucket/service.py

Issue 1082303002: buildbucket: put_batch endpoint (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: memcache Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import datetime 5 import datetime
6 import itertools 6 import itertools
7 import json 7 import json
8 import logging 8 import logging
9 import urlparse 9 import urlparse
10 10
11 from components import auth 11 from components import auth
12 from components import utils 12 from components import utils
13 from google.appengine.api import memcache
13 from google.appengine.api import taskqueue 14 from google.appengine.api import taskqueue
14 from google.appengine.ext import db 15 from google.appengine.ext import db
15 from google.appengine.ext import ndb 16 from google.appengine.ext import ndb
16 17
17 import acl 18 import acl
18 import errors 19 import errors
19 import model 20 import model
20 21
21 22
22 MAX_RETURN_BUILDS = 100 23 MAX_RETURN_BUILDS = 100
(...skipping 60 matching lines...)
83 84
84 85
85 def current_identity_cannot(action_format, *args): 86 def current_identity_cannot(action_format, *args):
86 action = action_format % args 87 action = action_format % args
87 msg = 'User %s cannot %s' % (auth.get_current_identity().to_bytes(), action) 88 msg = 'User %s cannot %s' % (auth.get_current_identity().to_bytes(), action)
88 logging.warning(msg) 89 logging.warning(msg)
89 raise auth.AuthorizationError(msg) 90 raise auth.AuthorizationError(msg)
90 91
91 92
92 class BuildBucketService(object): 93 class BuildBucketService(object):
93 def add( 94 @ndb.tasklet
94 self, bucket, tags=None, parameters=None, lease_expiration_date=None): 95 def add_async(
96 self, bucket, tags=None, parameters=None, lease_expiration_date=None,
97 client_operation_id=None):
95 """Adds the build entity to the build bucket. 98 """Adds the build entity to the build bucket.
96 99
97 Requires the current user to have permissions to add builds to the 100 Requires the current user to have permissions to add builds to the
98 |bucket|. 101 |bucket|.
99 102
100 Args: 103 Args:
101 bucket (str): destination bucket. Required. 104 bucket (str): destination bucket. Required.
102 tags (model.Tags): build tags. 105 tags (model.Tags): build tags.
103 parameters (dict): arbitrary build parameters. Cannot be changed after 106 parameters (dict): arbitrary build parameters. Cannot be changed after
104 build creation. 107 build creation.
105 lease_expiration_date (datetime.datetime): if not None, the build is 108 lease_expiration_date (datetime.datetime): if not None, the build is
106 created as leased and its lease_key is not None. 109 created as leased and its lease_key is not None.
110 client_operation_id (str): client-supplied operation id. If an
111 existing build with the same client id exists, it will be returned
112 instead.
Vadim Sh. 2015/04/16 00:12:21 mention that expires within 1 min
nodir 2015/04/16 00:36:20 Done.
107 113
108 Returns: 114 Returns:
109 A new Build. 115 A new Build.
110 """ 116 """
111 validate_bucket_name(bucket) 117 validate_bucket_name(bucket)
112 assert parameters is None or isinstance(parameters, dict) 118 assert parameters is None or isinstance(parameters, dict)
113 validate_lease_expiration_date(lease_expiration_date) 119 validate_lease_expiration_date(lease_expiration_date)
114 validate_tags(tags) 120 validate_tags(tags)
115 tags = tags or [] 121 tags = tags or []
116 122
117 identity = auth.get_current_identity() 123 identity = auth.get_current_identity()
118 if not acl.can_add_build(bucket, identity): 124 if not acl.can_add_build(bucket, identity):
119 raise current_identity_cannot('add builds to bucket %s', bucket) 125 raise current_identity_cannot('add builds to bucket %s', bucket)
120 126
127 if client_operation_id is not None:
128 client_operation_cache_key = (
129 'client_op/%s/%s/add_build' % (
130 identity.to_bytes(), client_operation_id))
Vadim Sh. 2015/04/16 00:12:21 forbid "/" in client_operation_id or hash it befor
nodir 2015/04/16 00:36:20 Done.
131 build_id = memcache.get(client_operation_cache_key)
132 if build_id:
133 build = yield model.Build.get_by_id_async(build_id)
134 if build: # pragma: no branch
135 raise ndb.Return(build)
136
121 build = model.Build( 137 build = model.Build(
122 id=model.new_build_id(), 138 id=model.new_build_id(),
123 bucket=bucket, 139 bucket=bucket,
124 tags=tags, 140 tags=tags,
125 parameters=parameters, 141 parameters=parameters,
126 status=model.BuildStatus.SCHEDULED, 142 status=model.BuildStatus.SCHEDULED,
127 created_by=identity, 143 created_by=identity,
128 ) 144 )
129 if lease_expiration_date is not None: 145 if lease_expiration_date is not None:
130 build.lease_expiration_date = lease_expiration_date 146 build.lease_expiration_date = lease_expiration_date
131 build.leasee = auth.get_current_identity() 147 build.leasee = auth.get_current_identity()
132 build.regenerate_lease_key() 148 build.regenerate_lease_key()
133 build.put() 149 yield build.put_async()
134 logging.info( 150 logging.info(
135 'Build %s was created by %s', build.key.id(), identity.to_bytes()) 151 'Build %s was created by %s', build.key.id(), identity.to_bytes())
136 return build 152
153 if client_operation_id is not None:
154 memcache.set(client_operation_cache_key, build.key.id(), 60)
Vadim Sh. 2015/04/16 00:12:21 do it async too, ndb supports memcache (forgot exa
nodir 2015/04/16 00:36:20 Done.
155 raise ndb.Return(build)
156
157 def add(self, *args, **kwargs):
158 """Sync version of add_async."""
159 return self.add_async(*args, **kwargs).get_result()
137 160
138 def get(self, build_id): 161 def get(self, build_id):
139 """Gets a build by |build_id|. 162 """Gets a build by |build_id|.
140 163
141 Requires the current user to have permissions to view the build. 164 Requires the current user to have permissions to view the build.
142 """ 165 """
143 build = model.Build.get_by_id(build_id) 166 build = model.Build.get_by_id(build_id)
144 if not build: 167 if not build:
145 return None 168 return None
146 identity = auth.get_current_identity() 169 identity = auth.get_current_identity()
(...skipping 458 matching lines...)
605 628
606 def reset_expired_builds(self): 629 def reset_expired_builds(self):
607 """For all building expired builds, resets their lease_key and state.""" 630 """For all building expired builds, resets their lease_key and state."""
608 q = model.Build.query( 631 q = model.Build.query(
609 model.Build.is_leased == True, 632 model.Build.is_leased == True,
610 model.Build.lease_expiration_date <= datetime.datetime.utcnow(), 633 model.Build.lease_expiration_date <= datetime.datetime.utcnow(),
611 ) 634 )
612 for key in q.iter(keys_only=True): 635 for key in q.iter(keys_only=True):
613 if self._reset_expired_build(key): # pragma: no branch 636 if self._reset_expired_build(key): # pragma: no branch
614 logging.info('Expired build %s was reset' % key.id()) 637 logging.info('Expired build %s was reset' % key.id())
OLDNEW

Powered by Google App Engine