def test_post(self, mock_etcd_lock, mock_changed, mock_copy): lock = mock.Mock() mock_etcd_lock.return_value.__enter__.return_value = lock lock.is_acquired.return_value = True mock_changed.return_value = True # Getting function and versions needs to happen in a db transaction with db_api.transaction(): func_db = db_api.get_function(self.func_id) self.assertEqual(0, len(func_db.versions)) body = {'description': 'new version'} resp = self.app.post_json('/v1/functions/%s/versions' % self.func_id, body) self.assertEqual(201, resp.status_int) self._assertDictContainsSubset(resp.json, body) mock_changed.assert_called_once_with(unit_base.DEFAULT_PROJECT_ID, self.func_id, "fake_md5", 0) mock_copy.assert_called_once_with(unit_base.DEFAULT_PROJECT_ID, self.func_id, "fake_md5", 0) # We need to set context as it was removed after the API call context.set_ctx(self.ctx) with db_api.transaction(): func_db = db_api.get_function(self.func_id) self.assertEqual(1, len(func_db.versions)) # Verify the latest function version by calling API resp = self.app.get('/v1/functions/%s' % self.func_id) self.assertEqual(200, resp.status_int) self.assertEqual(1, resp.json.get('latest_version'))
def post(self, job): """Creates a new job.""" params = job.to_dict() if not POST_REQUIRED.issubset(set(params.keys())): raise exc.InputException( 'Required param is missing. Required: %s' % POST_REQUIRED) # Check the input params. first_time, next_time, count = jobs.validate_job(params) LOG.info("Creating %s, params: %s", self.type, params) with db_api.transaction(): db_api.get_function(params['function_id']) values = { 'name': params.get('name'), 'pattern': params.get('pattern'), 'first_execution_time': first_time, 'next_execution_time': next_time, 'count': count, 'function_id': params['function_id'], 'function_input': params.get('function_input') or {}, 'status': status.RUNNING } db_job = db_api.create_job(values) return resources.Job.from_dict(db_job.to_dict())
def create_execution(engine_client, params): function_id = params['function_id'] is_sync = params.get('sync', True) with db_api.transaction(): func_db = db_api.get_function(function_id) runtime_db = func_db.runtime if runtime_db and runtime_db.status != status.AVAILABLE: raise exc.RuntimeNotAvailableException( 'Runtime %s is not available.' % func_db.runtime_id) # Increase function invoke count, the updated_at field will be also # updated. func_db.count = func_db.count + 1 params.update({'status': status.RUNNING}) db_model = db_api.create_execution(params) engine_client.create_execution(db_model.id, function_id, func_db.runtime_id, input=params.get('input'), is_sync=is_sync) if is_sync: # The execution should already be updated by engine service for sync # execution. db_model = db_api.get_execution(db_model.id) return db_model
def invoke(self, id, **kwargs): with db_api.transaction(): # The webhook url can be accessed without authentication, so # insecure is used here webhook_db = db_api.get_webhook(id, insecure=True) function_db = webhook_db.function trust_id = function_db.trust_id project_id = function_db.project_id version = webhook_db.function_version LOG.info('Invoking function %s(version %s) by webhook %s', webhook_db.function_id, version, id) # Setup user context ctx = keystone_utils.create_trust_context(trust_id, project_id) context.set_ctx(ctx) params = { 'function_id': webhook_db.function_id, 'function_version': version, 'sync': False, 'input': json.dumps(kwargs), 'description': constants.EXECUTION_BY_WEBHOOK % id } execution = executions.create_execution(self.engine_client, params) pecan.response.status = 202 return {'execution_id': execution.id}
def delete(self, id): """Delete the specified function.""" LOG.info("Delete function %s.", id) with db_api.transaction(): func_db = db_api.get_function(id) if len(func_db.jobs) > 0: raise exc.NotAllowedException( 'The function is still associated with running job(s).') if func_db.webhook: raise exc.NotAllowedException( 'The function is still associated with webhook.') # Even admin user can not delete other project's function because # the trust associated can only be removed by function owner. if func_db.project_id != context.get_ctx().projectid: raise exc.NotAllowedException( 'Function can only be deleted by its owner.') source = func_db.code['source'] if source == constants.PACKAGE_FUNCTION: self.storage_provider.delete(func_db.project_id, id) # Delete all resources created by orchestrator asynchronously. self.engine_client.delete_function(id) # Delete trust if needed if func_db.trust_id: keystone_util.delete_trust(func_db.trust_id) # Delete etcd keys etcd_util.delete_function(id) # This will also delete function service mapping as well. db_api.delete_function(id)
def post(self, **kwargs): LOG.info("Creating function, params=%s", kwargs) if not POST_REQUIRED.issubset(set(kwargs.keys())): raise exc.InputException( 'Required param is missing. Required: %s' % POST_REQUIRED) runtime = db_api.get_runtime(kwargs['runtime_id']) if runtime.status != 'available': raise exc.InputException('Runtime %s not available.' % kwargs['runtime_id']) values = { 'name': kwargs['name'], 'description': kwargs.get('description', None), 'runtime_id': kwargs['runtime_id'], 'code': json.loads(kwargs['code']), 'entry': kwargs.get('entry', 'main'), } if values['code'].get('package', False): data = kwargs['package'].file.read() ctx = context.get_ctx() with db_api.transaction(): func_db = db_api.create_function(values) self.storage_provider.store(ctx.projectid, func_db.id, data) pecan.response.status = 201 return resources.Function.from_dict(func_db.to_dict()).to_dict()
def handle_function_service_expiration(ctx, engine_client, orchestrator): context.set_ctx(ctx) delta = timedelta(seconds=CONF.engine.function_service_expiration) expiry_time = datetime.utcnow() - delta results = db_api.get_functions(sort_keys=['updated_at'], insecure=True, updated_at={'lte': expiry_time}) if len(results) == 0: return for func_db in results: if not func_db.service: continue with db_api.transaction(): LOG.info('Deleting service mapping and workers for function %s', func_db.id) # Delete resources related to the function engine_client.delete_function(func_db.id) # Delete service mapping and worker records db_api.delete_function_service_mapping(func_db.id) db_api.delete_function_workers(func_db.id)
def create_execution(self, ctx, execution_id, function_id, runtime_id, input=None): LOG.info( 'Creating execution. execution_id=%s, function_id=%s, ' 'runtime_id=%s', execution_id, function_id, runtime_id) with db_api.transaction(): execution = db_api.get_execution(execution_id) runtime = db_api.get_runtime(runtime_id) identifier = '%s-%s' % (runtime_id, runtime.name) labels = {'runtime_name': runtime.name, 'runtime_id': runtime_id} service_url = self.orchestrator.prepare_execution( function_id, identifier=identifier, labels=labels) output = self.orchestrator.run_execution(function_id, input=input, service_url=service_url) LOG.debug('Finished execution. execution_id=%s, output=%s', execution_id, output) execution.output = output execution.status = 'success' mapping = {'function_id': function_id, 'service_url': service_url} db_api.create_function_service_mapping(mapping)
def put(self, id, **kwargs): """Update function. - Function can not being used by job. - Function can not being executed. - (TODO)Function status should be changed so no execution will create when function is updating. """ values = {} for key in UPDATE_ALLOWED: if kwargs.get(key) is not None: values.update({key: kwargs[key]}) LOG.info('Update resource, params: %s', values, resource={ 'type': self.type, 'id': id }) ctx = context.get_ctx() if set(values.keys()).issubset(set(['name', 'description'])): func_db = db_api.update_function(id, values) else: source = values.get('code', {}).get('source') with db_api.transaction(): pre_func = db_api.get_function(id) if len(pre_func.jobs) > 0: raise exc.NotAllowedException( 'The function is still associated with running job(s).' ) pre_source = pre_func.code['source'] if source and source != pre_source: raise exc.InputException( "The function code type can not be changed.") if source == constants.IMAGE_FUNCTION: raise exc.InputException( "The image type function code can not be changed.") if (pre_source == constants.PACKAGE_FUNCTION and values.get('package') is not None): # Update the package data. data = values['package'].file.read() self.storage_provider.store(ctx.projectid, id, data) values.pop('package') if pre_source == constants.SWIFT_FUNCTION: swift_info = values['code'].get('swift', {}) self._check_swift(swift_info.get('container'), swift_info.get('object')) # Delete allocated resources in orchestrator. db_api.delete_function_service_mapping(id) self.engine_client.delete_function(id) func_db = db_api.update_function(id, values) pecan.response.status = 200 return resources.Function.from_dict(func_db.to_dict()).to_dict()
def put(self, id, func): """Update function. Currently, we only support update name, description, entry. """ values = {} for key in UPDATE_ALLOWED: if func.to_dict().get(key) is not None: values.update({key: func.to_dict()[key]}) LOG.info('Update resource, params: %s', values, resource={ 'type': self.type, 'id': id }) with db_api.transaction(): func_db = db_api.update_function(id, values) if 'entry' in values: # Update entry will delete allocated resources in orchestrator. db_api.delete_function_service_mapping(id) self.engine_client.delete_function(id) return resources.Function.from_dict(func_db.to_dict())
def _update_function_db(function_id): with db_api.transaction(): # NOTE(kong): Store function info in cache? func_db = db_api.get_function(function_id) runtime_db = func_db.runtime if runtime_db and runtime_db.status != status.AVAILABLE: raise exc.RuntimeNotAvailableException( 'Runtime %s is not available.' % func_db.runtime_id) # Function update is done using UPDATE ... FROM ... WHERE # non-locking clause. while func_db: count = func_db.count modified = db_api.conditional_update( models.Function, { 'count': count + 1, }, { 'id': function_id, 'count': count }, insecure=True, ) if not modified: LOG.warning("Retrying to update function count.") func_db = db_api.get_function(function_id) continue else: break return func_db.runtime_id
def post(self, **kwargs): LOG.info("Creating %s, params: %s", self.type, kwargs) # When using image to create function, runtime_id is not a required # param. if not POST_REQUIRED.issubset(set(kwargs.keys())): raise exc.InputException( 'Required param is missing. Required: %s' % POST_REQUIRED) values = { 'name': kwargs.get('name'), 'description': kwargs.get('description'), 'runtime_id': kwargs.get('runtime_id'), 'code': json.loads(kwargs['code']), 'entry': kwargs.get('entry', 'main.main'), } source = values['code'].get('source') if not source or source not in CODE_SOURCE: raise exc.InputException( 'Invalid code source specified, available sources: %s' % ', '.join(CODE_SOURCE)) if source != constants.IMAGE_FUNCTION: if not kwargs.get('runtime_id'): raise exc.InputException('"runtime_id" must be specified.') runtime = db_api.get_runtime(kwargs['runtime_id']) if runtime.status != 'available': raise exc.InputException('Runtime %s is not available.' % kwargs['runtime_id']) store = False if values['code']['source'] == constants.PACKAGE_FUNCTION: store = True data = kwargs['package'].file.read() elif values['code']['source'] == constants.SWIFT_FUNCTION: swift_info = values['code'].get('swift', {}) self._check_swift(swift_info.get('container'), swift_info.get('object')) if cfg.CONF.pecan.auth_enable: try: values['trust_id'] = keystone_util.create_trust().id LOG.debug('Trust %s created', values['trust_id']) except Exception: raise exc.TrustFailedException( 'Trust creation failed for function.') with db_api.transaction(): func_db = db_api.create_function(values) if store: ctx = context.get_ctx() self.storage_provider.store(ctx.projectid, func_db.id, data) pecan.response.status = 201 return resources.Function.from_dict(func_db.to_dict()).to_dict()
def delete(self, id): """Delete the specified function.""" LOG.info("Delete function [id=%s]", id) with db_api.transaction(): db_api.delete_function(id) self.storage_provider.delete(context.get_ctx().projectid, id)
def post(self, **kwargs): LOG.info("Creating %s, params: %s", self.type, kwargs) # When using image to create function, runtime_id is not a required # param. if not POST_REQUIRED.issubset(set(kwargs.keys())): raise exc.InputException( 'Required param is missing. Required: %s' % POST_REQUIRED) values = { 'name': kwargs['name'], 'description': kwargs.get('description'), 'runtime_id': kwargs.get('runtime_id'), 'code': json.loads(kwargs['code']), 'entry': kwargs.get('entry', 'main.main'), } source = values['code'].get('source') if not source or source not in CODE_SOURCE: raise exc.InputException( 'Invalid code source specified, available sources: %s' % ', '.join(CODE_SOURCE)) if source != 'image': if not kwargs.get('runtime_id'): raise exc.InputException('"runtime_id" must be specified.') runtime = db_api.get_runtime(kwargs['runtime_id']) if runtime.status != 'available': raise exc.InputException('Runtime %s is not available.' % kwargs['runtime_id']) store = False if values['code']['source'] == 'package': store = True data = kwargs['package'].file.read() elif values['code']['source'] == 'swift': # Auth needs to be enabled because qinling needs to check swift # object using user's credential. if not CONF.pecan.auth_enable: raise exc.InputException('Swift object not supported.') container = values['code']['swift'].get('container') object = values['code']['swift'].get('object') if not swift_util.check_object(container, object): raise exc.InputException('Object does not exist in Swift.') with db_api.transaction(): func_db = db_api.create_function(values) if store: ctx = context.get_ctx() self.storage_provider.store(ctx.projectid, func_db.id, data) pecan.response.status = 201 return resources.Function.from_dict(func_db.to_dict()).to_dict()
def delete(self, function_id, version): """Delete a specific function version. - The version should not being used by any job - The version should not being used by any webhook - Admin user can not delete normal user's version """ ctx = context.get_ctx() acl.enforce('function_version:delete', ctx) LOG.info("Deleting version %s of function %s.", version, function_id) with db_api.transaction(): version_db = db_api.get_function_version(function_id, version, insecure=False) latest_version = version_db.function.latest_version version_jobs = db_api.get_jobs( function_id=version_db.function_id, function_version=version_db.version_number, status={'nin': ['done', 'cancelled']}) if len(version_jobs) > 0: raise exc.NotAllowedException( 'The function version is still associated with running ' 'job(s).') version_webhook = db_api.get_webhooks( function_id=version_db.function_id, function_version=version_db.version_number, ) if len(version_webhook) > 0: raise exc.NotAllowedException( 'The function version is still associated with webhook.') filters = rest_utils.get_filters( function_id=version_db.function_id, function_version=version_db.version_number) version_aliases = db_api.get_function_aliases(**filters) if len(version_aliases) > 0: raise exc.NotAllowedException( 'The function version is still associated with alias.') # Delete resources for function version self.engine_client.delete_function(function_id, version=version) etcd_util.delete_function(function_id, version=version) self.storage_provider.delete(ctx.projectid, function_id, None, version=version) db_api.delete_function_version(function_id, version) if latest_version == version: version_db.function.latest_version = latest_version - 1 LOG.info("Version %s of function %s deleted.", version, function_id)
def delete(self, id): """Delete the specified function. Delete function will also delete all its versions. """ LOG.info("Delete function %s.", id) with db_api.transaction(): func_db = db_api.get_function(id) if len(func_db.jobs) > 0: raise exc.NotAllowedException( 'The function is still associated with running job(s).') if len(func_db.webhooks) > 0: raise exc.NotAllowedException( 'The function is still associated with webhook(s).') if len(func_db.aliases) > 0: raise exc.NotAllowedException( 'The function is still associated with function alias(es).' ) # Even admin user can not delete other project's function because # the trust associated can only be removed by function owner. if func_db.project_id != context.get_ctx().projectid: raise exc.NotAllowedException( 'Function can only be deleted by its owner.') # Delete trust if needed if func_db.trust_id: keystone_util.delete_trust(func_db.trust_id) for version_db in func_db.versions: # Delete all resources created by orchestrator asynchronously. self.engine_client.delete_function( id, version=version_db.version_number) # Delete etcd keys etcd_util.delete_function(id, version=version_db.version_number) # Delete function version packages. Versions is only supported # for package type function. self.storage_provider.delete(func_db.project_id, id, None, version=version_db.version_number) # Delete resources for function version 0(func_db.versions==[]) self.engine_client.delete_function(id) etcd_util.delete_function(id) source = func_db.code['source'] if source == constants.PACKAGE_FUNCTION: self.storage_provider.delete(func_db.project_id, id, func_db.code['md5sum']) # This will also delete function service mapping and function # versions as well. db_api.delete_function(id)
def put(self, id, runtime): """Update runtime. Currently, we support update name, description, image. When updating image, send message to engine for asynchronous handling. """ acl.enforce('runtime:update', context.get_ctx()) values = {} for key in UPDATE_ALLOWED: if runtime.to_dict().get(key) is not None: values.update({key: runtime.to_dict()[key]}) LOG.info('Update resource, params: %s', values, resource={ 'type': self.type, 'id': id }) image = values.get('image') with db_api.transaction(): if image is not None: pre_runtime = db_api.get_runtime(id) if pre_runtime.status != status.AVAILABLE: raise exc.RuntimeNotAvailableException( 'Runtime %s is not available.' % id) pre_image = pre_runtime.image if pre_image != image: # Ensure there is no function running in the runtime. db_funcs = db_api.get_functions(insecure=True, fields=['id'], runtime_id=id) func_ids = [func.id for func in db_funcs] for id in func_ids: if etcd_util.get_service_url(id): raise exc.NotAllowedException( 'Runtime %s is still in use by functions.' % id) values['status'] = status.UPGRADING self.engine_client.update_runtime( id, image=image, pre_image=pre_image, ) runtime_db = db_api.update_runtime(id, values) return resources.Runtime.from_db_obj(runtime_db)
def delete_runtime(self, ctx, runtime_id): LOG.info('Start to delete runtime, id=%s', runtime_id) with db_api.transaction(): runtime = db_api.get_runtime(runtime_id) identifier = '%s-%s' % (runtime_id, runtime.name) labels = {'runtime_name': runtime.name, 'runtime_id': runtime_id} self.orchestrator.delete_pool(identifier, labels=labels) db_api.delete_runtime(runtime_id) LOG.info('Runtime %s deleted.', runtime_id)
def scaledown_function(self, ctx, function_id, count=1): func_db = db_api.get_function(function_id) worker_deleted_num = (count if len(func_db.workers) > count else len(func_db.workers) - 1) workers = func_db.workers[:worker_deleted_num] with db_api.transaction(): for worker in workers: LOG.debug('Removing worker %s', worker.worker_name) self.orchestrator.delete_worker(worker.worker_name, ) db_api.delete_function_worker(worker.worker_name) LOG.info('Finished scaling up function %s.', function_id)
def put(self, id, runtime): """Update runtime. Currently, we only support update name, description, image. When updating image, send message to engine for asynchronous handling. """ values = {} for key in UPDATE_ALLOWED: if runtime.to_dict().get(key) is not None: values.update({key: runtime.to_dict()[key]}) LOG.info('Update resource, params: %s', values, resource={ 'type': self.type, 'id': id }) with db_api.transaction(): if 'image' in values: pre_runtime = db_api.get_runtime(id) if pre_runtime.status != status.AVAILABLE: raise exc.RuntimeNotAvailableException( 'Runtime %s is not available.' % id) pre_image = pre_runtime.image if pre_image != values['image']: # Ensure there is no function running in the runtime. db_funcs = db_api.get_functions(insecure=True, fields=['id'], runtime_id=id) func_ids = [func.id for func in db_funcs] mappings = db_api.get_function_service_mappings( insecure=True, function_id={'in': func_ids}) if mappings: raise exc.NotAllowedException( 'Runtime %s is still in use by functions.' % id) values['status'] = status.UPGRADING self.engine_client.update_runtime(id, image=values['image'], pre_image=pre_image) else: values.pop('image') runtime_db = db_api.update_runtime(id, values) return resources.Runtime.from_dict(runtime_db.to_dict())
def _create_function_version(self, project_id, function_id, **kwargs): with etcd_util.get_function_version_lock(function_id) as lock: if not lock.is_acquired(): return False with db_api.transaction(): # Get latest function package md5 and version number func_db = db_api.get_function(function_id, insecure=False) if func_db.code['source'] != constants.PACKAGE_FUNCTION: raise exc.NotAllowedException( "Function versioning only allowed for %s type " "function." % constants.PACKAGE_FUNCTION ) l_md5 = func_db.code['md5sum'] l_version = func_db.latest_version if len(func_db.versions) >= constants.MAX_VERSION_NUMBER: raise exc.NotAllowedException( 'Can not exceed maximum number(%s) of versions' % constants.MAX_VERSION_NUMBER ) # Check if the latest package changed since last version changed = self.storage_provider.changed_since(project_id, function_id, l_md5, l_version) if not changed: raise exc.NotAllowedException( 'Function package not changed since the latest ' 'version %s.' % l_version ) LOG.info("Creating %s, function_id: %s, old_version: %d", self.type, function_id, l_version) # Create new version and copy package. self.storage_provider.copy(project_id, function_id, l_md5, l_version) version = db_api.increase_function_version(function_id, l_version, **kwargs) func_db.latest_version = l_version + 1 LOG.info("New version %d for function %s created.", l_version + 1, function_id) return version
def scaleup_function(self, ctx, function_id, runtime_id, count=1): function = db_api.get_function(function_id) worker_names = self.orchestrator.scaleup_function( function_id, identifier=runtime_id, entry=function.entry, count=count) with db_api.transaction(): for name in worker_names: worker = {'function_id': function_id, 'worker_name': name} db_api.create_function_worker(worker) LOG.info('Finished scaling up function %s.', function_id)
def create_runtime(self, ctx, runtime_id): LOG.info('Start to create runtime %s.', runtime_id) with db_api.transaction(): runtime = db_api.get_runtime(runtime_id) try: self.orchestrator.create_pool(runtime_id, runtime.image) runtime.status = status.AVAILABLE LOG.info('Runtime %s created.', runtime_id) except Exception as e: LOG.exception( 'Failed to create pool for runtime %s. Error: %s', runtime_id, str(e)) runtime.status = status.ERROR
def delete(self, id): LOG.info("Delete resource.", resource={'type': self.type, 'id': id}) with db_api.transaction(): runtime_db = db_api.get_runtime(id) # Runtime can not be deleted if still associate with functions. funcs = db_api.get_functions(runtime_id={'eq': id}) if len(funcs): raise exc.NotAllowedException('Runtime %s is still in use.' % id) runtime_db.status = status.DELETING # Clean related resources asynchronously self.engine_client.delete_runtime(id)
def get_all(self, function_id): """Get all the versions of the given function. Admin user can get all versions for the normal user's function. """ acl.enforce('function_version:get_all', context.get_ctx()) LOG.info("Getting versions for function %s.", function_id) # Getting function and versions needs to happen in a db transaction with db_api.transaction(): func_db = db_api.get_function(function_id) db_versions = func_db.versions versions = [resources.FunctionVersion.from_db_obj(v) for v in db_versions] return resources.FunctionVersions(function_versions=versions)
def delete(self, id): """Delete runtime.""" LOG.info("Delete runtime [id=%s]", id) with db_api.transaction(): runtime_db = db_api.get_runtime(id) # Runtime can not be deleted if still associate with functions. funcs = db_api.get_functions(runtime_id={'eq': id}) if len(funcs): raise exc.NotAllowedException( 'Runtime %s is still in use.' % id ) runtime_db.status = 'deleting' # Clean related resources asynchronously self.engine_client.delete_runtime(id)
def delete(self, id): """Delete the specified function.""" LOG.info("Delete resource.", resource={'type': self.type, 'id': id}) with db_api.transaction(): func_db = db_api.get_function(id) if len(func_db.jobs) > 0: raise exc.NotAllowedException( 'The function is still associated with running job(s).') source = func_db.code['source'] if source == 'package': self.storage_provider.delete(context.get_ctx().projectid, id) # Delete all resources created by orchestrator asynchronously. self.engine_client.delete_function(id) # This will also delete function service mapping as well. db_api.delete_function(id)
def test_delete(self, mock_package_delete, mock_engine_delete, mock_etcd_delete): db_api.increase_function_version(self.func_id, 0, description="version 1") resp = self.app.delete('/v1/functions/%s/versions/1' % self.func_id) self.assertEqual(204, resp.status_int) mock_engine_delete.assert_called_once_with(self.func_id, version=1) mock_etcd_delete.assert_called_once_with(self.func_id, version=1) mock_package_delete.assert_called_once_with( unit_base.DEFAULT_PROJECT_ID, self.func_id, None, version=1) # We need to set context as it was removed after the API call context.set_ctx(self.ctx) with db_api.transaction(): func_db = db_api.get_function(self.func_id) self.assertEqual(0, len(func_db.versions)) self.assertEqual(0, func_db.latest_version)
def create_runtime(self, ctx, runtime_id): LOG.info('Start to create runtime, id=%s', runtime_id) with db_api.transaction(): runtime = db_api.get_runtime(runtime_id) identifier = '%s-%s' % (runtime_id, runtime.name) labels = {'runtime_name': runtime.name, 'runtime_id': runtime_id} try: self.orchestrator.create_pool( identifier, runtime.image, labels=labels, ) runtime.status = 'available' except Exception as e: LOG.exception( 'Failed to create pool for runtime %s. Error: %s', runtime_id, str(e)) runtime.status = 'error'
def post(self, job): """Creates a new job.""" params = job.to_dict() if not (params.get("function_id") or params.get("function_alias")): raise exc.InputException( 'Either function_alias or function_id must be provided.') # Check the input params. first_time, next_time, count = jobs.validate_job(params) LOG.info("Creating %s, params: %s", self.type, params) version = params.get('function_version', 0) # if function_alias provided function_alias = params.get('function_alias') if function_alias: alias_db = db_api.get_function_alias(function_alias) function_id = alias_db.function_id version = alias_db.function_version params.update({'function_id': function_id, 'version': version}) with db_api.transaction(): db_api.get_function(params['function_id']) if version > 0: db_api.get_function_version(params['function_id'], version) values = { 'name': params.get('name'), 'pattern': params.get('pattern'), 'first_execution_time': first_time, 'next_execution_time': next_time, 'count': count, 'function_id': params['function_id'], 'function_version': version, 'function_input': params.get('function_input'), 'status': status.RUNNING } db_job = db_api.create_job(values) return resources.Job.from_db_obj(db_job)