def test_get_schema_coalesces_known_schema(self): """Every cloudconfig module with schema is listed in allOf keyword.""" schema = get_schema() self.assertCountEqual( [ "cc_apk_configure", "cc_apt_configure", "cc_bootcmd", "cc_locale", "cc_ntp", "cc_resizefs", "cc_runcmd", "cc_snap", "cc_ubuntu_advantage", "cc_ubuntu_drivers", "cc_write_files", "cc_zypper_add_repo", "cc_chef", "cc_install_hotplug", ], [meta["id"] for meta in get_metas().values() if meta is not None], ) self.assertEqual("cloud-config-schema", schema["id"]) self.assertEqual("http://json-schema.org/draft-04/schema#", schema["$schema"]) self.assertCountEqual(["id", "$schema", "allOf"], get_schema().keys())
def test_validateconfig_schema_of_example(self, schema_id, example): """For a given example in a config module we test if it is valid according to the unified schema of all config modules """ schema = get_schema() config_load = load(example) # cloud-init-schema-v1 is permissive of additionalProperties at the # top-level. # To validate specific schemas against known documented examples # we need to only define the specific module schema and supply # strict=True. # TODO(Drop to pop/update once full schema is strict) schema.pop("allOf") schema.update(schema["$defs"][schema_id]) schema["additionalProperties"] = False # Some module examples reference keys defined in multiple schemas supplemental_schemas = { "cc_ubuntu_advantage": ["cc_power_state_change"], "cc_update_hostname": ["cc_set_hostname"], "cc_users_groups": ["cc_ssh_import_id"], "cc_disk_setup": ["cc_mounts"], } for supplement_id in supplemental_schemas.get(schema_id, []): supplemental_props = dict([(key, value) for key, value in schema["$defs"] [supplement_id]["properties"].items()]) schema["properties"].update(supplemental_props) validate_cloudconfig_schema(config_load, schema, strict=True)
def test_all_integration_test_cloud_config_schema(self): """Validate schema of cloud_tests yaml files looking for warnings.""" schema = get_schema() testsdir = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) integration_testdir = os.path.sep.join( [testsdir, 'cloud_tests', 'testcases']) errors = [] yaml_files = [] for root, _dirnames, filenames in os.walk(integration_testdir): yaml_files.extend([ os.path.join(root, f) for f in filenames if f.endswith(".yaml") ]) self.assertTrue(len(yaml_files) > 0) for filename in yaml_files: test_cfg = safe_load(open(filename)) cloud_config = test_cfg.get('cloud_config') if cloud_config: cloud_config = safe_load( cloud_config.replace("#cloud-config\n", "")) try: validate_cloudconfig_schema(cloud_config, schema, strict=True) except SchemaValidationError as e: errors.append('{0}: {1}'.format(filename, e)) if errors: raise AssertionError(', '.join(errors))
def test_schema_validation(self, config, error_msg): schema = get_schema() if error_msg is None: validate_cloudconfig_schema(config, schema, strict=True) else: with pytest.raises(SchemaValidationError, match=error_msg): validate_cloudconfig_schema(config, schema, strict=True)
def test_get_schema_coalesces_known_schema(self): """Every cloudconfig module with schema is listed in allOf keyword.""" schema = get_schema() self.assertCountEqual([ 'cc_apk_configure', 'cc_apt_configure', 'cc_bootcmd', 'cc_locale', 'cc_ntp', 'cc_resizefs', 'cc_runcmd', 'cc_snap', 'cc_ubuntu_advantage', 'cc_ubuntu_drivers', 'cc_write_files', 'cc_write_files_deferred', 'cc_zypper_add_repo', 'cc_chef', 'cc_install_hotplug', ], [subschema['id'] for subschema in schema['allOf']]) self.assertEqual('cloud-config-schema', schema['id']) self.assertEqual('http://json-schema.org/draft-04/schema#', schema['$schema']) # FULL_SCHEMA is updated by the get_schema call from cloudinit.config.schema import FULL_SCHEMA self.assertCountEqual(['id', '$schema', 'allOf'], FULL_SCHEMA.keys())
class TestSchemaDocExamples: schema = get_schema() @pytest.mark.parametrize("example_path", _get_meta_doc_examples()) @skipUnlessJsonSchema() def test_schema_doc_examples(self, example_path): validate_cloudconfig_file(example_path, self.schema)
def test_all_integration_test_cloud_config_schema(self): """Validate schema of cloud_tests yaml files looking for warnings.""" schema = get_schema() testsdir = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) integration_testdir = os.path.sep.join( [testsdir, 'cloud_tests', 'testcases']) errors = [] yaml_files = [] for root, _dirnames, filenames in os.walk(integration_testdir): yaml_files.extend([os.path.join(root, f) for f in filenames if f.endswith(".yaml")]) self.assertTrue(len(yaml_files) > 0) for filename in yaml_files: test_cfg = safe_load(open(filename)) cloud_config = test_cfg.get('cloud_config') if cloud_config: cloud_config = safe_load( cloud_config.replace("#cloud-config\n", "")) try: validate_cloudconfig_schema( cloud_config, schema, strict=True) except SchemaValidationError as e: errors.append( '{0}: {1}'.format( filename, e)) if errors: raise AssertionError(', '.join(errors))
def test_validateconfig_schema_of_example(self, schema_id, example): """For a given example in a config module we test if it is valid according to the unified schema of all config modules """ schema = get_schema() config_load = safe_load(example) validate_cloudconfig_schema(config_load, schema, strict=True)
def test_schema_validation(self, config, error_msg): """Assert expected schema validation and error messages.""" schema = get_schema() if error_msg is None: validate_cloudconfig_schema(config, schema, strict=True) else: with pytest.raises(SchemaValidationError, match=error_msg): validate_cloudconfig_schema(config, schema, strict=True)
def test_schema_validation(self, config, error_msg): """Assert expected schema validation and error messages.""" # New-style schema $defs exist in config/cloud-init-schema*.json schema = get_schema() if error_msg is None: validate_cloudconfig_schema(config, schema, strict=True) else: with pytest.raises(SchemaValidationError, match=error_msg): validate_cloudconfig_schema(config, schema, strict=True)
def test_get_schema_coalesces_known_schema(self): """Every cloudconfig module with schema is listed in allOf keyword.""" schema = get_schema() self.assertItemsEqual([ 'cc_bootcmd', 'cc_ntp', 'cc_resizefs', 'cc_runcmd', 'cc_zypper_add_repo' ], [subschema['id'] for subschema in schema['allOf']]) self.assertEqual('cloud-config-schema', schema['id']) self.assertEqual('http://json-schema.org/draft-04/schema#', schema['$schema']) # FULL_SCHEMA is updated by the get_schema call from cloudinit.config.schema import FULL_SCHEMA self.assertItemsEqual(['id', '$schema', 'allOf'], FULL_SCHEMA.keys())
class TestCloudConfigExamples: schema = get_schema() params = [(schema["id"], example) for schema in schema["allOf"] for example in schema["examples"]] @pytest.mark.parametrize("schema_id,example", params) @skipUnlessJsonSchema() def test_validateconfig_schema_of_example(self, schema_id, example): """ For a given example in a config module we test if it is valid according to the unified schema of all config modules """ config_load = safe_load(example) validate_cloudconfig_schema(config_load, self.schema, strict=True)
def test_get_schema_coalesces_known_schema(self): """Every cloudconfig module with schema is listed in allOf keyword.""" schema = get_schema() self.assertItemsEqual( [ 'cc_bootcmd', 'cc_ntp', 'cc_resizefs', 'cc_runcmd', 'cc_snap', 'cc_ubuntu_advantage', 'cc_ubuntu_drivers', 'cc_zypper_add_repo' ], [subschema['id'] for subschema in schema['allOf']]) self.assertEqual('cloud-config-schema', schema['id']) self.assertEqual( 'http://json-schema.org/draft-04/schema#', schema['$schema']) # FULL_SCHEMA is updated by the get_schema call from cloudinit.config.schema import FULL_SCHEMA self.assertItemsEqual(['id', '$schema', 'allOf'], FULL_SCHEMA.keys())
def test_all_integration_test_cloud_config_schema(self): """Validate schema of cloud_tests yaml files looking for warnings.""" schema = get_schema() testsdir = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) integration_testdir = os.path.sep.join( [testsdir, 'cloud_tests', 'testcases']) errors = [] out, _ = subp(['find', integration_testdir, '-name', '*yaml']) for filename in out.splitlines(): test_cfg = safe_load(open(filename)) cloud_config = test_cfg.get('cloud_config') if cloud_config: cloud_config = safe_load( cloud_config.replace("#cloud-config\n", "")) try: validate_cloudconfig_schema(cloud_config, schema, strict=True) except SchemaValidationError as e: errors.append('{0}: {1}'.format(filename, e)) if errors: raise AssertionError(', '.join(errors))
def test_get_schema_coalesces_known_schema(self): """Every cloudconfig module with schema is listed in allOf keyword.""" schema = get_schema() assert sorted(get_module_names()) == sorted( [meta["id"] for meta in get_metas().values() if meta is not None]) assert "http://json-schema.org/draft-04/schema#" == schema["$schema"] assert ["$defs", "$schema", "allOf"] == sorted(list(schema.keys())) # New style schema should be defined in static schema file in $defs expected_subschema_defs = [ { "$ref": "#/$defs/cc_apk_configure" }, { "$ref": "#/$defs/cc_apt_configure" }, { "$ref": "#/$defs/cc_apt_pipelining" }, { "$ref": "#/$defs/cc_bootcmd" }, { "$ref": "#/$defs/cc_byobu" }, { "$ref": "#/$defs/cc_ca_certs" }, { "$ref": "#/$defs/cc_chef" }, { "$ref": "#/$defs/cc_debug" }, { "$ref": "#/$defs/cc_disable_ec2_metadata" }, { "$ref": "#/$defs/cc_disk_setup" }, { "$ref": "#/$defs/cc_fan" }, { "$ref": "#/$defs/cc_final_message" }, { "$ref": "#/$defs/cc_growpart" }, { "$ref": "#/$defs/cc_grub_dpkg" }, { "$ref": "#/$defs/cc_install_hotplug" }, { "$ref": "#/$defs/cc_keyboard" }, { "$ref": "#/$defs/cc_keys_to_console" }, { "$ref": "#/$defs/cc_landscape" }, { "$ref": "#/$defs/cc_locale" }, { "$ref": "#/$defs/cc_lxd" }, { "$ref": "#/$defs/cc_mcollective" }, { "$ref": "#/$defs/cc_migrator" }, { "$ref": "#/$defs/cc_mounts" }, { "$ref": "#/$defs/cc_ntp" }, { "$ref": "#/$defs/cc_package_update_upgrade_install" }, { "$ref": "#/$defs/cc_phone_home" }, { "$ref": "#/$defs/cc_power_state_change" }, { "$ref": "#/$defs/cc_puppet" }, { "$ref": "#/$defs/cc_resizefs" }, { "$ref": "#/$defs/cc_resolv_conf" }, { "$ref": "#/$defs/cc_rh_subscription" }, { "$ref": "#/$defs/cc_rsyslog" }, { "$ref": "#/$defs/cc_runcmd" }, { "$ref": "#/$defs/cc_salt_minion" }, { "$ref": "#/$defs/cc_scripts_vendor" }, { "$ref": "#/$defs/cc_seed_random" }, { "$ref": "#/$defs/cc_set_hostname" }, { "$ref": "#/$defs/cc_set_passwords" }, { "$ref": "#/$defs/cc_snap" }, { "$ref": "#/$defs/cc_spacewalk" }, { "$ref": "#/$defs/cc_ssh_authkey_fingerprints" }, { "$ref": "#/$defs/cc_ssh_import_id" }, { "$ref": "#/$defs/cc_ssh" }, { "$ref": "#/$defs/cc_timezone" }, { "$ref": "#/$defs/cc_ubuntu_advantage" }, { "$ref": "#/$defs/cc_ubuntu_drivers" }, { "$ref": "#/$defs/cc_update_etc_hosts" }, { "$ref": "#/$defs/cc_update_hostname" }, { "$ref": "#/$defs/cc_users_groups" }, { "$ref": "#/$defs/cc_write_files" }, { "$ref": "#/$defs/cc_yum_add_repo" }, { "$ref": "#/$defs/cc_zypper_add_repo" }, ] found_subschema_defs = [] legacy_schema_keys = [] for subschema in schema["allOf"]: if "$ref" in subschema: found_subschema_defs.append(subschema) else: # Legacy subschema sourced from cc_* module 'schema' attr legacy_schema_keys.extend(subschema["properties"].keys()) assert expected_subschema_defs == found_subschema_defs # This list should remain empty unless we induct new modules with # legacy schema attributes defined within the cc_module. assert [] == sorted(legacy_schema_keys)
def test_get_schema_returns_global_when_set(self): """When FULL_SCHEMA global is already set, get_schema returns it.""" m_schema_path = 'cloudinit.config.schema.FULL_SCHEMA' with mock.patch(m_schema_path, {'here': 'iam'}): self.assertEqual({'here': 'iam'}, get_schema())
def test_schema_validation(self, config, error_msg): with pytest.raises(SchemaValidationError, match=error_msg): validate_cloudconfig_schema(config, get_schema(), strict=True)
def test_static_schema_file_is_valid(self, caplog): with caplog.at_level(logging.WARNING): get_schema() # Assert no warnings parsing our packaged schema file warnings = [msg for (_, _, msg) in caplog.record_tuples] assert [] == warnings
def test_get_schema_returns_global_when_set(self): """When FULL_SCHEMA global is already set, get_schema returns it.""" m_schema_path = 'cloudinit.config.schema.FULL_SCHEMA' with mock.patch(m_schema_path, {'here': 'iam'}): self.assertEqual({'here': 'iam'}, get_schema())
def test_get_schema_coalesces_known_schema(self): """Every cloudconfig module with schema is listed in allOf keyword.""" schema = get_schema() assert sorted( [ "cc_apk_configure", "cc_apt_configure", "cc_apt_pipelining", "cc_bootcmd", "cc_byobu", "cc_ca_certs", "cc_chef", "cc_debug", "cc_disable_ec2_metadata", "cc_disk_setup", "cc_install_hotplug", "cc_keyboard", "cc_locale", "cc_ntp", "cc_resizefs", "cc_runcmd", "cc_snap", "cc_ubuntu_advantage", "cc_ubuntu_drivers", "cc_write_files", "cc_zypper_add_repo", ] ) == sorted( [meta["id"] for meta in get_metas().values() if meta is not None] ) assert "http://json-schema.org/draft-04/schema#" == schema["$schema"] assert ["$defs", "$schema", "allOf"] == sorted(list(schema.keys())) # New style schema should be defined in static schema file in $defs expected_subschema_defs = [ {"$ref": "#/$defs/cc_apk_configure"}, {"$ref": "#/$defs/cc_apt_configure"}, {"$ref": "#/$defs/cc_apt_pipelining"}, {"$ref": "#/$defs/cc_bootcmd"}, {"$ref": "#/$defs/cc_byobu"}, {"$ref": "#/$defs/cc_ca_certs"}, {"$ref": "#/$defs/cc_chef"}, {"$ref": "#/$defs/cc_debug"}, {"$ref": "#/$defs/cc_disable_ec2_metadata"}, {"$ref": "#/$defs/cc_disk_setup"}, ] found_subschema_defs = [] legacy_schema_keys = [] for subschema in schema["allOf"]: if "$ref" in subschema: found_subschema_defs.append(subschema) else: # Legacy subschema sourced from cc_* module 'schema' attr legacy_schema_keys.extend(subschema["properties"].keys()) assert expected_subschema_defs == found_subschema_defs # This list will dwindle as we move legacy schema to new $defs assert [ "drivers", "keyboard", "locale", "locale_configfile", "ntp", "resize_rootfs", "runcmd", "snap", "ubuntu_advantage", "updates", "write_files", "write_files", "zypper", ] == sorted(legacy_schema_keys)