diff --git a/tripleo_common/tests/utils/test_roles.py b/tripleo_common/tests/utils/test_roles.py index b924f40a0..6af5dd45a 100644 --- a/tripleo_common/tests/utils/test_roles.py +++ b/tripleo_common/tests/utils/test_roles.py @@ -34,6 +34,20 @@ SAMPLE_ROLE = """ ServicesDefault: - OS::TripleO::Services::Ntp """ +SAMPLE_ROLE_NETWORK_DICT = """ +############################################################################### +# Role: sample # +############################################################################### +- name: sample + description: | + Sample! + networks: + InternalApi: + subnet: internal_api_subnet + HostnameFormatDefault: '%stackname%-sample-%index%' + ServicesDefault: + - OS::TripleO::Services::Ntp +""" SAMPLE_GENERATED_ROLE = """ ############################################################################### # Role: sample # @@ -54,6 +68,16 @@ SAMPLE_ROLE_OBJ = { 'name': 'sample', 'networks': ['InternalApi'] } +SAMPLE_ROLE_OBJ_NETWORK_DICT = { + 'HostnameFormatDefault': '%stackname%-sample-%index%', + 'ServicesDefault': ['OS::TripleO::Services::Ntp'], + 'description': 'Sample!\n', + 'name': 'sample', + 'networks': { + 'InternalApi': { + 'subnet': 'internal_api_subnet'} + } +} class TestRolesUtils(base.TestCase): @@ -111,6 +135,10 @@ class TestRolesUtils(base.TestCase): role = rolesutils.validate_role_yaml(SAMPLE_ROLE) self.assertEqual(SAMPLE_ROLE_OBJ, role) + def test_validate_role_with_network_dict(self): + role = rolesutils.validate_role_yaml(SAMPLE_ROLE_NETWORK_DICT) + self.assertEqual(SAMPLE_ROLE_OBJ_NETWORK_DICT, role) + def test_validate_role_yaml_with_file(self): m = mock.mock_open(read_data=SAMPLE_ROLE) with mock.patch('tripleo_common.utils.roles.open', m): @@ -133,6 +161,12 @@ class TestRolesUtils(base.TestCase): self.assertRaises(RoleMetadataError, rolesutils.validate_role_yaml, yaml.safe_dump(role)) + def test_validate_role_yaml_invalid_network_type(self): + role = yaml.safe_load(SAMPLE_ROLE) + role[0]['networks'] = 'should not be a string' + self.assertRaises(RoleMetadataError, rolesutils.validate_role_yaml, + yaml.safe_dump(role)) + @mock.patch('tripleo_common.utils.roles.check_role_exists') @mock.patch('tripleo_common.utils.roles.get_roles_list_from_directory') def test_generate_roles_with_one_role_generated(self, get_roles_mock, diff --git a/tripleo_common/utils/roles.py b/tripleo_common/utils/roles.py index 2cd2b08ac..40b5b1e6e 100644 --- a/tripleo_common/utils/roles.py +++ b/tripleo_common/utils/roles.py @@ -161,7 +161,7 @@ def validate_role_yaml(role_data=None, role_path=None): 'ServicesDefault': {'type': list}, 'tags': {'type': list}, 'description': {'type': six.string_types}, - 'networks': {'type': list}, + 'networks': {'type': [list, dict]}, 'networks_skip_config': {'type': list}, } @@ -170,8 +170,16 @@ def validate_role_yaml(role_data=None, role_path=None): # validate numeric metadata is numeric for k in schema: - if k in role and not isinstance(role[k], schema[k]['type']): - msg = "Role '{}': {} is not of expected type {}".format( - role['name'], k, schema[k]['type']) - raise RoleMetadataError(msg) + if k in role: + if k == 'networks': + if not (isinstance(role[k], schema[k]['type'][0]) or + isinstance(role[k], schema[k]['type'][1])): + msg = "Role '{}': {} is not of expected type {}".format( + role['name'], k, schema[k]['type']) + raise RoleMetadataError(msg) + else: + if not isinstance(role[k], schema[k]['type']): + msg = "Role '{}': {} is not of expected type {}".format( + role['name'], k, schema[k]['type']) + raise RoleMetadataError(msg) return role