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

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: async memcache, no consistency policy Created 5 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
« no previous file with comments | « appengine/cr-buildbucket/errors.py ('k') | appengine/cr-buildbucket/test/api_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 # 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
Vadim Sh. 2015/04/16 00:42:27 no longer used probably
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...) Expand 10 before | Expand all | Expand 10 after
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 a build with the same client operation id was added during last minute,
112 it will be returned instead.
107 113
108 Returns: 114 Returns:
109 A new Build. 115 A new Build.
110 """ 116 """
117 if client_operation_id is not None:
118 if not isinstance(client_operation_id, basestring): # pragma: no cover
119 raise errors.InvalidInputError('client_operation_id must be string')
120 if '/' in client_operation_id: # pragma: no cover
121 raise errors.InvalidInputError('client_operation_id must not contain /')
111 validate_bucket_name(bucket) 122 validate_bucket_name(bucket)
112 assert parameters is None or isinstance(parameters, dict) 123 assert parameters is None or isinstance(parameters, dict)
113 validate_lease_expiration_date(lease_expiration_date) 124 validate_lease_expiration_date(lease_expiration_date)
114 validate_tags(tags) 125 validate_tags(tags)
115 tags = tags or [] 126 tags = tags or []
116 127
128 ctx = ndb.get_context()
117 identity = auth.get_current_identity() 129 identity = auth.get_current_identity()
118 if not acl.can_add_build(bucket, identity): 130 if not acl.can_add_build(bucket, identity):
119 raise current_identity_cannot('add builds to bucket %s', bucket) 131 raise current_identity_cannot('add builds to bucket %s', bucket)
120 132
133 if client_operation_id is not None:
134 client_operation_cache_key = (
135 'client_op/%s/%s/add_build' % (
136 identity.to_bytes(), client_operation_id))
137 build_id = yield ctx.memcache_get(client_operation_cache_key)
138 if build_id:
139 build = yield model.Build.get_by_id_async(build_id)
140 if build: # pragma: no branch
141 raise ndb.Return(build)
142
121 build = model.Build( 143 build = model.Build(
122 id=model.new_build_id(), 144 id=model.new_build_id(),
123 bucket=bucket, 145 bucket=bucket,
124 tags=tags, 146 tags=tags,
125 parameters=parameters, 147 parameters=parameters,
126 status=model.BuildStatus.SCHEDULED, 148 status=model.BuildStatus.SCHEDULED,
127 created_by=identity, 149 created_by=identity,
128 ) 150 )
129 if lease_expiration_date is not None: 151 if lease_expiration_date is not None:
130 build.lease_expiration_date = lease_expiration_date 152 build.lease_expiration_date = lease_expiration_date
131 build.leasee = auth.get_current_identity() 153 build.leasee = auth.get_current_identity()
132 build.regenerate_lease_key() 154 build.regenerate_lease_key()
133 build.put() 155 yield build.put_async()
134 logging.info( 156 logging.info(
135 'Build %s was created by %s', build.key.id(), identity.to_bytes()) 157 'Build %s was created by %s', build.key.id(), identity.to_bytes())
136 return build 158
159 if client_operation_id is not None:
160 yield ctx.memcache_set(client_operation_cache_key, build.key.id(), 60)
161 raise ndb.Return(build)
162
163 def add(self, *args, **kwargs):
164 """Sync version of add_async."""
165 return self.add_async(*args, **kwargs).get_result()
137 166
138 def get(self, build_id): 167 def get(self, build_id):
139 """Gets a build by |build_id|. 168 """Gets a build by |build_id|.
140 169
141 Requires the current user to have permissions to view the build. 170 Requires the current user to have permissions to view the build.
142 """ 171 """
143 build = model.Build.get_by_id(build_id) 172 build = model.Build.get_by_id(build_id)
144 if not build: 173 if not build:
145 return None 174 return None
146 identity = auth.get_current_identity() 175 identity = auth.get_current_identity()
(...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 634
606 def reset_expired_builds(self): 635 def reset_expired_builds(self):
607 """For all building expired builds, resets their lease_key and state.""" 636 """For all building expired builds, resets their lease_key and state."""
608 q = model.Build.query( 637 q = model.Build.query(
609 model.Build.is_leased == True, 638 model.Build.is_leased == True,
610 model.Build.lease_expiration_date <= datetime.datetime.utcnow(), 639 model.Build.lease_expiration_date <= datetime.datetime.utcnow(),
611 ) 640 )
612 for key in q.iter(keys_only=True): 641 for key in q.iter(keys_only=True):
613 if self._reset_expired_build(key): # pragma: no branch 642 if self._reset_expired_build(key): # pragma: no branch
614 logging.info('Expired build %s was reset' % key.id()) 643 logging.info('Expired build %s was reset' % key.id())
OLDNEW
« no previous file with comments | « appengine/cr-buildbucket/errors.py ('k') | appengine/cr-buildbucket/test/api_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698