Пример #1
0
    def _mark_inquiry_complete(self, inquiry_id, result):
        """Mark Inquiry as completed

        This function updates the local LiveAction and Execution with a successful
        status as well as call the "post_run" function for the Inquirer runner so that
        the appropriate callback function is executed

        :param inquiry: The Inquiry for which the response is given
        :param requester_user: The user providing the response

        :rtype: bool - True if requester_user is able to respond. False if not.
        """

        # Update inquiry's execution result with a successful status and the validated response
        liveaction_db = action_utils.update_liveaction_status(
            status=action_constants.LIVEACTION_STATUS_SUCCEEDED,
            runner_info=system_info.get_process_info(),
            result=result,
            liveaction_id=inquiry_id)
        executions.update_execution(liveaction_db)

        # Call Inquiry runner's post_run to trigger callback to workflow
        runner_container = get_runner_container()
        action_db = get_action_by_ref(liveaction_db.action)
        runnertype_db = get_runnertype_by_name(action_db.runner_type['name'])
        runner = runner_container._get_runner(runnertype_db, action_db,
                                              liveaction_db)
        runner.post_run(status=action_constants.LIVEACTION_STATUS_SUCCEEDED,
                        result=result)

        return liveaction_db
Пример #2
0
    def _mark_inquiry_complete(self, inquiry_id, result):
        """Mark Inquiry as completed

        This function updates the local LiveAction and Execution with a successful
        status as well as call the "post_run" function for the Inquirer runner so that
        the appropriate callback function is executed

        :param inquiry: The Inquiry for which the response is given
        :param requester_user: The user providing the response

        :rtype: bool - True if requester_user is able to respond. False if not.
        """

        # Update inquiry's execution result with a successful status and the validated response
        liveaction_db = action_utils.update_liveaction_status(
            status=action_constants.LIVEACTION_STATUS_SUCCEEDED,
            runner_info=system_info.get_process_info(),
            result=result,
            liveaction_id=inquiry_id)
        executions.update_execution(liveaction_db)

        # Call Inquiry runner's post_run to trigger callback to workflow
        runner_container = get_runner_container()
        action_db = get_action_by_ref(liveaction_db.action)
        runnertype_db = get_runnertype_by_name(action_db.runner_type['name'])
        runner = runner_container._get_runner(runnertype_db, action_db, liveaction_db)
        runner.post_run(status=action_constants.LIVEACTION_STATUS_SUCCEEDED, result=result)

        return liveaction_db
Пример #3
0
    def dispatch(self, actionexec_db):
        action_ref = ResourceReference.from_string_reference(
            ref=actionexec_db.action)
        (action_db, _) = get_action_by_dict({
            'name': action_ref.name,
            'pack': action_ref.pack
        })
        runnertype_db = get_runnertype_by_name(action_db.runner_type['name'])
        runner_type = runnertype_db.name

        LOG.info('Dispatching runner for Action "%s"', actionexec_db)
        LOG.debug('    liverunner_type: %s', runner_type)
        LOG.debug('    RunnerType: %s', runnertype_db)
        LOG.debug('    ActionExecution: %s', actionexec_db)

        # Get runner instance.
        runner = self._get_runner(runnertype_db)
        LOG.debug('Runner instance for RunnerType "%s" is: %s',
                  runnertype_db.name, runner)

        # Invoke pre_run, run, post_run cycle.
        result, actionexec_db = self._do_run(runner, runnertype_db, action_db,
                                             actionexec_db)
        LOG.debug('runner do_run result: %s', result)

        actionsensor.post_trigger(actionexec_db)
        LOG.audit(
            'ActionExecution complete. actionexec_id="%s" resulted in '
            'actionexecution_db="%s"', actionexec_db.id, actionexec_db)

        return result
Пример #4
0
    def _do_enforce(self):
        # TODO: Refactor this to avoid additional lookup in cast_params
        action_ref = self.rule.action['ref']

        # Verify action referenced in the rule exists in the database
        action_db = action_utils.get_action_by_ref(action_ref)
        if not action_db:
            raise ValueError('Action "%s" doesn\'t exist' % (action_ref))

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

        params = self.rule.action.parameters
        LOG.info('Invoking action %s for trigger_instance %s with params %s.',
                 self.rule.action.ref, self.trigger_instance.id,
                 json.dumps(params))

        # update trace before invoking the action.
        trace_context = self._update_trace()
        LOG.debug('Updated trace %s with rule %s.', trace_context, self.rule.id)

        context, additional_contexts = self.get_action_execution_context(
            action_db=action_db,
            trace_context=trace_context)

        return self._invoke_action(action_db=action_db, runnertype_db=runnertype_db, params=params,
                                   context=context,
                                   additional_contexts=additional_contexts)
Пример #5
0
def respond(inquiry, response, requester=None):
    # Set requester to system user is not provided.
    if not requester:
        requester = cfg.CONF.system_user.user

    # Retrieve the liveaction from the database.
    liveaction_db = lv_db_access.LiveAction.get_by_id(
        inquiry.liveaction.get("id"))

    # Resume the parent workflow first. If the action execution for the inquiry is updated first,
    # it triggers handling of the action execution completion which will interact with the paused
    # parent workflow. The resuming logic that is executed here will then race with the completion
    # of the inquiry action execution, which will randomly result in the parent workflow stuck in
    # paused state.
    if liveaction_db.context.get("parent"):
        LOG.debug('Resuming workflow parent(s) for inquiry "%s".' %
                  str(inquiry.id))

        # For action execution under Action Chain workflows, request the entire
        # workflow to resume. Orquesta handles resume differently and so does not require root
        # to resume. Orquesta allows for specifc branches to resume while other is paused. When
        # there is no other paused branches, the conductor will resume the rest of the workflow.
        resume_target = (
            action_service.get_parent_liveaction(liveaction_db)
            if workflow_service.is_action_execution_under_workflow_context(
                liveaction_db) else
            action_service.get_root_liveaction(liveaction_db))

        if resume_target.status in action_constants.LIVEACTION_PAUSE_STATES:
            action_service.request_resume(resume_target, requester)

    # Succeed the liveaction and update result with the inquiry response.
    LOG.debug('Updating response for inquiry "%s".' % str(inquiry.id))

    result = fast_deepcopy_dict(inquiry.result)
    result["response"] = response

    liveaction_db = action_utils.update_liveaction_status(
        status=action_constants.LIVEACTION_STATUS_SUCCEEDED,
        end_timestamp=date_utils.get_datetime_utc_now(),
        runner_info=sys_info_utils.get_process_info(),
        result=result,
        liveaction_id=str(liveaction_db.id),
    )

    # Sync the liveaction with the corresponding action execution.
    execution_service.update_execution(liveaction_db)

    # Invoke inquiry post run to trigger a callback to parent workflow.
    LOG.debug('Invoking post run for inquiry "%s".' % str(inquiry.id))
    runner_container = container.get_runner_container()
    action_db = action_utils.get_action_by_ref(liveaction_db.action)
    runnertype_db = action_utils.get_runnertype_by_name(
        action_db.runner_type["name"])
    runner = runner_container._get_runner(runnertype_db, action_db,
                                          liveaction_db)
    runner.post_run(status=action_constants.LIVEACTION_STATUS_SUCCEEDED,
                    result=result)

    return liveaction_db
Пример #6
0
    def dispatch(self, actionexec_db):
        action_ref = ResourceReference.from_string_reference(ref=actionexec_db.action)
        (action_db, _) = get_action_by_dict(
            {'name': action_ref.name, 'pack': action_ref.pack})
        runnertype_db = get_runnertype_by_name(action_db.runner_type['name'])
        runner_type = runnertype_db.name

        LOG.info('Dispatching runner for Action "%s"', actionexec_db)
        LOG.debug('    liverunner_type: %s', runner_type)
        LOG.debug('    RunnerType: %s', runnertype_db)
        LOG.debug('    ActionExecution: %s', actionexec_db)

        # Get runner instance.
        runner = self._get_runner(runnertype_db)
        LOG.debug('Runner instance for RunnerType "%s" is: %s', runnertype_db.name, runner)

        # Invoke pre_run, run, post_run cycle.
        result, actionexec_db = self._do_run(runner, runnertype_db, action_db, actionexec_db)
        LOG.debug('runner do_run result: %s', result)

        actionsensor.post_trigger(actionexec_db)
        LOG.audit('ActionExecution complete.',
                  extra={'actionexecution': actionexec_db.to_serializable_dict()})

        return result
Пример #7
0
def invoke_post_run(liveaction_db, action_db=None):
    LOG.info('Invoking post run for action execution %s.', liveaction_db.id)

    # Identify action and runner.
    if not action_db:
        action_db = action_db_utils.get_action_by_ref(liveaction_db.action)

    if not action_db:
        LOG.exception('Unable to invoke post run. Action %s no longer exists.',
                      liveaction_db.action)
        return

    LOG.info('Action execution %s runs %s of runner type %s.',
             liveaction_db.id, action_db.name, action_db.runner_type['name'])

    # Get an instance of the action runner.
    runnertype_db = action_db_utils.get_runnertype_by_name(
        action_db.runner_type['name'])
    runner = runners.get_runner(runnertype_db.runner_module)

    # Configure the action runner.
    runner.container_service = RunnerContainerService()
    runner.action = action_db
    runner.action_name = action_db.name
    runner.action_execution_id = str(liveaction_db.id)
    runner.entry_point = RunnerContainerService.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 = RunnerContainerService.get_action_libs_abs_path(
        pack=action_db.pack, entry_point=action_db.entry_point)

    # Invoke the post_run method.
    runner.post_run(liveaction_db.status, liveaction_db.result)
Пример #8
0
    def _invoke_post_run(self, actionexec_db, action_db):
        LOG.info(
            "Invoking post run for action execution %s. Action=%s; Runner=%s",
            actionexec_db.id,
            action_db.name,
            action_db.runner_type["name"],
        )

        # Get an instance of the action runner.
        runnertype_db = get_runnertype_by_name(action_db.runner_type["name"])
        runner = get_runner(runnertype_db.runner_module)

        # Configure the action runner.
        runner.container_service = RunnerContainerService()
        runner.action = action_db
        runner.action_name = action_db.name
        runner.action_execution_id = str(actionexec_db.id)
        runner.entry_point = RunnerContainerService.get_entry_point_abs_path(
            pack=action_db.pack, entry_point=action_db.entry_point
        )
        runner.context = getattr(actionexec_db, "context", dict())
        runner.callback = getattr(actionexec_db, "callback", dict())
        runner.libs_dir_path = RunnerContainerService.get_action_libs_abs_path(
            pack=action_db.pack, entry_point=action_db.entry_point
        )

        # Invoke the post_run method.
        runner.post_run(actionexec_db.status, actionexec_db.result)
Пример #9
0
def register_runner_types():
    LOG.debug('Start : register default RunnerTypes.')

    for runnertype in RUNNER_TYPES:
        try:
            runnertype_db = get_runnertype_by_name(runnertype['name'])
            update = True
        except StackStormDBObjectNotFoundError:
            runnertype_db = None
            update = False

        runnertype_api = RunnerTypeAPI(**runnertype)
        runnertype_api.validate()
        runner_type_model = RunnerTypeAPI.to_model(runnertype_api)

        if runnertype_db:
            runner_type_model.id = runnertype_db.id

        try:
            runnertype_db = RunnerType.add_or_update(runner_type_model)

            extra = {'runnertype_db': runnertype_db}
            if update:
                LOG.audit('RunnerType updated. RunnerType %s', runnertype_db, extra=extra)
            else:
                LOG.audit('RunnerType created. RunnerType %s', runnertype_db, extra=extra)
        except Exception:
            LOG.exception('Unable to register runner type %s.', runnertype['name'])

    LOG.debug('End : register default RunnerTypes.')
Пример #10
0
    def dispatch(self, liveaction_db):
        action_db = get_action_by_ref(liveaction_db.action)
        if not action_db:
            raise Exception("Action %s not found in DB." % (liveaction_db.action))

        runnertype_db = get_runnertype_by_name(action_db.runner_type["name"])

        extra = {"liveaction_db": liveaction_db, "runnertype_db": runnertype_db}
        LOG.info("Dispatching Action to a runner", extra=extra)

        # Get runner instance.
        runner = self._get_runner(runnertype_db, action_db, liveaction_db)
        LOG.debug('Runner instance for RunnerType "%s" is: %s', runnertype_db.name, runner)

        # Process the request.
        if liveaction_db.status == action_constants.LIVEACTION_STATUS_CANCELING:
            liveaction_db = self._do_cancel(
                runner=runner, runnertype_db=runnertype_db, action_db=action_db, liveaction_db=liveaction_db
            )
        else:
            liveaction_db = self._do_run(
                runner=runner, runnertype_db=runnertype_db, action_db=action_db, liveaction_db=liveaction_db
            )

        return liveaction_db.result
Пример #11
0
 def test_get_runnertype_existing(self):
     # Lookup by id and verify name equals.
     runner = action_db_utils.get_runnertype_by_id(ActionDBUtilsTestCase.runnertype_db.id)
     self.assertEqual(runner.name, ActionDBUtilsTestCase.runnertype_db.name)
     # Lookup by name and verify id equals.
     runner = action_db_utils.get_runnertype_by_name(ActionDBUtilsTestCase.runnertype_db.name)
     self.assertEqual(runner.id, ActionDBUtilsTestCase.runnertype_db.id)
Пример #12
0
def cast_params(action_ref, params):
    """
    """
    action_db = action_db_util.get_action_by_ref(action_ref)
    action_parameters_schema = action_db.parameters
    runnertype_db = action_db_util.get_runnertype_by_name(action_db.runner_type['name'])
    runner_parameters_schema = runnertype_db.runner_parameters
    # combine into 1 list of parameter schemas
    parameters_schema = {}
    if runner_parameters_schema:
        parameters_schema.update(runner_parameters_schema)
    if action_parameters_schema:
        parameters_schema.update(action_parameters_schema)
    # cast each param individually
    for k, v in six.iteritems(params):
        parameter_schema = parameters_schema.get(k, None)
        if not parameter_schema:
            LOG.debug('Will skip cast of param[name: %s, value: %s]. No schema.', k, v)
            continue
        parameter_type = parameter_schema.get('type', None)
        if not parameter_type:
            LOG.debug('Will skip cast of param[name: %s, value: %s]. No type.', k, v)
            continue
        cast = get_cast(cast_type=parameter_type)
        if not cast:
            LOG.debug('Will skip cast of param[name: %s, value: %s]. No cast for %s.', k, v,
                      parameter_type)
            continue
        LOG.debug('Casting param: %s of type %s to type: %s', v, type(v), parameter_type)
        params[k] = cast(v)
    return params
Пример #13
0
    def dispatch(self, liveaction_db):
        action_db = get_action_by_ref(liveaction_db.action)
        if not action_db:
            raise Exception('Action %s not found in DB.' %
                            (liveaction_db.action))

        runnertype_db = get_runnertype_by_name(action_db.runner_type['name'])

        extra = {
            'liveaction_db': liveaction_db,
            'runnertype_db': runnertype_db
        }
        LOG.info('Dispatching Action to a runner', extra=extra)

        # Get runner instance.
        runner = get_runner(runnertype_db.runner_module)
        LOG.debug('Runner instance for RunnerType "%s" is: %s',
                  runnertype_db.name, runner)

        # Invoke pre_run, run, post_run cycle.
        liveaction_db = self._do_run(runner, runnertype_db, action_db,
                                     liveaction_db)

        extra = {'result': liveaction_db.result}
        LOG.debug('Runner do_run result', extra=extra)

        extra = {'liveaction_db': liveaction_db}
        LOG.audit('Liveaction completed', extra=extra)

        return liveaction_db.result
Пример #14
0
def get_schema_for_action_parameters(action_db):
    """
    Dynamically construct JSON schema for the provided action from the parameters metadata.

    Note: This schema is used to validate parameters which are passed to the action.
    """
    from st2common.util.action_db import get_runnertype_by_name
    runner_type = get_runnertype_by_name(action_db.runner_type['name'])

    parameters_schema = copy.deepcopy(runner_type.runner_parameters)

    for name, schema in six.iteritems(action_db.parameters):
        if name not in parameters_schema.keys():
            parameters_schema.update({name: schema})
        else:
            for attribute, value in six.iteritems(schema):
                validate_runner_parameter_attribute_override(
                    action_db.ref, name, attribute, value,
                    parameters_schema[name].get(attribute))

                parameters_schema[name][attribute] = value

    schema = get_schema_for_resource_parameters(
        parameters_schema=parameters_schema)

    if parameters_schema:
        schema['title'] = action_db.name
        if action_db.description:
            schema['description'] = action_db.description

    return schema
Пример #15
0
def register_runner(runner_type, experimental):
    # For backward compatibility reasons, we also register runners under the old names
    runner_names = [runner_type['name']] + runner_type.get('aliases', [])
    for runner_name in runner_names:
        runner_type['name'] = runner_name
        runner_experimental = runner_type.get('experimental', False)

        if runner_experimental and not experimental:
            LOG.debug('Skipping experimental runner "%s"' % (runner_name))
            continue

        # Remove additional, non db-model attributes
        non_db_attributes = ['experimental', 'aliases']
        for attribute in non_db_attributes:
            if attribute in runner_type:
                del runner_type[attribute]

        try:
            runner_type_db = get_runnertype_by_name(runner_name)
            update = True
        except StackStormDBObjectNotFoundError:
            runner_type_db = None
            update = False

        # Note: We don't want to overwrite "enabled" attribute which is already in the database
        # (aka we don't want to re-enable runner which has been disabled by the user)
        if runner_type_db and runner_type_db['enabled'] != runner_type[
                'enabled']:
            runner_type['enabled'] = runner_type_db['enabled']

        # If package is not provided, assume it's the same as module name for backward
        # compatibility reasons
        if not runner_type.get('runner_package', None):
            runner_type['runner_package'] = runner_type['runner_module']

        runner_type_api = RunnerTypeAPI(**runner_type)
        runner_type_api.validate()
        runner_type_model = RunnerTypeAPI.to_model(runner_type_api)

        if runner_type_db:
            runner_type_model.id = runner_type_db.id

        try:

            runner_type_db = RunnerType.add_or_update(runner_type_model)

            extra = {'runner_type_db': runner_type_db}
            if update:
                LOG.audit('RunnerType updated. RunnerType %s',
                          runner_type_db,
                          extra=extra)
            else:
                LOG.audit('RunnerType created. RunnerType %s',
                          runner_type_db,
                          extra=extra)
        except Exception:
            LOG.exception('Unable to register runner type %s.',
                          runner_type['name'])
            return 0
    return 1
Пример #16
0
    def dispatch(self, liveaction_db):
        action_db = get_action_by_ref(liveaction_db.action)
        if not action_db:
            raise Exception('Action %s not found in dB.' % liveaction_db.action)
        runnertype_db = get_runnertype_by_name(action_db.runner_type['name'])
        runner_type = runnertype_db.name

        LOG.info('Dispatching Action to runner \n%s',
                 json.dumps(liveaction_db.to_serializable_dict(), indent=4))
        LOG.debug('    liverunner_type: %s', runner_type)
        LOG.debug('    RunnerType: %s', runnertype_db)

        # Get runner instance.
        runner = get_runner(runnertype_db.runner_module)
        LOG.debug('Runner instance for RunnerType "%s" is: %s', runnertype_db.name, runner)

        # Invoke pre_run, run, post_run cycle.
        liveaction_db = self._do_run(runner, runnertype_db, action_db, liveaction_db)
        LOG.debug('runner do_run result: %s', liveaction_db.result)

        liveaction_serializable = liveaction_db.to_serializable_dict()

        extra = {'liveaction_db': liveaction_db}
        LOG.audit('liveaction complete.', extra=extra)
        LOG.info('result :\n%s.', json.dumps(liveaction_serializable.get('result', None), indent=4))

        return liveaction_db.result
Пример #17
0
    def _do_enforce(self):
        # TODO: Refactor this to avoid additional lookup in cast_params
        action_ref = self.rule.action['ref']

        # Verify action referenced in the rule exists in the database
        action_db = action_utils.get_action_by_ref(action_ref)
        if not action_db:
            raise ValueError('Action "%s" doesn\'t exist' % (action_ref))

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

        params = self.rule.action.parameters
        LOG.info('Invoking action %s for trigger_instance %s with params %s.',
                 self.rule.action.ref, self.trigger_instance.id,
                 json.dumps(params))

        # update trace before invoking the action.
        trace_context = self._update_trace()
        LOG.debug('Updated trace %s with rule %s.', trace_context,
                  self.rule.id)

        context, additional_contexts = self.get_action_execution_context(
            action_db=action_db, trace_context=trace_context)

        return self._invoke_action(action_db=action_db,
                                   runnertype_db=runnertype_db,
                                   params=params,
                                   context=context,
                                   additional_contexts=additional_contexts)
Пример #18
0
    def dispatch(self, liveaction_db):
        action_db = get_action_by_ref(liveaction_db.action)
        if not action_db:
            raise Exception('Action %s not found in DB.' %
                            (liveaction_db.action))

        runnertype_db = get_runnertype_by_name(action_db.runner_type['name'])

        extra = {
            'liveaction_db': liveaction_db,
            'runnertype_db': runnertype_db
        }
        LOG.info('Dispatching Action to a runner', extra=extra)

        # Get runner instance.
        runner = self._get_runner(runnertype_db, action_db, liveaction_db)
        LOG.debug('Runner instance for RunnerType "%s" is: %s',
                  runnertype_db.name, runner)

        # Process the request.
        liveaction_db = (self._do_cancel(runner, runnertype_db, action_db,
                                         liveaction_db) if liveaction_db.status
                         == action_constants.LIVEACTION_STATUS_CANCELING else
                         self._do_run(runner, runnertype_db, action_db,
                                      liveaction_db))

        return liveaction_db.result
Пример #19
0
def get_schema_for_action_parameters(action_db):
    """
    Dynamically construct JSON schema for the provided action from the parameters metadata.

    Note: This schema is used to validate parameters which are passed to the action.
    """
    from st2common.util.action_db import get_runnertype_by_name
    runner_type = get_runnertype_by_name(action_db.runner_type['name'])

    parameters_schema = copy.deepcopy(runner_type.runner_parameters)

    for name, schema in six.iteritems(action_db.parameters):
        if name not in parameters_schema.keys():
            parameters_schema.update({name: schema})
        else:
            for attribute, value in six.iteritems(schema):
                validate_runner_parameter_attribute_override(
                    action_db.ref, name, attribute,
                    value, parameters_schema[name].get(attribute))

                parameters_schema[name][attribute] = value

    schema = get_schema_for_resource_parameters(parameters_schema=parameters_schema)

    if parameters_schema:
        schema['title'] = action_db.name
        if action_db.description:
            schema['description'] = action_db.description

    return schema
Пример #20
0
    def dispatch(self, liveaction_db):
        action_db = get_action_by_ref(liveaction_db.action)
        if not action_db:
            raise Exception('Action %s not found in dB.' %
                            liveaction_db.action)
        runnertype_db = get_runnertype_by_name(action_db.runner_type['name'])
        runner_type = runnertype_db.name

        LOG.info('Dispatching Action to runner \n%s',
                 json.dumps(liveaction_db.to_serializable_dict(), indent=4))
        LOG.debug('    liverunner_type: %s', runner_type)
        LOG.debug('    RunnerType: %s', runnertype_db)

        # Get runner instance.
        runner = get_runner(runnertype_db.runner_module)
        LOG.debug('Runner instance for RunnerType "%s" is: %s',
                  runnertype_db.name, runner)

        # Invoke pre_run, run, post_run cycle.
        liveaction_db = self._do_run(runner, runnertype_db, action_db,
                                     liveaction_db)
        LOG.debug('runner do_run result: %s', liveaction_db.result)

        liveaction_serializable = liveaction_db.to_serializable_dict()

        extra = {'liveaction_db': liveaction_db}
        LOG.audit('liveaction complete.', extra=extra)
        LOG.info(
            'result :\n%s.',
            json.dumps(liveaction_serializable.get('result', None), indent=4))

        return liveaction_db.result
Пример #21
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)
Пример #22
0
def register_runner_types():
    LOG.debug('Start : register default RunnerTypes.')

    for runnertype in RUNNER_TYPES:
        try:
            runnertype_db = get_runnertype_by_name(runnertype['name'])
            update = True
        except StackStormDBObjectNotFoundError:
            runnertype_db = None
            update = False

        runnertype_api = RunnerTypeAPI(**runnertype)
        runnertype_api.validate()
        runner_type_model = RunnerTypeAPI.to_model(runnertype_api)

        if runnertype_db:
            runner_type_model.id = runnertype_db.id

        try:
            runnertype_db = RunnerType.add_or_update(runner_type_model)

            extra = {'runnertype_db': runnertype_db}
            if update:
                LOG.audit('RunnerType updated. RunnerType %s',
                          runnertype_db,
                          extra=extra)
            else:
                LOG.audit('RunnerType created. RunnerType %s',
                          runnertype_db,
                          extra=extra)
        except Exception:
            LOG.exception('Unable to register runner type %s.',
                          runnertype['name'])

    LOG.debug('End : register default RunnerTypes.')
Пример #23
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
Пример #24
0
def cast_params(action_ref, params, cast_overrides=None):
    """"""
    params = params or {}
    action_db = action_db_util.get_action_by_ref(action_ref)

    if not action_db:
        raise ValueError('Action with ref "%s" doesn\'t exist' % (action_ref))

    action_parameters_schema = action_db.parameters
    runnertype_db = action_db_util.get_runnertype_by_name(
        action_db.runner_type["name"])
    runner_parameters_schema = runnertype_db.runner_parameters
    # combine into 1 list of parameter schemas
    parameters_schema = {}
    if runner_parameters_schema:
        parameters_schema.update(runner_parameters_schema)
    if action_parameters_schema:
        parameters_schema.update(action_parameters_schema)
    # cast each param individually
    for k, v in six.iteritems(params):
        parameter_schema = parameters_schema.get(k, None)
        if not parameter_schema:
            LOG.debug(
                "Will skip cast of param[name: %s, value: %s]. No schema.", k,
                v)
            continue
        parameter_type = parameter_schema.get("type", None)
        if not parameter_type:
            LOG.debug("Will skip cast of param[name: %s, value: %s]. No type.",
                      k, v)
            continue
        # Pick up cast from teh override and then from the system suppied ones.
        cast = cast_overrides.get(parameter_type,
                                  None) if cast_overrides else None
        if not cast:
            cast = get_cast(cast_type=parameter_type)
        if not cast:
            LOG.debug(
                "Will skip cast of param[name: %s, value: %s]. No cast for %s.",
                k,
                v,
                parameter_type,
            )
            continue
        LOG.debug("Casting param: %s of type %s to type: %s", v, type(v),
                  parameter_type)

        try:
            params[k] = cast(v)
        except Exception as e:
            v_type = type(v).__name__
            msg = (
                'Failed to cast value "%s" (type: %s) for parameter "%s" of type "%s": %s. '
                "Perhaps the value is of an invalid type?" %
                (v, v_type, k, parameter_type, six.text_type(e)))
            raise ValueError(msg)

    return params
Пример #25
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)
Пример #26
0
def register_runner_types(experimental=False):
    """
    :param experimental: True to also register experimental runners.
    :type experimental: ``bool``
    """
    LOG.debug('Start : register default RunnerTypes.')

    for runner_type in RUNNER_TYPES:
        runner_type = copy.deepcopy(runner_type)

        # For backward compatibility reasons, we also register runners under the old names
        runner_names = [runner_type['name']] + runner_type.get('aliases', [])
        for runner_name in runner_names:
            runner_type['name'] = runner_name
            runner_experimental = runner_type.get('experimental', False)

            if runner_experimental and not experimental:
                LOG.debug('Skipping experimental runner "%s"' % (runner_name))
                continue

            # Remove additional, non db-model attributes
            non_db_attributes = ['experimental', 'aliases']
            for attribute in non_db_attributes:
                if attribute in runner_type:
                    del runner_type[attribute]

            try:
                runner_type_db = get_runnertype_by_name(runner_name)
                update = True
            except StackStormDBObjectNotFoundError:
                runner_type_db = None
                update = False

            # Note: We don't want to overwrite "enabled" attribute which is already in the database
            # (aka we don't want to re-enable runner which has been disabled by the user)
            if runner_type_db and runner_type_db['enabled'] != runner_type['enabled']:
                runner_type['enabled'] = runner_type_db['enabled']

            runner_type_api = RunnerTypeAPI(**runner_type)
            runner_type_api.validate()
            runner_type_model = RunnerTypeAPI.to_model(runner_type_api)

            if runner_type_db:
                runner_type_model.id = runner_type_db.id

            try:
                runner_type_db = RunnerType.add_or_update(runner_type_model)

                extra = {'runner_type_db': runner_type_db}
                if update:
                    LOG.audit('RunnerType updated. RunnerType %s', runner_type_db, extra=extra)
                else:
                    LOG.audit('RunnerType created. RunnerType %s', runner_type_db, extra=extra)
            except Exception:
                LOG.exception('Unable to register runner type %s.', runner_type['name'])

    LOG.debug('End : register default RunnerTypes.')
Пример #27
0
def _get_runner_model(action_api):
    runner_db = None
    # Check if runner exists.
    try:
        runner_db = get_runnertype_by_name(action_api.runner_type)
    except StackStormDBObjectNotFoundError:
        msg = 'RunnerType %s is not found.' % action_api.runner_type
        raise ValueValidationException(msg)
    return runner_db
Пример #28
0
def register_runner_types(experimental=False):
    """
    :param experimental: True to also register experimental runners.
    :type experimental: ``bool``
    """
    LOG.debug('Start : register default RunnerTypes.')

    for runner_type in RUNNER_TYPES:
        runner_type = copy.deepcopy(runner_type)

        # For backward compatibility reasons, we also register runners under the old names
        runner_names = [runner_type['name']] + runner_type.get('aliases', [])
        for runner_name in runner_names:
            runner_type['name'] = runner_name
            runner_experimental = runner_type.get('experimental', False)

            if runner_experimental and not experimental:
                LOG.debug('Skipping experimental runner "%s"' % (runner_name))
                continue

            # Remove additional, non db-model attributes
            non_db_attributes = ['experimental', 'aliases']
            for attribute in non_db_attributes:
                if attribute in runner_type:
                    del runner_type[attribute]

            try:
                runner_type_db = get_runnertype_by_name(runner_name)
                update = True
            except StackStormDBObjectNotFoundError:
                runner_type_db = None
                update = False

            runner_type_api = RunnerTypeAPI(**runner_type)
            runner_type_api.validate()
            runner_type_model = RunnerTypeAPI.to_model(runner_type_api)

            if runner_type_db:
                runner_type_model.id = runner_type_db.id

            try:
                runner_type_db = RunnerType.add_or_update(runner_type_model)

                extra = {'runner_type_db': runner_type_db}
                if update:
                    LOG.audit('RunnerType updated. RunnerType %s',
                              runner_type_db,
                              extra=extra)
                else:
                    LOG.audit('RunnerType created. RunnerType %s',
                              runner_type_db,
                              extra=extra)
            except Exception:
                LOG.exception('Unable to register runner type %s.',
                              runner_type['name'])

    LOG.debug('End : register default RunnerTypes.')
Пример #29
0
def _get_runner_model(action_api):
    runner_db = None
    # Check if runner exists.
    try:
        runner_db = get_runnertype_by_name(action_api.runner_type)
    except StackStormDBObjectNotFoundError:
        msg = 'RunnerType %s is not found.' % action_api.runner_type
        raise ValueValidationException(msg)
    return runner_db
Пример #30
0
def request(wf_def, ac_ex_db, st2_ctx):
    wf_ac_ex_id = str(ac_ex_db.id)
    LOG.info('[%s] Processing action execution request for workflow.',
             wf_ac_ex_id)

    # Load workflow definition into workflow spec model.
    spec_module = specs_loader.get_spec_module('native')
    wf_spec = spec_module.instantiate(wf_def)

    # Inspect the workflow spec.
    inspect(wf_spec, st2_ctx, raise_exception=True)

    # Identify the action to execute.
    action_db = action_utils.get_action_by_ref(ref=ac_ex_db.action['ref'])

    if not action_db:
        error = 'Unable to find action "%s".' % ac_ex_db.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'])

    # Render action execution parameters.
    runner_params, action_params = param_utils.render_final_params(
        runner_type_db.runner_parameters, action_db.parameters,
        ac_ex_db.parameters, ac_ex_db.context)

    # Instantiate the workflow conductor.
    conductor_params = {'inputs': action_params, 'context': st2_ctx}
    conductor = conducting.WorkflowConductor(wf_spec, **conductor_params)

    # Set the initial workflow state to requested.
    conductor.request_workflow_state(states.REQUESTED)

    # Serialize the conductor which initializes some internal values.
    data = conductor.serialize()

    # Create a record for workflow execution.
    wf_ex_db = wf_db_models.WorkflowExecutionDB(action_execution=str(
        ac_ex_db.id),
                                                spec=data['spec'],
                                                graph=data['graph'],
                                                flow=data['flow'],
                                                context=data['context'],
                                                input=data['input'],
                                                output=data['output'],
                                                errors=data['errors'],
                                                status=data['state'])

    # Insert new record into the database and publish to the message bus.
    wf_ex_db = wf_db_access.WorkflowExecution.insert(wf_ex_db, publish=True)
    LOG.info('[%s] Workflow execution "%s" created.', wf_ac_ex_id,
             str(wf_ex_db.id))

    return wf_ex_db
Пример #31
0
def respond(inquiry, response, requester=None):
    # Set requester to system user is not provided.
    if not requester:
        requester = cfg.CONF.system_user.user

    # Retrieve the liveaction from the database.
    liveaction_db = lv_db_access.LiveAction.get_by_id(inquiry.liveaction.get('id'))

    # Resume the parent workflow first. If the action execution for the inquiry is updated first,
    # it triggers handling of the action execution completion which will interact with the paused
    # parent workflow. The resuming logic that is executed here will then race with the completion
    # of the inquiry action execution, which will randomly result in the parent workflow stuck in
    # paused state.
    if liveaction_db.context.get('parent'):
        LOG.debug('Resuming workflow parent(s) for inquiry "%s".' % str(inquiry.id))

        # For action execution under Action Chain and Mistral workflows, request the entire
        # workflow to resume. Orquesta handles resume differently and so does not require root
        # to resume. Orquesta allows for specifc branches to resume while other is paused. When
        # there is no other paused branches, the conductor will resume the rest of the workflow.
        resume_target = (
            action_service.get_parent_liveaction(liveaction_db)
            if workflow_service.is_action_execution_under_workflow_context(liveaction_db)
            else action_service.get_root_liveaction(liveaction_db)
        )

        if resume_target.status in action_constants.LIVEACTION_PAUSE_STATES:
            action_service.request_resume(resume_target, requester)

    # Succeed the liveaction and update result with the inquiry response.
    LOG.debug('Updating response for inquiry "%s".' % str(inquiry.id))

    result = copy.deepcopy(inquiry.result)
    result['response'] = response

    liveaction_db = action_utils.update_liveaction_status(
        status=action_constants.LIVEACTION_STATUS_SUCCEEDED,
        end_timestamp=date_utils.get_datetime_utc_now(),
        runner_info=sys_info_utils.get_process_info(),
        result=result,
        liveaction_id=str(liveaction_db.id)
    )

    # Sync the liveaction with the corresponding action execution.
    execution_service.update_execution(liveaction_db)

    # Invoke inquiry post run to trigger a callback to parent workflow.
    LOG.debug('Invoking post run for inquiry "%s".' % str(inquiry.id))
    runner_container = container.get_runner_container()
    action_db = action_utils.get_action_by_ref(liveaction_db.action)
    runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name'])
    runner = runner_container._get_runner(runnertype_db, action_db, liveaction_db)
    runner.post_run(status=action_constants.LIVEACTION_STATUS_SUCCEEDED, result=result)

    return liveaction_db
Пример #32
0
def get_runner_model(action_api):
    runner_db = None
    # Check if runner exists.
    try:
        runner_db = get_runnertype_by_name(action_api.runner_type)
    except StackStormDBObjectNotFoundError:
        msg = ('RunnerType %s is not found. If you are using old and deprecated runner name, you '
               'need to switch to a new one. For more information, please see '
               'https://docs.stackstorm.com/upgrade_notes.html#st2-v0-9' % (action_api.runner_type))
        raise ValueValidationException(msg)
    return runner_db
Пример #33
0
def register_runner(runner_type, experimental):
    # For backward compatibility reasons, we also register runners under the old names
    runner_names = [runner_type['name']] + runner_type.get('aliases', [])
    for runner_name in runner_names:
        runner_type['name'] = runner_name
        runner_experimental = runner_type.get('experimental', False)

        if runner_experimental and not experimental:
            LOG.debug('Skipping experimental runner "%s"' % (runner_name))
            continue

        # Remove additional, non db-model attributes
        non_db_attributes = ['experimental', 'aliases']
        for attribute in non_db_attributes:
            if attribute in runner_type:
                del runner_type[attribute]

        try:
            runner_type_db = get_runnertype_by_name(runner_name)
            update = True
        except StackStormDBObjectNotFoundError:
            runner_type_db = None
            update = False

        # Note: We don't want to overwrite "enabled" attribute which is already in the database
        # (aka we don't want to re-enable runner which has been disabled by the user)
        if runner_type_db and runner_type_db['enabled'] != runner_type['enabled']:
            runner_type['enabled'] = runner_type_db['enabled']

        # If package is not provided, assume it's the same as module name for backward
        # compatibility reasons
        if not runner_type.get('runner_package', None):
            runner_type['runner_package'] = runner_type['runner_module']

        runner_type_api = RunnerTypeAPI(**runner_type)
        runner_type_api.validate()
        runner_type_model = RunnerTypeAPI.to_model(runner_type_api)

        if runner_type_db:
            runner_type_model.id = runner_type_db.id

        try:

            runner_type_db = RunnerType.add_or_update(runner_type_model)

            extra = {'runner_type_db': runner_type_db}
            if update:
                LOG.audit('RunnerType updated. RunnerType %s', runner_type_db, extra=extra)
            else:
                LOG.audit('RunnerType created. RunnerType %s', runner_type_db, extra=extra)
        except Exception:
            LOG.exception('Unable to register runner type %s.', runner_type['name'])
            return 0
    return 1
Пример #34
0
    def _invoke_action(self,
                       action_db,
                       runnertype_db,
                       params,
                       context=None,
                       additional_contexts=None):
        """
        Schedule an action execution.

        :type action_exec_spec: :class:`ActionExecutionSpecDB`

        :param params: Partially rendered parameters to execute the action with.
        :type params: ``dict``

        :rtype: :class:`LiveActionDB` on successful scheduling, None otherwise.
        """
        action_ref = action_db.ref
        runnertype_db = action_utils.get_runnertype_by_name(
            action_db.runner_type['name'])

        liveaction_db = LiveActionDB(action=action_ref,
                                     context=context,
                                     parameters=params)

        try:
            liveaction_db.parameters = self.get_resolved_parameters(
                runnertype_db=runnertype_db,
                action_db=action_db,
                params=liveaction_db.parameters,
                context=liveaction_db.context,
                additional_contexts=additional_contexts)
        except param_exc.ParamException as e:
            # We still need to create a request, so liveaction_db is assigned an ID
            liveaction_db, execution_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))

        liveaction_db, execution_db = action_service.request(liveaction_db)

        return execution_db
Пример #35
0
    def _cast_params(action_ref, params):
        def cast_object(x):
            if isinstance(x, str) or isinstance(x, unicode):
                try:
                    return json.loads(x)
                except:
                    return ast.literal_eval(x)
            else:
                return x

        casts = {
            'array': (lambda x: ast.literal_eval(x)
                      if isinstance(x, str) or isinstance(x, unicode) else x),
            'boolean':
            (lambda x: ast.literal_eval(x.capitalize())
             if isinstance(x, str) or isinstance(x, unicode) else x),
            'integer':
            int,
            'number':
            float,
            'object':
            cast_object,
            'string':
            str
        }

        action_db = action_db_util.get_action_by_ref(action_ref)
        action_parameters_schema = action_db.parameters
        runnertype_db = action_db_util.get_runnertype_by_name(
            action_db.runner_type['name'])
        runner_parameters_schema = runnertype_db.runner_parameters
        # combine into 1 list of parameter schemas
        parameters_schema = {}
        if runner_parameters_schema:
            parameters_schema.update(runner_parameters_schema)
        if action_parameters_schema:
            parameters_schema.update(action_parameters_schema)
        # cast each param individually
        for k, v in six.iteritems(params):
            parameter_schema = parameters_schema.get(k, None)
            if not parameter_schema:
                continue
            parameter_type = parameter_schema.get('type', None)
            if not parameter_type:
                continue
            cast = casts.get(parameter_type, None)
            LOG.debug('Casting param: %s of type %s to type: %s', v, type(v),
                      parameter_type)
            if not cast:
                continue
            params[k] = cast(v)
        return params
Пример #36
0
def register_runner_types(experimental=False):
    """
    :param experimental: True to also register experimental runners.
    :type experimental: ``bool``
    """
    LOG.debug("Start : register default RunnerTypes.")

    for runner_type in RUNNER_TYPES:
        runner_type = copy.deepcopy(runner_type)

        # For backward compatibility reasons, we also register runners under the old names
        runner_names = [runner_type["name"]] + runner_type.get("aliases", [])
        for runner_name in runner_names:
            runner_type["name"] = runner_name
            runner_experimental = runner_type.get("experimental", False)

            if runner_experimental and not experimental:
                LOG.debug('Skipping experimental runner "%s"' % (runner_name))
                continue

            # Remove additional, non db-model attributes
            non_db_attributes = ["experimental", "aliases"]
            for attribute in non_db_attributes:
                if attribute in runner_type:
                    del runner_type[attribute]

            try:
                runner_type_db = get_runnertype_by_name(runner_name)
                update = True
            except StackStormDBObjectNotFoundError:
                runner_type_db = None
                update = False

            runner_type_api = RunnerTypeAPI(**runner_type)
            runner_type_api.validate()
            runner_type_model = RunnerTypeAPI.to_model(runner_type_api)

            if runner_type_db:
                runner_type_model.id = runner_type_db.id

            try:
                runner_type_db = RunnerType.add_or_update(runner_type_model)

                extra = {"runner_type_db": runner_type_db}
                if update:
                    LOG.audit("RunnerType updated. RunnerType %s", runner_type_db, extra=extra)
                else:
                    LOG.audit("RunnerType created. RunnerType %s", runner_type_db, extra=extra)
            except Exception:
                LOG.exception("Unable to register runner type %s.", runner_type["name"])

    LOG.debug("End : register default RunnerTypes.")
Пример #37
0
def invoke_post_run(liveaction_db, action_db=None):
    # NOTE: This import has intentionally been moved here to avoid massive performance overhead
    # (1+ second) for other functions inside this module which don't need to use those imports.
    from st2common.runners import base as runners
    from st2common.util import action_db as action_db_utils
    from st2common.content import utils as content_utils

    LOG.info("Invoking post run for action execution %s.", liveaction_db.id)

    # Identify action and runner.
    if not action_db:
        action_db = action_db_utils.get_action_by_ref(liveaction_db.action)

    if not action_db:
        LOG.error(
            "Unable to invoke post run. Action %s no longer exists.",
            liveaction_db.action,
        )
        return

    LOG.info(
        "Action execution %s runs %s of runner type %s.",
        liveaction_db.id,
        action_db.name,
        action_db.runner_type["name"],
    )

    # Get instance of the action runner and related configuration.
    runner_type_db = action_db_utils.get_runnertype_by_name(
        action_db.runner_type["name"])

    runner = runners.get_runner(name=runner_type_db.name)

    entry_point = content_utils.get_entry_point_abs_path(
        pack=action_db.pack, entry_point=action_db.entry_point)

    libs_dir_path = content_utils.get_action_libs_abs_path(
        pack=action_db.pack, entry_point=action_db.entry_point)

    # Configure the action runner.
    runner.runner_type_db = runner_type_db
    runner.action = action_db
    runner.action_name = action_db.name
    runner.liveaction = liveaction_db
    runner.liveaction_id = str(liveaction_db.id)
    runner.entry_point = entry_point
    runner.context = getattr(liveaction_db, "context", dict())
    runner.callback = getattr(liveaction_db, "callback", dict())
    runner.libs_dir_path = libs_dir_path

    # Invoke the post_run method.
    runner.post_run(liveaction_db.status, liveaction_db.result)
Пример #38
0
def schedule(liveaction):
    """
    Schedule an action to be run.

    :return: (liveaction, execution)
    :rtype: tuple
    """
    # Use the user context from the parent action execution. Subtasks in a workflow
    # action can be invoked by a system user and so we want to use the user context
    # from the original workflow action.
    if getattr(liveaction, 'context', None) and 'parent' in liveaction.context:
        parent = LiveAction.get_by_id(liveaction.context['parent'])
        liveaction.context['user'] = getattr(parent, 'context', dict()).get('user')

    # Validate action.
    action_db = action_utils.get_action_by_ref(liveaction.action)
    if not action_db:
        raise ValueError('Action "%s" cannot be found.' % liveaction.action)
    if not action_db.enabled:
        raise ValueError('Unable to execute. Action "%s" is disabled.' % liveaction.action)

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

    if not hasattr(liveaction, 'parameters'):
        liveaction.parameters = dict()

    # Validate action parameters.
    schema = util_schema.get_parameter_schema(action_db)
    validator = util_schema.get_validator()
    jsonschema.validate(liveaction.parameters, schema, validator)

    # validate that no immutable params are being overriden. Although possible to
    # ignore the override it is safer to inform the user to avoid surprises.
    immutables = _get_immutable_params(action_db.parameters)
    immutables.extend(_get_immutable_params(runnertype_db.runner_parameters))
    overridden_immutables = [p for p in six.iterkeys(liveaction.parameters) if p in immutables]
    if len(overridden_immutables) > 0:
        raise ValueError('Override of immutable parameter(s) %s is unsupported.'
                         % str(overridden_immutables))

    # Write to database and send to message queue.
    liveaction.status = LIVEACTION_STATUS_SCHEDULED
    liveaction.start_timestamp = isotime.add_utc_tz(datetime.datetime.utcnow())
    # Publish creation after both liveaction and actionexecution are created.
    liveaction = LiveAction.add_or_update(liveaction, publish=False)
    execution = executions.create_execution_object(liveaction, publish=False)
    # assume that this is a creation.
    LiveAction.publish_create(liveaction)
    ActionExecution.publish_create(execution)
    LOG.audit('Action execution scheduled. LiveAction=%s. ActionExecution=%s', liveaction,
              execution)
    return liveaction, execution
Пример #39
0
def get_runner_model(action_api):
    runner_db = None
    # Check if runner exists.
    try:
        runner_db = get_runnertype_by_name(action_api.runner_type)
    except StackStormDBObjectNotFoundError:
        msg = (
            'RunnerType %s is not found. If you are using old and deprecated runner name, you '
            'need to switch to a new one. For more information, please see '
            'https://docs.stackstorm.com/upgrade_notes.html#st2-v0-9' %
            (action_api.runner_type))
        raise ValueValidationException(msg)
    return runner_db
Пример #40
0
def request(wf_def, ac_ex_db):
    # Load workflow definition into workflow spec model.
    spec_module = specs_loader.get_spec_module('native')
    wf_spec = spec_module.instantiate(wf_def)

    # Inspect the workflow spec.
    wf_spec.inspect(raise_exception=True)

    # Identify the action to execute.
    action_db = ac_db_util.get_action_by_ref(ref=ac_ex_db.action['ref'])

    if not action_db:
        error = 'Unable to find action "%s".' % ac_ex_db.action['ref']
        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'])

    # Render action execution parameters.
    runner_params, action_params = param_utils.render_final_params(
        runner_type_db.runner_parameters,
        action_db.parameters,
        ac_ex_db.parameters,
        ac_ex_db.context
    )

    # Instantiate the workflow conductor.
    conductor = conducting.WorkflowConductor(wf_spec, **action_params)
    conductor.set_workflow_state(states.REQUESTED)

    # Serialize the conductor which initializes some internal values.
    data = conductor.serialize()

    # Create a record for workflow execution.
    wf_ex_db = wf_db_models.WorkflowExecutionDB(
        action_execution=str(ac_ex_db.id),
        spec=data['spec'],
        graph=data['graph'],
        flow=data['flow'],
        input=data['input'],
        output=data['output'],
        errors=data['errors'],
        status=data['state']
    )

    # Insert new record into the database and publish to the message bus.
    wf_ex_db = wf_db_access.WorkflowExecution.insert(wf_ex_db, publish=True)

    return wf_ex_db
Пример #41
0
def cast_params(action_ref, params, cast_overrides=None):
    """
    """
    params = params or {}
    action_db = action_db_util.get_action_by_ref(action_ref)

    if not action_db:
        raise ValueError('Action with ref "%s" doesn\'t exist' % (action_ref))

    action_parameters_schema = action_db.parameters
    runnertype_db = action_db_util.get_runnertype_by_name(action_db.runner_type['name'])
    runner_parameters_schema = runnertype_db.runner_parameters
    # combine into 1 list of parameter schemas
    parameters_schema = {}
    if runner_parameters_schema:
        parameters_schema.update(runner_parameters_schema)
    if action_parameters_schema:
        parameters_schema.update(action_parameters_schema)
    # cast each param individually
    for k, v in six.iteritems(params):
        parameter_schema = parameters_schema.get(k, None)
        if not parameter_schema:
            LOG.debug('Will skip cast of param[name: %s, value: %s]. No schema.', k, v)
            continue
        parameter_type = parameter_schema.get('type', None)
        if not parameter_type:
            LOG.debug('Will skip cast of param[name: %s, value: %s]. No type.', k, v)
            continue
        # Pick up cast from teh override and then from the system suppied ones.
        cast = cast_overrides.get(parameter_type, None) if cast_overrides else None
        if not cast:
            cast = get_cast(cast_type=parameter_type)
        if not cast:
            LOG.debug('Will skip cast of param[name: %s, value: %s]. No cast for %s.', k, v,
                      parameter_type)
            continue
        LOG.debug('Casting param: %s of type %s to type: %s', v, type(v), parameter_type)

        try:
            params[k] = cast(v)
        except Exception as e:
            v_type = type(v).__name__
            msg = ('Failed to cast value "%s" (type: %s) for parameter "%s" of type "%s": %s. '
                   'Perhaphs the value is of an invalid type?' %
                   (v, v_type, k, parameter_type, str(e)))
            raise ValueError(msg)

    return params
Пример #42
0
def get_parameter_schema(model):
    # Dynamically construct JSON schema from the parameters metadata.
    schema = {}
    from st2common.util.action_db import get_runnertype_by_name
    runner_type = get_runnertype_by_name(model.runner_type['name'])
    normalize = lambda x: {k: v if v else SCHEMA_ANY_TYPE for k, v in six.iteritems(x)}
    properties = normalize(runner_type.runner_parameters)
    properties.update(normalize(model.parameters))
    if properties:
        schema['title'] = model.name
        if model.description:
            schema['description'] = model.description
        schema['type'] = 'object'
        schema['properties'] = properties
        schema['additionalProperties'] = False
    return schema
Пример #43
0
def cast_params(action_ref, params, cast_overrides=None):
    """
    """
    params = params or {}
    action_db = action_db_util.get_action_by_ref(action_ref)

    if not action_db:
        raise ValueError('Action with ref "%s" doesn\'t exist' % (action_ref))

    action_parameters_schema = action_db.parameters
    runnertype_db = action_db_util.get_runnertype_by_name(
        action_db.runner_type['name'])
    runner_parameters_schema = runnertype_db.runner_parameters
    # combine into 1 list of parameter schemas
    parameters_schema = {}
    if runner_parameters_schema:
        parameters_schema.update(runner_parameters_schema)
    if action_parameters_schema:
        parameters_schema.update(action_parameters_schema)
    # cast each param individually
    for k, v in six.iteritems(params):
        parameter_schema = parameters_schema.get(k, None)
        if not parameter_schema:
            LOG.debug(
                'Will skip cast of param[name: %s, value: %s]. No schema.', k,
                v)
            continue
        parameter_type = parameter_schema.get('type', None)
        if not parameter_type:
            LOG.debug('Will skip cast of param[name: %s, value: %s]. No type.',
                      k, v)
            continue
        # Pick up cast from teh override and then from the system suppied ones.
        cast = cast_overrides.get(parameter_type,
                                  None) if cast_overrides else None
        if not cast:
            cast = get_cast(cast_type=parameter_type)
        if not cast:
            LOG.debug(
                'Will skip cast of param[name: %s, value: %s]. No cast for %s.',
                k, v, parameter_type)
            continue
        LOG.debug('Casting param: %s of type %s to type: %s', v, type(v),
                  parameter_type)
        params[k] = cast(v)
    return params
Пример #44
0
def validate_action(action_api):
    runner_db = None
    # Check if runner exists.
    try:
        runner_db = get_runnertype_by_name(action_api.runner_type)
    except StackStormDBObjectNotFoundError:
        msg = 'RunnerType %s is not found.' % action_api.runner_type
        raise ValueValidationException(msg)

    # Check if pack is valid.
    if not _is_valid_pack(action_api.pack):
        msg = 'Content pack %s does not exist in %s.' % (
            action_api.pack, cfg.CONF.content.packs_base_path)
        raise ValueValidationException(msg)

    # Check if parameters defined are valid.
    _validate_parameters(action_api.parameters, runner_db.runner_parameters)
Пример #45
0
def get_schema_for_action_parameters(action_db, runnertype_db=None):
    """
    Dynamically construct JSON schema for the provided action from the parameters metadata.

    Note: This schema is used to validate parameters which are passed to the action.
    """
    if not runnertype_db:
        from st2common.util.action_db import get_runnertype_by_name

        runnertype_db = get_runnertype_by_name(action_db.runner_type["name"])

    # Note: We need to perform a deep merge because user can only specify a single parameter
    # attribute when overriding it in an action metadata.
    parameters_schema = {}
    deep_update(parameters_schema, runnertype_db.runner_parameters)
    deep_update(parameters_schema, action_db.parameters)

    # Perform validation, make sure user is not providing parameters which can't
    # be overriden
    runner_parameter_names = list(runnertype_db.runner_parameters.keys())

    for name, schema in six.iteritems(action_db.parameters):
        if name not in runner_parameter_names:
            continue

        for attribute, value in six.iteritems(schema):
            runner_param_value = runnertype_db.runner_parameters[name].get(
                attribute)
            validate_runner_parameter_attribute_override(
                action_ref=action_db.ref,
                param_name=name,
                attr_name=attribute,
                runner_param_attr_value=runner_param_value,
                action_param_attr_value=value,
            )

    schema = get_schema_for_resource_parameters(
        parameters_schema=parameters_schema)

    if parameters_schema:
        schema["title"] = action_db.name
        if action_db.description:
            schema["description"] = action_db.description

    return schema
Пример #46
0
def validate_action(action_api):
    runner_db = None
    # Check if runner exists.
    try:
        runner_db = get_runnertype_by_name(action_api.runner_type)
    except StackStormDBObjectNotFoundError:
        msg = 'RunnerType %s is not found.' % action_api.runner_type
        raise ValueValidationException(msg)

    # Check if pack is valid.
    if not _is_valid_pack(action_api.pack):
        msg = 'Content pack %s does not exist in %s.' % (
            action_api.pack,
            cfg.CONF.content.packs_base_path)
        raise ValueValidationException(msg)

    # Check if parameters defined are valid.
    _validate_parameters(action_api.parameters, runner_db.runner_parameters)
Пример #47
0
    def dispatch(self, liveaction_db):
        action_db = get_action_by_ref(liveaction_db.action)
        if not action_db:
            raise Exception("Action %s not found in DB." %
                            (liveaction_db.action))

        liveaction_db.context["pack"] = action_db.pack

        runner_type_db = get_runnertype_by_name(action_db.runner_type["name"])

        extra = {
            "liveaction_db": liveaction_db,
            "runner_type_db": runner_type_db
        }
        LOG.info("Dispatching Action to a runner", extra=extra)

        # Get runner instance.
        runner = self._get_runner(runner_type_db, action_db, liveaction_db)

        LOG.debug('Runner instance for RunnerType "%s" is: %s',
                  runner_type_db.name, runner)

        # Process the request.
        funcs = {
            action_constants.LIVEACTION_STATUS_REQUESTED: self._do_run,
            action_constants.LIVEACTION_STATUS_SCHEDULED: self._do_run,
            action_constants.LIVEACTION_STATUS_RUNNING: self._do_run,
            action_constants.LIVEACTION_STATUS_CANCELING: self._do_cancel,
            action_constants.LIVEACTION_STATUS_PAUSING: self._do_pause,
            action_constants.LIVEACTION_STATUS_RESUMING: self._do_resume,
        }

        if liveaction_db.status not in funcs:
            raise actionrunner.ActionRunnerDispatchError(
                "Action runner is unable to dispatch the liveaction because it is "
                'in an unsupported status of "%s".' % liveaction_db.status)

        with CounterWithTimer(key="action.executions"):
            status = liveaction_db.status
            with CounterWithTimer(key="action.executions.process.%s" %
                                  (status)):
                liveaction_db = funcs[liveaction_db.status](runner)

        return liveaction_db.result
Пример #48
0
    def dispatch(self, liveaction_db):
        action_db = get_action_by_ref(liveaction_db.action)
        if not action_db:
            raise Exception('Action %s not found in DB.' %
                            (liveaction_db.action))

        liveaction_db.context['pack'] = action_db.pack

        runnertype_db = get_runnertype_by_name(action_db.runner_type['name'])

        extra = {
            'liveaction_db': liveaction_db,
            'runnertype_db': runnertype_db
        }
        LOG.info('Dispatching Action to a runner', extra=extra)

        # Get runner instance.
        runner = self._get_runner(runnertype_db, action_db, liveaction_db)

        LOG.debug('Runner instance for RunnerType "%s" is: %s',
                  runnertype_db.name, runner)

        # Process the request.
        funcs = {
            action_constants.LIVEACTION_STATUS_REQUESTED: self._do_run,
            action_constants.LIVEACTION_STATUS_SCHEDULED: self._do_run,
            action_constants.LIVEACTION_STATUS_RUNNING: self._do_run,
            action_constants.LIVEACTION_STATUS_CANCELING: self._do_cancel,
            action_constants.LIVEACTION_STATUS_PAUSING: self._do_pause,
            action_constants.LIVEACTION_STATUS_RESUMING: self._do_resume
        }

        if liveaction_db.status not in funcs:
            raise actionrunner.ActionRunnerDispatchError(
                'Action runner is unable to dispatch the liveaction because it is '
                'in an unsupported status of "%s".' % liveaction_db.status)

        liveaction_db = funcs[liveaction_db.status](
            runner=runner,
            runnertype_db=runnertype_db,
            action_db=action_db,
            liveaction_db=liveaction_db)

        return liveaction_db.result
Пример #49
0
    def _invoke_action(self, action_db, runnertype_db, params, context=None,
                       additional_contexts=None):
        """
        Schedule an action execution.

        :type action_exec_spec: :class:`ActionExecutionSpecDB`

        :param params: Partially rendered parameters to execute the action with.
        :type params: ``dict``

        :rtype: :class:`LiveActionDB` on successful scheduling, None otherwise.
        """
        action_ref = action_db.ref
        runnertype_db = action_utils.get_runnertype_by_name(action_db.runner_type['name'])

        liveaction_db = LiveActionDB(action=action_ref, context=context, parameters=params)

        try:
            liveaction_db.parameters = self.get_resolved_parameters(
                runnertype_db=runnertype_db,
                action_db=action_db,
                params=liveaction_db.parameters,
                context=liveaction_db.context,
                additional_contexts=additional_contexts)
        except param_exc.ParamException as e:
            # We still need to create a request, so liveaction_db is assigned an ID
            liveaction_db, execution_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': 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))

        liveaction_db, execution_db = action_service.request(liveaction_db)

        return execution_db
Пример #50
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)
Пример #51
0
    def _cast_params(action_ref, params):
        casts = {
            'array': (lambda x: ast.literal_eval(x)
                      if isinstance(x, str) or isinstance(x, unicode) else x),
            'boolean':
            (lambda x: ast.literal_eval(x.capitalize())
             if isinstance(x, str) or isinstance(x, unicode) else x),
            'integer':
            int,
            'number':
            float,
            'object': (lambda x: json.loads(x)
                       if isinstance(x, str) or isinstance(x, unicode) else x),
            'string':
            str
        }

        action_db = action_db_util.get_action_by_ref(
            ResourceReference.from_string_reference(ref=action_ref))
        action_parameters_schema = action_db.parameters
        runnertype_db = action_db_util.get_runnertype_by_name(
            action_db.runner_type['name'])
        runner_parameters_schema = runnertype_db.runner_parameters
        # combine into 1 list of parameter schemas
        parameters_schema = {}
        if runner_parameters_schema:
            parameters_schema.update(runner_parameters_schema)
        if action_parameters_schema:
            parameters_schema.update(action_parameters_schema)
        # cast each param individually
        for k, v in six.iteritems(params):
            parameter_schema = parameters_schema.get(k, None)
            if not parameter_schema:
                continue
            parameter_type = parameter_schema.get('type', None)
            if not parameter_type:
                continue
            cast = casts.get(parameter_type, None)
            if not cast:
                continue
            params[k] = cast(v)
        return params
Пример #52
0
Файл: base.py Проект: beryah/st2
    def dispatch(self, liveaction_db):
        action_db = get_action_by_ref(liveaction_db.action)
        if not action_db:
            raise Exception('Action %s not found in DB.' % (liveaction_db.action))

        runnertype_db = get_runnertype_by_name(action_db.runner_type['name'])

        extra = {'liveaction_db': liveaction_db, 'runnertype_db': runnertype_db}
        LOG.info('Dispatching Action to a runner', extra=extra)

        # Get runner instance.
        runner = self._get_runner(runnertype_db, action_db, liveaction_db)
        LOG.debug('Runner instance for RunnerType "%s" is: %s', runnertype_db.name, runner)

        # Process the request.
        liveaction_db = (self._do_cancel(runner, runnertype_db, action_db, liveaction_db)
                         if liveaction_db.status == action_constants.LIVEACTION_STATUS_CANCELING
                         else self._do_run(runner, runnertype_db, action_db, liveaction_db))

        return liveaction_db.result
Пример #53
0
def schedule(execution):

    # Use the user context from the parent action execution. Subtasks in a workflow
    # action can be invoked by a system user and so we want to use the user context
    # from the original workflow action.
    if getattr(execution, 'context', None) and 'parent' in execution.context:
        parent = ActionExecution.get_by_id(execution.context['parent'])
        execution.context['user'] = getattr(parent, 'context', dict()).get('user')

    # Validate action.
    action_db = action_utils.get_action_by_ref(execution.action)
    if not action_db:
        raise ValueError('Action "%s" cannot be found.' % execution.action)
    if not action_db.enabled:
        raise ValueError('Unable to execute. Action "%s" is disabled.' % execution.action)

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

    if not hasattr(execution, 'parameters'):
        execution.parameters = dict()

    # Validate action parameters.
    schema = util_schema.get_parameter_schema(action_db)
    validator = util_schema.get_validator()
    jsonschema.validate(execution.parameters, schema, validator)

    # validate that no immutable params are being overriden. Although possible to
    # ignore the override it is safer to inform the user to avoid surprises.
    immutables = _get_immutable_params(action_db.parameters)
    immutables.extend(_get_immutable_params(runnertype_db.runner_parameters))
    overridden_immutables = [p for p in six.iterkeys(execution.parameters) if p in immutables]
    if len(overridden_immutables) > 0:
        raise ValueError('Override of immutable parameter(s) %s is unsupported.'
                         % str(overridden_immutables))

    # Write to database and send to message queue.
    execution.status = ACTIONEXEC_STATUS_SCHEDULED
    execution.start_timestamp = isotime.add_utc_tz(datetime.datetime.utcnow())
    execution = ActionExecution.add_or_update(execution)
    LOG.audit('Action execution scheduled. ActionExecution=%s.', execution)
    return execution
Пример #54
0
def get_schema_for_action_parameters(action_db):
    """
    Dynamically construct JSON schema for the provided action from the parameters metadata.

    Note: This schema is used to validate parameters which are passed to the action.
    """
    from st2common.util.action_db import get_runnertype_by_name
    runner_type = get_runnertype_by_name(action_db.runner_type['name'])

    parameters_schema = {}
    parameters_schema.update(runner_type.runner_parameters)
    parameters_schema.update(action_db.parameters)

    schema = get_schema_for_resource_parameters(parameters_schema=parameters_schema)

    if parameters_schema:
        schema['title'] = action_db.name
        if action_db.description:
            schema['description'] = action_db.description

    return schema
Пример #55
0
def get_schema_for_action_parameters(action_db, runnertype_db=None):
    """
    Dynamically construct JSON schema for the provided action from the parameters metadata.

    Note: This schema is used to validate parameters which are passed to the action.
    """
    if not runnertype_db:
        from st2common.util.action_db import get_runnertype_by_name
        runnertype_db = get_runnertype_by_name(action_db.runner_type['name'])

    # Note: We need to perform a deep merge because user can only specify a single parameter
    # attribute when overriding it in an action metadata.
    parameters_schema = {}
    deep_update(parameters_schema, runnertype_db.runner_parameters)
    deep_update(parameters_schema, action_db.parameters)

    # Perform validation, make sure user is not providing parameters which can't
    # be overriden
    runner_parameter_names = list(runnertype_db.runner_parameters.keys())

    for name, schema in six.iteritems(action_db.parameters):
        if name not in runner_parameter_names:
            continue

        for attribute, value in six.iteritems(schema):
            runner_param_value = runnertype_db.runner_parameters[name].get(attribute)
            validate_runner_parameter_attribute_override(action_ref=action_db.ref,
                                                         param_name=name,
                                                         attr_name=attribute,
                                                         runner_param_attr_value=runner_param_value,
                                                         action_param_attr_value=value)

    schema = get_schema_for_resource_parameters(parameters_schema=parameters_schema)

    if parameters_schema:
        schema['title'] = action_db.name
        if action_db.description:
            schema['description'] = action_db.description

    return schema
Пример #56
0
def cast_params(action_ref, params, cast_overrides=None):
    """
    """
    params = params or {}
    action_db = action_db_util.get_action_by_ref(action_ref)

    if not action_db:
        raise ValueError('Action with ref "%s" doesn\'t exist' % (action_ref))

    action_parameters_schema = action_db.parameters
    runnertype_db = action_db_util.get_runnertype_by_name(action_db.runner_type["name"])
    runner_parameters_schema = runnertype_db.runner_parameters
    # combine into 1 list of parameter schemas
    parameters_schema = {}
    if runner_parameters_schema:
        parameters_schema.update(runner_parameters_schema)
    if action_parameters_schema:
        parameters_schema.update(action_parameters_schema)
    # cast each param individually
    for k, v in six.iteritems(params):
        parameter_schema = parameters_schema.get(k, None)
        if not parameter_schema:
            LOG.debug("Will skip cast of param[name: %s, value: %s]. No schema.", k, v)
            continue
        parameter_type = parameter_schema.get("type", None)
        if not parameter_type:
            LOG.debug("Will skip cast of param[name: %s, value: %s]. No type.", k, v)
            continue
        # Pick up cast from teh override and then from the system suppied ones.
        cast = cast_overrides.get(parameter_type, None) if cast_overrides else None
        if not cast:
            cast = get_cast(cast_type=parameter_type)
        if not cast:
            LOG.debug("Will skip cast of param[name: %s, value: %s]. No cast for %s.", k, v, parameter_type)
            continue
        LOG.debug("Casting param: %s of type %s to type: %s", v, type(v), parameter_type)
        params[k] = cast(v)
    return params
Пример #57
0
def get_schema_for_action_parameters(action_db):
    """
    Dynamically construct JSON schema for the provided action from the parameters metadata.

    Note: This schema is used to validate parameters which are passed to the action.
    """
    def normalize(x):
        return {k: v if v else SCHEMA_ANY_TYPE for k, v in six.iteritems(x)}

    schema = {}
    from st2common.util.action_db import get_runnertype_by_name
    runner_type = get_runnertype_by_name(action_db.runner_type['name'])

    properties = normalize(runner_type.runner_parameters)
    properties.update(normalize(action_db.parameters))
    if properties:
        schema['title'] = action_db.name
        if action_db.description:
            schema['description'] = action_db.description
        schema['type'] = 'object'
        schema['properties'] = properties
        schema['additionalProperties'] = False
    return schema
Пример #58
0
    def _cast_params(action_ref, params):
        casts = {
            'array': (lambda x: ast.literal_eval(x) if isinstance(x, str) or isinstance(x, unicode)
                      else x),
            'boolean': (lambda x: ast.literal_eval(x.capitalize())
                        if isinstance(x, str) or isinstance(x, unicode) else x),
            'integer': int,
            'number': float,
            'object': (lambda x: json.loads(x) if isinstance(x, str) or isinstance(x, unicode)
                       else x),
            'string': str
        }

        action_db = action_db_util.get_action_by_ref(
            ResourceReference.from_string_reference(ref=action_ref))
        action_parameters_schema = action_db.parameters
        runnertype_db = action_db_util.get_runnertype_by_name(action_db.runner_type['name'])
        runner_parameters_schema = runnertype_db.runner_parameters
        # combine into 1 list of parameter schemas
        parameters_schema = {}
        if runner_parameters_schema:
            parameters_schema.update(runner_parameters_schema)
        if action_parameters_schema:
            parameters_schema.update(action_parameters_schema)
        # cast each param individually
        for k, v in six.iteritems(params):
            parameter_schema = parameters_schema.get(k, None)
            if not parameter_schema:
                continue
            parameter_type = parameter_schema.get('type', None)
            if not parameter_type:
                continue
            cast = casts.get(parameter_type, None)
            if not cast:
                continue
            params[k] = cast(v)
        return params