Esempio n. 1
0
    def post(self, webhook):
        acl.enforce('webhook:create', context.get_ctx())

        params = webhook.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.')

        # 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,
                'function_version': version
            })

        LOG.info("Creating %s, params: %s", self.type, params)

        # Even admin user can not expose normal user's function
        db_api.get_function(params['function_id'], insecure=False)

        version = params.get('function_version', 0)
        if version > 0:
            db_api.get_function_version(params['function_id'], version)

        webhook_d = db_api.create_webhook(params).to_dict()

        return resources.Webhook.from_dict(
            self._add_webhook_url(webhook_d['id'], webhook_d))
Esempio n. 2
0
    def get(self, alias_name):
        acl.enforce('function_alias:get', context.get_ctx())
        LOG.info("Getting function alias  %s.", alias_name)

        alias = db_api.get_function_alias(alias_name)

        return resources.FunctionAlias.from_db_obj(alias)
Esempio n. 3
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.')

        LOG.info("Creating %s, params: %s", self.type, params)

        # Check the input params.
        first_time, next_time, count = jobs.validate_job(params)

        version = params.get('function_version', 0)
        function_alias = params.get('function_alias')

        if function_alias:
            # Check if the alias exists.
            db_api.get_function_alias(function_alias)
        else:
            # Check the function(version) exists.
            db_api.get_function(params['function_id'])
            if version > 0:
                # Check if the version exists.
                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_alias': function_alias,
            'function_id': params.get("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)
Esempio n. 4
0
    def test_post(self):
        name = 'TestAlias'
        body = {
            'function_id': self.func_id,
            'name': name,
            'description': 'new alias'
        }

        resp = self.app.post_json('/v1/aliases', body)

        self.assertEqual(201, resp.status_int)
        self._assertDictContainsSubset(resp.json, body)

        context.set_ctx(self.ctx)

        func_alias_db = db_api.get_function_alias(name)
        self.assertEqual(name, func_alias_db.name)
        self.assertEqual(0, func_alias_db.function_version)
Esempio n. 5
0
    def put(self, id, webhook):
        acl.enforce('webhook:update', context.get_ctx())

        values = {}
        for key in UPDATE_ALLOWED:
            if webhook.to_dict().get(key) is not None:
                values.update({key: webhook.to_dict()[key]})

        LOG.info('Update %s %s, params: %s', self.type, id, values)

        # Even admin user can not expose normal user's function
        webhook_db = db_api.get_webhook(id, insecure=False)
        pre_alias = webhook_db.function_alias
        pre_function_id = webhook_db.function_id
        pre_version = webhook_db.function_version

        new_alias = values.get("function_alias")
        new_function_id = values.get("function_id", pre_function_id)
        new_version = values.get("function_version", pre_version)

        function_id = pre_function_id
        version = pre_version
        if new_alias and new_alias != pre_alias:
            alias_db = db_api.get_function_alias(new_alias)
            function_id = alias_db.function_id
            version = alias_db.function_version
            # If function_alias is provided, we don't store either functin id
            # or function version.
            values.update({'function_id': None, 'function_version': None})
        elif new_function_id != pre_function_id or new_version != pre_version:
            function_id = new_function_id
            version = new_version
            values.update({"function_alias": None})

        db_api.get_function(function_id, insecure=False)
        if version and version > 0:
            db_api.get_function_version(function_id, version)

        webhook = db_api.update_webhook(id, values).to_dict()
        return resources.Webhook.from_dict(self._add_webhook_url(id, webhook))
Esempio n. 6
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_alias = webhook_db.function_alias

            if function_alias:
                alias = db_api.get_function_alias(function_alias,
                                                  insecure=True)
                function_id = alias.function_id
                function_version = alias.function_version
                function_db = db_api.get_function(function_id, insecure=True)
            else:
                function_db = webhook_db.function
                function_id = webhook_db.function_id
                function_version = webhook_db.function_version

            trust_id = function_db.trust_id
            project_id = function_db.project_id

        LOG.info('Invoking function %s(version %s) by webhook %s', function_id,
                 function_version, id)

        # Setup user context
        ctx = keystone_utils.create_trust_context(trust_id, project_id)
        context.set_ctx(ctx)

        params = {
            'function_id': function_id,
            'function_version': function_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}
Esempio n. 7
0
def create_execution(engine_client, params):
    function_alias = params.get('function_alias')
    function_id = params.get('function_id')
    version = params.get('function_version', 0)
    is_sync = params.get('sync', True)
    input = params.get('input')

    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})

    func_db = db_api.get_function(function_id)
    runtime_id = func_db.runtime_id

    # Image type function does not need runtime
    if runtime_id:
        runtime_db = db_api.get_runtime(runtime_id)
        if runtime_db and runtime_db.status != status.AVAILABLE:
            raise exc.RuntimeNotAvailableException(
                'Runtime %s is not available.' % func_db.runtime_id)

    if version > 0:
        if func_db.code['source'] != constants.PACKAGE_FUNCTION:
            raise exc.InputException(
                "Can not specify version for %s type function." %
                constants.PACKAGE_FUNCTION)

        # update version count
        version_db = db_api.get_function_version(function_id, version)
        pre_version_count = version_db.count
        _update_function_version_db(version_db.id, pre_version_count)
    else:
        pre_count = func_db.count
        _update_function_db(function_id, pre_count)

    # input in params should be a string.
    if input:
        try:
            params['input'] = json.loads(input)
        except ValueError:
            params['input'] = {'__function_input': input}

    params.update({'status': status.RUNNING})
    db_model = db_api.create_execution(params)

    try:
        engine_client.create_execution(db_model.id,
                                       function_id,
                                       version,
                                       runtime_id,
                                       input=params.get('input'),
                                       is_sync=is_sync)
    except exc.QinlingException:
        # Catch RPC errors for executions:
        #   - for RemoteError in an RPC call, the execution status would be
        #     handled in the engine side;
        #   - for other exceptions in an RPC call or cast, the execution status
        #     would remain RUNNING so we should update it.
        db_model = db_api.get_execution(db_model.id)
        if db_model.status == status.RUNNING:
            db_model = db_api.update_execution(db_model.id,
                                               {'status': status.ERROR})
        return db_model

    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
Esempio n. 8
0
def handle_job(engine_client):
    """Execute job task with no db transactions."""
    jobs_db = db_api.get_next_jobs(timeutils.utcnow() + timedelta(seconds=3))

    for job in jobs_db:
        job_id = job.id
        func_alias = job.function_alias

        if func_alias:
            alias = db_api.get_function_alias(func_alias, insecure=True)
            func_id = alias.function_id
            func_version = alias.function_version
        else:
            func_id = job.function_id
            func_version = job.function_version

        LOG.debug("Processing job: %s, function: %s(version %s)", job_id,
                  func_id, func_version)

        func_db = db_api.get_function(func_id, insecure=True)
        trust_id = func_db.trust_id

        try:
            # Setup context before schedule job.
            ctx = keystone_utils.create_trust_context(
                trust_id, job.project_id
            )
            context.set_ctx(ctx)

            if (job.count is not None and job.count > 0):
                job.count -= 1

            # Job delete/update is done using UPDATE ... FROM ... WHERE
            # non-locking clause.
            if job.count == 0:
                modified = db_api.conditional_update(
                    models.Job,
                    {
                        'status': status.DONE,
                        'count': 0
                    },
                    {
                        'id': job_id,
                        'status': status.RUNNING
                    },
                    insecure=True,
                )
            else:
                next_time = jobs.get_next_execution_time(
                    job.pattern,
                    job.next_execution_time
                )

                modified = db_api.conditional_update(
                    models.Job,
                    {
                        'next_execution_time': next_time,
                        'count': job.count
                    },
                    {
                        'id': job_id,
                        'next_execution_time': job.next_execution_time
                    },
                    insecure=True,
                )

            if not modified:
                LOG.warning(
                    'Job %s has been already handled by another periodic '
                    'task.', job_id
                )
                continue

            LOG.debug(
                "Starting to execute function %s(version %s) by job %s",
                func_id, func_version, job_id
            )

            params = {
                'function_id': func_id,
                'function_version': func_version,
                'input': job.function_input,
                'sync': False,
                'description': constants.EXECUTION_BY_JOB % job_id
            }
            executions.create_execution(engine_client, params)
        except Exception:
            LOG.exception("Failed to process job %s", job_id)
        finally:
            context.set_ctx(None)