def _get_leasable_build(build_id): build = model.Build.get_by_id(build_id) if build is None: raise errors.BuildNotFoundError() if not user.can_lease_build_async(build).get_result(): raise user.current_identity_cannot('lease build %s', build.key.id()) if build.is_luci: raise errors.InvalidInputError('cannot lease a swarmbucket build') return build
def check_scheduling_permissions(bucket_ids): """Checks if the requester can schedule builds in any of the buckets. Raises auth.AuthorizationError on insufficient permissions. """ can_add = utils.async_apply(set(bucket_ids), user.can_add_build_async) forbidden = [b for b, can in can_add if not can] if forbidden: raise user.current_identity_cannot('add builds to buckets %s', forbidden)
def get_async(build_id): """Gets a build by |build_id|. Requires the current user to have permissions to view the build. """ build = yield model.Build.get_by_id_async(build_id) if not build: raise ndb.Return(None) if not (yield user.can_view_build_async(build)): raise user.current_identity_cannot('view build %s', build.key.id()) raise ndb.Return(build)
def get_build_async(check_access): build = yield model.Build.get_by_id_async(build_id) if build is None: raise errors.BuildNotFoundError() if check_access and not (yield user.can_cancel_build_async(build)): raise user.current_identity_cannot('cancel build %s', build.key.id()) if build.proto.status == common_pb2.CANCELED: raise ndb.Return(build, False) if build.is_ended: raise errors.BuildIsCompletedError( 'Cannot cancel a completed build') raise ndb.Return(build, True)
def txn(): build = _get_leasable_build(build_id) if not user.can_reset_build_async(build).get_result(): raise user.current_identity_cannot('reset build %s', build.key.id()) if build.is_ended: raise errors.BuildIsCompletedError( 'Cannot reset a completed build') build.proto.status = common_pb2.SCHEDULED build.status_changed_time = utils.utcnow() build.clear_lease() build.url = None _fut_results(build.put_async(), events.on_build_resetting_async(build)) return build
def pause(bucket_id, is_paused): if not user.can_pause_buckets_async(bucket_id).get_result(): raise user.current_identity_cannot('pause bucket of %s', bucket_id) _reject_swarming_bucket(bucket_id) @ndb.transactional def try_set_pause(): state = (model.BucketState.get_by_id(bucket_id) or model.BucketState(id=bucket_id)) if state.is_paused != is_paused: state.is_paused = is_paused state.put() try_set_pause()
def convert_bucket(bucket): """Converts a bucket string to a bucket id and checks access. A synchronous wrapper for api_common.to_bucket_id_async that also checks access. Raises: auth.AuthorizationError if the requester doesn't have access to the bucket. errors.InvalidInputError if bucket is invalid or ambiguous. """ bucket_id = api_common.to_bucket_id_async(bucket).get_result() # Check access here to return user-supplied bucket name, # as opposed to computed bucket id to prevent sniffing bucket names. if not bucket_id or not user.can_access_bucket_async(bucket_id).get_result(): raise user.current_identity_cannot('access bucket %r', bucket) return bucket_id
def check_acls_async(bucket_ids, inc_metric=None): """Checks access to the buckets. Raises an error if the current identity doesn't have access to any of the buckets. """ assert bucket_ids bucket_ids = sorted(set(bucket_ids)) for bucket_id in bucket_ids: config.validate_bucket_id(bucket_id) futs = [user.can_search_builds_async(b) for b in bucket_ids] for bucket_id, fut in zip(bucket_ids, futs): if not (yield fut): if inc_metric: # pragma: no cover inc_metric.increment(fields={'bucket': bucket_id}) raise user.current_identity_cannot('search builds in bucket %s', bucket_id)
def delete_many_builds(bucket_id, status, tags=None, created_by=None): if status not in (model.BuildStatus.SCHEDULED, model.BuildStatus.STARTED): raise errors.InvalidInputError( 'status can be STARTED or SCHEDULED, not %s' % status) if not user.can_delete_scheduled_builds_async(bucket_id).get_result(): raise user.current_identity_cannot('delete builds of %s', bucket_id) # Validate created_by prior scheduled a push task. created_by = user.parse_identity(created_by) deferred.defer( _task_delete_many_builds, bucket_id, status, tags=tags, created_by=created_by, # Schedule it on the backend module of the same version. # This assumes that both frontend and backend are uploaded together. _target='%s.backend' % modules.get_current_version_name(), # Retry immediatelly. _retry_options=taskqueue.TaskRetryOptions( min_backoff_seconds=0, max_backoff_seconds=1, ), )