예제 #1
0
def index_resources(
        config, policies, date=None, concurrency=5,
        accounts=None, tag=None, verbose=False):
    """index policy resources"""
    logging.basicConfig(level=(verbose and logging.DEBUG or logging.INFO))
    logging.getLogger('botocore').setLevel(logging.WARNING)
    logging.getLogger('elasticsearch').setLevel(logging.WARNING)
    logging.getLogger('urllib3').setLevel(logging.WARNING)
    logging.getLogger('requests').setLevel(logging.WARNING)
    logging.getLogger('c7n.worker').setLevel(logging.INFO)

    # validating the config and policy files.
    with open(config) as fh:
        config = yaml.safe_load(fh.read())
    jsonschema.validate(config, CONFIG_SCHEMA)

    with open(policies) as fh:
        policies = yaml.safe_load(fh.read())
    load_resources()
    schema.validate(policies)

    date = valid_date(date, delta=1)

    with ProcessPoolExecutor(max_workers=concurrency) as w:
        futures = {}
        jobs = []

        for account in config.get('accounts'):
            if accounts and account['name'] not in accounts:
                continue
            if tag:
                found = False
                for t in account['tags'].values():
                    if tag == t:
                        found = True
                        break
                if not found:
                    continue
            for region in account.get('regions'):
                for policy in policies.get('policies'):
                    p = (config, account, region, policy, date)
                    jobs.append(p)

        for j in jobs:
            log.debug("submit account:{} region:{} policy:{} date:{}".format(
                j[1]['name'], j[2], j[3]['name'], j[4]))
            futures[w.submit(index_account_resources, *j)] = j

        # Process completed
        for f in as_completed(futures):
            config, account, region, policy, date = futures[f]
            if f.exception():
                log.warning(
                    "error account:{} region:{} policy:{} error:{}".format(
                        account['name'], region, policy['name'], f.exception()))
                continue
            log.info("complete account:{} region:{} policy:{}".format(
                account['name'], region, policy['name']))
예제 #2
0
def index_resources(
        config, policies, date=None, concurrency=5,
        accounts=None, tag=None, verbose=False):
    """index policy resources"""
    logging.basicConfig(level=(verbose and logging.DEBUG or logging.INFO))
    logging.getLogger('botocore').setLevel(logging.WARNING)
    logging.getLogger('elasticsearch').setLevel(logging.WARNING)
    logging.getLogger('urllib3').setLevel(logging.WARNING)
    logging.getLogger('requests').setLevel(logging.WARNING)
    logging.getLogger('c7n.worker').setLevel(logging.INFO)

    # validating the config and policy files.
    with open(config) as fh:
        config = yaml.safe_load(fh.read())
    jsonschema.validate(config, CONFIG_SCHEMA)

    with open(policies) as fh:
        policies = yaml.safe_load(fh.read())
    load_resources()
    schema.validate(policies)

    date = valid_date(date, delta=1)

    with ProcessPoolExecutor(max_workers=concurrency) as w:
        futures = {}
        jobs = []

        for account in config.get('accounts'):
            if accounts and account['name'] not in accounts:
                continue
            if tag:
                found = False
                for t in account['tags'].values():
                    if tag == t:
                        found = True
                        break
                if not found:
                    continue
            for region in account.get('regions'):
                for policy in policies.get('policies'):
                    p = (config, account, region, policy, date)
                    jobs.append(p)

        for j in jobs:
            log.debug("submit account:{} region:{} policy:{} date:{}".format(
                j[1]['name'], j[2], j[3]['name'], j[4]))
            futures[w.submit(index_account_resources, *j)] = j

        # Process completed
        for f in as_completed(futures):
            config, account, region, policy, date = futures[f]
            if f.exception():
                log.warning(
                    "error account:{} region:{} policy:{} error:{}".format(
                        account['name'], region, policy['name'], f.exception()))
                continue
            log.info("complete account:{} region:{} policy:{}".format(
                account['name'], region, policy['name']))
예제 #3
0
def load(options, path, format='yaml', validate=True):
    # should we do os.path.expanduser here?
    if not os.path.exists(path):
        raise IOError("Invalid path for config %r" % path)

    load_resources()
    with open(path) as fh:
        if format == 'yaml':
            data = utils.yaml_load(fh.read())
        elif format == 'json':
            data = utils.loads(fh.read())
            validate = False

    # Test for empty policy file
    if not data or data.get('policies') is None:
        return None

    if validate:
        from c7n.schema import validate
        errors = validate(data)
        if errors:
            raise Exception("Failed to validate on policy %s \n %s" %
                            (errors[1], errors[0]))

    collection = PolicyCollection.from_data(data, options)
    return collection
예제 #4
0
def load(options, path, format='yaml', validate=True, vars=None):
    # should we do os.path.expanduser here?
    if not os.path.exists(path):
        raise IOError("Invalid path for config %r" % path)

    load_resources()
    data = utils.load_file(path, format=format, vars=vars)

    if format == 'json':
        validate = False

    if isinstance(data, list):
        log.warning('yaml in invalid format. The "policies:" line is probably missing.')
        return None

    # Test for empty policy file
    if not data or data.get('policies') is None:
        return None

    if validate:
        from c7n.schema import validate
        errors = validate(data)
        if errors:
            raise Exception(
                "Failed to validate on policy %s \n %s" % (
                    errors[1], errors[0]))

    collection = PolicyCollection.from_data(data, options)
    if validate:
        # non schema validation of policies
        [p.validate() for p in collection]
    return collection
예제 #5
0
def validate(options):
    if not os.path.exists(options.config):
        raise ValueError("Invalid path for config %r" % options.config)

    options.dryrun = True
    format = options.config.rsplit('.', 1)[-1]
    with open(options.config) as fh:
        if format in ('yml', 'yaml'):
            data = yaml.safe_load(fh.read())
        if format in ('json',):
            data = json.load(fh)


    errors = schema.validate(data)
    if not errors:
        null_config = Bag(dryrun=True, log_group=None, cache=None, assume_role="na")
        for p in data.get('policies', ()):
            try:
                Policy(p, null_config, Bag())
            except Exception as e:
                log.error("Policy: %s is invalid: %s" % (
                    p.get('name', 'unknown'), e))
                sys.exit(1)
                return
        log.info("Config valid")
        return

    log.error("Invalid configuration")
    for e in errors:
        log.error(" %s" % e)
    sys.exit(1)
예제 #6
0
def validate(options):
    if not os.path.exists(options.config):
        raise ValueError("Invalid path for config %r" % options.config)

    options.dryrun = True
    format = options.config.rsplit('.', 1)[-1]
    with open(options.config) as fh:
        if format in ('yml', 'yaml'):
            data = yaml.safe_load(fh.read())
        if format in ('json',):
            data = json.load(fh)


    errors = schema.validate(data)
    if not errors:
        null_config = Bag(dryrun=True, log_group=None, cache=None, assume_role="na")
        for p in data.get('policies', ()):
            try:
                Policy(p, null_config, Bag())
            except Exception as e:
                log.error("Policy: %s is invalid: %s" % (
                    p.get('name', 'unknown'), e))
                sys.exit(1)
                return
        log.info("Config valid")
        return

    log.error("Invalid configuration")
    for e in errors:
        log.error(" %s" % e)
    sys.exit(1)
예제 #7
0
def validate(options):
    load_resources()
    if len(options.configs) < 1:
        log.error('no config files specified')
        sys.exit(1)

    used_policy_names = set()
    schm = schema.generate()
    errors = []
    for config_file in options.configs:
        config_file = os.path.expanduser(config_file)
        if not os.path.exists(config_file):
            raise ValueError("Invalid path for config %r" % config_file)

        options.dryrun = True
        fmt = config_file.rsplit('.', 1)[-1]
        with open(config_file) as fh:
            if fmt in ('yml', 'yaml'):
                data = yaml.safe_load(fh.read())
            elif fmt in ('json', ):
                data = json.load(fh)
            else:
                log.error("The config file must end in .json, .yml or .yaml.")
                raise ValueError(
                    "The config file must end in .json, .yml or .yaml.")

        errors += schema.validate(data, schm)
        conf_policy_names = {
            p.get('name', 'unknown')
            for p in data.get('policies', ())
        }
        dupes = conf_policy_names.intersection(used_policy_names)
        if len(dupes) >= 1:
            errors.append(
                ValueError(
                    "Only one policy with a given name allowed, duplicates: %s"
                    % (", ".join(dupes))))
        used_policy_names = used_policy_names.union(conf_policy_names)
        if not errors:
            null_config = Bag(dryrun=True,
                              log_group=None,
                              cache=None,
                              assume_role="na")
            for p in data.get('policies', ()):
                try:
                    policy = Policy(p, null_config, Bag())
                    policy.validate()
                except Exception as e:
                    msg = "Policy: %s is invalid: %s" % (p.get(
                        'name', 'unknown'), e)
                    errors.append(msg)
        if not errors:
            log.info("Configuration valid: {}".format(config_file))
            continue

        log.error("Configuration invalid: {}".format(config_file))
        for e in errors:
            log.error("%s" % e)
    if errors:
        sys.exit(1)
예제 #8
0
def load(options, path, format=None, validate=True, vars=None):
    # should we do os.path.expanduser here?
    if not os.path.exists(path):
        raise IOError("Invalid path for config %r" % path)

    from c7n.schema import validate, StructureParser
    data = utils.load_file(path, format=format, vars=vars)

    structure = StructureParser()
    structure.validate(data)
    load_resources(structure.get_resource_types(data))

    if isinstance(data, list):
        log.warning(
            'yaml in invalid format. The "policies:" line is probably missing.'
        )
        return None

    if validate:
        errors = validate(data)
        if errors:
            raise PolicyValidationError("Failed to validate policy %s \n %s" %
                                        (errors[1], errors[0]))

    # Test for empty policy file
    if not data or data.get('policies') is None:
        return None

    collection = PolicyCollection.from_data(data, options)
    if validate:
        # non schema validation of policies
        [p.validate() for p in collection]
    return collection
예제 #9
0
def load(options, path, format='yaml', validate=True, vars=None):
    # should we do os.path.expanduser here?
    if not os.path.exists(path):
        raise IOError("Invalid path for config %r" % path)

    load_resources()
    data = utils.load_file(path, format=format, vars=vars)

    if format == 'json':
        validate = False

    if isinstance(data, list):
        log.warning('yaml in invalid format. The "policies:" line is probably missing.')
        return None

    # Test for empty policy file
    if not data or data.get('policies') is None:
        return None

    if validate:
        from c7n.schema import validate
        errors = validate(data)
        if errors:
            raise Exception(
                "Failed to validate on policy %s \n %s" % (
                    errors[1], errors[0]))

    collection = PolicyCollection.from_data(data, options)
    if validate:
        # non schema validation of policies
        [p.validate() for p in collection]
    return collection
예제 #10
0
def validate(options):
    load_resources()
    if len(options.configs) < 1:
        log.error('no config files specified')
        sys.exit(1)

    used_policy_names = set()
    schm = schema.generate()
    errors = []

    for config_file in options.configs:
        config_file = os.path.expanduser(config_file)
        if not os.path.exists(config_file):
            raise ValueError("Invalid path for config %r" % config_file)

        options.dryrun = True
        fmt = config_file.rsplit('.', 1)[-1]
        with open(config_file) as fh:
            if fmt in ('yml', 'yaml'):
                data = yaml.safe_load(fh.read())
            elif fmt in ('json',):
                data = json.load(fh)
            else:
                log.error("The config file must end in .json, .yml or .yaml.")
                raise ValueError("The config file must end in .json, .yml or .yaml.")

        errors += schema.validate(data, schm)
        conf_policy_names = {
            p.get('name', 'unknown') for p in data.get('policies', ())}
        dupes = conf_policy_names.intersection(used_policy_names)
        if len(dupes) >= 1:
            errors.append(ValueError(
                "Only one policy with a given name allowed, duplicates: %s" % (
                    ", ".join(dupes)
                )
            ))
        used_policy_names = used_policy_names.union(conf_policy_names)
        if not errors:
            null_config = Config.empty(dryrun=True, account_id='na', region='na')
            for p in data.get('policies', ()):
                try:
                    policy = Policy(p, null_config, Bag())
                    policy.validate()
                except Exception as e:
                    msg = "Policy: %s is invalid: %s" % (
                        p.get('name', 'unknown'), e)
                    errors.append(msg)
        if not errors:
            log.info("Configuration valid: {}".format(config_file))
            continue

        log.error("Configuration invalid: {}".format(config_file))
        for e in errors:
            log.error("%s" % e)
    if errors:
        sys.exit(1)
예제 #11
0
def validate(options):
    load_resources()
    if options.config is not None:
        # support the old -c option
        options.configs.append(options.config)
    if len(options.configs) < 1:
        # no configs to test
        # We don't have the parser object, so fake ArgumentParser.error
        eprint('Error: no config files specified')
        sys.exit(1)
    used_policy_names = set()
    schm = schema.generate()
    errors = []
    for config_file in options.configs:
        config_file = os.path.expanduser(config_file)
        if not os.path.exists(config_file):
            raise ValueError("Invalid path for config %r" % config_file)

        options.dryrun = True
        format = config_file.rsplit('.', 1)[-1]
        with open(config_file) as fh:
            if format in ('yml', 'yaml'):
                data = yaml.safe_load(fh.read())
            if format in ('json', ):
                data = json.load(fh)

        errors = schema.validate(data, schm)
        conf_policy_names = {p['name'] for p in data.get('policies', ())}
        dupes = conf_policy_names.intersection(used_policy_names)
        if len(dupes) >= 1:
            errors.append(
                ValueError(
                    "Only one policy with a given name allowed, duplicates: %s"
                    % (", ".join(dupes))))
        used_policy_names = used_policy_names.union(conf_policy_names)
        if not errors:
            null_config = Bag(dryrun=True,
                              log_group=None,
                              cache=None,
                              assume_role="na")
            for p in data.get('policies', ()):
                try:
                    Policy(p, null_config, Bag())
                except Exception as e:
                    msg = "Policy: %s is invalid: %s" % (p.get(
                        'name', 'unknown'), e)
                    errors.append(msg)
        if not errors:
            log.info("Configuration valid: {}".format(config_file))
            continue

        log.error("Configuration invalid: {}".format(config_file))
        for e in errors:
            log.error(" %s" % e)
    if errors:
        sys.exit(1)
예제 #12
0
def validate(options, policy_collection):
    errors = schema.validate(policy_collection.data)
    if not errors:
        log.info("Config valid")
        return

    log.error("Invalid configuration")
    for e in errors:
        log.error(" %s" % e)
    sys.exit(1)
예제 #13
0
def validate(options, policy_collection):
    errors = schema.validate(policy_collection.data)
    if not errors:
        log.info("Config valid")
        return

    log.error("Invalid configuration")
    for e in errors:
        log.error(" %s" % e)
    sys.exit(1)
예제 #14
0
def validate(options):
    load_resources()
    if options.config is not None:
        # support the old -c option
        options.configs.append(options.config)
    if len(options.configs) < 1:
        # no configs to test
        # We don't have the parser object, so fake ArgumentParser.error
        print('custodian validate: error: no config files specified',
              file=sys.stderr)
        sys.exit(2)
    used_policy_names = set()
    schm = schema.generate()
    errors = []
    for config_file in options.configs:
        config_file = os.path.expanduser(config_file)
        if not os.path.exists(config_file):
            raise ValueError("Invalid path for config %r" % config_file)

        options.dryrun = True
        format = config_file.rsplit('.', 1)[-1]
        with open(config_file) as fh:
            if format in ('yml', 'yaml'):
                data = yaml.safe_load(fh.read())
            if format in ('json',):
                data = json.load(fh)

        errors = schema.validate(data, schm)
        conf_policy_names = {p['name'] for p in data.get('policies', ())}
        dupes = conf_policy_names.intersection(used_policy_names)
        if len(dupes) >= 1:
            errors.append(ValueError(
                "Only one policy with a given name allowed, duplicates: %s" % (
                    ", ".join(dupes)
                )
            ))
        used_policy_names = used_policy_names.union(conf_policy_names)
        if not errors:
            null_config = Bag(dryrun=True, log_group=None, cache=None, assume_role="na")
            for p in data.get('policies', ()):
                try:
                    Policy(p, null_config, Bag())
                except Exception as e:
                    msg = "Policy: %s is invalid: %s" % (
                        p.get('name', 'unknown'), e)
                    errors.append(msg)
        if not errors:
            log.info("Configuration valid: {}".format(config_file))
            continue

        log.error("Configuration invalid: {}".format(config_file))
        for e in errors:
            log.error(" %s" % e)
    if errors:
        sys.exit(1)
예제 #15
0
    def test_duplicate_policies(self):
        data = {
            "policies": [
                {"name": "monday-morning", "resource": "ec2"},
                {"name": "monday-morning", "resource": "ec2"},
            ]
        }

        result = validate(data)
        self.assertEqual(len(result), 2)
        self.assertTrue(isinstance(result[0], ValueError))
        self.assertTrue("monday-morning" in str(result[0]))
예제 #16
0
    def test_duplicate_policies(self):
        data = {
            "policies": [
                {"name": "monday-morning", "resource": "ec2"},
                {"name": "monday-morning", "resource": "ec2"},
            ]
        }

        result = validate(data)
        self.assertEqual(len(result), 2)
        self.assertTrue(isinstance(result[0], ValueError))
        self.assertTrue("monday-morning" in str(result[0]))
예제 #17
0
    def test_duplicate_policies(self):
        data = {
            'policies': [
                {'name': 'monday-morning',
                 'resource': 'ec2'},
                {'name': 'monday-morning',
                 'resource': 'ec2'},
                ]}

        result = validate(data)
        self.assertEqual(len(result), 1)
        self.assertTrue(isinstance(result[0], ValueError))
        self.assertTrue('monday-morning' in str(result[0]))
예제 #18
0
 def test_py3_policy_error(self):
     data = {
         'policies': [{
             'name': 'policy-ec2',
             'resource': 'ec2',
             'actions': [
                 {'type': 'terminate',
                  'force': 'asdf'}]}]}
     result = validate(data)
     self.assertEqual(len(result), 2)
     err, policy = result
     self.assertTrue("'asdf' is not of type 'boolean'" in str(err).replace("u'", "'"))
     self.assertEqual(policy, 'policy-ec2')
예제 #19
0
 def test_py3_policy_error(self):
     data = {
         'policies': [{
             'name': 'policy-ec2',
             'resource': 'ec2',
             'actions': [
                 {'type': 'terminate',
                  'force': 'asdf'}]}]}
     result = validate(data)
     self.assertEqual(len(result), 2)
     err, policy = result
     self.assertTrue("'asdf' is not of type 'boolean'" in str(err).replace("u'", "'"))
     self.assertEqual(policy, 'policy-ec2')
예제 #20
0
    def test_duplicate_policies(self):
        data = {
            'policies': [
                {'name': 'monday-morning',
                 'resource': 'ec2'},
                {'name': 'monday-morning',
                 'resource': 'ec2'},
                ]}

        result = validate(data)
        self.assertEqual(len(result), 1)
        self.assertTrue(isinstance(result[0], ValueError))
        self.assertTrue('monday-morning' in str(result[0]))
예제 #21
0
 def test_handle_specific_error_fail(self, mock_specific_error):
     from jsonschema.exceptions import ValidationError
     data = {
             'policies': [{'name': 'test',
              'resource': 'ec2',
              'filters': {
                  'type': 'ebs',
                  'invalid': []}
                 }]
         }
     mock_specific_error.side_effect = ValueError('The specific error crapped out hard')
     resp = validate(data)
     # if it is 2, then we know we got the exception from specific_error
     self.assertEqual(len(resp), 2)
     self.assertIsInstance(resp[0], ValidationError)
     self.assertIsInstance(resp[1], ValidationError)
예제 #22
0
 def test_handle_specific_error_fail(self, mock_specific_error):
     from jsonschema.exceptions import ValidationError
     data = {
             'policies': [{'name': 'test',
              'resource': 'ec2',
              'filters': {
                  'type': 'ebs',
                  'invalid': []}
                 }]
         }
     mock_specific_error.side_effect = ValueError('The specific error crapped out hard')
     resp = validate(data)
     # if it is 2, then we know we got the exception from specific_error
     self.assertEqual(len(resp), 2)
     self.assertIsInstance(resp[0], ValidationError)
     self.assertIsInstance(resp[1], ValidationError)
예제 #23
0
def load(options, path, format='yaml', validate=True):
    if not os.path.exists(path):
        raise ValueError("Invalid path for config %r" % path)
    
    with open(path) as fh:
        if format == 'yaml':
            data = utils.yaml_load(fh.read())
        elif format == 'json':
            data = utils.loads(fh.read())
            validate = False
    if validate:
        from c7n.schema import validate
        errors = validate(data)
        if errors:
            raise errors[0]
    return PolicyCollection(data, options)
예제 #24
0
    def test_handle_specific_error_fail(self, mock_specific_error):
        from jsonschema.exceptions import ValidationError

        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "aws.ec2",
                    "filters": {"type": "ebs", "invalid": []},
                }
            ]
        }
        mock_specific_error.side_effect = ValueError(
            "The specific error crapped out hard"
        )
        resp = validate(data)
        # if it is 2, then we know we got the exception from specific_error
        self.assertEqual(len(resp), 2)
        self.assertIsInstance(resp[0], ValidationError)
        self.assertIsInstance(resp[1], ValidationError)
예제 #25
0
def validate(options):
    if not os.path.exists(options.config):
        raise ValueError("Invalid path for config %r" % options.config)

    format = options.config.rsplit('.', 1)[-1]
    with open(options.config) as fh:
        if format in ('yml', 'yaml'):
            data = yaml.safe_load(fh.read())
        if format in ('json', ):
            data = json.load(fh)

    errors = schema.validate(data)
    if not errors:
        log.info("Config valid")
        return

    log.error("Invalid configuration")
    for e in errors:
        log.error(" %s" % e)
    sys.exit(1)
예제 #26
0
    def test_handle_specific_error_fail(self, mock_specific_error):
        from jsonschema.exceptions import ValidationError

        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "aws.ec2",
                    "filters": {"type": "ebs", "invalid": []},
                }
            ]
        }
        mock_specific_error.side_effect = ValueError(
            "The specific error crapped out hard"
        )
        resp = validate(data)
        # if it is 2, then we know we got the exception from specific_error
        self.assertEqual(len(resp), 2)
        self.assertIsInstance(resp[0], ValidationError)
        self.assertIsInstance(resp[1], ValidationError)
예제 #27
0
def validate(options):
    if not os.path.exists(options.config):
        raise ValueError("Invalid path for config %r" % options.config)

    format = options.config.rsplit('.', 1)[-1]
    with open(options.config) as fh:
        if format in ('yml', 'yaml'):
            data = yaml.safe_load(fh.read())
        if format in ('json',):
            data = json.load(fh)

    errors = schema.validate(data)
    if not errors:
        log.info("Config valid")
        return

    log.error("Invalid configuration")
    for e in errors:
        log.error(" %s" % e)
    sys.exit(1)
예제 #28
0
def load(options, path, format='yaml', validate=True):
    # should we do os.path.expanduser here?
    if not os.path.exists(path):
        raise IOError("Invalid path for config %r" % path)

    load_resources()
    with open(path) as fh:
        if format == 'yaml':
            data = utils.yaml_load(fh.read())
        elif format == 'json':
            data = utils.loads(fh.read())
            validate = False

    # Test for empty policy file
    if not data or data.get('policies') is None:
        return None

    if validate:
        from c7n.schema import validate
        errors = validate(data)
        if errors:
            raise Exception("Failed to validate on policy %s \n %s" % (errors[1], errors[0]))

    return PolicyCollection(data, options)
예제 #29
0
def validate(options):
    from c7n import schema

    if len(options.configs) < 1:
        log.error('no config files specified')
        sys.exit(1)

    used_policy_names = set()
    structure = StructureParser()
    errors = []

    for config_file in options.configs:

        config_file = os.path.expanduser(config_file)
        if not os.path.exists(config_file):
            raise ValueError("Invalid path for config %r" % config_file)

        options.dryrun = True
        fmt = config_file.rsplit('.', 1)[-1]

        with open(config_file) as fh:
            if fmt in ('yml', 'yaml', 'json'):
                data = yaml.load(fh.read(), Loader=DuplicateKeyCheckLoader)
            else:
                log.error("The config file must end in .json, .yml or .yaml.")
                raise ValueError("The config file must end in .json, .yml or .yaml.")

        try:
            structure.validate(data)
        except PolicyValidationError as e:
            log.error("Configuration invalid: {}".format(config_file))
            log.error("%s" % e)
            errors.append(e)
            continue

        load_resources(structure.get_resource_types(data))
        schm = schema.generate()
        errors += schema.validate(data, schm)
        conf_policy_names = {
            p.get('name', 'unknown') for p in data.get('policies', ())}
        dupes = conf_policy_names.intersection(used_policy_names)
        if len(dupes) >= 1:
            errors.append(ValueError(
                "Only one policy with a given name allowed, duplicates: %s" % (
                    ", ".join(dupes)
                )
            ))
        used_policy_names = used_policy_names.union(conf_policy_names)
        if not errors:
            null_config = Config.empty(dryrun=True, account_id='na', region='na')
            for p in data.get('policies', ()):
                try:
                    policy = Policy(p, null_config, Bag())
                    policy.validate()
                except Exception as e:
                    msg = "Policy: %s is invalid: %s" % (
                        p.get('name', 'unknown'), e)
                    errors.append(msg)
        if not errors:
            log.info("Configuration valid: {}".format(config_file))
            continue

        log.error("Configuration invalid: {}".format(config_file))
        for e in errors:
            log.error("%s" % e)
    if errors:
        sys.exit(1)
예제 #30
0
 def test_empty_skeleton(self):
     self.assertEqual(validate({'policies': []}), [])
예제 #31
0
 def test_empty_skeleton(self):
     self.assertEqual(validate({'policies': []}), [])
예제 #32
0
def validate(options):
    from c7n import schema

    if len(options.configs) < 1:
        log.error('no config files specified')
        sys.exit(1)

    used_policy_names = set()
    structure = StructureParser()
    errors = []
    found_deprecations = False
    footnotes = deprecated.Footnotes()

    for config_file in options.configs:

        config_file = os.path.expanduser(config_file)
        if not os.path.exists(config_file):
            raise ValueError("Invalid path for config %r" % config_file)

        options.dryrun = True
        fmt = config_file.rsplit('.', 1)[-1]

        with open(config_file) as fh:
            if fmt in ('yml', 'yaml', 'json'):
                # our loader is safe loader derived.
                data = yaml.load(
                    fh.read(),
                    Loader=DuplicateKeyCheckLoader)  # nosec nosemgrep
            else:
                log.error("The config file must end in .json, .yml or .yaml.")
                raise ValueError(
                    "The config file must end in .json, .yml or .yaml.")

        try:
            structure.validate(data)
        except PolicyValidationError as e:
            log.error("Configuration invalid: {}".format(config_file))
            log.error("%s" % e)
            errors.append(e)
            continue

        load_resources(structure.get_resource_types(data))
        schm = schema.generate()
        errors += schema.validate(data, schm)
        conf_policy_names = {
            p.get('name', 'unknown')
            for p in data.get('policies', ())
        }
        dupes = conf_policy_names.intersection(used_policy_names)
        if len(dupes) >= 1:
            errors.append(
                ValueError(
                    "Only one policy with a given name allowed, duplicates: %s"
                    % (", ".join(dupes))))
        used_policy_names = used_policy_names.union(conf_policy_names)
        source_locator = None
        if fmt in ('yml', 'yaml'):
            # For yaml files there is at least the expectation that the policy
            # name is on a line by itself. With JSON, the file could be one big
            # line. At this stage we are only attempting to find line number for
            # policies in yaml files.
            source_locator = SourceLocator(config_file)
        if not errors:
            null_config = Config.empty(dryrun=True,
                                       account_id='na',
                                       region='na')
            for p in data.get('policies', ()):
                try:
                    policy = Policy(p, null_config, Bag())
                    policy.validate()
                    # If the policy is invalid, there isn't much point checking
                    # for deprecated usage as there is no guarantee as to the
                    # state of the policy.
                    if options.check_deprecations != deprecated.SKIP:
                        report = deprecated.report(policy)
                        if report:
                            found_deprecations = True
                            log.warning(
                                "deprecated usage found in policy\n" +
                                report.format(source_locator=source_locator,
                                              footnotes=footnotes))

                except Exception as e:
                    msg = "Policy: %s is invalid: %s" % (p.get(
                        'name', 'unknown'), e)
                    errors.append(msg)
        if not errors:
            log.info("Configuration valid: {}".format(config_file))
            continue

        log.error("Configuration invalid: {}".format(config_file))
        for e in errors:
            log.error("%s" % e)
    if found_deprecations:
        notes = footnotes()
        if notes:
            log.warning("deprecation footnotes:\n" + notes)
        if options.check_deprecations == deprecated.STRICT:
            sys.exit(1)
    if errors:
        sys.exit(1)