Пример #1
0
    def test_get_value_from_datastore_through_render_live_params(self):
        # Register datastore value to be refered by this test-case
        register_kwargs = [
            {
                'name': 'test_key',
                'value': 'foo'
            },
            {
                'name': 'user1:test_key',
                'value': 'bar',
                'scope': FULL_USER_SCOPE
            },
            {
                'name': '%s:test_key' % cfg.CONF.system_user.user,
                'value': 'baz',
                'scope': FULL_USER_SCOPE
            },
        ]
        for kwargs in register_kwargs:
            KeyValuePair.add_or_update(KeyValuePairDB(**kwargs))

        # Assert that datastore value can be got via the Jinja expression from individual scopes.
        context = {'user': '******'}
        param = {
            'system_value': {
                'default': '{{ st2kv.system.test_key }}'
            },
            'user_value': {
                'default': '{{ st2kv.user.test_key }}'
            },
        }
        live_params = param_utils.render_live_params(runner_parameters={},
                                                     action_parameters=param,
                                                     params={},
                                                     action_context=context)

        self.assertEqual(live_params['system_value'], 'foo')
        self.assertEqual(live_params['user_value'], 'bar')

        # Assert that datastore value in the user-scope that is registered by user1
        # cannot be got by the operation of user2.
        context = {'user': '******'}
        param = {'user_value': {'default': '{{ st2kv.user.test_key }}'}}
        live_params = param_utils.render_live_params(runner_parameters={},
                                                     action_parameters=param,
                                                     params={},
                                                     action_context=context)

        self.assertEqual(live_params['user_value'], '')

        # Assert that system-user's scope is selected when user and api_user parameter specified
        context = {}
        param = {'user_value': {'default': '{{ st2kv.user.test_key }}'}}
        live_params = param_utils.render_live_params(runner_parameters={},
                                                     action_parameters=param,
                                                     params={},
                                                     action_context=context)

        self.assertEqual(live_params['user_value'], 'baz')
Пример #2
0
    def test_get_value_from_datastore_through_render_live_params(self):
        # Register datastore value to be refered by this test-case
        register_kwargs = [
            {"name": "test_key", "value": "foo"},
            {"name": "user1:test_key", "value": "bar", "scope": FULL_USER_SCOPE},
            {
                "name": "%s:test_key" % cfg.CONF.system_user.user,
                "value": "baz",
                "scope": FULL_USER_SCOPE,
            },
        ]
        for kwargs in register_kwargs:
            KeyValuePair.add_or_update(KeyValuePairDB(**kwargs))

        # Assert that datastore value can be got via the Jinja expression from individual scopes.
        context = {"user": "******"}
        param = {
            "system_value": {"default": "{{ st2kv.system.test_key }}"},
            "user_value": {"default": "{{ st2kv.user.test_key }}"},
        }
        live_params = param_utils.render_live_params(
            runner_parameters={},
            action_parameters=param,
            params={},
            action_context=context,
        )

        self.assertEqual(live_params["system_value"], "foo")
        self.assertEqual(live_params["user_value"], "bar")

        # Assert that datastore value in the user-scope that is registered by user1
        # cannot be got by the operation of user2.
        context = {"user": "******"}
        param = {"user_value": {"default": "{{ st2kv.user.test_key }}"}}
        live_params = param_utils.render_live_params(
            runner_parameters={},
            action_parameters=param,
            params={},
            action_context=context,
        )

        self.assertEqual(live_params["user_value"], "")

        # Assert that system-user's scope is selected when user and api_user parameter specified
        context = {}
        param = {"user_value": {"default": "{{ st2kv.user.test_key }}"}}
        live_params = param_utils.render_live_params(
            runner_parameters={},
            action_parameters=param,
            params={},
            action_context=context,
        )

        self.assertEqual(live_params["user_value"], "baz")
Пример #3
0
    def test_get_live_params_with_additional_context(self):
        runner_param_info = {
            'r1': {
                'default': 'some'
            }
        }
        action_param_info = {
            'r2': {
                'default': '{{ r1 }}'
            }
        }
        params = {
            'r3': 'lolcathost',
            'r1': '{{ additional.stuff }}'
        }
        action_context = {}
        additional_contexts = {
            'additional': {
                'stuff': 'generic'
            }
        }

        live_params = param_utils.render_live_params(
            runner_param_info, action_param_info, params, action_context, additional_contexts)

        expected_params = {
            'r1': 'generic',
            'r3': 'lolcathost'
        }
        self.assertEqual(live_params, expected_params)
Пример #4
0
    def _schedule_execution(self, liveaction):
        # Initialize execution context if it does not exist.
        if not hasattr(liveaction, 'context'):
            liveaction.context = dict()

        liveaction.context['user'] = get_requester()
        LOG.debug('User is: %s' % liveaction.context['user'])

        # Retrieve other st2 context from request header.
        if 'st2-context' in pecan.request.headers and pecan.request.headers['st2-context']:
            context = jsonify.try_loads(pecan.request.headers['st2-context'])
            if not isinstance(context, dict):
                raise ValueError('Unable to convert st2-context from the headers into JSON.')
            liveaction.context.update(context)

        # Schedule the action execution.
        liveaction_db = LiveActionAPI.to_model(liveaction)
        liveaction_db, actionexecution_db = action_service.create_request(liveaction_db)

        action_db = action_utils.get_action_by_ref(liveaction_db.action)
        runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name'])

        try:
            liveaction_db.parameters = param_utils.render_live_params(
                runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters,
                liveaction_db.context)
        except ParamException as e:
            raise ValueValidationException(str(e))

        liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False)

        _, actionexecution_db = action_service.publish_request(liveaction_db, actionexecution_db)
        from_model_kwargs = self._get_from_model_kwargs_for_request(request=pecan.request)
        return ActionExecutionAPI.from_model(actionexecution_db, from_model_kwargs)
Пример #5
0
    def test_get_live_params_with_additional_context(self):
        runner_param_info = {
            'r1': {
                'default': 'some'
            }
        }
        action_param_info = {
            'r2': {
                'default': '{{ r1 }}'
            }
        }
        params = {
            'r3': 'lolcathost',
            'r1': '{{ additional.stuff }}'
        }
        action_context = {}
        additional_contexts = {
            'additional': {
                'stuff': 'generic'
            }
        }

        live_params = param_utils.render_live_params(
            runner_param_info, action_param_info, params, action_context, additional_contexts)

        expected_params = {
            'r1': 'generic',
            'r2': 'generic',
            'r3': 'lolcathost'
        }
        self.assertEqual(live_params, expected_params)
Пример #6
0
def request_action_execution(wf_ex_db, task_ex_db, st2_ctx, ac_ex_req):
    wf_ac_ex_id = wf_ex_db.action_execution
    action_ref = ac_ex_req['action']
    action_input = ac_ex_req['input']
    item_id = ac_ex_req.get('item_id')

    # If the task is with items and item_id is not provided, raise exception.
    if task_ex_db.itemized and item_id is None:
        msg = 'Unable to request action execution. Identifier for the item is not provided.'
        raise Exception(msg)

    # Identify the action to execute.
    action_db = action_utils.get_action_by_ref(ref=action_ref)

    if not action_db:
        error = 'Unable to find action "%s".' % action_ref
        raise ac_exc.InvalidActionReferencedException(error)

    # Identify the runner for the action.
    runner_type_db = action_utils.get_runnertype_by_name(
        action_db.runner_type['name'])

    # Set context for the action execution.
    ac_ex_ctx = {
        'parent': st2_ctx,
        'orquesta': {
            'workflow_execution_id': str(wf_ex_db.id),
            'task_execution_id': str(task_ex_db.id),
            'task_name': task_ex_db.task_name,
            'task_id': task_ex_db.task_id
        }
    }

    if item_id is not None:
        ac_ex_ctx['orquesta']['item_id'] = item_id

    # Render action execution parameters and setup action execution object.
    ac_ex_params = param_utils.render_live_params(
        runner_type_db.runner_parameters or {}, action_db.parameters or {},
        action_input or {}, ac_ex_ctx)

    lv_ac_db = lv_db_models.LiveActionDB(action=action_ref,
                                         workflow_execution=str(wf_ex_db.id),
                                         task_execution=str(task_ex_db.id),
                                         context=ac_ex_ctx,
                                         parameters=ac_ex_params)

    # Set the task execution to running first otherwise a race can occur
    # where the action execution finishes first and the completion handler
    # conflicts with this status update.
    task_ex_db.status = states.RUNNING
    task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False)

    # Request action execution.
    lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
    msg = '[%s] Action execution "%s" requested for task "%s".'
    LOG.info(msg, wf_ac_ex_id, str(ac_ex_db.id), task_ex_db.task_id)

    return ac_ex_db
Пример #7
0
    def _schedule_execution(self,
                            liveaction,
                            user=None,
                            context_string=None,
                            show_secrets=False):
        # Initialize execution context if it does not exist.
        if not hasattr(liveaction, 'context'):
            liveaction.context = dict()

        liveaction.context['user'] = user
        LOG.debug('User is: %s' % liveaction.context['user'])

        # Retrieve other st2 context from request header.
        if context_string:
            context = try_loads(context_string)
            if not isinstance(context, dict):
                raise ValueError(
                    'Unable to convert st2-context from the headers into JSON.'
                )
            liveaction.context.update(context)

        # Schedule the action execution.
        liveaction_db = LiveActionAPI.to_model(liveaction)
        liveaction_db, actionexecution_db = action_service.create_request(
            liveaction_db)

        action_db = action_utils.get_action_by_ref(liveaction_db.action)
        runnertype_db = action_utils.get_runnertype_by_name(
            action_db.runner_type['name'])

        try:
            liveaction_db.parameters = param_utils.render_live_params(
                runnertype_db.runner_parameters, action_db.parameters,
                liveaction_db.parameters, liveaction_db.context)
        except ParamException:
            # By this point the execution is already in the DB therefore need to mark it failed.
            _, e, tb = sys.exc_info()
            action_service.update_status(liveaction=liveaction_db,
                                         new_status=LIVEACTION_STATUS_FAILED,
                                         result={
                                             'error':
                                             str(e),
                                             'traceback':
                                             ''.join(
                                                 traceback.format_tb(tb, 20))
                                         })
            # Might be a good idea to return the actual ActionExecution rather than bubble up
            # the execption.
            raise ValueValidationException(str(e))

        liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False)

        _, actionexecution_db = action_service.publish_request(
            liveaction_db, actionexecution_db)
        execution_api = ActionExecutionAPI.from_model(
            actionexecution_db, mask_secrets=(not show_secrets))

        return Response(json=execution_api, status=http_client.CREATED)
Пример #8
0
    def test_get_value_from_datastore_through_render_live_params(self):
        # Register datastore value to be refered by this test-case
        register_kwargs = [
            {'name': 'test_key', 'value': 'foo'},
            {'name': 'user1:test_key', 'value': 'bar', 'scope': FULL_USER_SCOPE},
            {'name': '%s:test_key' % cfg.CONF.system_user.user, 'value': 'baz',
             'scope': FULL_USER_SCOPE},
        ]
        for kwargs in register_kwargs:
            KeyValuePair.add_or_update(KeyValuePairDB(**kwargs))

        # Assert that datastore value can be got via the Jinja expression from individual scopes.
        context = {'user': '******'}
        param = {
            'system_value': {'default': '{{ st2kv.system.test_key }}'},
            'user_value': {'default': '{{ st2kv.user.test_key }}'},
        }
        live_params = param_utils.render_live_params(runner_parameters={},
                                                     action_parameters=param,
                                                     params={},
                                                     action_context=context)

        self.assertEqual(live_params['system_value'], 'foo')
        self.assertEqual(live_params['user_value'], 'bar')

        # Assert that datastore value in the user-scope that is registered by user1
        # cannot be got by the operation of user2.
        context = {'user': '******'}
        param = {'user_value': {'default': '{{ st2kv.user.test_key }}'}}
        live_params = param_utils.render_live_params(runner_parameters={},
                                                     action_parameters=param,
                                                     params={},
                                                     action_context=context)

        self.assertEqual(live_params['user_value'], '')

        # Assert that system-user's scope is selected when user and api_user parameter specified
        context = {}
        param = {'user_value': {'default': '{{ st2kv.user.test_key }}'}}
        live_params = param_utils.render_live_params(runner_parameters={},
                                                     action_parameters=param,
                                                     params={},
                                                     action_context=context)

        self.assertEqual(live_params['user_value'], 'baz')
Пример #9
0
    def get_resolved_parameters(self, action_db, runnertype_db, params, context=None,
                                additional_contexts=None):
        resolved_params = param_utils.render_live_params(
            runner_parameters=runnertype_db.runner_parameters,
            action_parameters=action_db.parameters,
            params=params,
            action_context=context,
            additional_contexts=additional_contexts)

        return resolved_params
Пример #10
0
    def get_resolved_parameters(self, action_db, runnertype_db, params, context=None,
                                additional_contexts=None):
        resolved_params = param_utils.render_live_params(
            runner_parameters=runnertype_db.runner_parameters,
            action_parameters=action_db.parameters,
            params=params,
            action_context=context,
            additional_contexts=additional_contexts)

        return resolved_params
Пример #11
0
    def test_get_live_params_with_additional_context(self):
        runner_param_info = {"r1": {"default": "some"}}
        action_param_info = {"r2": {"default": "{{ r1 }}"}}
        params = {"r3": "lolcathost", "r1": "{{ additional.stuff }}"}
        action_context = {"user": None}
        additional_contexts = {"additional": {"stuff": "generic"}}

        live_params = param_utils.render_live_params(
            runner_param_info,
            action_param_info,
            params,
            action_context,
            additional_contexts,
        )

        expected_params = {"r1": "generic", "r2": "generic", "r3": "lolcathost"}
        self.assertEqual(live_params, expected_params)
Пример #12
0
    def _schedule_execution(self, liveaction):
        # Initialize execution context if it does not exist.
        if not hasattr(liveaction, 'context'):
            liveaction.context = dict()

        liveaction.context['user'] = get_requester()
        LOG.debug('User is: %s' % liveaction.context['user'])

        # Retrieve other st2 context from request header.
        if 'st2-context' in pecan.request.headers and pecan.request.headers[
                'st2-context']:
            context = jsonify.try_loads(pecan.request.headers['st2-context'])
            if not isinstance(context, dict):
                raise ValueError(
                    'Unable to convert st2-context from the headers into JSON.'
                )
            liveaction.context.update(context)

        # Schedule the action execution.
        liveaction_db = LiveActionAPI.to_model(liveaction)
        liveaction_db, actionexecution_db = action_service.create_request(
            liveaction_db)

        action_db = action_utils.get_action_by_ref(liveaction_db.action)
        runnertype_db = action_utils.get_runnertype_by_name(
            action_db.runner_type['name'])

        try:
            liveaction_db.parameters = param_utils.render_live_params(
                runnertype_db.runner_parameters, action_db.parameters,
                liveaction_db.parameters, liveaction_db.context)
        except ParamException as e:
            raise ValueValidationException(str(e))

        liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False)

        _, actionexecution_db = action_service.publish_request(
            liveaction_db, actionexecution_db)
        from_model_kwargs = self._get_from_model_kwargs_for_request(
            request=pecan.request)
        return ActionExecutionAPI.from_model(actionexecution_db,
                                             from_model_kwargs)
Пример #13
0
    def _schedule_execution(self, liveaction, user=None):
        # Initialize execution context if it does not exist.
        if not hasattr(liveaction, 'context'):
            liveaction.context = dict()

        liveaction.context['user'] = user
        LOG.debug('User is: %s' % liveaction.context['user'])

        # Retrieve other st2 context from request header.
        if 'st2-context' in pecan.request.headers and pecan.request.headers['st2-context']:
            context = jsonify.try_loads(pecan.request.headers['st2-context'])
            if not isinstance(context, dict):
                raise ValueError('Unable to convert st2-context from the headers into JSON.')
            liveaction.context.update(context)

        # Schedule the action execution.
        liveaction_db = LiveActionAPI.to_model(liveaction)
        liveaction_db, actionexecution_db = action_service.create_request(liveaction_db)

        action_db = action_utils.get_action_by_ref(liveaction_db.action)
        runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name'])

        try:
            liveaction_db.parameters = param_utils.render_live_params(
                runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters,
                liveaction_db.context)
        except ParamException:
            # By this point the execution is already in the DB therefore need to mark it failed.
            _, e, tb = sys.exc_info()
            action_service.update_status(
                liveaction=liveaction_db,
                new_status=LIVEACTION_STATUS_FAILED,
                result={'error': str(e), 'traceback': ''.join(traceback.format_tb(tb, 20))})
            # Might be a good idea to return the actual ActionExecution rather than bubble up
            # the execption.
            raise ValueValidationException(str(e))

        liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False)

        _, actionexecution_db = action_service.publish_request(liveaction_db, actionexecution_db)
        from_model_kwargs = self._get_from_model_kwargs_for_request(request=pecan.request)
        return ActionExecutionAPI.from_model(actionexecution_db, from_model_kwargs)
def base(event, context, passthrough=False):
    # Set up logging
    logger = logging.getLogger()

    # Read DEBUG value from the environment variable
    debug = os.environ.get('ST2_DEBUG', False)
    if str(debug).lower() in ['true', '1']:
        debug = True

    if debug:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    if isinstance(event, basestring):
        try:
            event = json.loads(event)
        except ValueError as e:
            LOG.error("ERROR: Can not parse `event`: '{}'\n{}".format(
                str(event), str(e)))
            raise e

    LOG.info("Received event: " + json.dumps(event, indent=2))

    # Special case for Lambda function being called over HTTP via API gateway
    # See
    # https://serverless.com/framework/docs/providers/aws/events/apigateway
    # #example-lambda-proxy-event-default
    # for details
    is_event_body_string = (isinstance(event.get('body'), basestring) is True)
    content_type = event.get('headers', {}).get('content-type', '').lower()

    if is_event_body_string:
        if content_type == 'application/json':
            try:
                event['body'] = json.loads(event['body'])
            except Exception as e:
                LOG.warn('`event` has `body` which is not JSON: %s',
                         str(e.message))
        elif content_type == 'application/x-www-form-urlencoded':
            try:
                event['body'] = dict(
                    parse_qsl(['body'], keep_blank_values=True))
            except Exception as e:
                LOG.warn('`event` has `body` which is not `%s`: %s',
                         content_type, str(e.message))
        else:
            LOG.warn('Unsupported event content type: %s' % (content_type))

    action_name = os.environ['ST2_ACTION']
    try:
        action_db = ACTIONS[action_name]
    except KeyError:
        raise ValueError('No action named "%s" has been installed.' %
                         (action_name))

    manager = DriverManager(namespace='st2common.runners.runner',
                            invoke_on_load=False,
                            name=action_db.runner_type['name'])
    runnertype_db = RunnerTypeAPI.to_model(
        RunnerTypeAPI(**manager.driver.get_metadata()[0]))

    if passthrough:
        runner = PassthroughRunner()
    else:
        runner = manager.driver.get_runner()

    runner._sandbox = False
    runner.runner_type_db = runnertype_db
    runner.action = action_db
    runner.action_name = action_db.name
    # runner.liveaction = liveaction_db
    # runner.liveaction_id = str(liveaction_db.id)
    # runner.execution = ActionExecution.get(liveaction__id=runner.liveaction_id)
    # runner.execution_id = str(runner.execution.id)
    runner.entry_point = content_utils.get_entry_point_abs_path(
        pack=action_db.pack, entry_point=action_db.entry_point)
    runner.context = {}  # getattr(liveaction_db, 'context', dict())
    # runner.callback = getattr(liveaction_db, 'callback', dict())
    runner.libs_dir_path = content_utils.get_action_libs_abs_path(
        pack=action_db.pack, entry_point=action_db.entry_point)

    # For re-run, get the ActionExecutionDB in which the re-run is based on.
    # rerun_ref_id = runner.context.get('re-run', {}).get('ref')
    # runner.rerun_ex_ref = ActionExecution.get(id=rerun_ref_id) if rerun_ref_id else None

    config_schema = CONFIG_SCHEMAS.get(action_db.pack, None)
    config_values = os.environ.get('ST2_CONFIG', None)
    if config_schema and config_values:
        runner._config = validate_config_against_schema(
            config_schema=config_schema,
            config_object=json.loads(config_values),
            config_path=None,
            pack_name=action_db.pack)

    param_values = os.environ.get('ST2_PARAMETERS', None)
    try:
        if param_values:
            live_params = param_utils.render_live_params(
                runner_parameters=runnertype_db.runner_parameters,
                action_parameters=action_db.parameters,
                params=json.loads(param_values),
                action_context={},
                additional_contexts={'input': event})
        else:
            live_params = event

        if debug and 'log_level' not in live_params:
            # Set log_level runner parameter
            live_params['log_level'] = 'DEBUG'

        runner_params, action_params = param_utils.render_final_params(
            runner_parameters=runnertype_db.runner_parameters,
            action_parameters=action_db.parameters,
            params=live_params,
            action_context={})
    except ParamException as e:
        raise actionrunner.ActionRunnerException(str(e))

    runner.runner_parameters = runner_params

    LOG.debug('Performing pre-run for runner: %s', runner.runner_id)
    runner.pre_run()

    (status, output, context) = runner.run(action_params)

    output_values = os.environ.get('ST2_OUTPUT', None)
    if output_values:
        try:
            result = param_utils.render_live_params(
                runner_parameters=runnertype_db.runner_parameters,
                action_parameters=action_db.parameters,
                params=json.loads(output_values),
                action_context={},
                additional_contexts={
                    'input': event,
                    'output': output
                })
        except ParamException as e:
            raise actionrunner.ActionRunnerException(str(e))
    else:
        result = output

    # Log the logs generated by the action. We do that so the actual action logs
    # (action stderr) end up in CloudWatch
    output = output or {}

    if output.get('stdout', None):
        LOG.info('Action stdout: %s' % (output['stdout']))

    if output.get('stderr', None):
        LOG.info('Action stderr and logs: %s' % (output['stderr']))

    return {
        'event': event,
        'live_params': live_params,
        'output': output,
        'result': result
    }
Пример #15
0
def main():
    # Read DEBUG value from the environment variable
    debug = os.environ.get('ST2_DEBUG', False)
    if str(debug).lower() in ['true', '1']:
        debug = True

    if debug:
        LOG.setLevel(logging.DEBUG)
    else:
        LOG.setLevel(logging.INFO)

    # Read
    input = os.environ.get('ST2_INPUT', {})
    if isinstance(input, six.string_types):
        try:
            input = json.loads(input)
        except ValueError as e:
            LOG.error("ERROR: Can not parse `input`: '{}'\n{}".format(str(input), str(e)))
            raise e

    LOG.debug("Received input: " + json.dumps(input, indent=2))

    # Read action name from environment variable
    action_name = os.environ['ST2_ACTION']
    try:
        action_db = ACTIONS[action_name]
    except KeyError:
        raise ValueError('No action named "%s" has been installed.' % (action_name))

    # Initialize runner
    manager = DriverManager(namespace='st2common.runners.runner', invoke_on_load=False,
                            name=action_db.runner_type['name'])

    runnertype_db = RunnerTypeAPI.to_model(RunnerTypeAPI(**manager.driver.get_metadata()))

    runner = manager.driver.get_runner()

    runner._sandbox = False
    runner.runner_type_db = runnertype_db
    runner.action = action_db
    runner.action_name = action_db.name
    runner.entry_point = content_utils.get_entry_point_abs_path(pack=action_db.pack,
        entry_point=action_db.entry_point)
    runner.context = {}
    runner.libs_dir_path = content_utils.get_action_libs_abs_path(pack=action_db.pack,
        entry_point=action_db.entry_point)

    config_schema = CONFIG_SCHEMAS.get(action_db.pack, None)
    config_values = os.environ.get('ST2_CONFIG', None)
    if config_schema and config_values:
        runner._config = validate_config_against_schema(config_schema=config_schema,
                                                        config_object=json.loads(config_values),
                                                        config_path=None,
                                                        pack_name=action_db.pack)

    param_values = os.environ.get('ST2_PARAMETERS', None)
    try:
        if param_values:
            live_params = param_utils.render_live_params(
                runner_parameters=runnertype_db.runner_parameters,
                action_parameters=action_db.parameters,
                params=json.loads(param_values),
                action_context={},
                additional_contexts={
                    'input': input
                })
        else:
            live_params = input

        if debug and 'log_level' not in live_params:
            # Set log_level runner parameter
            live_params['log_level'] = 'DEBUG'

        runner_params, action_params = param_utils.render_final_params(
            runner_parameters=runnertype_db.runner_parameters,
            action_parameters=action_db.parameters,
            params=live_params,
            action_context={})
    except ParamException as e:
        raise actionrunner.ActionRunnerException(str(e))

    runner.runner_parameters = runner_params


    LOG.debug('Performing pre-run for runner: %s', runner.runner_id)
    runner.pre_run()

    (status, output, context) = runner.run(action_params)

    try:
        output['result'] = json.loads(output['result'])
    except Exception:
        pass

    output_values = os.environ.get('ST2_OUTPUT', None)
    if output_values:
        try:
            result = param_utils.render_live_params(
                runner_parameters={},
                action_parameters={},
                params=json.loads(output_values),
                action_context={},
                additional_contexts={
                    'input': input,
                    'output': output
                })
        except ParamException as e:
            raise actionrunner.ActionRunnerException(str(e))
    else:
        result = output

    output = output or {}

    if output.get('stdout', None):
        LOG.info('Action stdout: %s' % (output['stdout']))

    if output.get('stderr', None):
        LOG.info('Action stderr and logs: %s' % (output['stderr']))

    print(json.dumps(result))
Пример #16
0
    def _schedule_execution(self, liveaction, requester_user, action_db, user=None,
                            context_string=None, show_secrets=False):
        # Initialize execution context if it does not exist.
        if not hasattr(liveaction, 'context'):
            liveaction.context = dict()

        liveaction.context['user'] = user
        liveaction.context['pack'] = action_db.pack

        LOG.debug('User is: %s' % liveaction.context['user'])

        # Retrieve other st2 context from request header.
        if context_string:
            context = try_loads(context_string)
            if not isinstance(context, dict):
                raise ValueError('Unable to convert st2-context from the headers into JSON.')
            liveaction.context.update(context)

        # Include RBAC context (if RBAC is available and enabled)
        if cfg.CONF.rbac.enable:
            user_db = UserDB(name=user)
            role_dbs = rbac_service.get_roles_for_user(user_db=user_db, include_remote=True)
            roles = [role_db.name for role_db in role_dbs]
            liveaction.context['rbac'] = {
                'user': user,
                'roles': roles
            }

        # Schedule the action execution.
        liveaction_db = LiveActionAPI.to_model(liveaction)
        runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name'])

        try:
            liveaction_db.parameters = param_utils.render_live_params(
                runnertype_db.runner_parameters, action_db.parameters, liveaction_db.parameters,
                liveaction_db.context)
        except param_exc.ParamException:
            # We still need to create a request, so liveaction_db is assigned an ID
            liveaction_db, actionexecution_db = action_service.create_request(
                liveaction=liveaction_db,
                action_db=action_db,
                runnertype_db=runnertype_db)

            # By this point the execution is already in the DB therefore need to mark it failed.
            _, e, tb = sys.exc_info()
            action_service.update_status(
                liveaction=liveaction_db,
                new_status=action_constants.LIVEACTION_STATUS_FAILED,
                result={'error': six.text_type(e),
                        'traceback': ''.join(traceback.format_tb(tb, 20))})
            # Might be a good idea to return the actual ActionExecution rather than bubble up
            # the exception.
            raise validation_exc.ValueValidationException(six.text_type(e))

        # The request should be created after the above call to render_live_params
        # so any templates in live parameters have a chance to render.
        liveaction_db, actionexecution_db = action_service.create_request(liveaction=liveaction_db,
            action_db=action_db,
            runnertype_db=runnertype_db)

        _, actionexecution_db = action_service.publish_request(liveaction_db, actionexecution_db)
        mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)
        execution_api = ActionExecutionAPI.from_model(actionexecution_db, mask_secrets=mask_secrets)

        return Response(json=execution_api, status=http_client.CREATED)
Пример #17
0
def request_task_execution(wf_ex_db, task_id, task_spec, task_ctx, st2_ctx):
    # Create a record for task execution.
    task_ex_db = wf_db_models.TaskExecutionDB(
        workflow_execution=str(wf_ex_db.id),
        task_name=task_spec.name or task_id,
        task_id=task_id,
        task_spec=task_spec.serialize(),
        initial_context=task_ctx,
        status=states.REQUESTED
    )

    # Insert new record into the database.
    task_ex_db = wf_db_access.TaskExecution.insert(task_ex_db, publish=False)

    try:
        # Return here if no action is specified in task spec.
        if task_spec.action is None:
            # Set the task execution to running.
            task_ex_db.status = states.RUNNING
            task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False)

            # Fast forward task execution to completion.
            update_task_execution(str(task_ex_db.id), states.SUCCEEDED)
            update_task_flow(str(task_ex_db.id), publish=False)

            # Refresh and return the task execution
            return wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id))

        # Identify the action to execute.
        action_db = ac_db_util.get_action_by_ref(ref=task_spec.action)

        if not action_db:
            error = 'Unable to find action "%s".' % task_spec.action
            raise ac_exc.InvalidActionReferencedException(error)

        # Identify the runner for the action.
        runner_type_db = ac_db_util.get_runnertype_by_name(action_db.runner_type['name'])

        # Set context for the action execution.
        ac_ex_ctx = {
            'parent': st2_ctx,
            'orchestra': {
                'workflow_execution_id': str(wf_ex_db.id),
                'task_execution_id': str(task_ex_db.id),
                'task_name': task_spec.name or task_id,
                'task_id': task_id
            }
        }

        # Render action execution parameters and setup action execution object.
        ac_ex_params = param_utils.render_live_params(
            runner_type_db.runner_parameters or {},
            action_db.parameters or {},
            getattr(task_spec, 'input', None) or {},
            ac_ex_ctx
        )

        lv_ac_db = lv_db_models.LiveActionDB(
            action=task_spec.action,
            workflow_execution=str(wf_ex_db.id),
            task_execution=str(task_ex_db.id),
            context=ac_ex_ctx,
            parameters=ac_ex_params
        )

        # Request action execution.
        ac_svc.request(lv_ac_db)

        # Set the task execution to running.
        task_ex_db.status = states.RUNNING
        task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False)
    except Exception as e:
        result = {'errors': [{'message': str(e), 'task_id': task_ex_db.task_id}]}
        update_task_execution(str(task_ex_db.id), states.FAILED, result)
        raise e

    return task_ex_db
Пример #18
0
def request_action_execution(wf_ex_db,
                             task_ex_db,
                             st2_ctx,
                             ac_ex_req,
                             delay=None):
    wf_ac_ex_id = wf_ex_db.action_execution
    action_ref = ac_ex_req['action']
    action_input = ac_ex_req['input']
    item_id = ac_ex_req.get('item_id')

    # If the task is with items and item_id is not provided, raise exception.
    if task_ex_db.itemized and item_id is None:
        msg = 'Unable to request action execution. Identifier for the item is not provided.'
        raise Exception(msg)

    # Identify the action to execute.
    action_db = action_utils.get_action_by_ref(ref=action_ref)

    if not action_db:
        error = 'Unable to find action "%s".' % action_ref
        raise ac_exc.InvalidActionReferencedException(error)

    # Identify the runner for the action.
    runner_type_db = action_utils.get_runnertype_by_name(
        action_db.runner_type['name'])

    # Identify action pack name
    pack_name = action_ref.split('.')[0] if action_ref else st2_ctx.get('pack')

    # Set context for the action execution.
    ac_ex_ctx = {
        'pack': pack_name,
        'user': st2_ctx.get('user'),
        'parent': st2_ctx,
        'orquesta': {
            'workflow_execution_id': str(wf_ex_db.id),
            'task_execution_id': str(task_ex_db.id),
            'task_name': task_ex_db.task_name,
            'task_id': task_ex_db.task_id,
            'task_route': task_ex_db.task_route
        }
    }

    if st2_ctx.get('api_user'):
        ac_ex_ctx['api_user'] = st2_ctx.get('api_user')

    if st2_ctx.get('source_channel'):
        ac_ex_ctx['source_channel'] = st2_ctx.get('source_channel')

    if item_id is not None:
        ac_ex_ctx['orquesta']['item_id'] = item_id

    # Render action execution parameters and setup action execution object.
    ac_ex_params = param_utils.render_live_params(
        runner_type_db.runner_parameters or {}, action_db.parameters or {},
        action_input or {}, ac_ex_ctx)

    # The delay spec is in seconds and scheduler expects milliseconds.
    if delay is not None and delay > 0:
        delay = delay * 1000

    # Instantiate the live action record.
    lv_ac_db = lv_db_models.LiveActionDB(action=action_ref,
                                         workflow_execution=str(wf_ex_db.id),
                                         task_execution=str(task_ex_db.id),
                                         delay=delay,
                                         context=ac_ex_ctx,
                                         parameters=ac_ex_params)

    # Set notification if instructed.
    if (wf_ex_db.notify and wf_ex_db.notify.get('config')
            and wf_ex_db.notify.get('tasks')
            and task_ex_db.task_name in wf_ex_db.notify['tasks']):
        lv_ac_db.notify = notify_api_models.NotificationsHelper.to_model(
            wf_ex_db.notify['config'])

    # Set the task execution to running first otherwise a race can occur
    # where the action execution finishes first and the completion handler
    # conflicts with this status update.
    task_ex_db.status = statuses.RUNNING
    task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False)

    # Request action execution.
    lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
    msg = '[%s] Action execution "%s" requested for task "%s", route "%s".'
    LOG.info(msg, wf_ac_ex_id, str(ac_ex_db.id), task_ex_db.task_id,
             str(task_ex_db.task_route))

    return ac_ex_db
Пример #19
0
def request_task_execution(wf_ex_db, task_id, task_spec, task_ctx, st2_ctx):
    wf_ac_ex_id = wf_ex_db.action_execution
    LOG.info('[%s] Processing task execution request for "%s".', wf_ac_ex_id,
             task_id)

    # Create a record for task execution.
    task_ex_db = wf_db_models.TaskExecutionDB(
        workflow_execution=str(wf_ex_db.id),
        task_name=task_spec.name or task_id,
        task_id=task_id,
        task_spec=task_spec.serialize(),
        context=task_ctx,
        status=states.REQUESTED)

    # Insert new record into the database.
    task_ex_db = wf_db_access.TaskExecution.insert(task_ex_db, publish=False)
    task_ex_id = str(task_ex_db.id)
    LOG.info('[%s] Task execution "%s" created for task "%s".', wf_ac_ex_id,
             task_ex_id, task_id)

    try:
        # Return here if no action is specified in task spec.
        if task_spec.action is None:
            # Set the task execution to running.
            task_ex_db.status = states.RUNNING
            task_ex_db = wf_db_access.TaskExecution.update(task_ex_db,
                                                           publish=False)

            # Fast forward task execution to completion.
            update_task_execution(str(task_ex_db.id), states.SUCCEEDED)
            update_task_flow(str(task_ex_db.id), publish=False)

            # Refresh and return the task execution
            return wf_db_access.TaskExecution.get_by_id(str(task_ex_db.id))

        # Identify the action to execute.
        action_db = action_utils.get_action_by_ref(ref=task_spec.action)

        if not action_db:
            error = 'Unable to find action "%s".' % task_spec.action
            raise ac_exc.InvalidActionReferencedException(error)

        # Identify the runner for the action.
        runner_type_db = action_utils.get_runnertype_by_name(
            action_db.runner_type['name'])

        # Set context for the action execution.
        ac_ex_ctx = {
            'parent': st2_ctx,
            'orquesta': {
                'workflow_execution_id': str(wf_ex_db.id),
                'task_execution_id': str(task_ex_db.id),
                'task_name': task_spec.name or task_id,
                'task_id': task_id
            }
        }

        # Render action execution parameters and setup action execution object.
        ac_ex_params = param_utils.render_live_params(
            runner_type_db.runner_parameters or {}, action_db.parameters or {},
            getattr(task_spec, 'input', None) or {}, ac_ex_ctx)

        lv_ac_db = lv_db_models.LiveActionDB(action=task_spec.action,
                                             workflow_execution=str(
                                                 wf_ex_db.id),
                                             task_execution=str(task_ex_db.id),
                                             context=ac_ex_ctx,
                                             parameters=ac_ex_params)

        # Set the task execution to running first otherwise a race can occur
        # where the action execution finishes first and the completion handler
        # conflicts with this status update.
        task_ex_db.status = states.RUNNING
        task_ex_db = wf_db_access.TaskExecution.update(task_ex_db,
                                                       publish=False)

        # Request action execution.
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)

        msg = '[%s] Action execution "%s" requested for task "%s".'
        LOG.info(msg, wf_ac_ex_id, str(ac_ex_db.id), task_id)
    except Exception as e:
        LOG.exception('[%s] Failed task execution for task "%s".', wf_ac_ex_id,
                      task_id)
        result = {
            'errors': [{
                'message': str(e),
                'task_id': task_ex_db.task_id
            }]
        }
        update_task_execution(str(task_ex_db.id), states.FAILED, result)
        raise e

    return task_ex_db
Пример #20
0
    def _schedule_execution(self,
                            liveaction,
                            requester_user,
                            user=None,
                            context_string=None,
                            show_secrets=False,
                            pack=None):
        # Initialize execution context if it does not exist.
        if not hasattr(liveaction, 'context'):
            liveaction.context = dict()

        liveaction.context['user'] = user
        liveaction.context['pack'] = pack
        LOG.debug('User is: %s' % liveaction.context['user'])

        # Retrieve other st2 context from request header.
        if context_string:
            context = try_loads(context_string)
            if not isinstance(context, dict):
                raise ValueError(
                    'Unable to convert st2-context from the headers into JSON.'
                )
            liveaction.context.update(context)

        # Include RBAC context (if RBAC is available and enabled)
        if cfg.CONF.rbac.enable:
            user_db = UserDB(name=user)
            role_dbs = rbac_service.get_roles_for_user(user_db=user_db,
                                                       include_remote=True)
            roles = [role_db.name for role_db in role_dbs]
            liveaction.context['rbac'] = {'user': user, 'roles': roles}

        # Schedule the action execution.
        liveaction_db = LiveActionAPI.to_model(liveaction)
        action_db = action_utils.get_action_by_ref(liveaction_db.action)
        runnertype_db = action_utils.get_runnertype_by_name(
            action_db.runner_type['name'])

        try:
            liveaction_db.parameters = param_utils.render_live_params(
                runnertype_db.runner_parameters, action_db.parameters,
                liveaction_db.parameters, liveaction_db.context)
        except param_exc.ParamException:

            # We still need to create a request, so liveaction_db is assigned an ID
            liveaction_db, actionexecution_db = action_service.create_request(
                liveaction_db)

            # By this point the execution is already in the DB therefore need to mark it failed.
            _, e, tb = sys.exc_info()
            action_service.update_status(
                liveaction=liveaction_db,
                new_status=action_constants.LIVEACTION_STATUS_FAILED,
                result={
                    'error': str(e),
                    'traceback': ''.join(traceback.format_tb(tb, 20))
                })
            # Might be a good idea to return the actual ActionExecution rather than bubble up
            # the exception.
            raise validation_exc.ValueValidationException(str(e))

        # The request should be created after the above call to render_live_params
        # so any templates in live parameters have a chance to render.
        liveaction_db, actionexecution_db = action_service.create_request(
            liveaction_db)
        liveaction_db = LiveAction.add_or_update(liveaction_db, publish=False)

        _, actionexecution_db = action_service.publish_request(
            liveaction_db, actionexecution_db)
        mask_secrets = self._get_mask_secrets(requester_user,
                                              show_secrets=show_secrets)
        execution_api = ActionExecutionAPI.from_model(
            actionexecution_db, mask_secrets=mask_secrets)

        return Response(json=execution_api, status=http_client.CREATED)
Пример #21
0
def request_action_execution(wf_ex_db, task_ex_db, st2_ctx, ac_ex_req, delay=None):
    wf_ac_ex_id = wf_ex_db.action_execution
    action_ref = ac_ex_req['action']
    action_input = ac_ex_req['input']
    item_id = ac_ex_req.get('item_id')

    # If the task is with items and item_id is not provided, raise exception.
    if task_ex_db.itemized and item_id is None:
        msg = 'Unable to request action execution. Identifier for the item is not provided.'
        raise Exception(msg)

    # Identify the action to execute.
    action_db = action_utils.get_action_by_ref(ref=action_ref)

    if not action_db:
        error = 'Unable to find action "%s".' % action_ref
        raise ac_exc.InvalidActionReferencedException(error)

    # Identify the runner for the action.
    runner_type_db = action_utils.get_runnertype_by_name(action_db.runner_type['name'])

    # Identify action pack name
    pack_name = action_ref.split('.')[0] if action_ref else st2_ctx.get('pack')

    # Set context for the action execution.
    ac_ex_ctx = {
        'pack': pack_name,
        'user': st2_ctx.get('user'),
        'parent': st2_ctx,
        'orquesta': {
            'workflow_execution_id': str(wf_ex_db.id),
            'task_execution_id': str(task_ex_db.id),
            'task_name': task_ex_db.task_name,
            'task_id': task_ex_db.task_id,
            'task_route': task_ex_db.task_route
        }
    }

    if st2_ctx.get('api_user'):
        ac_ex_ctx['api_user'] = st2_ctx.get('api_user')

    if item_id is not None:
        ac_ex_ctx['orquesta']['item_id'] = item_id

    # Render action execution parameters and setup action execution object.
    ac_ex_params = param_utils.render_live_params(
        runner_type_db.runner_parameters or {},
        action_db.parameters or {},
        action_input or {},
        ac_ex_ctx
    )

    # The delay spec is in seconds and scheduler expects milliseconds.
    if delay is not None and delay > 0:
        delay = delay * 1000

    # Instantiate the live action record.
    lv_ac_db = lv_db_models.LiveActionDB(
        action=action_ref,
        workflow_execution=str(wf_ex_db.id),
        task_execution=str(task_ex_db.id),
        delay=delay,
        context=ac_ex_ctx,
        parameters=ac_ex_params
    )

    # Set notification if instructed.
    if (wf_ex_db.notify and wf_ex_db.notify.get('config') and
            wf_ex_db.notify.get('tasks') and task_ex_db.task_name in wf_ex_db.notify['tasks']):
        lv_ac_db.notify = notify_api_models.NotificationsHelper.to_model(wf_ex_db.notify['config'])

    # Set the task execution to running first otherwise a race can occur
    # where the action execution finishes first and the completion handler
    # conflicts with this status update.
    task_ex_db.status = statuses.RUNNING
    task_ex_db = wf_db_access.TaskExecution.update(task_ex_db, publish=False)

    # Request action execution.
    lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
    msg = '[%s] Action execution "%s" requested for task "%s", route "%s".'
    LOG.info(msg, wf_ac_ex_id, str(ac_ex_db.id), task_ex_db.task_id, str(task_ex_db.task_route))

    return ac_ex_db