def test_instance_age(self):
     data = {
         'policies': [
             {'name': 'ancient-instances',
              'resource': 'ec2',
              'query': [{'instance-state-name': 'running'}],
              'filters': [{'days': 60, 'type': 'instance-age'}]
          }]}
     schema = generate(['ec2'])
     validator = Validator(schema)
     errors = list(validator.iter_errors(data))
     self.assertEqual(len(errors), 0)
 def test_instance_age(self):
     data = {
         'policies': [
             {'name': 'ancient-instances',
              'resource': 'ec2',
              'query': [{'instance-state-name': 'running'}],
              'filters': [{'days': 60, 'type': 'instance-age'}]
          }]}
     schema = generate(['ec2'])
     validator = Validator(schema)
     errors = list(validator.iter_errors(data))
     self.assertEqual(len(errors), 0)
 def test_instance_age(self):
     data = {
         "policies": [
             {
                 "name": "ancient-instances",
                 "resource": "ec2",
                 "query": [{"instance-state-name": "running"}],
                 "filters": [{"days": 60, "type": "instance-age"}],
             }
         ]
     }
     schema = generate(["ec2"])
     validator = Validator(schema)
     errors = list(validator.iter_errors(data))
     self.assertEqual(len(errors), 0)
 def test_value_filter_short_form_invalid(self):
     for rtype in ["elb", "rds", "ec2"]:
         data = {
             'policies': [
                 {'name': 'instance-policy',
                  'resource': 'elb',
                  'filters': [
                      {"tag:Role": "webserver"}]}
             ]}
         schema = generate([rtype])
         # Disable standard value short form
         schema['definitions']['filters']['valuekv'] = {'type': 'number'}
         validator = Validator(schema)
         errors = list(validator.iter_errors(data))
         self.assertEqual(len(errors), 1)
 def test_instance_age(self):
     data = {
         "policies": [
             {
                 "name": "ancient-instances",
                 "resource": "ec2",
                 "query": [{"instance-state-name": "running"}],
                 "filters": [{"days": 60, "type": "instance-age"}],
             }
         ]
     }
     schema = generate(["ec2"])
     validator = Validator(schema)
     errors = list(validator.iter_errors(data))
     self.assertEqual(len(errors), 0)
 def test_value_filter_short_form_invalid(self):
     for rtype in ["elb", "rds", "ec2"]:
         data = {
             'policies': [
                 {'name': 'instance-policy',
                  'resource': 'elb',
                  'filters': [
                      {"tag:Role": "webserver"}]}
             ]}
         schema = generate([rtype])
         # Disable standard value short form
         schema['definitions']['filters']['valuekv'] = {'type': 'number'}
         validator = Validator(schema)
         errors = list(validator.iter_errors(data))
         self.assertEqual(len(errors), 1)
    def test_mark_for_op(self):
        data = {
            "policies": [
                {
                    "name": "ebs-mark-delete",
                    "resource": "ebs",
                    "filters": [],
                    "actions": [{"type": "mark-for-op", "op": "delete", "days": 30}],
                }
            ]
        }
        schema = generate(["ebs"])
        validator = Validator(schema)

        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)
    def test_mark_for_op(self):
        data = {
            "policies": [
                {
                    "name": "ebs-mark-delete",
                    "resource": "ebs",
                    "filters": [],
                    "actions": [{"type": "mark-for-op", "op": "delete", "days": 30}],
                }
            ]
        }
        schema = generate(["ebs"])
        validator = Validator(schema)

        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)
    def test_mark_for_op(self):
        data = {
            'policies': [{
                'name': 'ebs-mark-delete',
                'resource': 'ebs',
                'filters': [],
                'actions': [{
                    'type': 'mark-for-op',
                    'op': 'delete',
                    'days': 30}]}]
            }
        schema = generate(['ebs'])
        validator = Validator(schema)

        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)
    def test_mark_for_op(self):
        data = {
            'policies': [{
                'name': 'ebs-mark-delete',
                'resource': 'ebs',
                'filters': [],
                'actions': [{
                    'type': 'mark-for-op',
                    'op': 'delete',
                    'days': 30}]}]
            }
        schema = generate(['ebs'])
        validator = Validator(schema)

        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)
 def test_offhours_stop(self):
     data = {
         'policies': [
             {'name': 'ec2-offhours-stop',
              'resource': 'ec2',
              'filters': [
                  {'tag:aws:autoscaling:groupName': 'absent'},
                  {'type': 'offhour',
                   'tag': 'c7n_downtime',
                   'default_tz': 'et',
                   'offhour': 19}]
              }]
         }
     schema = generate(['ec2'])
     validator = Validator(schema)
     errors = list(validator.iter_errors(data))
     self.assertEqual(len(errors), 0)
 def test_value_filter_short_form_invalid(self):
     for rtype in ["elb", "rds", "ec2"]:
         data = {
             "policies": [
                 {
                     "name": "instance-policy",
                     "resource": "elb",
                     "filters": [{"tag:Role": "webserver"}],
                 }
             ]
         }
         schema = generate([rtype])
         # Disable standard value short form
         schema["definitions"]["filters"]["valuekv"] = {"type": "number"}
         validator = Validator(schema)
         errors = list(validator.iter_errors(data))
         self.assertEqual(len(errors), 1)
 def test_value_filter_short_form_invalid(self):
     for rtype in ["elb", "rds", "ec2"]:
         data = {
             "policies": [
                 {
                     "name": "instance-policy",
                     "resource": "elb",
                     "filters": [{"tag:Role": "webserver"}],
                 }
             ]
         }
         schema = generate([rtype])
         # Disable standard value short form
         schema["definitions"]["filters"]["valuekv"] = {"type": "number"}
         validator = Validator(schema)
         errors = list(validator.iter_errors(data))
         self.assertEqual(len(errors), 1)
 def test_offhours_stop(self):
     data = {
         'policies': [
             {'name': 'ec2-offhours-stop',
              'resource': 'ec2',
              'filters': [
                  {'tag:aws:autoscaling:groupName': 'absent'},
                  {'type': 'offhour',
                   'tag': 'maid_downtime',
                   'default_tz': 'et',
                   'hour': 19}]
              }]
         }
     schema = generate(['ec2'])
     validator = Validator(schema)
     errors = list(validator.iter_errors(data))
     self.assertEqual(len(errors), 0)
 def test_offhours_stop(self):
     data = {
         "policies": [
             {
                 "name": "ec2-offhours-stop",
                 "resource": "ec2",
                 "filters": [
                     {"tag:aws:autoscaling:groupName": "absent"},
                     {
                         "type": "offhour",
                         "tag": "c7n_downtime",
                         "default_tz": "et",
                         "offhour": 19,
                     },
                 ],
             }
         ]
     }
     schema = generate(["ec2"])
     validator = Validator(schema)
     errors = list(validator.iter_errors(data))
     self.assertEqual(len(errors), 0)
 def test_offhours_stop(self):
     data = {
         "policies": [
             {
                 "name": "ec2-offhours-stop",
                 "resource": "ec2",
                 "filters": [
                     {"tag:aws:autoscaling:groupName": "absent"},
                     {
                         "type": "offhour",
                         "tag": "c7n_downtime",
                         "default_tz": "et",
                         "offhour": 19,
                     },
                 ],
             }
         ]
     }
     schema = generate(["ec2"])
     validator = Validator(schema)
     errors = list(validator.iter_errors(data))
     self.assertEqual(len(errors), 0)
Beispiel #17
0
 def test_runtime(self):
     data = lambda runtime: {
         'policies': [{
             'name': 'test',
             'resource': 's3',
             'mode': {
                 'type': 'periodic',
                 'runtime': runtime}}]
         }
     errors_with = lambda r: list(Validator(generate()).iter_errors(data(r)))
     self.assertEqual(len(errors_with('python2.7')), 0)
     self.assertEqual(len(errors_with('python3.6')), 0)
     self.assertEqual(len(errors_with('python4.5')), 1)
 def test_runtime(self):
     data = lambda runtime: {
         'policies': [{
             'name': 'test',
             'resource': 's3',
             'mode': {
                 'execution-options': {
                     'metrics_enabled': False
                 },
                 'type': 'periodic',
                 'schedule': 'xyz',
                 'runtime': runtime
             }
         }]
     }
     errors_with = lambda r: list(
         Validator(generate()).iter_errors(data(r)))
     self.assertEqual(len(errors_with('python2.7')), 0)
     self.assertEqual(len(errors_with('python3.6')), 0)
     self.assertEqual(len(errors_with('python4.5')), 1)
 def test_runtime(self):
     data = lambda runtime: {   # NOQA
         "policies": [
             {
                 "name": "test",
                 "resource": "s3",
                 "mode": {
                     "execution-options": {"metrics_enabled": False},
                     "type": "periodic",
                     "schedule": "xyz",
                     "runtime": runtime,
                 },
             }
         ]
     }
     errors_with = lambda r: list( # NOQA
         Validator(generate()).iter_errors(data(r)))
     self.assertEqual(len(errors_with("python2.7")), 0)
     self.assertEqual(len(errors_with("python3.6")), 0)
     self.assertEqual(len(errors_with("python4.5")), 1)
class SchemaTest(BaseTest):

    validator = None

    def findError(self, data, validator):
        e = best_match(validator.iter_errors(data))
        ex = specific_error(list(validator.iter_errors(data))[0])
        return e, ex

    def setUp(self):
        if not self.validator:
            self.validator = Validator(generate())

    def test_schema_plugin_name_mismatch(self):
        for k, v in resources.items():
            for fname, f in v.filter_registry.items():
                if fname in ('or', 'and', 'not'):
                    continue
                self.assertIn(
                    fname, f.schema['properties']['type']['enum'])
            for aname, a in v.action_registry.items():
                self.assertIn(
                    aname, a.schema['properties']['type']['enum'])

    def test_schema(self):
        try:
            schema = generate()
            Validator.check_schema(schema)
        except Exception:
            self.fail("Invalid schema")

    def test_schema_serialization(self):
        try:
            dumps(generate())
        except:
            self.fail("Failed to serialize schema")

    def test_empty_skeleton(self):
        self.assertEqual(validate({'policies': []}), [])

    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]))

    def test_semantic_error(self):
        data = {
            'policies': [
                {'name': 'test',
                 'resource': 'ec2',
                 'filters': {
                     'type': 'ebs',
                     'skipped_devices': []}
                    }]
            }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(
                error.absolute_schema_path))

        self.assertTrue(
            "'skipped_devices': []" in error.message)
        self.assertTrue(
            "u'type': u'ebs'" in error.message or
            "'type': 'ebs'" in error.message
        )

    @mock.patch('c7n.schema.specific_error')
    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)

    def test_vars_and_tags(self):
        data = {
            'vars': {'alpha': 1, 'beta': 2},
            'policies': [{
                'name': 'test',
                'resource': 'ec2',
                'tags': ['controls']}]}
        self.assertEqual(list(self.validator.iter_errors(data)), [])

    def test_semantic_error_on_value_derived(self):
        data = {
            'policies': [
                {'name': 'test',
                 'resource': 'ec2',
                 'filters': [
                     {'type': 'ebs',
                      'skipped_devices': []}
                     ]}
            ]}
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(
                error.absolute_schema_path))
        self.assertTrue(
            "Additional properties are not allowed " in error.message
        )
        self.assertTrue(
            "'skipped_devices' was unexpected" in error.message
        )

    def test_invalid_resource_type(self):
        data = {
            'policies': [
                {'name': 'instance-policy',
                 'resource': 'ec3',
                 'filters': []}]}
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)

    def test_value_filter_short_form_invalid(self):
        for rtype in ["elb", "rds", "ec2"]:
            data = {
                'policies': [
                    {'name': 'instance-policy',
                     'resource': 'elb',
                     'filters': [
                         {"tag:Role": "webserver"}]}
                ]}
            schema = generate([rtype])
            # Disable standard value short form
            schema['definitions']['filters']['valuekv'] = {'type': 'number'}
            validator = Validator(schema)
            errors = list(validator.iter_errors(data))
            self.assertEqual(len(errors), 1)

    def test_nested_bool_operators(self):
        data = {
            'policies': [
                {'name': 'test',
                 'resource': 'ec2',
                 'filters': [
                     {'or': [
                         {'tag:Role': 'webserver'},
                         {'type': 'value', 'key': 'x', 'value': []},
                         {'and': [
                             {'tag:Name': 'cattle'},
                             {'tag:Env': 'prod'}]
                          }]
                      }]
                 }]
            }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_value_filter_short_form(self):
        data = {
            'policies': [
                {'name': 'instance-policy',
                 'resource': 'elb',
                 'filters': [
                     {"tag:Role": "webserver"}]}
                ]}

        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_event_inherited_value_filter(self):
        data = {
            'policies': [
                {'name': 'test',
                 'resource': 'ec2',
                 'filters': [
                     {'type': 'event',
                      'key': "detail.requestParameters",
                      "value": "absent"}]}]
            }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_ebs_inherited_value_filter(self):
        data = {
            'policies': [
                {'name': 'test',
                 'resource': 'ec2',
                 'filters': [
                     {'type': 'ebs',
                      'key': 'Encrypted',
                      'value': False,
                      'skip-devices': [
                          '/dev/sda1',
                          '/dev/xvda']}
                     ]}
                ]}
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_offhours_stop(self):
        data = {
            'policies': [
                {'name': 'ec2-offhours-stop',
                 'resource': 'ec2',
                 'filters': [
                     {'tag:aws:autoscaling:groupName': 'absent'},
                     {'type': 'offhour',
                      'tag': 'c7n_downtime',
                      'default_tz': 'et',
                      'offhour': 19}]
                 }]
            }
        schema = generate(['ec2'])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_instance_age(self):
        data = {
            'policies': [
                {'name': 'ancient-instances',
                 'resource': 'ec2',
                 'query': [{'instance-state-name': 'running'}],
                 'filters': [{'days': 60, 'type': 'instance-age'}]
             }]}
        schema = generate(['ec2'])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_mark_for_op(self):
        data = {
            'policies': [{
                'name': 'ebs-mark-delete',
                'resource': 'ebs',
                'filters': [],
                'actions': [{
                    'type': 'mark-for-op',
                    'op': 'delete',
                    'days': 30}]}]
            }
        schema = generate(['ebs'])
        validator = Validator(schema)

        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_runtime(self):
        data = lambda runtime: {
            'policies': [{
                'name': 'test',
                'resource': 's3',
                'mode': {
                    'execution-options': {'metrics_enabled': False},
                    'type': 'periodic',
                    'schedule': 'xyz',
                    'runtime': runtime}}]
            }
        errors_with = lambda r: list(Validator(generate()).iter_errors(data(r)))
        self.assertEqual(len(errors_with('python2.7')), 0)
        self.assertEqual(len(errors_with('python3.6')), 0)
        self.assertEqual(len(errors_with('python4.5')), 1)
class SchemaTest(BaseTest):

    validator = None

    def findError(self, data, validator):
        e = best_match(validator.iter_errors(data))
        ex = specific_error(list(validator.iter_errors(data))[0])
        return e, ex

    def setUp(self):
        if not self.validator:
            self.validator = Validator(generate())

    def test_schema_plugin_name_mismatch(self):
        for k, v in resources.items():
            for fname, f in v.filter_registry.items():
                if fname in ("or", "and", "not"):
                    continue
                self.assertIn(fname, f.schema["properties"]["type"]["enum"])
            for aname, a in v.action_registry.items():
                self.assertIn(aname, a.schema["properties"]["type"]["enum"])

    def test_schema(self):
        try:
            schema = generate()
            Validator.check_schema(schema)
        except Exception:
            self.fail("Invalid schema")

    def test_schema_serialization(self):
        try:
            dumps(generate())
        except Exception:
            self.fail("Failed to serialize schema")

    def test_empty_skeleton(self):
        self.assertEqual(validate({"policies": []}), [])

    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]))

    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')

    def test_semantic_error_common_filter_provider_prefixed(self):
        data = {
            'policies': [{
                'name': 'test',
                'resource': 's3',
                'filters': [{
                    'type': 'metrics',
                    'name': 'BucketSizeBytes',
                    'dimensions': [{
                        'StorageType': 'StandardStorage'}],
                    'days': 7,
                    'value': 100,
                    'op': 'gte'}]}]}
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        # the repr unicode situation on py2.7 makes this harder to do
        # an exact match
        if sys.version_info.major == 2:
            return self.assertIn('StorageType', str(error))
        self.assertIn(
            "[{'StorageType': 'StandardStorage'}] is not of type 'object'",
            str(error))

    def test_semantic_mode_error(self):
        data = {
            'policies': [{
                'name': 'test',
                'resource': 'ec2',
                'mode': {
                    'type': 'periodic',
                    'scheduled': 'oops'}}]}
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(error.absolute_schema_path)
        )
        self.assertTrue("'scheduled' was unexpected" in str(error))
        self.assertTrue(len(str(error)) < 2000)

    def test_semantic_error_policy_scope(self):

        data = {
            'policies': [
                {'actions': [{'key': 'TagPolicyCompliance',
                              'type': 'tag',
                              'value': 'This resource should have tags following policy'}],
                 'description': 'Identify resources which lack our accounting tags',
                 'filters': [{'tag:Environment': 'absent'},
                             {'tag:Service': 'absent'},
                             {'or': [{'tag:Owner': 'absent'},
                                     {'tag:ResponsibleParty': 'absent'},
                                     {'tag:Contact': 'absent'},
                                     {'tag:Creator': 'absent'}]}],
                 'name': 'tagging-compliance-waf',
                 'resource': 'aws.waf'}]}

        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = policy_error_scope(specific_error(errors[0]), data)
        self.assertTrue("policy:tagging-compliance-waf" in error.message)

    def test_semantic_error(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": {"type": "ebs", "skipped_devices": []},
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(error.absolute_schema_path)
        )

        self.assertTrue("'skipped_devices': []" in error.message)
        self.assertTrue(
            "u'type': u'ebs'" in error.message or "'type': 'ebs'" in error.message
        )

    @mock.patch("c7n.schema.specific_error")
    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)

    def test_vars_and_tags(self):
        data = {
            "vars": {"alpha": 1, "beta": 2},
            "policies": [{"name": "test", "resource": "ec2", "tags": ["controls"]}],
        }
        self.assertEqual(list(self.validator.iter_errors(data)), [])

    def test_semantic_error_on_value_derived(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [{"type": "ebs", "skipped_devices": []}],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(error.absolute_schema_path)
        )
        self.assertTrue("Additional properties are not allowed " in error.message)
        self.assertTrue("'skipped_devices' was unexpected" in error.message)

    def test_invalid_resource_type(self):
        data = {
            "policies": [{"name": "instance-policy", "resource": "ec3", "filters": []}]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)

    def test_value_filter_short_form_invalid(self):
        for rtype in ["elb", "rds", "ec2"]:
            data = {
                "policies": [
                    {
                        "name": "instance-policy",
                        "resource": "elb",
                        "filters": [{"tag:Role": "webserver"}],
                    }
                ]
            }
            schema = generate([rtype])
            # Disable standard value short form
            schema["definitions"]["filters"]["valuekv"] = {"type": "number"}
            validator = Validator(schema)
            errors = list(validator.iter_errors(data))
            self.assertEqual(len(errors), 1)

    def test_nested_bool_operators(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [
                        {
                            "or": [
                                {"tag:Role": "webserver"},
                                {"type": "value", "key": "x", "value": []},
                                {"and": [{"tag:Name": "cattle"}, {"tag:Env": "prod"}]},
                            ]
                        }
                    ],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_bool_operator_child_validation(self):
        data = {'policies': [
            {'name': 'test', 'resource': 'ec2', 'filters': [
                {'or': [{'type': 'imagex', 'key': 'tag:Foo', 'value': 'a'}]}]}]}
        errors = list(self.validator.iter_errors(data))
        self.assertTrue(errors)

    def test_value_filter_short_form(self):
        data = {
            "policies": [
                {
                    "name": "instance-policy",
                    "resource": "elb",
                    "filters": [{"tag:Role": "webserver"}],
                }
            ]
        }

        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_event_inherited_value_filter(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [
                        {
                            "type": "event",
                            "key": "detail.requestParameters",
                            "value": "absent",
                        }
                    ],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_ebs_inherited_value_filter(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [
                        {
                            "type": "ebs",
                            "key": "Encrypted",
                            "value": False,
                            "skip-devices": ["/dev/sda1", "/dev/xvda"],
                        }
                    ],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_offhours_stop(self):
        data = {
            "policies": [
                {
                    "name": "ec2-offhours-stop",
                    "resource": "ec2",
                    "filters": [
                        {"tag:aws:autoscaling:groupName": "absent"},
                        {
                            "type": "offhour",
                            "tag": "c7n_downtime",
                            "default_tz": "et",
                            "offhour": 19,
                        },
                    ],
                }
            ]
        }
        schema = generate(["ec2"])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_instance_age(self):
        data = {
            "policies": [
                {
                    "name": "ancient-instances",
                    "resource": "ec2",
                    "query": [{"instance-state-name": "running"}],
                    "filters": [{"days": 60, "type": "instance-age"}],
                }
            ]
        }
        schema = generate(["ec2"])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_mark_for_op(self):
        data = {
            "policies": [
                {
                    "name": "ebs-mark-delete",
                    "resource": "ebs",
                    "filters": [],
                    "actions": [{"type": "mark-for-op", "op": "delete", "days": 30}],
                }
            ]
        }
        schema = generate(["ebs"])
        validator = Validator(schema)

        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_runtime(self):
        data = lambda runtime: {   # NOQA
            "policies": [
                {
                    "name": "test",
                    "resource": "s3",
                    "mode": {
                        "execution-options": {"metrics_enabled": False},
                        "type": "periodic",
                        "schedule": "xyz",
                        "runtime": runtime,
                    },
                }
            ]
        }
        errors_with = lambda r: list( # NOQA
            Validator(generate()).iter_errors(data(r)))
        self.assertEqual(len(errors_with("python2.7")), 0)
        self.assertEqual(len(errors_with("python3.6")), 0)
        self.assertEqual(len(errors_with("python4.5")), 1)

    def test_element_resolve(self):
        vocab = resource_vocabulary()
        self.assertEqual(ElementSchema.resolve(vocab, 'mode.periodic').type, 'periodic')
        self.assertEqual(ElementSchema.resolve(vocab, 'aws.ec2').type, 'ec2')
        self.assertEqual(ElementSchema.resolve(vocab, 'aws.ec2.actions.stop').type, 'stop')
        self.assertRaises(ValueError, ElementSchema.resolve, vocab, 'aws.ec2.actions.foo')

    def test_element_doc(self):

        class A(object):
            pass

        class B(object):
            """Hello World

            xyz
            """

        class C(B):
            pass

        class D(ValueFilter):
            pass

        class E(ValueFilter):
            """Something"""

        class F(D):
            pass

        class G(E):
            pass

        self.assertEqual(ElementSchema.doc(G), "Something")
        self.assertEqual(ElementSchema.doc(D), "")
        self.assertEqual(ElementSchema.doc(F), "")
        self.assertEqual(
            ElementSchema.doc(B), "Hello World\n\nxyz")
 def test_schema(self):
     try:
         schema = generate()
         Validator.check_schema(schema)
     except Exception:
         self.fail("Invalid schema")
 def setUp(self):
     if not self.validator:
         self.validator = Validator(generate())
Beispiel #24
0
class SchemaTest(BaseTest):

    validator = None

    def findError(self, data, validator):
        e = best_match(validator.iter_errors(data))
        ex = specific_error(list(validator.iter_errors(data))[0])
        return e, ex

    def setUp(self):
        if not self.validator:
            self.validator = Validator(generate())

    def test_schema(self):
        try:
            schema = generate()
            Validator.check_schema(schema)
        except Exception:
            self.fail("Invalid schema")

    def test_empty_skeleton(self):
        self.assertEqual(validate({'policies': []}), [])

    def test_semantic_error(self):
        data = {
            'policies': [{
                'name': 'test',
                'resource': 'ec2',
                'filters': {
                    'type': 'ebs',
                    'skipped_devices': []
                }
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(
                error.absolute_schema_path))
        self.assertEqual(
            error.message,
            "{'skipped_devices': [], 'type': 'ebs'} is not of type 'array'")

    def test_semantic_error_on_value_derived(self):
        data = {
            'policies': [{
                'name': 'test',
                'resource': 'ec2',
                'filters': [{
                    'type': 'ebs',
                    'skipped_devices': []
                }]
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(
                error.absolute_schema_path))
        self.assertEqual(error.message,
                         ("Additional properties are not allowed "
                          "('skipped_devices' was unexpected)"))

    def test_invalid_resource_type(self):
        data = {
            'policies': [{
                'name': 'instance-policy',
                'resource': 'ec3',
                'filters': []
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)

    def test_value_filter_short_form_invalid(self):
        for rtype in ["elb", "rds", "ec2"]:
            data = {
                'policies': [{
                    'name': 'instance-policy',
                    'resource': 'elb',
                    'filters': [{
                        "tag:Role": "webserver"
                    }]
                }]
            }
            schema = generate([rtype])
            # Disable standard value short form
            schema['definitions']['filters']['valuekv'] = {'type': 'number'}
            validator = Validator(schema)
            errors = list(validator.iter_errors(data))
            self.assertEqual(len(errors), 1)

    def test_nested_bool_operators(self):
        data = {
            'policies': [{
                'name':
                'test',
                'resource':
                'ec2',
                'filters': [{
                    'or': [{
                        'tag:Role': 'webserver'
                    }, {
                        'type': 'value',
                        'key': 'x',
                        'value': []
                    }, {
                        'and': [{
                            'tag:Name': 'cattle'
                        }, {
                            'tag:Env': 'prod'
                        }]
                    }]
                }]
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_value_filter_short_form(self):
        data = {
            'policies': [{
                'name': 'instance-policy',
                'resource': 'elb',
                'filters': [{
                    "tag:Role": "webserver"
                }]
            }]
        }

        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_event_inherited_value_filter(self):
        data = {
            'policies': [{
                'name':
                'test',
                'resource':
                'ec2',
                'filters': [{
                    'type': 'event',
                    'key': "detail.requestParameters",
                    "value": "absent"
                }]
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_ebs_inherited_value_filter(self):
        data = {
            'policies': [{
                'name':
                'test',
                'resource':
                'ec2',
                'filters': [{
                    'type': 'ebs',
                    'key': 'Encrypted',
                    'value': False,
                    'skip-devices': ['/dev/sda1', '/dev/xvda']
                }]
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_offhours_stop(self):
        data = {
            'policies': [{
                'name':
                'ec2-offhours-stop',
                'resource':
                'ec2',
                'filters': [{
                    'tag:aws:autoscaling:groupName': 'absent'
                }, {
                    'type': 'offhour',
                    'tag': 'maid_downtime',
                    'default_tz': 'et',
                    'hour': 19
                }]
            }]
        }
        schema = generate(['ec2'])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_instance_age(self):
        data = {
            'policies': [{
                'name': 'ancient-instances',
                'resource': 'ec2',
                'query': [{
                    'instance-state-name': 'running'
                }],
                'filters': [{
                    'days': 60,
                    'type': 'instance-age'
                }]
            }]
        }
        schema = generate(['ec2'])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_mark_for_op(self):
        data = {
            'policies': [{
                'name':
                'ebs-mark-delete',
                'resource':
                'ebs',
                'filters': [],
                'actions': [{
                    'type': 'mark-for-op',
                    'op': 'delete',
                    'days': 30
                }]
            }]
        }
        schema = generate(['ebs'])
        validator = Validator(schema)

        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)
Beispiel #25
0
 def setUp(self):
     if not self.validator:
         self.validator = Validator(generate())
class SchemaTest(BaseTest):

    validator = None

    def findError(self, data, validator):
        e = best_match(validator.iter_errors(data))
        ex = specific_error(list(validator.iter_errors(data))[0])
        return e, ex

    def setUp(self):
        if not self.validator:
            self.validator = Validator(generate())

    def test_schema_plugin_name_mismatch(self):
        for k, v in resources.items():
            for fname, f in v.filter_registry.items():
                if fname in ("or", "and", "not"):
                    continue
                self.assertIn(fname, f.schema["properties"]["type"]["enum"])
            for aname, a in v.action_registry.items():
                self.assertIn(aname, a.schema["properties"]["type"]["enum"])

    def test_schema(self):
        try:
            schema = generate()
            Validator.check_schema(schema)
        except Exception:
            self.fail("Invalid schema")

    def test_schema_serialization(self):
        try:
            dumps(generate())
        except Exception:
            self.fail("Failed to serialize schema")

    def test_empty_skeleton(self):
        self.assertEqual(validate({"policies": []}), [])

    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]))

    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')

    def test_semantic_mode_error(self):
        data = {
            'policies': [{
                'name': 'test',
                'resource': 'ec2',
                'mode': {
                    'type': 'periodic',
                    'scheduled': 'oops'}}]}
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(error.absolute_schema_path)
        )
        self.assertTrue("'scheduled' was unexpected" in str(error))
        self.assertTrue(len(str(error)) < 2000)

    def test_semantic_error_policy_scope(self):

        data = {
            'policies': [
                {'actions': [{'key': 'TagPolicyCompliance',
                              'type': 'tag',
                              'value': 'This resource should have tags following policy'}],
                 'description': 'Identify resources which lack our accounting tags',
                 'filters': [{'tag:Environment': 'absent'},
                             {'tag:Service': 'absent'},
                             {'or': [{'tag:Owner': 'absent'},
                                     {'tag:ResponsibleParty': 'absent'},
                                     {'tag:Contact': 'absent'},
                                     {'tag:Creator': 'absent'}]}],
                 'name': 'tagging-compliance-waf',
                 'resource': 'aws.waf'}]}

        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = policy_error_scope(specific_error(errors[0]), data)
        self.assertTrue("policy:tagging-compliance-waf" in error.message)

    def test_semantic_error(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": {"type": "ebs", "skipped_devices": []},
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(error.absolute_schema_path)
        )

        self.assertTrue("'skipped_devices': []" in error.message)
        self.assertTrue(
            "u'type': u'ebs'" in error.message or "'type': 'ebs'" in error.message
        )

    @mock.patch("c7n.schema.specific_error")
    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)

    def test_vars_and_tags(self):
        data = {
            "vars": {"alpha": 1, "beta": 2},
            "policies": [{"name": "test", "resource": "ec2", "tags": ["controls"]}],
        }
        self.assertEqual(list(self.validator.iter_errors(data)), [])

    def test_semantic_error_on_value_derived(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [{"type": "ebs", "skipped_devices": []}],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(error.absolute_schema_path)
        )
        self.assertTrue("Additional properties are not allowed " in error.message)
        self.assertTrue("'skipped_devices' was unexpected" in error.message)

    def test_invalid_resource_type(self):
        data = {
            "policies": [{"name": "instance-policy", "resource": "ec3", "filters": []}]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)

    def test_value_filter_short_form_invalid(self):
        for rtype in ["elb", "rds", "ec2"]:
            data = {
                "policies": [
                    {
                        "name": "instance-policy",
                        "resource": "elb",
                        "filters": [{"tag:Role": "webserver"}],
                    }
                ]
            }
            schema = generate([rtype])
            # Disable standard value short form
            schema["definitions"]["filters"]["valuekv"] = {"type": "number"}
            validator = Validator(schema)
            errors = list(validator.iter_errors(data))
            self.assertEqual(len(errors), 1)

    def test_nested_bool_operators(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [
                        {
                            "or": [
                                {"tag:Role": "webserver"},
                                {"type": "value", "key": "x", "value": []},
                                {"and": [{"tag:Name": "cattle"}, {"tag:Env": "prod"}]},
                            ]
                        }
                    ],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_value_filter_short_form(self):
        data = {
            "policies": [
                {
                    "name": "instance-policy",
                    "resource": "elb",
                    "filters": [{"tag:Role": "webserver"}],
                }
            ]
        }

        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_event_inherited_value_filter(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [
                        {
                            "type": "event",
                            "key": "detail.requestParameters",
                            "value": "absent",
                        }
                    ],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_ebs_inherited_value_filter(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [
                        {
                            "type": "ebs",
                            "key": "Encrypted",
                            "value": False,
                            "skip-devices": ["/dev/sda1", "/dev/xvda"],
                        }
                    ],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_offhours_stop(self):
        data = {
            "policies": [
                {
                    "name": "ec2-offhours-stop",
                    "resource": "ec2",
                    "filters": [
                        {"tag:aws:autoscaling:groupName": "absent"},
                        {
                            "type": "offhour",
                            "tag": "c7n_downtime",
                            "default_tz": "et",
                            "offhour": 19,
                        },
                    ],
                }
            ]
        }
        schema = generate(["ec2"])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_instance_age(self):
        data = {
            "policies": [
                {
                    "name": "ancient-instances",
                    "resource": "ec2",
                    "query": [{"instance-state-name": "running"}],
                    "filters": [{"days": 60, "type": "instance-age"}],
                }
            ]
        }
        schema = generate(["ec2"])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_mark_for_op(self):
        data = {
            "policies": [
                {
                    "name": "ebs-mark-delete",
                    "resource": "ebs",
                    "filters": [],
                    "actions": [{"type": "mark-for-op", "op": "delete", "days": 30}],
                }
            ]
        }
        schema = generate(["ebs"])
        validator = Validator(schema)

        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_runtime(self):
        data = lambda runtime: {   # NOQA
            "policies": [
                {
                    "name": "test",
                    "resource": "s3",
                    "mode": {
                        "execution-options": {"metrics_enabled": False},
                        "type": "periodic",
                        "schedule": "xyz",
                        "runtime": runtime,
                    },
                }
            ]
        }
        errors_with = lambda r: list( # NOQA
            Validator(generate()).iter_errors(data(r)))
        self.assertEqual(len(errors_with("python2.7")), 0)
        self.assertEqual(len(errors_with("python3.6")), 0)
        self.assertEqual(len(errors_with("python4.5")), 1)
Beispiel #27
0
class SchemaTest(BaseTest):

    validator = None

    def findError(self, data, validator):
        e = best_match(validator.iter_errors(data))
        ex = specific_error(list(validator.iter_errors(data))[0])
        return e, ex

    def setUp(self):
        if not self.validator:
            self.validator = Validator(generate())

    def test_schema(self):
        try:
            schema = generate()
            Validator.check_schema(schema)
        except Exception:
            self.fail("Invalid schema")

    def test_schema_serialization(self):
        try:
            dumps(generate())
        except:
            self.fail("Failed to serialize schema")

    def test_empty_skeleton(self):
        self.assertEqual(validate({'policies': []}), [])

    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]))

    def test_semantic_error(self):
        data = {
            'policies': [{
                'name': 'test',
                'resource': 'ec2',
                'filters': {
                    'type': 'ebs',
                    'skipped_devices': []
                }
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(
                error.absolute_schema_path))

        self.assertTrue("'skipped_devices': []" in error.message)
        self.assertTrue("'type': 'ebs'" in error.message)

    @mock.patch('c7n.schema.specific_error')
    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)

    def test_vars_and_tags(self):
        data = {
            'vars': {
                'alpha': 1,
                'beta': 2
            },
            'policies': [{
                'name': 'test',
                'resource': 'ec2',
                'tags': ['controls']
            }]
        }
        self.assertEqual(list(self.validator.iter_errors(data)), [])

    def test_semantic_error_on_value_derived(self):
        data = {
            'policies': [{
                'name': 'test',
                'resource': 'ec2',
                'filters': [{
                    'type': 'ebs',
                    'skipped_devices': []
                }]
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(
                error.absolute_schema_path))
        self.assertEqual(error.message,
                         ("Additional properties are not allowed "
                          "('skipped_devices' was unexpected)"))

    def test_invalid_resource_type(self):
        data = {
            'policies': [{
                'name': 'instance-policy',
                'resource': 'ec3',
                'filters': []
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)

    def test_value_filter_short_form_invalid(self):
        for rtype in ["elb", "rds", "ec2"]:
            data = {
                'policies': [{
                    'name': 'instance-policy',
                    'resource': 'elb',
                    'filters': [{
                        "tag:Role": "webserver"
                    }]
                }]
            }
            schema = generate([rtype])
            # Disable standard value short form
            schema['definitions']['filters']['valuekv'] = {'type': 'number'}
            validator = Validator(schema)
            errors = list(validator.iter_errors(data))
            self.assertEqual(len(errors), 1)

    def test_nested_bool_operators(self):
        data = {
            'policies': [{
                'name':
                'test',
                'resource':
                'ec2',
                'filters': [{
                    'or': [{
                        'tag:Role': 'webserver'
                    }, {
                        'type': 'value',
                        'key': 'x',
                        'value': []
                    }, {
                        'and': [{
                            'tag:Name': 'cattle'
                        }, {
                            'tag:Env': 'prod'
                        }]
                    }]
                }]
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_value_filter_short_form(self):
        data = {
            'policies': [{
                'name': 'instance-policy',
                'resource': 'elb',
                'filters': [{
                    "tag:Role": "webserver"
                }]
            }]
        }

        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_event_inherited_value_filter(self):
        data = {
            'policies': [{
                'name':
                'test',
                'resource':
                'ec2',
                'filters': [{
                    'type': 'event',
                    'key': "detail.requestParameters",
                    "value": "absent"
                }]
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_ebs_inherited_value_filter(self):
        data = {
            'policies': [{
                'name':
                'test',
                'resource':
                'ec2',
                'filters': [{
                    'type': 'ebs',
                    'key': 'Encrypted',
                    'value': False,
                    'skip-devices': ['/dev/sda1', '/dev/xvda']
                }]
            }]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_offhours_stop(self):
        data = {
            'policies': [{
                'name':
                'ec2-offhours-stop',
                'resource':
                'ec2',
                'filters': [{
                    'tag:aws:autoscaling:groupName': 'absent'
                }, {
                    'type': 'offhour',
                    'tag': 'maid_downtime',
                    'default_tz': 'et',
                    'offhour': 19
                }]
            }]
        }
        schema = generate(['ec2'])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_instance_age(self):
        data = {
            'policies': [{
                'name': 'ancient-instances',
                'resource': 'ec2',
                'query': [{
                    'instance-state-name': 'running'
                }],
                'filters': [{
                    'days': 60,
                    'type': 'instance-age'
                }]
            }]
        }
        schema = generate(['ec2'])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_mark_for_op(self):
        data = {
            'policies': [{
                'name':
                'ebs-mark-delete',
                'resource':
                'ebs',
                'filters': [],
                'actions': [{
                    'type': 'mark-for-op',
                    'op': 'delete',
                    'days': 30
                }]
            }]
        }
        schema = generate(['ebs'])
        validator = Validator(schema)

        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)
class SchemaTest(BaseTest):

    validator = None

    def findError(self, data, validator):
        e = best_match(validator.iter_errors(data))
        ex = specific_error(list(validator.iter_errors(data))[0])
        return e, ex

    def setUp(self):
        if not self.validator:
            self.validator = Validator(generate())

    def test_schema(self):
        try:
            schema = generate()
            Validator.check_schema(schema)
        except Exception:
            self.fail("Invalid schema")

    def test_schema_serialization(self):
        try:
            dumps(generate())
        except:
            self.fail("Failed to serialize schema")

    def test_empty_skeleton(self):
        self.assertEqual(validate({'policies': []}), [])

    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]))

    def test_semantic_error(self):
        data = {
            'policies': [
                {'name': 'test',
                 'resource': 'ec2',
                 'filters': {
                     'type': 'ebs',
                     'skipped_devices': []}
                    }]
            }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(
                error.absolute_schema_path))

        self.assertTrue(
            "'skipped_devices': []" in error.message)
        self.assertTrue(
            "'type': 'ebs'" in error.message)

    def test_vars_and_tags(self):
        data = {
            'vars': {'alpha': 1, 'beta': 2},
            'policies': [{
                'name': 'test',
                'resource': 'ec2',
                'tags': ['controls']}]}
        self.assertEqual(list(self.validator.iter_errors(data)), [])

    def test_semantic_error_on_value_derived(self):
        data = {
            'policies': [
                {'name': 'test',
                 'resource': 'ec2',
                 'filters': [
                     {'type': 'ebs',
                      'skipped_devices': []}
                     ]}
            ]}
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(
                error.absolute_schema_path))
        self.assertEqual(
            error.message,
            ("Additional properties are not allowed "
             "('skipped_devices' was unexpected)"))

    def test_invalid_resource_type(self):
        data = {
            'policies': [
                {'name': 'instance-policy',
                 'resource': 'ec3',
                 'filters': []}]}
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)

    def test_value_filter_short_form_invalid(self):
        for rtype in ["elb", "rds", "ec2"]:
            data = {
                'policies': [
                    {'name': 'instance-policy',
                     'resource': 'elb',
                     'filters': [
                         {"tag:Role": "webserver"}]}
                ]}
            schema = generate([rtype])
            # Disable standard value short form
            schema['definitions']['filters']['valuekv'] = {'type': 'number'}
            validator = Validator(schema)
            errors = list(validator.iter_errors(data))
            self.assertEqual(len(errors), 1)

    def test_nested_bool_operators(self):
        data = {
            'policies': [
                {'name': 'test',
                 'resource': 'ec2',
                 'filters': [
                     {'or': [
                         {'tag:Role': 'webserver'},
                         {'type': 'value', 'key': 'x', 'value': []},
                         {'and': [
                             {'tag:Name': 'cattle'},
                             {'tag:Env': 'prod'}]
                          }]
                      }]
                 }]
            }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_value_filter_short_form(self):
        data = {
            'policies': [
                {'name': 'instance-policy',
                 'resource': 'elb',
                 'filters': [
                     {"tag:Role": "webserver"}]}
                ]}

        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_event_inherited_value_filter(self):
        data = {
            'policies': [
                {'name': 'test',
                 'resource': 'ec2',
                 'filters': [
                     {'type': 'event',
                      'key': "detail.requestParameters",
                      "value": "absent"}]}]
            }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_ebs_inherited_value_filter(self):
        data = {
            'policies': [
                {'name': 'test',
                 'resource': 'ec2',
                 'filters': [
                     {'type': 'ebs',
                      'key': 'Encrypted',
                      'value': False,
                      'skip-devices': [
                          '/dev/sda1',
                          '/dev/xvda']}
                     ]}
                ]}
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_offhours_stop(self):
        data = {
            'policies': [
                {'name': 'ec2-offhours-stop',
                 'resource': 'ec2',
                 'filters': [
                     {'tag:aws:autoscaling:groupName': 'absent'},
                     {'type': 'offhour',
                      'tag': 'maid_downtime',
                      'default_tz': 'et',
                      'hour': 19}]
                 }]
            }
        schema = generate(['ec2'])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_instance_age(self):
        data = {
            'policies': [
                {'name': 'ancient-instances',
                 'resource': 'ec2',
                 'query': [{'instance-state-name': 'running'}],
                 'filters': [{'days': 60, 'type': 'instance-age'}]
             }]}
        schema = generate(['ec2'])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_mark_for_op(self):
        data = {
            'policies': [{
                'name': 'ebs-mark-delete',
                'resource': 'ebs',
                'filters': [],
                'actions': [{
                    'type': 'mark-for-op',
                    'op': 'delete',
                    'days': 30}]}]
            }
        schema = generate(['ebs'])
        validator = Validator(schema)

        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)
Beispiel #29
0
 def test_schema(self):
     try:
         schema = generate()
         Validator.check_schema(schema)
     except Exception:
         self.fail("Invalid schema")
Beispiel #30
0
class SchemaTest(BaseTest):

    validator = None

    def findError(self, data, validator):
        e = best_match(validator.iter_errors(data))
        ex = specific_error(list(validator.iter_errors(data))[0])
        return e, ex

    def setUp(self):
        if not self.validator:
            self.validator = Validator(generate())

    def test_schema_plugin_name_mismatch(self):
        for k, v in resources.items():
            for fname, f in v.filter_registry.items():
                if fname in ("or", "and", "not"):
                    continue
                self.assertIn(fname, f.schema["properties"]["type"]["enum"])
            for aname, a in v.action_registry.items():
                self.assertIn(aname, a.schema["properties"]["type"]["enum"])

    def test_schema(self):
        try:
            schema = generate()
            Validator.check_schema(schema)
        except Exception:
            self.fail("Invalid schema")

    def test_schema_serialization(self):
        try:
            dumps(generate())
        except Exception:
            self.fail("Failed to serialize schema")

    def test_empty_skeleton(self):
        self.assertEqual(validate({"policies": []}), [])

    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]))

    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')

    def test_semantic_mode_error(self):
        data = {
            'policies': [{
                'name': 'test',
                'resource': 'ec2',
                'mode': {
                    'type': 'periodic',
                    'scheduled': 'oops'}}]}
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(error.absolute_schema_path)
        )
        self.assertTrue("'scheduled' was unexpected" in str(error))
        self.assertTrue(len(str(error)) < 2000)

    def test_semantic_error(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": {"type": "ebs", "skipped_devices": []},
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(error.absolute_schema_path)
        )

        self.assertTrue("'skipped_devices': []" in error.message)
        self.assertTrue(
            "u'type': u'ebs'" in error.message or "'type': 'ebs'" in error.message
        )

    @mock.patch("c7n.schema.specific_error")
    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)

    def test_vars_and_tags(self):
        data = {
            "vars": {"alpha": 1, "beta": 2},
            "policies": [{"name": "test", "resource": "ec2", "tags": ["controls"]}],
        }
        self.assertEqual(list(self.validator.iter_errors(data)), [])

    def test_semantic_error_on_value_derived(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [{"type": "ebs", "skipped_devices": []}],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)
        error = specific_error(errors[0])
        self.assertTrue(
            len(errors[0].absolute_schema_path) < len(error.absolute_schema_path)
        )
        self.assertTrue("Additional properties are not allowed " in error.message)
        self.assertTrue("'skipped_devices' was unexpected" in error.message)

    def test_invalid_resource_type(self):
        data = {
            "policies": [{"name": "instance-policy", "resource": "ec3", "filters": []}]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(len(errors), 1)

    def test_value_filter_short_form_invalid(self):
        for rtype in ["elb", "rds", "ec2"]:
            data = {
                "policies": [
                    {
                        "name": "instance-policy",
                        "resource": "elb",
                        "filters": [{"tag:Role": "webserver"}],
                    }
                ]
            }
            schema = generate([rtype])
            # Disable standard value short form
            schema["definitions"]["filters"]["valuekv"] = {"type": "number"}
            validator = Validator(schema)
            errors = list(validator.iter_errors(data))
            self.assertEqual(len(errors), 1)

    def test_nested_bool_operators(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [
                        {
                            "or": [
                                {"tag:Role": "webserver"},
                                {"type": "value", "key": "x", "value": []},
                                {"and": [{"tag:Name": "cattle"}, {"tag:Env": "prod"}]},
                            ]
                        }
                    ],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_value_filter_short_form(self):
        data = {
            "policies": [
                {
                    "name": "instance-policy",
                    "resource": "elb",
                    "filters": [{"tag:Role": "webserver"}],
                }
            ]
        }

        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_event_inherited_value_filter(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [
                        {
                            "type": "event",
                            "key": "detail.requestParameters",
                            "value": "absent",
                        }
                    ],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_ebs_inherited_value_filter(self):
        data = {
            "policies": [
                {
                    "name": "test",
                    "resource": "ec2",
                    "filters": [
                        {
                            "type": "ebs",
                            "key": "Encrypted",
                            "value": False,
                            "skip-devices": ["/dev/sda1", "/dev/xvda"],
                        }
                    ],
                }
            ]
        }
        errors = list(self.validator.iter_errors(data))
        self.assertEqual(errors, [])

    def test_offhours_stop(self):
        data = {
            "policies": [
                {
                    "name": "ec2-offhours-stop",
                    "resource": "ec2",
                    "filters": [
                        {"tag:aws:autoscaling:groupName": "absent"},
                        {
                            "type": "offhour",
                            "tag": "c7n_downtime",
                            "default_tz": "et",
                            "offhour": 19,
                        },
                    ],
                }
            ]
        }
        schema = generate(["ec2"])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_instance_age(self):
        data = {
            "policies": [
                {
                    "name": "ancient-instances",
                    "resource": "ec2",
                    "query": [{"instance-state-name": "running"}],
                    "filters": [{"days": 60, "type": "instance-age"}],
                }
            ]
        }
        schema = generate(["ec2"])
        validator = Validator(schema)
        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_mark_for_op(self):
        data = {
            "policies": [
                {
                    "name": "ebs-mark-delete",
                    "resource": "ebs",
                    "filters": [],
                    "actions": [{"type": "mark-for-op", "op": "delete", "days": 30}],
                }
            ]
        }
        schema = generate(["ebs"])
        validator = Validator(schema)

        errors = list(validator.iter_errors(data))
        self.assertEqual(len(errors), 0)

    def test_runtime(self):
        data = lambda runtime: {   # NOQA
            "policies": [
                {
                    "name": "test",
                    "resource": "s3",
                    "mode": {
                        "execution-options": {"metrics_enabled": False},
                        "type": "periodic",
                        "schedule": "xyz",
                        "runtime": runtime,
                    },
                }
            ]
        }
        errors_with = lambda r: list( # NOQA
            Validator(generate()).iter_errors(data(r)))
        self.assertEqual(len(errors_with("python2.7")), 0)
        self.assertEqual(len(errors_with("python3.6")), 0)
        self.assertEqual(len(errors_with("python4.5")), 1)