Esempio n. 1
0
    def _value_to_sort(self, config, r):
        expr = config.get('key')
        vtype = config.get('value_type', 'string')
        vregex = config.get('value_regex')
        v = None

        try:
            # extract value based on jmespath
            if expr:
                v = self.get_resource_value(expr, r, vregex)

            if v is not None:
                # now convert to expected type
                if vtype == 'number':
                    v = float(v)
                elif vtype == 'date':
                    v = parse_date(v)
                else:
                    v = str(v)
        except (AttributeError, ValueError):
            v = None

        if v is None:
            v = config.get('null_sort_value')
        return v
Esempio n. 2
0
    def validate(self):
        if len(self.data) == 1:
            return self

        # `resource_count` requires a slightly different schema than the rest of
        # the value filters because it operates on the full resource list
        if self.data.get('value_type') == 'resource_count':
            return self._validate_resource_count()
        elif self.data.get('value_type') == 'date':
            if not parse_date(self.data.get('value')):
                raise PolicyValidationError(
                    "value_type: date with invalid date value:%s",
                    self.data.get('value', ''))
        if 'key' not in self.data and 'key' in self.required_keys:
            raise PolicyValidationError("Missing 'key' in value filter %s" %
                                        self.data)
        if ('value' not in self.data and 'value_from' not in self.data
                and 'value' in self.required_keys):
            raise PolicyValidationError("Missing 'value' in value filter %s" %
                                        self.data)
        if 'op' in self.data:
            if not self.data['op'] in OPERATORS:
                raise PolicyValidationError(
                    "Invalid operator in value filter %s" % self.data)
            if self.data['op'] in {'regex', 'regex-case'}:
                # Sanity check that we can compile
                try:
                    re.compile(self.data['value'])
                except re.error as e:
                    raise PolicyValidationError("Invalid regex: %s %s" %
                                                (e, self.data))
        if 'value_regex' in self.data:
            return self._validate_value_regex(self.data['value_regex'])

        return self
Esempio n. 3
0
    def process_lambda(self, client, r):
        exclude_aliases = self.data.get('exclude-aliases', True)
        retain_latest = self.data.get('retain-latest', False)
        date_threshold = self.data.get('older-than')
        date_threshold = (date_threshold and parse_date(datetime.utcnow()) -
                          timedelta(days=date_threshold) or None)
        aliased_versions = ()

        if exclude_aliases:
            aliased_versions = self.get_aliased_versions(client, r)

        versions_pager = client.get_paginator('list_versions_by_function')
        versions_pager.PAGE_ITERATOR_CLASS = query.RetryPageIterator
        pager = versions_pager.paginate(FunctionName=r['FunctionName'])

        matched = total = 0
        latest_sha = None

        for page in pager:
            versions = page.get('Versions')
            for v in versions:
                if v['Version'] == '$LATEST':
                    latest_sha = v['CodeSha256']
                    continue
                total += v['CodeSize']
                if v['FunctionArn'] in aliased_versions:
                    continue
                if date_threshold and parse_date(
                        v['LastModified']) > date_threshold:
                    continue
                # Retain numbered version, not required, but it feels like a good thing
                # to do. else the latest alias will still point.
                if retain_latest and latest_sha and v[
                        'CodeSha256'] == latest_sha:
                    continue
                matched += v['CodeSize']
                self.manager.retry(client.delete_function,
                                   FunctionName=v['FunctionArn'])
        return (matched, total)
Esempio n. 4
0
    def process_value_type(self, sentinel, value, resource):
        if self.vtype == 'normalize' and isinstance(value, str):
            return sentinel, value.strip().lower()

        elif self.vtype == 'expr':
            sentinel = self.get_resource_value(sentinel, resource)
            return sentinel, value

        elif self.vtype == 'integer':
            try:
                value = int(str(value).strip())
            except ValueError:
                value = 0
        elif self.vtype == 'size':
            try:
                return sentinel, len(value)
            except TypeError:
                return sentinel, 0
        elif self.vtype == 'unique_size':
            try:
                return sentinel, len(set(value))
            except TypeError:
                return sentinel, 0
        elif self.vtype == 'swap':
            return value, sentinel
        elif self.vtype == 'date':
            return parse_date(sentinel), parse_date(value)
        elif self.vtype == 'age':
            if not isinstance(sentinel, datetime.datetime):
                sentinel = datetime.datetime.now(tz=tzutc()) - timedelta(sentinel)
            value = parse_date(value)
            if value is None:
                # compatiblity
                value = 0
            # Reverse the age comparison, we want to compare the value being
            # greater than the sentinel typically. Else the syntax for age
            # comparisons is intuitively wrong.
            return value, sentinel
        elif self.vtype == 'cidr':
            s = parse_cidr(sentinel)
            v = parse_cidr(value)
            if (isinstance(s, ipaddress._BaseAddress) and isinstance(v, ipaddress._BaseNetwork)):
                return v, s
            return s, v
        elif self.vtype == 'cidr_size':
            cidr = parse_cidr(value)
            if cidr:
                return sentinel, cidr.prefixlen
            return sentinel, 0

        # Allows for expiration filtering, for events in the future as opposed
        # to events in the past which age filtering allows for.
        elif self.vtype == 'expiration':
            if not isinstance(sentinel, datetime.datetime):
                sentinel = datetime.datetime.now(tz=tzutc()) + timedelta(sentinel)
            value = parse_date(value)
            if value is None:
                value = 0
            return sentinel, value

        # Allows for comparing version numbers, for things that you expect a minimum version number.
        elif self.vtype == 'version':
            s = ComparableVersion(sentinel)
            v = ComparableVersion(value)
            return s, v

        return sentinel, value
Esempio n. 5
0
def test_parse_date_floor():
    # bulk of parse date tests are actually in test_filters
    assert utils.parse_date(30) is None
    assert utils.parse_date(1) is None
    assert utils.parse_date('3000') is None
    assert utils.parse_date('30') is None