Exemple #1
0
def create_trigger_instance(trigger, payload, occurrence_time):
    """
    This creates a trigger instance object given trigger and payload.
    Trigger can be just a string reference (pack.name) or a ``dict``
    containing  'type' and 'parameters'.

    :param trigger: Dictionary with trigger query filters.
    :type trigger: ``dict``

    :param payload: Trigger payload.
    :type payload: ``dict``
    """
    # TODO: This is nasty, this should take a unique reference and not a dict
    if isinstance(trigger, six.string_types):
        trigger_db = TriggerService.get_trigger_db_by_ref(trigger)
    else:
        type = trigger.get('type', None)
        parameters = trigger.get('parameters', {})
        trigger_db = TriggerService.get_trigger_db_given_type_and_params(type=type,
                                                                         parameters=parameters)

    if trigger_db is None:
        LOG.info('No trigger in db for %s', trigger)
        return None

    trigger_ref = trigger_db.get_reference().ref

    trigger_instance = TriggerInstanceDB()
    trigger_instance.trigger = trigger_ref
    trigger_instance.payload = payload
    trigger_instance.occurrence_time = occurrence_time
    return TriggerInstance.add_or_update(trigger_instance)
Exemple #2
0
    def test_rule_enforcement_is_created_on_exception_3(self):
        # 1. Exception in payload_lookup.get_value
        rule_enforcement_dbs = list(RuleEnforcement.get_all())
        self.assertEqual(rule_enforcement_dbs, [])

        self._setup_sample_trigger('st2.test.trigger4')
        rule_4_db = self._setup_sample_rule(RULE_4)
        rules = [rule_4_db]
        trigger_instance = container_utils.create_trigger_instance(
            'dummy_pack_1.st2.test.trigger4',
            {'k1': 't2_p_v', 'k2': 'v2'},
            date_utils.get_datetime_utc_now()
        )
        trigger = get_trigger_db_by_ref(trigger_instance.trigger)

        rules_matcher = RulesMatcher(trigger_instance, trigger, rules)
        matching_rules = rules_matcher.get_matching_rules()
        self.assertEqual(matching_rules, [])
        self.assertEqual(len(matching_rules), 0)

        rule_enforcement_dbs = list(RuleEnforcement.get_all())
        self.assertEqual(len(rule_enforcement_dbs), 1)

        expected_failure = ('Failed to match rule "yoyohoneysingh.st2.test.rule4" against trigger '
                            'instance "%s": There might be a problem with the criteria in rule '
                            'yoyohoneysingh.st2.test.rule4: exception in equals' %
                            (str(trigger_instance.id)))
        self.assertEqual(rule_enforcement_dbs[0].failure_reason, expected_failure)
        self.assertEqual(rule_enforcement_dbs[0].trigger_instance_id, str(trigger_instance.id))
        self.assertEqual(rule_enforcement_dbs[0].rule['id'], str(rule_4_db.id))
        self.assertEqual(rule_enforcement_dbs[0].status, RULE_ENFORCEMENT_STATUS_FAILED)
Exemple #3
0
def create_trigger_instance(trigger, payload, occurrence_time, raise_on_no_trigger=False):
    """
    This creates a trigger instance object given trigger and payload.
    Trigger can be just a string reference (pack.name) or a ``dict``
    containing  'type' and 'parameters'.

    :param trigger: Dictionary with trigger query filters.
    :type trigger: ``dict``

    :param payload: Trigger payload.
    :type payload: ``dict``
    """
    # TODO: This is nasty, this should take a unique reference and not a dict
    if isinstance(trigger, six.string_types):
        trigger_db = TriggerService.get_trigger_db_by_ref(trigger)
    else:
        type_ = trigger.get('type', None)
        parameters = trigger.get('parameters', {})
        trigger_db = TriggerService.get_trigger_db_given_type_and_params(type=type_,
                                                                         parameters=parameters)

    if trigger_db is None:
        LOG.debug('No trigger in db for %s', trigger)
        if raise_on_no_trigger:
            raise StackStormDBObjectNotFoundError('Trigger not found for %s', trigger)
        return None

    trigger_ref = trigger_db.get_reference().ref

    trigger_instance = TriggerInstanceDB()
    trigger_instance.trigger = trigger_ref
    trigger_instance.payload = payload
    trigger_instance.occurrence_time = occurrence_time
    trigger_instance.status = TRIGGER_INSTANCE_PENDING
    return TriggerInstance.add_or_update(trigger_instance)
Exemple #4
0
def create_trigger_instance(trigger, payload, occurrence_time, raise_on_no_trigger=False):
    """
    This creates a trigger instance object given trigger and payload.
    Trigger can be just a string reference (pack.name) or a ``dict`` containing 'id' or
    'uid' or type' and 'parameters' keys.

    :param trigger: Trigger reference or dictionary with trigger query filters.
    :type trigger: ``str`` or ``dict``

    :param payload: Trigger payload.
    :type payload: ``dict``
    """
    # TODO: This is nasty, this should take a unique reference and not a dict
    if isinstance(trigger, six.string_types):
        trigger_db = TriggerService.get_trigger_db_by_ref(trigger)
    else:
        # If id / uid is available we try to look up Trigger by id. This way we can avoid bug in
        # pymongo / mongoengine related to "parameters" dictionary lookups
        trigger_id = trigger.get('id', None)
        trigger_uid = trigger.get('uid', None)

        # TODO: Remove parameters dictionary look up when we can confirm each trigger dictionary
        # passed to this method always contains id or uid
        if trigger_id:
            LOG.debug('Looking up TriggerDB by id: %s', trigger_id)
            trigger_db = TriggerService.get_trigger_db_by_id(id=trigger_id)
        elif trigger_uid:
            LOG.debug('Looking up TriggerDB by uid: %s', trigger_uid)
            trigger_db = TriggerService.get_trigger_db_by_uid(uid=trigger_uid)
        else:
            # Last resort - look it up by parameters
            trigger_type = trigger.get('type', None)
            parameters = trigger.get('parameters', {})

            LOG.debug('Looking up TriggerDB by type and parameters: type=%s, parameters=%s',
                      trigger_type, parameters)
            trigger_db = TriggerService.get_trigger_db_given_type_and_params(type=trigger_type,
                                                                             parameters=parameters)

    if trigger_db is None:
        LOG.debug('No trigger in db for %s', trigger)
        if raise_on_no_trigger:
            raise StackStormDBObjectNotFoundError('Trigger not found for %s', trigger)
        return None

    trigger_ref = trigger_db.get_reference().ref

    trigger_instance = TriggerInstanceDB()
    trigger_instance.trigger = trigger_ref
    trigger_instance.payload = payload
    trigger_instance.occurrence_time = occurrence_time
    trigger_instance.status = TRIGGER_INSTANCE_PENDING
    return TriggerInstance.add_or_update(trigger_instance)
 def test_get_matching_rules(self):
     self._setup_sample_trigger('st2.test.trigger1')
     trigger_instance = container_utils.create_trigger_instance(
         'dummy_pack_1.st2.test.trigger1',
         {'k1': 't1_p_v', 'k2': 'v2'},
         datetime.datetime.utcnow()
     )
     trigger = get_trigger_db_by_ref(trigger_instance.trigger)
     rules = self._get_sample_rules()
     rules_matcher = RulesMatcher(trigger_instance, trigger, rules)
     matching_rules = rules_matcher.get_matching_rules()
     self.assertTrue(matching_rules is not None)
     self.assertEqual(len(matching_rules), 1)
Exemple #6
0
    def get_matching_rules_for_trigger(self, trigger_instance):
        trigger = trigger_instance.trigger
        trigger = get_trigger_db_by_ref(trigger_instance.trigger)
        rules = Rule.query(trigger=trigger_instance.trigger, enabled=True)
        LOG.info('Found %d rules defined for trigger %s (type=%s)', len(rules), trigger['name'],
                 trigger['type'])
        matcher = RulesMatcher(trigger_instance=trigger_instance,
                               trigger=trigger, rules=rules)

        matching_rules = matcher.get_matching_rules()
        LOG.info('Matched %s rule(s) for trigger_instance %s (type=%s)', len(matching_rules),
                 trigger['name'], trigger['type'])
        return matching_rules
Exemple #7
0
    def _delete_shadow_trigger(triggertype_db):
        # shadow Trigger's have the same name as the shadowed TriggerType.
        triggertype_ref = ResourceReference(name=triggertype_db.name, pack=triggertype_db.pack)
        trigger_db = TriggerService.get_trigger_db_by_ref(triggertype_ref.ref)
        if not trigger_db:
            LOG.warn('No shadow trigger found for %s. Will skip delete.', triggertype_db)
            return
        try:
            Trigger.delete(trigger_db)
        except Exception:
            LOG.exception('Database delete encountered exception during delete of id="%s". ',
                          trigger_db.id)

        extra = {'trigger_db': trigger_db}
        LOG.audit('Trigger deleted. Trigger.id=%s' % (trigger_db.id), extra=extra)
 def test_trigger_instance_payload_with_special_values(self):
     # Test a rule where TriggerInstance payload contains a dot (".") and $
     self._setup_sample_trigger('st2.test.trigger2')
     trigger_instance = container_utils.create_trigger_instance(
         'dummy_pack_1.st2.test.trigger2',
         {'k1': 't1_p_v', 'k2.k2': 'v2', 'k3.more.nested.deep': 'some.value',
          'k4.even.more.nested$': 'foo', 'yep$aaa': 'b'},
         date_utils.get_datetime_utc_now()
     )
     trigger = get_trigger_db_by_ref(trigger_instance.trigger)
     rules = self._get_sample_rules()
     rules_matcher = RulesMatcher(trigger_instance, trigger, rules)
     matching_rules = rules_matcher.get_matching_rules()
     self.assertTrue(matching_rules is not None)
     self.assertEqual(len(matching_rules), 1)
Exemple #9
0
    def test_trigger_instance_payload_with_special_values(self):
        # Test a rule where TriggerInstance payload contains a dot (".") and $
        self._setup_sample_trigger('st2.test.trigger1')
        self._setup_sample_trigger('st2.test.trigger2')
        rule_db_1 = self._setup_sample_rule(RULE_1)
        rule_db_2 = self._setup_sample_rule(RULE_2)
        rule_db_3 = self._setup_sample_rule(RULE_3)
        rules = [rule_db_1, rule_db_2, rule_db_3]
        trigger_instance = container_utils.create_trigger_instance(
            'dummy_pack_1.st2.test.trigger2', {
                'k1': 't1_p_v',
                'k2.k2': 'v2',
                'k3.more.nested.deep': 'some.value',
                'k4.even.more.nested$': 'foo',
                'yep$aaa': 'b'
            }, date_utils.get_datetime_utc_now())

        trigger = get_trigger_db_by_ref(trigger_instance.trigger)
        rules_matcher = RulesMatcher(trigger_instance, trigger, rules)
        matching_rules = rules_matcher.get_matching_rules()
        self.assertIsNotNone(matching_rules)
        self.assertEqual(len(matching_rules), 1)
def create_trigger_instance(trigger,
                            payload,
                            occurrence_time,
                            raise_on_no_trigger=False):
    """
    This creates a trigger instance object given trigger and payload.
    Trigger can be just a string reference (pack.name) or a ``dict``
    containing  'type' and 'parameters'.

    :param trigger: Dictionary with trigger query filters.
    :type trigger: ``dict``

    :param payload: Trigger payload.
    :type payload: ``dict``
    """
    # TODO: This is nasty, this should take a unique reference and not a dict
    if isinstance(trigger, six.string_types):
        trigger_db = TriggerService.get_trigger_db_by_ref(trigger)
    else:
        type_ = trigger.get('type', None)
        parameters = trigger.get('parameters', {})
        trigger_db = TriggerService.get_trigger_db_given_type_and_params(
            type=type_, parameters=parameters)

    if trigger_db is None:
        LOG.debug('No trigger in db for %s', trigger)
        if raise_on_no_trigger:
            raise StackStormDBObjectNotFoundError('Trigger not found for %s',
                                                  trigger)
        return None

    trigger_ref = trigger_db.get_reference().ref

    trigger_instance = TriggerInstanceDB()
    trigger_instance.trigger = trigger_ref
    trigger_instance.payload = payload
    trigger_instance.occurrence_time = occurrence_time
    return TriggerInstance.add_or_update(trigger_instance)
Exemple #11
0
    def get_matching_rules_for_trigger(self, trigger_instance):
        trigger = trigger_instance.trigger

        trigger_db = get_trigger_db_by_ref(trigger_instance.trigger)

        if not trigger_db:
            LOG.error('No matching trigger found in db for trigger instance %s.', trigger_instance)
            return None

        rules = get_rules_given_trigger(trigger=trigger)

        LOG.info('Found %d rules defined for trigger %s', len(rules),
                 trigger_db.get_reference().ref)

        if len(rules) < 1:
            return rules

        matcher = RulesMatcher(trigger_instance=trigger_instance,
                               trigger=trigger_db, rules=rules)

        matching_rules = matcher.get_matching_rules()
        LOG.info('Matched %s rule(s) for trigger_instance %s (trigger=%s)', len(matching_rules),
                 trigger_instance['id'], trigger_db.ref)
        return matching_rules
Exemple #12
0
def validate_trigger_payload(trigger_type_ref,
                             payload,
                             throw_on_inexistent_trigger=False):
    """
    This function validates trigger payload parameters for system and user-defined triggers.

    :param trigger_type_ref: Reference of a trigger type / trigger / trigger dictionary object.
    :type trigger_type_ref: ``str``

    :param payload: Trigger payload.
    :type payload: ``dict``

    :return: Cleaned payload on success, None if validation is not performed.
    """
    if not trigger_type_ref:
        return None

    # NOTE: Due to the awful code in some other places we also need to support a scenario where
    # this variable is a dictionary and contains various TriggerDB object attributes.
    if isinstance(trigger_type_ref, dict):
        if trigger_type_ref.get('type', None):
            trigger_type_ref = trigger_type_ref['type']
        else:
            trigger_db = triggers.get_trigger_db_by_ref_or_dict(
                trigger_type_ref)

            if not trigger_db:
                # Corresponding TriggerDB not found, likely a corrupted database, skip the
                # validation.
                return None

            trigger_type_ref = trigger_db.type

    is_system_trigger = trigger_type_ref in SYSTEM_TRIGGER_TYPES
    if is_system_trigger:
        # System trigger
        payload_schema = SYSTEM_TRIGGER_TYPES[trigger_type_ref][
            'payload_schema']
    else:
        # We assume Trigger ref and not TriggerType ref is passed in if second
        # part (trigger name) is a valid UUID version 4
        try:
            trigger_uuid = uuid.UUID(trigger_type_ref.split('.')[-1])
        except ValueError:
            is_trigger_db = False
        else:
            is_trigger_db = (trigger_uuid.version == 4)

        if is_trigger_db:
            trigger_db = triggers.get_trigger_db_by_ref(trigger_type_ref)

            if trigger_db:
                trigger_type_ref = trigger_db.type

        trigger_type_db = triggers.get_trigger_type_db(trigger_type_ref)

        if not trigger_type_db:
            # Trigger doesn't exist in the database
            if throw_on_inexistent_trigger:
                msg = (
                    'Trigger type with reference "%s" doesn\'t exist in the database'
                    % (trigger_type_ref))
                raise ValueError(msg)

            return None

        payload_schema = getattr(trigger_type_db, 'payload_schema', {})
        if not payload_schema:
            # Payload schema not defined for the this trigger
            return None

    # We only validate non-system triggers if config option is set (enabled)
    if not is_system_trigger and not cfg.CONF.system.validate_trigger_payload:
        LOG.debug(
            'Got non-system trigger "%s", but trigger payload validation for non-system'
            'triggers is disabled, skipping validation.' % (trigger_type_ref))
        return None

    cleaned = util_schema.validate(instance=payload,
                                   schema=payload_schema,
                                   cls=util_schema.CustomValidator,
                                   use_default=True,
                                   allow_default_none=True)

    return cleaned
Exemple #13
0
def validate_trigger_payload(trigger_type_ref, payload, throw_on_inexistent_trigger=False):
    """
    This function validates trigger payload parameters for system and user-defined triggers.

    :param trigger_type_ref: Reference of a trigger type / trigger / trigger dictionary object.
    :type trigger_type_ref: ``str``

    :param payload: Trigger payload.
    :type payload: ``dict``

    :return: Cleaned payload on success, None if validation is not performed.
    """
    if not trigger_type_ref:
        return None

    # NOTE: Due to the awful code in some other places we also need to support a scenario where
    # this variable is a dictionary and contains various TriggerDB object attributes.
    if isinstance(trigger_type_ref, dict):
        if trigger_type_ref.get('type', None):
            trigger_type_ref = trigger_type_ref['type']
        else:
            trigger_db = triggers.get_trigger_db_by_ref_or_dict(trigger_type_ref)

            if not trigger_db:
                # Corresponding TriggerDB not found, likely a corrupted database, skip the
                # validation.
                return None

            trigger_type_ref = trigger_db.type

    is_system_trigger = trigger_type_ref in SYSTEM_TRIGGER_TYPES
    if is_system_trigger:
        # System trigger
        payload_schema = SYSTEM_TRIGGER_TYPES[trigger_type_ref]['payload_schema']
    else:
        # We assume Trigger ref and not TriggerType ref is passed in if second
        # part (trigger name) is a valid UUID version 4
        try:
            trigger_uuid = uuid.UUID(trigger_type_ref.split('.')[-1])
        except ValueError:
            is_trigger_db = False
        else:
            is_trigger_db = (trigger_uuid.version == 4)

        if is_trigger_db:
            trigger_db = triggers.get_trigger_db_by_ref(trigger_type_ref)

            if trigger_db:
                trigger_type_ref = trigger_db.type

        trigger_type_db = triggers.get_trigger_type_db(trigger_type_ref)

        if not trigger_type_db:
            # Trigger doesn't exist in the database
            if throw_on_inexistent_trigger:
                msg = ('Trigger type with reference "%s" doesn\'t exist in the database' %
                       (trigger_type_ref))
                raise ValueError(msg)

            return None

        payload_schema = getattr(trigger_type_db, 'payload_schema', {})
        if not payload_schema:
            # Payload schema not defined for the this trigger
            return None

    # We only validate non-system triggers if config option is set (enabled)
    if not is_system_trigger and not cfg.CONF.system.validate_trigger_payload:
        LOG.debug('Got non-system trigger "%s", but trigger payload validation for non-system'
                  'triggers is disabled, skipping validation.' % (trigger_type_ref))
        return None

    cleaned = util_schema.validate(instance=payload, schema=payload_schema,
                                   cls=util_schema.CustomValidator, use_default=True,
                                   allow_default_none=True)

    return cleaned