Example #1
0
def ListAllConfigs(client):
  """Yield tuples of (config_set, revision, subscription)."""
  with client.transaction(read_only=True):
    # First look up the global index.
    subscription_index_key = client.key('SubscriptionIndex', 'global')
    subscription_index = client.get(subscription_index_key)
    if subscription_index is None:
      return

    # Then for each instance in the 'config_sets', create a key based on the
    # subscription_index_key as a parent, and look those up in one go.
    config_sets = client.get_multi([
        client.key('Subscription', key, parent=subscription_index_key)
        for key in subscription_index['config_sets']
    ])

  # From there we can then go through each of the subscriptions in the retrieved
  # configs
  subscriptions = []
  for config in config_sets:
    sheriff_config = sheriff_pb2.SheriffConfig()
    sheriff_config.ParseFromString(config['sheriff_config'])
    for subscription in sheriff_config.subscriptions:
      subscriptions.append((
          config['config_set'],
          config['revision'],
          subscription,
      ))
  return subscriptions
Example #2
0
def Validate(content):
    """Takes raw content to determine whether it is a valid configuration.

  This function ensures that the protocol buffer contents are a syntactically
  and semantically valid sheriff configuration.

  Args:
    content: Bytes representing a text format protocol buffer.

  Returns:
    A valid SherifConfig object.
  """
    try:
        result = text_format.Parse(content, sheriff_pb2.SheriffConfig())
    except text_format.ParseError as error:
        raise InvalidConfig('SheriffConfig Validation Error: %s' % (error))

    # Go through each of the subscriptions, and ensure we find the semantically
    # required fields.
    for (index, subscription) in enumerate(result.subscriptions):
        if subscription.contact_email is None or len(
                subscription.contact_email) == 0:
            raise MissingEmail(result, index)
        if subscription.name is None or len(subscription.name) == 0:
            raise MissingName(result, index)
        if subscription.patterns is None or len(subscription.patterns) == 0:
            raise MissingPatterns(result, index)
        for (pattern_idx, pattern) in enumerate(subscription.patterns):
            field = pattern.WhichOneof('pattern')
            if field is None:
                raise InvalidPattern(
                    result, index, pattern_idx,
                    'must provide either \'glob\' or \'regex\'')
            elif field == 'glob' and len(pattern.glob) == 0:
                raise InvalidPattern(result, index, pattern_idx,
                                     'glob must not be empty')
            elif field == 'regex' and len(pattern.regex) == 0:
                raise InvalidPattern(result, index, pattern_idx,
                                     'regex must not be empty')

    return result
Example #3
0
def FindMatchingConfigs(client, request):
    """Yield tuples of (config_set, revision, subscription)."""
    with client.transaction(read_only=True):
        # First look up the global index.
        subscription_index_key = client.key('SubscriptionIndex', 'global')
        subscription_index = client.get(subscription_index_key)
        if subscription_index is None:
            return

        # Then for each instance in the 'config_sets', create a key based on the
        # subscription_index_key as a parent, and look those up in one go.
        config_sets = client.get_multi([
            client.key('Subscription', key, parent=subscription_index_key)
            for key in subscription_index['config_sets']
        ])

    # From there we can then go through each of the subscriptions in the retrieved
    # configs, and yield the ones that have patterns applying to the request.
    for config in config_sets:
        sheriff_config = sheriff_pb2.SheriffConfig()
        sheriff_config.ParseFromString(config['sheriff_config'])
        for subscription in sheriff_config.subscriptions:
            for pattern in subscription.patterns:
                if pattern.HasField('glob'):
                    matcher = re.compile(fnmatch.translate(pattern.glob))
                elif pattern.HasField('regex'):
                    matcher = re.compile(pattern.regex)
                else:
                    # TODO(dberris): this is the extension point for supporting new
                    # matchers; for now we'll skip the new patterns we don't handle yet.
                    continue
                result = matcher.match(request.path)
                if result is not None:
                    yield (config['config_set'], config['revision'],
                           subscription)
                    # We break immediately after the yield, so that we can ignore the rest
                    # of the patterns defined for this subscription.
                    break
Example #4
0
def Validate(content):
    """Takes raw content to determine whether it is a valid configuration.

  This function ensures that the protocol buffer contents are a syntactically
  and semantically valid sheriff configuration.

  Args:
    content: Bytes representing a text format protocol buffer.

  Returns:
    A valid SherifConfig object.
  """
    try:
        result = text_format.Parse(content, sheriff_pb2.SheriffConfig())
    except text_format.ParseError as error:
        raise InvalidConfig('SheriffConfig Validation Error: %s' % (error))

    # Go through each of the subscriptions, and ensure we find the semantically
    # required fields.
    def ValidatePattern(index, pattern_idx, pattern, group):
        field = pattern.WhichOneof('pattern')
        if field is None:
            raise InvalidPattern(result, index, pattern_idx,
                                 'must provide either \'glob\' or \'regex\'',
                                 group)
        elif field == 'glob' and len(pattern.glob) == 0:
            raise InvalidPattern(result, index, pattern_idx,
                                 'glob must not be empty', group)
        elif field == 'regex' and len(pattern.regex) == 0:
            raise InvalidPattern(result, index, pattern_idx,
                                 'regex must not be empty', group)
        try:
            matcher.CompilePattern(pattern)
        except re2.error as e:
            raise InvalidPattern(result, index, pattern_idx,
                                 'failed: %s' % (e, ), group)

    for (index, subscription) in enumerate(result.subscriptions):
        if subscription.contact_email is None or len(
                subscription.contact_email) == 0:
            raise MissingEmail(result, index)
        if subscription.name is None or len(subscription.name) == 0:
            raise MissingName(result, index)
        if not subscription.rules.match:
            raise MissingPatterns(result, index)

        for (pattern_idx, pattern) in enumerate(subscription.rules.match):
            ValidatePattern(index, pattern_idx, pattern, 'rules.match')
        for (pattern_idx, pattern) in enumerate(subscription.rules.exclude):
            ValidatePattern(index, pattern_idx, pattern, 'rules.exclude')
        for (pattern_idx,
             pattern) in enumerate(subscription.auto_triage.rules.match):
            ValidatePattern(index, pattern_idx, pattern,
                            'auto_triage.rules.match')
        for (pattern_idx,
             pattern) in enumerate(subscription.auto_triage.rules.exclude):
            ValidatePattern(index, pattern_idx, pattern,
                            'auto_triage.rules.exclude')
        for (pattern_idx,
             pattern) in enumerate(subscription.auto_bisection.rules.match):
            ValidatePattern(index, pattern_idx, pattern,
                            'auto_bisection.rules.match')
        for (pattern_idx,
             pattern) in enumerate(subscription.auto_bisection.rules.exclude):
            ValidatePattern(index, pattern_idx, pattern,
                            'auto_bisection.rules.exclude')

        # Validate patterns for anomaly configurations.
        for (anomaly_config_idx,
             anomaly_config) in enumerate(subscription.anomaly_configs):
            for (pattern_idx,
                 pattern) in enumerate(anomaly_config.rules.match):
                ValidatePattern(
                    index, pattern_idx, pattern,
                    'anomaly_configs[{}].rules.match'.format(
                        anomaly_config_idx))
            for (pattern_idx,
                 pattern) in enumerate(anomaly_config.rules.exclude):
                ValidatePattern(
                    index, pattern_idx, pattern,
                    'anomaly_configs[{}].rules.exclude'.format(
                        anomaly_config_idx))

    return result