Esempio n. 1
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
Esempio n. 2
0
def create_execution(engine_client, params):
    function_id = params['function_id']
    is_sync = params.get('sync', True)
    input = params.get('input')

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

    runtime_id = _update_function_db(function_id)

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

    engine_client.create_execution(db_model.id,
                                   function_id,
                                   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
Esempio n. 3
0
    def test_create_execution_prepare_execution_exception(
            self, etcd_util_get_service_url_mock):
        """test_create_execution_prepare_execution_exception

        Create execution for image type function, prepare_execution method
        raises exception.
        """
        function = self.create_function()
        function_id = function.id
        runtime_id = function.runtime_id
        db_api.update_function(
            function_id, {
                'code': {
                    'source': constants.IMAGE_FUNCTION,
                    'image': self.rand_name('image', prefix=self.prefix)
                }
            })
        function = db_api.get_function(function_id)
        execution = self.create_execution(function_id=function_id)
        execution_id = execution.id
        prepare_execution = self.orchestrator.prepare_execution
        prepare_execution.side_effect = exc.OrchestratorException(
            'Exception in prepare_execution')
        etcd_util_get_service_url_mock.return_value = None

        self.default_engine.create_execution(mock.Mock(), execution_id,
                                             function_id, 0, runtime_id)

        execution = db_api.get_execution(execution_id)
        self.assertEqual(execution.status, status.ERROR)
        self.assertEqual(execution.logs, '')
        self.assertEqual(execution.result,
                         {'error': 'Function execution failed.'})
Esempio n. 4
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)
Esempio n. 5
0
    def test_create_execution_package_type_function(
            self, etcd_util_get_service_url_mock):
        function = self.create_function()
        function_id = function.id
        runtime_id = function.runtime_id
        execution = self.create_execution(function_id=function_id)
        execution_id = execution.id
        self.default_engine.function_load_check = mock.Mock(return_value='')
        etcd_util_get_service_url_mock.return_value = None
        self.orchestrator.prepare_execution.return_value = (mock.Mock(),
                                                            'svc_url')
        self.orchestrator.run_execution.return_value = (True, {
            'success':
            True,
            'logs':
            'execution log',
            'output':
            'success output'
        })

        self.default_engine.create_execution(mock.Mock(), execution_id,
                                             function_id, 0, runtime_id)

        self.default_engine.function_load_check.assert_called_once_with(
            function_id, 0, runtime_id)
        etcd_util_get_service_url_mock.assert_called_once_with(function_id, 0)
        self.orchestrator.prepare_execution.assert_called_once_with(
            function_id,
            0,
            rlimit=self.rlimit,
            image=None,
            identifier=runtime_id,
            labels={'runtime_id': runtime_id},
            input=None)
        self.orchestrator.run_execution.assert_called_once_with(
            execution_id,
            function_id,
            0,
            rlimit=self.rlimit,
            input=None,
            identifier=runtime_id,
            service_url='svc_url',
            entry=function.entry,
            trust_id=function.trust_id)

        execution = db_api.get_execution(execution_id)

        self.assertEqual(execution.status, status.SUCCESS)
        self.assertEqual(execution.logs, 'execution log')
        self.assertEqual(execution.result, {'output': 'success output'})
Esempio n. 6
0
    def test_create_execution_loadcheck_exception(self):
        function = self.create_function()
        function_id = function.id
        runtime_id = function.runtime_id
        execution = self.create_execution(function_id=function_id)
        execution_id = execution.id
        self.default_engine.function_load_check = mock.Mock(
            side_effect=exc.OrchestratorException(
                'Exception in scaleup_function'))

        self.default_engine.create_execution(mock.Mock(), execution_id,
                                             function_id, 0, runtime_id)

        execution = db_api.get_execution(execution_id)

        self.assertEqual(execution.status, status.ERROR)
        self.assertEqual(execution.logs, '')
        self.assertEqual(execution.result,
                         {'error': 'Function execution failed.'})
Esempio n. 7
0
    def post(self, execution):
        params = execution.to_dict()

        LOG.info("Creating execution. [execution=%s]", params)

        function_id = params['function_id']

        # Check if the service url is existing.
        try:
            mapping = db_api.get_function_service_mapping(function_id)
            LOG.debug('Found Service url for function: %s', function_id)

            func_url = '%s/execute' % mapping.service_url
            LOG.info('Invoke function %s, url: %s', function_id, func_url)

            r = requests.post(func_url, data=params.get('input'))
            params.update({
                'status': 'success',
                'output': {
                    'result': r.json()
                }
            })
            db_model = db_api.create_execution(params)

            return resources.Execution.from_dict(db_model.to_dict())
        except exc.DBEntityNotFoundError:
            pass

        func = db_api.get_function(function_id)
        runtime_id = func.runtime_id
        params.update({'status': 'running'})

        db_model = db_api.create_execution(params)

        self.engine_client.create_execution(db_model.id,
                                            function_id,
                                            runtime_id,
                                            input=params.get('input'))

        updated_db = db_api.get_execution(db_model.id)

        return resources.Execution.from_dict(updated_db.to_dict())
Esempio n. 8
0
    def test_create_execution_found_service_url(
            self, etcd_util_get_service_url_mock,
            engine_utils_url_request_mock, engine_utils_get_request_data_mock):
        function = self.create_function()
        function_id = function.id
        runtime_id = function.runtime_id
        execution = self.create_execution(function_id=function_id)
        execution_id = execution.id
        self.default_engine.function_load_check = mock.Mock(return_value='')
        etcd_util_get_service_url_mock.return_value = 'svc_url'
        engine_utils_get_request_data_mock.return_value = 'data'
        engine_utils_url_request_mock.return_value = (False, {
            'success': False,
            'logs': 'execution log',
            'output': 'failed output'
        })

        self.default_engine.create_execution(mock.Mock(),
                                             execution_id,
                                             function_id,
                                             0,
                                             runtime_id,
                                             input='input')

        self.default_engine.function_load_check.assert_called_once_with(
            function_id, 0, runtime_id)
        etcd_util_get_service_url_mock.assert_called_once_with(function_id, 0)
        engine_utils_get_request_data_mock.assert_called_once_with(
            mock.ANY, function_id, 0, execution_id, self.rlimit, 'input',
            function.entry, function.trust_id, self.qinling_endpoint,
            function.timeout)
        engine_utils_url_request_mock.assert_called_once_with(
            self.default_engine.session, 'svc_url/execute', body='data')

        execution = db_api.get_execution(execution_id)

        self.assertEqual(execution.status, status.FAILED)
        self.assertEqual(execution.logs, 'execution log')
        self.assertEqual(execution.result, {
            'success': False,
            'output': 'failed output'
        })
Esempio n. 9
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, input=%s', execution_id, function_id, runtime_id,
            input)

        # FIXME(kong): Make the transaction range smaller.
        with db_api.transaction():
            execution = db_api.get_execution(execution_id)
            function = db_api.get_function(function_id)

            if function.service:
                func_url = '%s/execute' % function.service.service_url
                LOG.debug('Found service url for function: %s, url: %s',
                          function_id, func_url)

                data = {'input': input, 'execution_id': execution_id}
                r = self.session.post(func_url, json=data)
                res = r.json()

                LOG.debug('Finished execution %s', execution_id)

                success = res.pop('success')
                execution.status = status.SUCCESS if success else status.FAILED
                execution.logs = res.pop('logs', '')
                execution.output = res
                return

            source = function.code['source']
            image = None
            identifier = None
            labels = None

            if source == constants.IMAGE_FUNCTION:
                image = function.code['image']
                identifier = ('%s-%s' %
                              (common.generate_unicode_uuid(dashed=False),
                               function_id))[:63]
                labels = {'function_id': function_id}
            else:
                identifier = runtime_id
                labels = {'runtime_id': runtime_id}

            worker_name, service_url = self.orchestrator.prepare_execution(
                function_id,
                image=image,
                identifier=identifier,
                labels=labels,
                input=input,
                entry=function.entry,
                trust_id=function.trust_id)
            output = self.orchestrator.run_execution(
                execution_id,
                function_id,
                input=input,
                identifier=identifier,
                service_url=service_url,
            )

            logs = ''
            # Execution log is only available for non-image source execution.
            if service_url:
                logs = output.pop('logs', '')
                success = output.pop('success')
            else:
                # If the function is created from docker image, the output is
                # direct output, here we convert to a dict to fit into the db
                # schema.
                output = {'output': output}
                success = True

            LOG.debug('Finished execution. execution_id=%s, output=%s',
                      execution_id, output)
            execution.output = output
            execution.logs = logs
            execution.status = status.SUCCESS if success else status.FAILED

            # No service is created in orchestrator for single container.
            if not image:
                mapping = {
                    'function_id': function_id,
                    'service_url': service_url,
                }
                db_api.create_function_service_mapping(mapping)
                worker = {
                    'function_id': function_id,
                    'worker_name': worker_name
                }
                db_api.create_function_worker(worker)
Esempio n. 10
0
    def get(self, id):
        LOG.info("Fetch resource.", resource={'type': self.type, 'id': id})

        execution_db = db_api.get_execution(id)

        return resources.Execution.from_dict(execution_db.to_dict())
Esempio n. 11
0
    def get_all(self, execution_id):
        LOG.info("Get logs for execution %s.", execution_id)
        execution_db = db_api.get_execution(execution_id)

        return execution_db.logs
Esempio n. 12
0
def create_execution(engine_client, params):
    function_id = params['function_id']
    is_sync = params.get('sync', True)
    input = params.get('input')
    version = params.get('function_version', 0)

    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. 13
0
    def get(self, id):
        LOG.info("Fetch execution [id=%s]", id)

        execution_db = db_api.get_execution(id)

        return resources.Execution.from_dict(execution_db.to_dict())
Esempio n. 14
0
    def test_create_execution_image_type_function(self, mock_svc_url):
        """Create 2 executions for an image type function."""
        function = self.create_function()
        function_id = function.id
        runtime_id = function.runtime_id
        db_api.update_function(
            function_id, {
                'code': {
                    'source': constants.IMAGE_FUNCTION,
                    'image': self.rand_name('image', prefix=self.prefix)
                }
            })
        function = db_api.get_function(function_id)
        execution_1 = self.create_execution(function_id=function_id)
        execution_1_id = execution_1.id
        execution_2 = self.create_execution(function_id=function_id)
        execution_2_id = execution_2.id
        mock_svc_url.return_value = None
        self.orchestrator.prepare_execution.return_value = (mock.Mock(), None)
        self.orchestrator.run_execution.side_effect = [(True, {
            'duration': 5,
            'logs': 'fake log'
        }), (False, {
            'duration': 0,
            'error': 'Function execution failed.'
        })]

        # Create two executions, with different results
        self.default_engine.create_execution(mock.Mock(), execution_1_id,
                                             function_id, 0, runtime_id)
        self.default_engine.create_execution(mock.Mock(),
                                             execution_2_id,
                                             function_id,
                                             0,
                                             runtime_id,
                                             input='input')

        get_service_url_calls = [
            mock.call(function_id, 0),
            mock.call(function_id, 0)
        ]
        mock_svc_url.assert_has_calls(get_service_url_calls)

        prepare_calls = [
            mock.call(function_id,
                      0,
                      rlimit=self.rlimit,
                      image=function.code['image'],
                      identifier=mock.ANY,
                      labels=None,
                      input=None),
            mock.call(function_id,
                      0,
                      rlimit=self.rlimit,
                      image=function.code['image'],
                      identifier=mock.ANY,
                      labels=None,
                      input='input')
        ]
        self.orchestrator.prepare_execution.assert_has_calls(prepare_calls)

        run_calls = [
            mock.call(execution_1_id,
                      function_id,
                      0,
                      rlimit=None,
                      input=None,
                      identifier=mock.ANY,
                      service_url=None,
                      entry=function.entry,
                      trust_id=function.trust_id),
            mock.call(execution_2_id,
                      function_id,
                      0,
                      rlimit=None,
                      input='input',
                      identifier=mock.ANY,
                      service_url=None,
                      entry=function.entry,
                      trust_id=function.trust_id)
        ]
        self.orchestrator.run_execution.assert_has_calls(run_calls)

        execution_1 = db_api.get_execution(execution_1_id)
        execution_2 = db_api.get_execution(execution_2_id)

        self.assertEqual(status.SUCCESS, execution_1.status)
        self.assertEqual('fake log', execution_1.logs)
        self.assertEqual({"duration": 5}, execution_1.result)
        self.assertEqual(status.FAILED, execution_2.status)
        self.assertEqual('', execution_2.logs)
        self.assertEqual({
            'duration': 0,
            'error': 'Function execution failed.'
        }, execution_2.result)
Esempio n. 15
0
    def get(self, id):
        LOG.info("Get resource.", resource={'type': self.type, 'id': id})

        execution_db = db_api.get_execution(id)

        return resources.Execution.from_db_obj(execution_db)