Example #1
0
    def enforce(self):
        # TODO: Refactor this to avoid additiona lookup in cast_params
        # TODO: rename self.rule.action -> self.rule.action_exec_spec
        action_ref = self.rule.action['ref']
        action_db = action_db_util.get_action_by_ref(action_ref)
        if not action_db:
            raise ValueError('Action "%s" doesn\'t exist' % (action_ref))

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

        context = {
            'trigger_instance': reference.get_ref_from_model(self.trigger_instance),
            'rule': reference.get_ref_from_model(self.rule),
            'user': get_system_username()
        }

        liveaction_db = RuleEnforcer._invoke_action(self.rule.action, data, context)
        if not liveaction_db:
            extra = {'trigger_instance_db': self.trigger_instance, 'rule_db': self.rule}
            LOG.audit('Rule enforcement failed. Liveaction for Action %s failed. '
                      'TriggerInstance: %s and Rule: %s',
                      self.rule.action.name, self.trigger_instance, self.rule,
                      extra=extra)
            return None

        extra = {'trigger_instance_db': self.trigger_instance, 'rule_db': self.rule,
                 'liveaction_db': liveaction_db}
        LOG.audit('Rule enforced. Liveaction %s, TriggerInstance %s and Rule %s.',
                  liveaction_db, self.trigger_instance, self.rule, extra=extra)

        return liveaction_db
Example #2
0
    def enforce(self):
        data = self.data_transformer(self.rule.action.parameters)
        LOG.info('Invoking action %s for trigger_instance %s with data %s.',
                 self.rule.action.ref, self.trigger_instance.id,
                 json.dumps(data))
        context = {
            'trigger_instance':
            reference.get_ref_from_model(self.trigger_instance),
            'rule': reference.get_ref_from_model(self.rule),
            'user': get_system_username()
        }

        liveaction = RuleEnforcer._invoke_action(self.rule.action, data,
                                                 context)
        if not liveaction:
            LOG.audit(
                'Rule enforcement failed. liveaction for Action %s failed. '
                'TriggerInstance: %s and Rule: %s', self.rule.action.name,
                self.trigger_instance, self.rule)
            return None

        liveaction_db = liveaction.get('id', None)
        LOG.audit(
            'Rule enforced. liveaction %s, TriggerInstance %s and Rule %s.',
            liveaction_db, self.trigger_instance, self.rule)

        return liveaction_db
Example #3
0
 def test_to_reference_no_model_id(self):
     try:
         model = copy.copy(self.__model)
         model.id = None
         reference.get_ref_from_model(model)
         self.assertTrue(False, 'Exception expected.')
     except db.StackStormDBObjectMalformedError:
         self.assertTrue(True)
Example #4
0
 def test_to_reference_no_model_id(self):
     try:
         model = copy.copy(self.__model)
         model.id = None
         reference.get_ref_from_model(model)
         self.assertTrue(False, 'Exception expected.')
     except db.StackStormDBObjectMalformedError:
         self.assertTrue(True)
Example #5
0
    def enforce(self):
        # TODO: Refactor this to avoid additiona lookup in cast_params
        # TODO: rename self.rule.action -> self.rule.action_exec_spec
        action_ref = self.rule.action['ref']
        action_db = action_db_util.get_action_by_ref(action_ref)
        if not action_db:
            raise ValueError('Action "%s" doesn\'t exist' % (action_ref))

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

        # 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 = {
            'trigger_instance':
            reference.get_ref_from_model(self.trigger_instance),
            'rule': reference.get_ref_from_model(self.rule),
            'user': get_system_username(),
            TRACE_CONTEXT: trace_context
        }

        liveaction_db = RuleEnforcer._invoke_action(self.rule.action, data,
                                                    context)
        if not liveaction_db:
            extra = {
                'trigger_instance_db': self.trigger_instance,
                'rule_db': self.rule
            }
            LOG.audit(
                'Rule enforcement failed. Liveaction for Action %s failed. '
                'TriggerInstance: %s and Rule: %s',
                self.rule.action.name,
                self.trigger_instance,
                self.rule,
                extra=extra)
            return None

        extra = {
            'trigger_instance_db': self.trigger_instance,
            'rule_db': self.rule,
            'liveaction_db': liveaction_db
        }
        LOG.audit(
            'Rule enforced. Liveaction %s, TriggerInstance %s and Rule %s.',
            liveaction_db,
            self.trigger_instance,
            self.rule,
            extra=extra)

        return liveaction_db
Example #6
0
    def enforce(self):
        # TODO: Refactor this to avoid additional lookup in cast_params
        # TODO: rename self.rule.action -> self.rule.action_exec_spec
        action_ref = self.rule.action['ref']
        action_db = action_db_util.get_action_by_ref(action_ref)
        if not action_db:
            raise ValueError('Action "%s" doesn\'t exist' % (action_ref))

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

        # 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 = {
            'trigger_instance': reference.get_ref_from_model(self.trigger_instance),
            'rule': reference.get_ref_from_model(self.rule),
            'user': get_system_username(),
            TRACE_CONTEXT: trace_context
        }

        extra = {'trigger_instance_db': self.trigger_instance, 'rule_db': self.rule}
        rule_spec = {'ref': self.rule.ref, 'id': str(self.rule.id), 'uid': self.rule.uid}
        enforcement_db = RuleEnforcementDB(trigger_instance_id=str(self.trigger_instance.id),
                                           rule=rule_spec)
        try:
            execution_db = RuleEnforcer._invoke_action(self.rule.action, data, context)
            # pylint: disable=no-member
            enforcement_db.execution_id = str(execution_db.id)
            # pylint: enable=no-member
        except:
            LOG.exception('Failed kicking off execution for rule %s.', self.rule, extra=extra)
            return None
        finally:
            self._update_enforcement(enforcement_db)

        extra['execution_db'] = execution_db
        # pylint: disable=no-member
        if execution_db.status not in EXEC_KICKED_OFF_STATES:
            # pylint: enable=no-member
            LOG.audit('Rule enforcement failed. Execution of Action %s failed. '
                      'TriggerInstance: %s and Rule: %s',
                      self.rule.action.name, self.trigger_instance, self.rule,
                      extra=extra)
            return execution_db

        LOG.audit('Rule enforced. Execution %s, TriggerInstance %s and Rule %s.',
                  execution_db, self.trigger_instance, self.rule, extra=extra)

        return execution_db
Example #7
0
    def get_action_execution_context(self, action_db, trace_context=None):
        context = {
            "trigger_instance": reference.get_ref_from_model(self.trigger_instance),
            "rule": reference.get_ref_from_model(self.rule),
            "user": get_system_username(),
            "pack": action_db.pack,
        }

        if trace_context is not None:
            context[TRACE_CONTEXT] = trace_context

        # Additional non-action / global context
        additional_context = {TRIGGER_PAYLOAD_PREFIX: self.trigger_instance.payload}

        return context, additional_context
Example #8
0
    def _schedule_execution(self, action_alias_db, params, notify, context):
        action_ref = action_alias_db.action_ref
        action_db = action_utils.get_action_by_ref(action_ref)

        if not action_db:
            raise StackStormDBObjectNotFoundError('Action with ref "%s" not found ' % (action_ref))

        assert_request_user_has_resource_db_permission(request=pecan.request, resource_db=action_db,
            permission_type=PermissionType.ACTION_EXECUTE)

        try:
            # prior to shipping off the params cast them to the right type.
            params = action_param_utils.cast_params(action_ref=action_alias_db.action_ref,
                                                    params=params,
                                                    cast_overrides=CAST_OVERRIDES)
            if not context:
                context = {
                    'action_alias_ref': reference.get_ref_from_model(action_alias_db),
                    'user': get_system_username()
                }
            liveaction = LiveActionDB(action=action_alias_db.action_ref, context=context,
                                      parameters=params, notify=notify)
            _, action_execution_db = action_service.request(liveaction)
            return ActionExecutionAPI.from_model(action_execution_db)
        except ValueError as e:
            LOG.exception('Unable to execute action.')
            pecan.abort(http_client.BAD_REQUEST, str(e))
        except jsonschema.ValidationError as e:
            LOG.exception('Unable to execute action. Parameter validation failed.')
            pecan.abort(http_client.BAD_REQUEST, str(e))
        except Exception as e:
            LOG.exception('Unable to execute action. Unexpected error encountered.')
            pecan.abort(http_client.INTERNAL_SERVER_ERROR, str(e))
Example #9
0
 def _schedule_execution(self, action_alias_db, params, notify, context):
     try:
         # prior to shipping off the params cast them to the right type.
         params = action_param_utils.cast_params(
             action_ref=action_alias_db.action_ref,
             params=params,
             cast_overrides=CAST_OVERRIDES)
         if not context:
             context = {
                 'action_alias_ref':
                 reference.get_ref_from_model(action_alias_db),
                 'user':
                 get_system_username()
             }
         liveaction = LiveActionDB(action=action_alias_db.action_ref,
                                   context=context,
                                   parameters=params,
                                   notify=notify)
         _, action_execution_db = action_service.request(liveaction)
         return action_execution_db
     except ValueError as e:
         LOG.exception('Unable to execute action.')
         pecan.abort(http_client.BAD_REQUEST, str(e))
     except jsonschema.ValidationError as e:
         LOG.exception(
             'Unable to execute action. Parameter validation failed.')
         pecan.abort(http_client.BAD_REQUEST, str(e))
     except Exception as e:
         LOG.exception(
             'Unable to execute action. Unexpected error encountered.')
         pecan.abort(http_client.INTERNAL_SERVER_ERROR, str(e))
    def _schedule_execution(self, action_alias_db, params, notify, context, requester_user,
                            show_secrets):
        action_ref = action_alias_db.action_ref
        action_db = action_utils.get_action_by_ref(action_ref)

        if not action_db:
            raise StackStormDBObjectNotFoundError('Action with ref "%s" not found ' % (action_ref))

        assert_user_has_resource_db_permission(user_db=requester_user, resource_db=action_db,
                                               permission_type=PermissionType.ACTION_EXECUTE)

        try:
            # prior to shipping off the params cast them to the right type.
            params = action_param_utils.cast_params(action_ref=action_alias_db.action_ref,
                                                    params=params,
                                                    cast_overrides=CAST_OVERRIDES)
            if not context:
                context = {
                    'action_alias_ref': reference.get_ref_from_model(action_alias_db),
                    'user': get_system_username()
                }
            liveaction = LiveActionDB(action=action_alias_db.action_ref, context=context,
                                      parameters=params, notify=notify)
            _, action_execution_db = action_service.request(liveaction)
            mask_secrets = self._get_mask_secrets(requester_user, show_secrets=show_secrets)
            return ActionExecutionAPI.from_model(action_execution_db, mask_secrets=mask_secrets)
        except ValueError as e:
            LOG.exception('Unable to execute action.')
            abort(http_client.BAD_REQUEST, str(e))
        except jsonschema.ValidationError as e:
            LOG.exception('Unable to execute action. Parameter validation failed.')
            abort(http_client.BAD_REQUEST, str(e))
        except Exception as e:
            LOG.exception('Unable to execute action. Unexpected error encountered.')
            abort(http_client.INTERNAL_SERVER_ERROR, str(e))
Example #11
0
    def get_action_execution_context(self, action_db, trace_context=None):
        context = {
            'trigger_instance': reference.get_ref_from_model(self.trigger_instance),
            'rule': reference.get_ref_from_model(self.rule),
            'user': get_system_username(),
            'pack': action_db.pack,
        }

        if trace_context is not None:
            context[TRACE_CONTEXT] = trace_context

        # Additional non-action / global context
        additional_context = {
            TRIGGER_PAYLOAD_PREFIX: self.trigger_instance.payload
        }

        return context, additional_context
Example #12
0
    def post(self, payload):
        action_alias_name = payload.name if payload else None

        if not action_alias_name:
            pecan.abort(http_client.BAD_REQUEST,
                        'Alias execution "name" is required')

        format_str = payload.format or ''
        command = payload.command or ''

        try:
            action_alias_db = ActionAlias.get_by_name(action_alias_name)
        except ValueError:
            action_alias_db = None

        if not action_alias_db:
            msg = 'Unable to identify action alias with name "%s".' % (
                action_alias_name)
            pecan.abort(http_client.NOT_FOUND, msg)
            return

        if not action_alias_db.enabled:
            msg = 'Action alias with name "%s" is disabled.' % (
                action_alias_name)
            pecan.abort(http_client.BAD_REQUEST, msg)
            return

        execution_parameters = self._extract_parameters(
            action_alias_db=action_alias_db,
            format_str=format_str,
            param_stream=command)
        notify = self._get_notify_field(payload)

        context = {
            'action_alias_ref': reference.get_ref_from_model(action_alias_db),
            'api_user': payload.user,
            'user': get_requester(),
            'source_channel': payload.source_channel
        }

        execution = self._schedule_execution(action_alias_db=action_alias_db,
                                             params=execution_parameters,
                                             notify=notify,
                                             context=context)

        result = {
            'execution': execution,
            'actionalias': ActionAliasAPI.from_model(action_alias_db)
        }

        if action_alias_db.ack and 'format' in action_alias_db.ack:
            result.update({
                'message':
                render({'alias': action_alias_db.ack['format']},
                       result)['alias']
            })

        return result
Example #13
0
    def post(self, payload):
        action_alias_name = payload.name if payload else None

        if not action_alias_name:
            pecan.abort(http_client.BAD_REQUEST, 'Alias execution "name" is required')

        format_str = payload.format or ''
        command = payload.command or ''

        try:
            action_alias_db = ActionAlias.get_by_name(action_alias_name)
        except ValueError:
            action_alias_db = None

        if not action_alias_db:
            msg = 'Unable to identify action alias with name "%s".' % (action_alias_name)
            pecan.abort(http_client.NOT_FOUND, msg)
            return

        if not action_alias_db.enabled:
            msg = 'Action alias with name "%s" is disabled.' % (action_alias_name)
            pecan.abort(http_client.BAD_REQUEST, msg)
            return

        execution_parameters = extract_parameters_for_action_alias_db(
            action_alias_db=action_alias_db,
            format_str=format_str,
            param_stream=command)
        notify = self._get_notify_field(payload)

        context = {
            'action_alias_ref': reference.get_ref_from_model(action_alias_db),
            'api_user': payload.user,
            'user': get_requester(),
            'source_channel': payload.source_channel
        }

        execution = self._schedule_execution(action_alias_db=action_alias_db,
                                             params=execution_parameters,
                                             notify=notify,
                                             context=context)

        result = {
            'execution': execution,
            'actionalias': ActionAliasAPI.from_model(action_alias_db)
        }

        if action_alias_db.ack:
            if 'format' in action_alias_db.ack:
                result.update({
                    'message': render({'alias': action_alias_db.ack['format']}, result)['alias']
                })
            if 'extra' in action_alias_db.ack:
                result.update({
                    'extra': render(action_alias_db.ack['extra'], result)
                })

        return result
Example #14
0
    def _do_enforce(self):
        params = self.get_resolved_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 = {
            'trigger_instance': reference.get_ref_from_model(self.trigger_instance),
            'rule': reference.get_ref_from_model(self.rule),
            'user': get_system_username(),
            TRACE_CONTEXT: trace_context
        }

        return RuleEnforcer._invoke_action(self.rule.action, params, context)
Example #15
0
 def setUpClass(cls):
     super(EnforceTest, cls).setUpClass()
     # Create TriggerTypes before creation of Rule to avoid failure. Rule requires the
     # Trigger and therefore TriggerType to be created prior to rule creation.
     cls.models = FixturesLoader().save_fixtures_to_db(
         fixtures_pack=PACK, fixtures_dict=FIXTURES_1)
     cls.models.update(FixturesLoader().save_fixtures_to_db(
         fixtures_pack=PACK, fixtures_dict=FIXTURES_2))
     MOCK_TRIGGER_INSTANCE.trigger = reference.get_ref_from_model(
         cls.models['triggers']['trigger1.yaml'])
Example #16
0
 def setUpClass(cls):
     super(EnforceTest, cls).setUpClass()
     # Create TriggerTypes before creation of Rule to avoid failure. Rule requires the
     # Trigger and therefore TriggerType to be created prior to rule creation.
     cls.models = FixturesLoader().save_fixtures_to_db(
         fixtures_pack=PACK, fixtures_dict=FIXTURES_1)
     cls.models.update(FixturesLoader().save_fixtures_to_db(
         fixtures_pack=PACK, fixtures_dict=FIXTURES_2))
     MOCK_TRIGGER_INSTANCE.trigger = reference.get_ref_from_model(
         cls.models['triggers']['trigger1.yaml'])
Example #17
0
    def _do_enforce(self):
        params = self.get_resolved_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 = {
            'trigger_instance':
            reference.get_ref_from_model(self.trigger_instance),
            'rule': reference.get_ref_from_model(self.rule),
            'user': get_system_username(),
            TRACE_CONTEXT: trace_context
        }

        return RuleEnforcer._invoke_action(self.rule.action, params, context)
Example #18
0
    def enforce(self):
        data = self.data_transformer(self.rule.action.parameters)
        LOG.info('Invoking action %s for trigger_instance %s with data %s.',
                 self.rule.action.ref, self.trigger_instance.id,
                 json.dumps(data))
        context = {
            'trigger_instance': reference.get_ref_from_model(self.trigger_instance),
            'rule': reference.get_ref_from_model(self.rule),
            'user': get_system_username()
        }

        action_execution = RuleEnforcer._invoke_action(self.rule.action, data, context)
        if not action_execution:
            LOG.audit('Rule enforcement failed. ActionExecution for Action %s failed. '
                      'TriggerInstance: %s and Rule: %s',
                      self.rule.action.name, self.trigger_instance, self.rule)
            return None

        actionexecution_db = action_execution.get('id', None)
        LOG.audit('Rule enforced. ActionExecution %s, TriggerInstance %s and Rule %s.',
                  actionexecution_db, self.trigger_instance, self.rule)

        return actionexecution_db
Example #19
0
    def post(self, payload):
        action_alias_name = payload.name if payload else None

        if not action_alias_name:
            pecan.abort(http_client.BAD_REQUEST, 'Alias execution "name" is required')

        format_str = payload.format or ''
        command = payload.command or ''

        try:
            action_alias_db = ActionAlias.get_by_name(action_alias_name)
        except ValueError:
            action_alias_db = None

        if not action_alias_db:
            msg = 'Unable to identify action alias with name "%s".' % (action_alias_name)
            pecan.abort(http_client.NOT_FOUND, msg)
            return

        if not action_alias_db.enabled:
            msg = 'Action alias with name "%s" is disabled.' % (action_alias_name)
            pecan.abort(http_client.BAD_REQUEST, msg)
            return

        execution_parameters = self._extract_parameters(action_alias_db=action_alias_db,
                                                        format_str=format_str,
                                                        param_stream=command)
        notify = self._get_notify_field(payload)

        context = {
            'action_alias_ref': reference.get_ref_from_model(action_alias_db),
            'api_user': payload.user,
            'user': get_system_username(),
            'source_channel': payload.source_channel
        }

        execution = self._schedule_execution(action_alias_db=action_alias_db,
                                             params=execution_parameters,
                                             notify=notify,
                                             context=context)

        return str(execution.id)
Example #20
0
 def _schedule_execution(self, action_alias_db, params, notify):
     try:
         # prior to shipping off the params cast them to the right type.
         params = action_param_utils.cast_params(action_ref=action_alias_db.action_ref,
                                                 params=params,
                                                 cast_overrides=CAST_OVERRIDES)
         context = {
             'action_alias_ref': reference.get_ref_from_model(action_alias_db),
             'user': get_system_username()
         }
         liveaction = LiveActionDB(action=action_alias_db.action_ref, context=context,
                                   parameters=params, notify=notify)
         _, action_execution_db = action_service.request(liveaction)
         return action_execution_db
     except ValueError as e:
         LOG.exception('Unable to execute action.')
         pecan.abort(http_client.BAD_REQUEST, str(e))
     except jsonschema.ValidationError as e:
         LOG.exception('Unable to execute action. Parameter validation failed.')
         pecan.abort(http_client.BAD_REQUEST, str(e))
     except Exception as e:
         LOG.exception('Unable to execute action. Unexpected error encountered.')
         pecan.abort(http_client.INTERNAL_SERVER_ERROR, str(e))
Example #21
0
from st2common.models.db.reactor import TriggerDB, TriggerInstanceDB, \
    RuleDB, ActionExecutionSpecDB
from st2common.models.db.action import ActionDB, ActionExecutionDB
import st2common.services.action as action_service
from st2common.util import reference
from st2reactor.rules.enforcer import RuleEnforcer
import st2tests.config as tests_config

MOCK_TRIGGER = TriggerDB()
MOCK_TRIGGER.id = 'trigger-test.id'
MOCK_TRIGGER.name = 'trigger-test.name'
MOCK_TRIGGER.pack = 'dummypack1'

MOCK_TRIGGER_INSTANCE = TriggerInstanceDB()
MOCK_TRIGGER_INSTANCE.id = 'triggerinstance-test'
MOCK_TRIGGER_INSTANCE.trigger = reference.get_ref_from_model(MOCK_TRIGGER)
MOCK_TRIGGER_INSTANCE.payload = {}
MOCK_TRIGGER_INSTANCE.occurrence_time = datetime.datetime.utcnow()

MOCK_ACTION = ActionDB()
MOCK_ACTION.id = 'action-test-1.id'
MOCK_ACTION.name = 'action-test-1.name'

MOCK_ACTION_EXECUTION = ActionExecutionDB()
MOCK_ACTION_EXECUTION.id = 'actionexec-test-1.id'
MOCK_ACTION_EXECUTION.name = 'actionexec-test-1.name'
MOCK_ACTION_EXECUTION.status = 'scheduled'

MOCK_RULE_1 = RuleDB()
MOCK_RULE_1.id = 'rule-test-1'
MOCK_RULE_1.trigger = reference.get_str_resource_ref_from_model(MOCK_TRIGGER)
Example #22
0
 def test_to_reference(self):
     ref = reference.get_ref_from_model(self.__model)
     self.assertEqual(ref, self.__ref, 'Failed to generated equivalent ref.')
Example #23
0
 def test_to_reference_no_model(self):
     try:
         reference.get_ref_from_model(None)
         self.assertTrue(False, 'Exception expected.')
     except ValueError:
         self.assertTrue(True)
Example #24
0
 def test_to_reference(self):
     ref = reference.get_ref_from_model(self.__model)
     self.assertEqual(ref, self.__ref,
                      'Failed to generated equivalent ref.')
Example #25
0
 def test_to_reference_no_model(self):
     try:
         reference.get_ref_from_model(None)
         self.assertTrue(False, 'Exception expected.')
     except ValueError:
         self.assertTrue(True)
Example #26
0
    def _post(self,
              payload,
              requester_user,
              show_secrets=False,
              match_multiple=False):
        action_alias_name = payload.name if payload else None

        if not action_alias_name:
            abort(http_client.BAD_REQUEST,
                  'Alias execution "name" is required')
            return

        if not requester_user:
            requester_user = UserDB(cfg.CONF.system_user.user)

        format_str = payload.format or ''
        command = payload.command or ''

        try:
            action_alias_db = ActionAlias.get_by_name(action_alias_name)
        except ValueError:
            action_alias_db = None

        if not action_alias_db:
            msg = 'Unable to identify action alias with name "%s".' % (
                action_alias_name)
            abort(http_client.NOT_FOUND, msg)
            return

        if not action_alias_db.enabled:
            msg = 'Action alias with name "%s" is disabled.' % (
                action_alias_name)
            abort(http_client.BAD_REQUEST, msg)
            return

        if match_multiple:
            multiple_execution_parameters = extract_parameters_for_action_alias_db(
                action_alias_db=action_alias_db,
                format_str=format_str,
                param_stream=command,
                match_multiple=match_multiple)
        else:
            multiple_execution_parameters = [
                extract_parameters_for_action_alias_db(
                    action_alias_db=action_alias_db,
                    format_str=format_str,
                    param_stream=command,
                    match_multiple=match_multiple)
            ]

        notify = self._get_notify_field(payload)

        context = {
            'action_alias_ref': reference.get_ref_from_model(action_alias_db),
            'api_user': payload.user,
            'user': requester_user.name,
            'source_channel': payload.source_channel,
        }

        inject_immutable_parameters(
            action_alias_db=action_alias_db,
            multiple_execution_parameters=multiple_execution_parameters,
            action_context=context)

        results = []
        for execution_parameters in multiple_execution_parameters:
            execution = self._schedule_execution(
                action_alias_db=action_alias_db,
                params=execution_parameters,
                notify=notify,
                context=context,
                show_secrets=show_secrets,
                requester_user=requester_user)

            result = {
                'execution': execution,
                'actionalias': ActionAliasAPI.from_model(action_alias_db)
            }

            if action_alias_db.ack:
                try:
                    if 'format' in action_alias_db.ack:
                        message = render(
                            {'alias': action_alias_db.ack['format']},
                            result)['alias']

                        result.update({'message': message})
                except UndefinedError as e:
                    result.update({
                        'message':
                        ('Cannot render "format" in field "ack" for alias. ' +
                         six.text_type(e))
                    })

                try:
                    if 'extra' in action_alias_db.ack:
                        result.update({
                            'extra':
                            render(action_alias_db.ack['extra'], result)
                        })
                except UndefinedError as e:
                    result.update({
                        'extra':
                        ('Cannot render "extra" in field "ack" for alias. ' +
                         six.text_type(e))
                    })

            results.append(result)

        return results
Example #27
0
    def post(self, payload, requester_user=None, show_secrets=False):
        action_alias_name = payload.name if payload else None

        if not action_alias_name:
            abort(http_client.BAD_REQUEST,
                  'Alias execution "name" is required')
            return

        if not requester_user:
            requester_user = UserDB(cfg.CONF.system_user.user)

        format_str = payload.format or ''
        command = payload.command or ''

        try:
            action_alias_db = ActionAlias.get_by_name(action_alias_name)
        except ValueError:
            action_alias_db = None

        if not action_alias_db:
            msg = 'Unable to identify action alias with name "%s".' % (
                action_alias_name)
            abort(http_client.NOT_FOUND, msg)
            return

        if not action_alias_db.enabled:
            msg = 'Action alias with name "%s" is disabled.' % (
                action_alias_name)
            abort(http_client.BAD_REQUEST, msg)
            return

        execution_parameters = extract_parameters_for_action_alias_db(
            action_alias_db=action_alias_db,
            format_str=format_str,
            param_stream=command)
        notify = self._get_notify_field(payload)

        context = {
            'action_alias_ref': reference.get_ref_from_model(action_alias_db),
            'api_user': payload.user,
            'user': requester_user.name,
            'source_channel': payload.source_channel
        }

        execution = self._schedule_execution(action_alias_db=action_alias_db,
                                             params=execution_parameters,
                                             notify=notify,
                                             context=context,
                                             show_secrets=show_secrets,
                                             requester_user=requester_user)

        result = {
            'execution': execution,
            'actionalias': ActionAliasAPI.from_model(action_alias_db)
        }

        if action_alias_db.ack:
            try:
                if 'format' in action_alias_db.ack:
                    result.update({
                        'message':
                        render({'alias': action_alias_db.ack['format']},
                               result)['alias']
                    })
            except UndefinedError as e:
                result.update({
                    'message':
                    'Cannot render "format" in field "ack" for alias. ' +
                    e.message
                })

            try:
                if 'extra' in action_alias_db.ack:
                    result.update({
                        'extra':
                        render(action_alias_db.ack['extra'], result)
                    })
            except UndefinedError as e:
                result.update({
                    'extra':
                    'Cannot render "extra" in field "ack" for alias. ' +
                    e.message
                })

        return Response(json=result, status=http_client.CREATED)
Example #28
0
    def enforce(self):
        params = self.get_resolved_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 = {
            'trigger_instance':
            reference.get_ref_from_model(self.trigger_instance),
            'rule': reference.get_ref_from_model(self.rule),
            'user': get_system_username(),
            TRACE_CONTEXT: trace_context
        }

        extra = {
            'trigger_instance_db': self.trigger_instance,
            'rule_db': self.rule
        }
        rule_spec = {
            'ref': self.rule.ref,
            'id': str(self.rule.id),
            'uid': self.rule.uid
        }
        enforcement_db = RuleEnforcementDB(trigger_instance_id=str(
            self.trigger_instance.id),
                                           rule=rule_spec)
        try:
            execution_db = RuleEnforcer._invoke_action(self.rule.action,
                                                       params, context)
            # pylint: disable=no-member
            enforcement_db.execution_id = str(execution_db.id)
            # pylint: enable=no-member
        except:
            LOG.exception('Failed kicking off execution for rule %s.',
                          self.rule,
                          extra=extra)
            return None
        finally:
            self._update_enforcement(enforcement_db)

        extra['execution_db'] = execution_db
        # pylint: disable=no-member
        if execution_db.status not in EXEC_KICKED_OFF_STATES:
            # pylint: enable=no-member
            LOG.audit(
                'Rule enforcement failed. Execution of Action %s failed. '
                'TriggerInstance: %s and Rule: %s',
                self.rule.action.name,
                self.trigger_instance,
                self.rule,
                extra=extra)
            return execution_db

        LOG.audit(
            'Rule enforced. Execution %s, TriggerInstance %s and Rule %s.',
            execution_db,
            self.trigger_instance,
            self.rule,
            extra=extra)

        return execution_db
Example #29
0
from st2common.models.db.reactor import TriggerDB, TriggerInstanceDB, \
    RuleDB, ActionExecutionSpecDB
from st2common.models.db.action import ActionDB, ActionExecutionDB
import st2common.services.action as action_service
from st2common.util import reference
from st2reactor.rules.enforcer import RuleEnforcer
import st2tests.config as tests_config

MOCK_TRIGGER = TriggerDB()
MOCK_TRIGGER.id = 'trigger-test.id'
MOCK_TRIGGER.name = 'trigger-test.name'
MOCK_TRIGGER.pack = 'dummypack1'

MOCK_TRIGGER_INSTANCE = TriggerInstanceDB()
MOCK_TRIGGER_INSTANCE.id = 'triggerinstance-test'
MOCK_TRIGGER_INSTANCE.trigger = reference.get_ref_from_model(MOCK_TRIGGER)
MOCK_TRIGGER_INSTANCE.payload = {}
MOCK_TRIGGER_INSTANCE.occurrence_time = datetime.datetime.utcnow()

MOCK_ACTION = ActionDB()
MOCK_ACTION.id = 'action-test-1.id'
MOCK_ACTION.name = 'action-test-1.name'

MOCK_ACTION_EXECUTION = ActionExecutionDB()
MOCK_ACTION_EXECUTION.id = 'actionexec-test-1.id'
MOCK_ACTION_EXECUTION.name = 'actionexec-test-1.name'
MOCK_ACTION_EXECUTION.status = 'scheduled'

MOCK_RULE_1 = RuleDB()
MOCK_RULE_1.id = 'rule-test-1'
MOCK_RULE_1.trigger = reference.get_str_resource_ref_from_model(MOCK_TRIGGER)
Example #30
0
    def _post(self, payload, requester_user, show_secrets=False, match_multiple=False):
        action_alias_name = payload.name if payload else None

        if not action_alias_name:
            abort(http_client.BAD_REQUEST, 'Alias execution "name" is required')
            return

        if not requester_user:
            requester_user = UserDB(cfg.CONF.system_user.user)

        format_str = payload.format or ''
        command = payload.command or ''

        try:
            action_alias_db = ActionAlias.get_by_name(action_alias_name)
        except ValueError:
            action_alias_db = None

        if not action_alias_db:
            msg = 'Unable to identify action alias with name "%s".' % (action_alias_name)
            abort(http_client.NOT_FOUND, msg)
            return

        if not action_alias_db.enabled:
            msg = 'Action alias with name "%s" is disabled.' % (action_alias_name)
            abort(http_client.BAD_REQUEST, msg)
            return

        if match_multiple:
            multiple_execution_parameters = extract_parameters_for_action_alias_db(
                action_alias_db=action_alias_db,
                format_str=format_str,
                param_stream=command,
                match_multiple=match_multiple)
        else:
            multiple_execution_parameters = [
                extract_parameters_for_action_alias_db(
                    action_alias_db=action_alias_db,
                    format_str=format_str,
                    param_stream=command,
                    match_multiple=match_multiple)
            ]

        notify = self._get_notify_field(payload)

        context = {
            'action_alias_ref': reference.get_ref_from_model(action_alias_db),
            'api_user': payload.user,
            'user': requester_user.name,
            'source_channel': payload.source_channel
        }

        results = []
        for execution_parameters in multiple_execution_parameters:
            execution = self._schedule_execution(action_alias_db=action_alias_db,
                                                 params=execution_parameters,
                                                 notify=notify,
                                                 context=context,
                                                 show_secrets=show_secrets,
                                                 requester_user=requester_user)

            result = {
                'execution': execution,
                'actionalias': ActionAliasAPI.from_model(action_alias_db)
            }

            if action_alias_db.ack:
                try:
                    if 'format' in action_alias_db.ack:
                        message = render({'alias': action_alias_db.ack['format']}, result)['alias']

                        result.update({
                            'message': message
                        })
                except UndefinedError as e:
                    result.update({
                        'message': ('Cannot render "format" in field "ack" for alias. ' +
                                    six.text_type(e))
                    })

                try:
                    if 'extra' in action_alias_db.ack:
                        result.update({
                            'extra': render(action_alias_db.ack['extra'], result)
                        })
                except UndefinedError as e:
                    result.update({
                        'extra': ('Cannot render "extra" in field "ack" for alias. ' +
                                  six.text_type(e))
                    })

            results.append(result)

        return results
Example #31
0
    def enforce(self):
        # TODO: Refactor this to avoid additional lookup in cast_params
        # TODO: rename self.rule.action -> self.rule.action_exec_spec
        action_ref = self.rule.action['ref']
        action_db = action_db_util.get_action_by_ref(action_ref)
        if not action_db:
            raise ValueError('Action "%s" doesn\'t exist' % (action_ref))

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

        # 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 = {
            'trigger_instance':
            reference.get_ref_from_model(self.trigger_instance),
            'rule': reference.get_ref_from_model(self.rule),
            'user': get_system_username(),
            TRACE_CONTEXT: trace_context
        }

        extra = {
            'trigger_instance_db': self.trigger_instance,
            'rule_db': self.rule
        }
        rule_spec = {
            'ref': self.rule.ref,
            'id': str(self.rule.id),
            'uid': self.rule.uid
        }
        enforcement_db = RuleEnforcementDB(trigger_instance_id=str(
            self.trigger_instance.id),
                                           rule=rule_spec)
        try:
            execution_db = RuleEnforcer._invoke_action(self.rule.action, data,
                                                       context)
            # pylint: disable=no-member
            enforcement_db.execution_id = str(execution_db.id)
            # pylint: enable=no-member
        except:
            LOG.exception('Failed kicking off execution for rule %s.',
                          self.rule,
                          extra=extra)
            return None
        finally:
            self._update_enforcement(enforcement_db)

        extra['execution_db'] = execution_db
        # pylint: disable=no-member
        if execution_db.status not in EXEC_KICKED_OFF_STATES:
            # pylint: enable=no-member
            LOG.audit(
                'Rule enforcement failed. Execution of Action %s failed. '
                'TriggerInstance: %s and Rule: %s',
                self.rule.action.name,
                self.trigger_instance,
                self.rule,
                extra=extra)
            return execution_db

        LOG.audit(
            'Rule enforced. Execution %s, TriggerInstance %s and Rule %s.',
            execution_db,
            self.trigger_instance,
            self.rule,
            extra=extra)

        return execution_db