Пример #1
0
    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'))
Пример #2
0
    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())
Пример #3
0
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
Пример #4
0
    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}
Пример #5
0
    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)
Пример #6
0
    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()
Пример #7
0
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)
Пример #8
0
    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)
Пример #9
0
    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()
Пример #10
0
    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())
Пример #11
0
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
Пример #12
0
    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()
Пример #13
0
    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)
Пример #14
0
    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()
Пример #15
0
    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)
Пример #16
0
    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)
Пример #17
0
    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)
Пример #18
0
    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)
Пример #19
0
    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)
Пример #20
0
    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())
Пример #21
0
    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
Пример #22
0
    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)
Пример #23
0
    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
Пример #24
0
    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)
Пример #25
0
    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)
Пример #26
0
    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)
Пример #27
0
    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)
Пример #28
0
    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)
Пример #29
0
    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'
Пример #30
0
    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)