Beispiel #1
0
    def _render_criteria_pattern(self, criteria_pattern, criteria_context):
        # Note: Here we want to use strict comparison to None to make sure that
        # other falsy values such as integer 0 are handled correctly.
        if criteria_pattern is None:
            return None

        if not isinstance(criteria_pattern, six.string_types):
            # We only perform rendering if value is a string - rendering a non-string value
            # makes no sense
            return criteria_pattern

        LOG.debug(
            'Rendering criteria pattern (%s) with context: %s',
            criteria_pattern,
            criteria_context
        )

        to_complex = False

        # Check if jinja variable is in criteria_pattern and if so lets ensure
        # the proper type is applied to it using to_complex jinja filter
        if len(re.findall(MATCH_CRITERIA, criteria_pattern)) > 0:
            LOG.debug("Rendering Complex")
            complex_criteria_pattern = re.sub(
                MATCH_CRITERIA, r'\1\2 | to_complex\3',
                criteria_pattern
            )

            try:
                criteria_rendered = render_template_with_system_context(
                    value=complex_criteria_pattern,
                    context=criteria_context
                )
                criteria_rendered = json.loads(criteria_rendered)
                to_complex = True
            except ValueError as error:
                LOG.debug('Criteria pattern not valid JSON: %s', error)

        if not to_complex:
            criteria_rendered = render_template_with_system_context(
                value=criteria_pattern,
                context=criteria_context
            )

        LOG.debug(
            'Rendered criteria pattern: %s',
            criteria_rendered
        )

        return criteria_rendered
Beispiel #2
0
    def _render_criteria_pattern(self, criteria_pattern, criteria_context):
        # Note: Here we want to use strict comparison to None to make sure that
        # other falsy values such as integer 0 are handled correctly.
        if criteria_pattern is None:
            return None

        if not isinstance(criteria_pattern, six.string_types):
            # We only perform rendering if value is a string - rendering a non-string value
            # makes no sense
            return criteria_pattern

        LOG.debug('Rendering criteria pattern (%s) with context: %s',
                  criteria_pattern, criteria_context)

        to_complex = False

        # Check if jinja variable is in criteria_pattern and if so lets ensure
        # the proper type is applied to it using to_complex jinja filter
        if len(re.findall(MATCH_CRITERIA, criteria_pattern)) > 0:
            LOG.debug("Rendering Complex")
            complex_criteria_pattern = re.sub(MATCH_CRITERIA,
                                              r'\1\2 | to_complex\3',
                                              criteria_pattern)

            try:
                criteria_rendered = render_template_with_system_context(
                    value=complex_criteria_pattern, context=criteria_context)
                criteria_rendered = json.loads(criteria_rendered)
                to_complex = True
            except ValueError, error:
                LOG.debug('Criteria pattern not valid JSON: %s', error)
Beispiel #3
0
    def _render_criteria_pattern(self, criteria_pattern):
        if not criteria_pattern:
            return None

        if not isinstance(criteria_pattern, six.string_types):
            # We only perform rendering if value is a string - rendering a non-string value
            # makes no sense
            return criteria_pattern

        criteria_pattern = render_template_with_system_context(value=criteria_pattern)
        return criteria_pattern
Beispiel #4
0
    def _render_criteria_pattern(self, criteria_pattern):
        # Note: Here we want to use strict comparison to None to make sure that
        # other falsy values such as integer 0 are handled correctly.
        if criteria_pattern is None:
            return None

        if not isinstance(criteria_pattern, six.string_types):
            # We only perform rendering if value is a string - rendering a non-string value
            # makes no sense
            return criteria_pattern

        criteria_pattern = render_template_with_system_context(value=criteria_pattern)
        return criteria_pattern
Beispiel #5
0
    def _render_criteria_pattern(self, criteria_pattern):
        # Note: Here we want to use strict comparison to None to make sure that
        # other falsy values such as integer 0 are handled correctly.
        if criteria_pattern is None:
            return None

        if not isinstance(criteria_pattern, six.string_types):
            # We only perform rendering if value is a string - rendering a non-string value
            # makes no sense
            return criteria_pattern

        criteria_pattern = render_template_with_system_context(value=criteria_pattern)
        return criteria_pattern
Beispiel #6
0
class RuleFilter(object):
    def __init__(self, trigger_instance, trigger, rule, extra_info=False):
        """
        :param trigger_instance: TriggerInstance DB object.
        :type trigger_instance: :class:`TriggerInstanceDB``

        :param trigger: Trigger DB object.
        :type trigger: :class:`TriggerDB`

        :param rule: Rule DB object.
        :type rule: :class:`RuleDB`
        """
        self.trigger_instance = trigger_instance
        self.trigger = trigger
        self.rule = rule
        self.extra_info = extra_info

        # Base context used with a logger
        self._base_logger_context = {
            'rule': self.rule,
            'trigger': self.trigger,
            'trigger_instance': self.trigger_instance
        }

    def filter(self):
        """
        Return true if the rule is applicable to the provided trigger instance.

        :rtype: ``bool``
        """
        LOG.info('Validating rule %s for %s.',
                 self.rule.ref,
                 self.trigger['name'],
                 extra=self._base_logger_context)

        if not self.rule.enabled:
            if self.extra_info:
                LOG.info('Validation failed for rule %s as it is disabled.',
                         self.rule.ref)
            return False

        criteria = self.rule.criteria
        is_rule_applicable = True

        if criteria and not self.trigger_instance.payload:
            return False

        payload_lookup = PayloadLookup(self.trigger_instance.payload)

        LOG.debug('Trigger payload: %s',
                  self.trigger_instance.payload,
                  extra=self._base_logger_context)

        for (criterion_k, criterion_v) in six.iteritems(criteria):
            is_rule_applicable, payload_value, criterion_pattern = self._check_criterion(
                criterion_k, criterion_v, payload_lookup)
            if not is_rule_applicable:
                if self.extra_info:
                    criteria_extra_info = '\n'.join([
                        '  key: %s' % criterion_k,
                        '  pattern: %s' % criterion_pattern,
                        '  type: %s' % criterion_v['type'],
                        '  payload: %s' % payload_value
                    ])
                    LOG.info('Validation for rule %s failed on criteria -\n%s',
                             self.rule.ref,
                             criteria_extra_info,
                             extra=self._base_logger_context)
                break

        if not is_rule_applicable:
            LOG.debug('Rule %s not applicable for %s.',
                      self.rule.id,
                      self.trigger['name'],
                      extra=self._base_logger_context)

        return is_rule_applicable

    def _check_criterion(self, criterion_k, criterion_v, payload_lookup):
        if 'type' not in criterion_v:
            # Comparison operator type not specified, can't perform a comparison
            return (False, None, None)

        criteria_operator = criterion_v['type']
        criteria_condition = criterion_v.get('condition', None)
        criteria_pattern = criterion_v.get('pattern', None)

        # Render the pattern (it can contain a jinja expressions)
        try:
            criteria_pattern = self._render_criteria_pattern(
                criteria_pattern=criteria_pattern,
                criteria_context=payload_lookup.context)
        except Exception:
            LOG.exception('Failed to render pattern value "%s" for key "%s"' %
                          (criteria_pattern, criterion_k),
                          extra=self._base_logger_context)
            return (False, None, None)

        try:
            matches = payload_lookup.get_value(criterion_k)
            # pick value if only 1 matches else will end up being an array match.
            if matches:
                payload_value = matches[0] if len(matches) > 0 else matches
            else:
                payload_value = None
        except:
            LOG.exception('Failed transforming criteria key %s',
                          criterion_k,
                          extra=self._base_logger_context)
            return (False, None, None)

        op_func = criteria_operators.get_operator(criteria_operator)

        try:
            if criteria_operator == criteria_operators.SEARCH:
                result = op_func(value=payload_value,
                                 criteria_pattern=criteria_pattern,
                                 criteria_condition=criteria_condition,
                                 check_function=self._bool_criterion)
            else:
                result = op_func(value=payload_value,
                                 criteria_pattern=criteria_pattern)
        except:
            LOG.exception(
                'There might be a problem with the criteria in rule %s.',
                self.rule,
                extra=self._base_logger_context)
            return (False, None, None)

        return result, payload_value, criteria_pattern

    def _bool_criterion(self, criterion_k, criterion_v, payload_lookup):
        # Pass through to _check_criterion, but pull off and return only the
        # final result
        return self._check_criterion(criterion_k, criterion_v,
                                     payload_lookup)[0]

    def _render_criteria_pattern(self, criteria_pattern, criteria_context):
        # Note: Here we want to use strict comparison to None to make sure that
        # other falsy values such as integer 0 are handled correctly.
        if criteria_pattern is None:
            return None

        if not isinstance(criteria_pattern, six.string_types):
            # We only perform rendering if value is a string - rendering a non-string value
            # makes no sense
            return criteria_pattern

        LOG.debug('Rendering criteria pattern (%s) with context: %s',
                  criteria_pattern, criteria_context)

        to_complex = False

        # Check if jinja variable is in criteria_pattern and if so lets ensure
        # the proper type is applied to it using to_complex jinja filter
        if len(re.findall(MATCH_CRITERIA, criteria_pattern)) > 0:
            LOG.debug("Rendering Complex")
            complex_criteria_pattern = re.sub(MATCH_CRITERIA,
                                              r'\1\2 | to_complex\3',
                                              criteria_pattern)

            try:
                criteria_rendered = render_template_with_system_context(
                    value=complex_criteria_pattern, context=criteria_context)
                criteria_rendered = json.loads(criteria_rendered)
                to_complex = True
            except ValueError, error:
                LOG.debug('Criteria pattern not valid JSON: %s', error)

        if not to_complex:
            criteria_rendered = render_template_with_system_context(
                value=criteria_pattern, context=criteria_context)

        LOG.debug('Rendered criteria pattern: %s', criteria_rendered)

        return criteria_rendered