From 2f75e217185cfeb64b8f43be87418dcf29684be6 Mon Sep 17 00:00:00 2001 From: Ivan Kliuk Date: Fri, 14 Aug 2015 20:48:40 +0300 Subject: [PATCH] [Tech debt] Networking validation schema change * Removed redundant 'network_group.NETWORK_GROUP' JSON-schema. * Added 'networks.NETWORK_CONFIGURATION', 'networks.NETWORK_GROUP' and 'networks.NETWORK_GROUPS' JSON-schemas. * Network parameters are validated with corresponding JSON-schema. * Improved testing of validation process. Change-Id: Id86c1543ddd437f15242b384034d72e29a7e4ebc Partial-bug: #1365368 Partial-bug: #1341026 Partial-bug: #1469328 --- .../api/v1/handlers/network_configuration.py | 7 +- .../v1/validators/json_schema/base_types.py | 13 ++ .../validators/json_schema/network_group.py | 33 --- .../api/v1/validators/json_schema/networks.py | 145 +++++++++---- .../api/v1/validators/json_schema/release.py | 4 +- nailgun/nailgun/api/v1/validators/network.py | 32 +-- nailgun/nailgun/test/base.py | 16 +- .../test/integration/test_network_models.py | 2 +- .../integration/test_network_validation.py | 6 +- .../test_network_configuration_validator.py | 202 ++++++++++++++---- .../test/unit/test_network_group_handler.py | 7 +- 11 files changed, 331 insertions(+), 136 deletions(-) delete mode 100644 nailgun/nailgun/api/v1/validators/json_schema/network_group.py diff --git a/nailgun/nailgun/api/v1/handlers/network_configuration.py b/nailgun/nailgun/api/v1/handlers/network_configuration.py index 57efec2253..6a0345d8ae 100644 --- a/nailgun/nailgun/api/v1/handlers/network_configuration.py +++ b/nailgun/nailgun/api/v1/handlers/network_configuration.py @@ -29,6 +29,7 @@ from nailgun.objects.serializers.network_configuration \ from nailgun.objects.serializers.network_configuration \ import NovaNetworkConfigurationSerializer +from nailgun.api.v1.validators.network import NetworkConfigurationValidator from nailgun.api.v1.validators.network import NetworkTemplateValidator from nailgun.api.v1.validators.network \ import NeutronNetworkConfigurationValidator @@ -190,6 +191,8 @@ class NetworkConfigurationVerifyHandler(ProviderHandler): """Network configuration verify handler base """ + validator = NetworkConfigurationValidator + @content def PUT(self, cluster_id): """:IMPORTANT: this method should be rewritten to be more RESTful @@ -205,7 +208,9 @@ class NetworkConfigurationVerifyHandler(ProviderHandler): self.launch_verify(cluster) def launch_verify(self, cluster): - data = self.validator.validate_networks_update(web.data(), cluster) + data = self.validator.validate_networks_update( + self.validator.base_validation(web.data()), + cluster) data["networks"] = [ n for n in data["networks"] if n.get("name") != "fuelweb_admin" diff --git a/nailgun/nailgun/api/v1/validators/json_schema/base_types.py b/nailgun/nailgun/api/v1/validators/json_schema/base_types.py index 929729e58e..870a371c8c 100644 --- a/nailgun/nailgun/api/v1/validators/json_schema/base_types.py +++ b/nailgun/nailgun/api/v1/validators/json_schema/base_types.py @@ -74,7 +74,20 @@ IP_ADDRESS = { {'format': 'ipv4'}, {'format': 'ipv6'}, ] +} +IP_ADDRESS_RANGE = { + "type": "array", + "minItems": 2, + "maxItems": 2, + "uniqueItems": True, + "items": { + "type": "string", + 'anyOf': [ + {'format': 'ipv4'}, + {'format': 'ipv6'}, + ] + } } NULLABLE_IP_ADDRESS = { diff --git a/nailgun/nailgun/api/v1/validators/json_schema/network_group.py b/nailgun/nailgun/api/v1/validators/json_schema/network_group.py deleted file mode 100644 index 275f1fc889..0000000000 --- a/nailgun/nailgun/api/v1/validators/json_schema/network_group.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2015 Mirantis, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from nailgun.api.v1.validators.json_schema import base_types -from nailgun.api.v1.validators.json_schema import networks - -NETWORK_GROUP = { - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "NetworkGroup", - "description": "Serialized NetworkGroup object", - "type": "object", - "properties": { - "id": {"type": "integer"}, - "name": {"type": "string"}, - "release": base_types.NULLABLE_ID, - "vlan_start": base_types.NULLABLE_NON_NEGATIVE_INTEGER, - "cidr": base_types.NET_ADDRESS, - "gateway": base_types.NULLABLE_IP_ADDRESS, - "group_id": base_types.NULLABLE_ID, - "meta": networks.NETWORK - } -} diff --git a/nailgun/nailgun/api/v1/validators/json_schema/networks.py b/nailgun/nailgun/api/v1/validators/json_schema/networks.py index e6eeae3581..1f835d8dd0 100644 --- a/nailgun/nailgun/api/v1/validators/json_schema/networks.py +++ b/nailgun/nailgun/api/v1/validators/json_schema/networks.py @@ -15,28 +15,15 @@ from nailgun.api.v1.validators.json_schema import base_types from nailgun import consts -IP_RANGE = { - "type": "array", - "minItems": 2, - "maxItems": 2, - "uniqueItems": True, - "items": { - "type": "string", - 'anyOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'}, - ] - } -} - -NETWORK = { +NETWORK_META = { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", + "additionalProperties": False, "properties": { "name": {"type": "string"}, "cidr": base_types.NULLABLE_NET_ADDRESS, "gateway": base_types.NULLABLE_IP_ADDRESS, - "ip_range": IP_RANGE, + "ip_range": base_types.IP_ADDRESS_RANGE, "vlan_start": base_types.NULLABLE_NON_NEGATIVE_INTEGER, "seg_type": { "type": "string", @@ -59,35 +46,119 @@ NETWORK = { "uniqueItems": True, "items": {"type": "string", "pattern": "^[a-zA-Z_]+$"} } - }, - "additionalProperties": False + } } -NETWORKS = { +_NETWORK_GROUP = { + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "NetworkGroup", + "description": "Serialized NetworkGroup object", + "type": "object", + "required": ["id"], + "additionalProperties": False, + "properties": { + "id": {"type": "integer"}, + "group_id": base_types.NULLABLE_ID, + "name": {"type": "string"}, + "release": base_types.NULLABLE_ID, + "gateway": base_types.NULLABLE_IP_ADDRESS, + "cidr": base_types.NULLABLE_NET_ADDRESS, + "vlan_start": base_types.NULLABLE_NON_NEGATIVE_INTEGER, + "ip_ranges": { + "type": "array", + "items": base_types.IP_ADDRESS_RANGE, + }, + "meta": NETWORK_META + } +} + +NETWORK_GROUPS = { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", + "required": ["networks"], "properties": { "networks": { "type": "array", - "items": { - "type": "object", - "properties": { - "id": {"type": "integer"}, - "group_id": base_types.NULLABLE_ID, - "name": {"type": "string"}, - "gateway": base_types.NULLABLE_IP_ADDRESS, - "cidr": base_types.NULLABLE_NET_ADDRESS, - "vlan_start": base_types.NULLABLE_NON_NEGATIVE_INTEGER, - "ip_ranges": { - "type": "array", - "items": IP_RANGE - }, - "meta": NETWORK + "items": _NETWORK_GROUP + } + } +} + +NOVA_NETWORK_CONFIGURATION = { + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "networking_parameters": { + "type": "object", + "additionalProperties": False, + "properties": { + "dns_nameservers": base_types.IP_ADDRESS_RANGE, + "fixed_network_size": base_types.NON_NEGATIVE_INTEGER, + "fixed_networks_amount": base_types.NON_NEGATIVE_INTEGER, + "fixed_networks_cidr": base_types.NET_ADDRESS, + "fixed_networks_vlan_start": base_types.NON_NEGATIVE_INTEGER, + "net_manager": { + "enum": list(consts.NOVA_NET_MANAGERS) }, - "required": ["id"], - "additionalProperties": False + "floating_ranges": { + "type": "array", + "items": base_types.IP_ADDRESS_RANGE + } } } - }, - "required": ["networks"], + } +} + +NEUTRON_NETWORK_CONFIGURATION = { + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "networking_parameters": { + "type": "object", + "additionalProperties": False, + "properties": { + "base_mac": base_types.MAC_ADDRESS, + "configuration_template": base_types.NULLABLE_STRING, + "dns_nameservers": base_types.IP_ADDRESS_RANGE, + "floating_ranges": { + "type": "array", + "items": base_types.IP_ADDRESS_RANGE + }, + "gre_id_range": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "uniqueItems": True, + "items": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "exclusiveMinimum": False, + "exclusiveMaximum": False + }, + }, + "internal_cidr": base_types.NULLABLE_NET_ADDRESS, + "internal_gateway": base_types.NULLABLE_IP_ADDRESS, + "net_l23_provider": { + "enum": list(consts.NEUTRON_L23_PROVIDERS) + }, + "segmentation_type": { + "enum": list(consts.NEUTRON_SEGMENT_TYPES) + }, + "vlan_range": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "uniqueItems": True, + "items": { + "type": "integer", + "minimum": 2, + "maximum": 4094, + "exclusiveMinimum": False, + "exclusiveMaximum": False + } + } + } + } + } } diff --git a/nailgun/nailgun/api/v1/validators/json_schema/release.py b/nailgun/nailgun/api/v1/validators/json_schema/release.py index b5e4f68e0b..9af32ccbc5 100644 --- a/nailgun/nailgun/api/v1/validators/json_schema/release.py +++ b/nailgun/nailgun/api/v1/validators/json_schema/release.py @@ -21,7 +21,7 @@ NOVA_NETWORK_SCHEMA = { 'properties': { 'networks': { 'type': 'array', - 'items': networks.NETWORK}, + 'items': networks.NETWORK_META}, 'config': {'type': 'object'}}, 'required': ['networks', 'config'] } @@ -31,7 +31,7 @@ NEUTRON_SCHEMA = { 'properties': { 'networks': { 'type': 'array', - 'items': networks.NETWORK}, + 'items': networks.NETWORK_META}, 'config': {'type': 'object'}}, 'required': ['networks', 'config'] } diff --git a/nailgun/nailgun/api/v1/validators/network.py b/nailgun/nailgun/api/v1/validators/network.py index a0063e489d..1d312ac1d3 100644 --- a/nailgun/nailgun/api/v1/validators/network.py +++ b/nailgun/nailgun/api/v1/validators/network.py @@ -19,10 +19,9 @@ import six from oslo_serialization import jsonutils from nailgun.api.v1.validators.base import BasicValidator -from nailgun.api.v1.validators.json_schema import network_group as ng_scheme from nailgun.api.v1.validators.json_schema.network_template import \ NETWORK_TEMPLATE -from nailgun.api.v1.validators.json_schema import networks as network_schema +from nailgun.api.v1.validators.json_schema import networks from nailgun import consts from nailgun.db import db from nailgun.db.sqlalchemy.models import Cluster @@ -43,10 +42,11 @@ class NetworkConfigurationValidator(BasicValidator): @classmethod def validate_networks_data(cls, data, cluster): + data = cls.base_validation(data) + if 'networks' in data: + cls.validate_schema(data, networks.NETWORK_GROUPS) data = cls.validate_networks_update(data, cluster) - else: - data = cls.base_validation(data) cls.additional_network_validation(data, cluster) @@ -54,8 +54,7 @@ class NetworkConfigurationValidator(BasicValidator): @classmethod def validate_networks_update(cls, data, cluster): - data = cls.base_validation(data) - cls.validate_schema(data, network_schema.NETWORKS) + cls.validate_schema(data, networks.NETWORK_GROUPS) net_ids = [ng['id'] for ng in data['networks']] ng_db_by_id = dict( @@ -92,11 +91,10 @@ class NetworkConfigurationValidator(BasicValidator): # Depending on notation required parameters must be either in # the request or DB - if notation == consts.NETWORK_NOTATION.ip_ranges: - if not ip_ranges and not ng_db.ip_ranges: - raise errors.InvalidData( - "No IP ranges were specified for network " - "{0}".format(net_id)) + if not ip_ranges and notation == consts.NETWORK_NOTATION.ip_ranges: + raise errors.InvalidData( + "No IP ranges were specified for network " + "{0}".format(net_id)) if notation in [consts.NETWORK_NOTATION.cidr, consts.NETWORK_NOTATION.ip_ranges]: @@ -159,6 +157,13 @@ class NovaNetworkConfigurationValidator(NetworkConfigurationValidator): return data + @classmethod + def additional_network_validation(cls, data, cluster): + if 'networking_parameters' in data: + cls.validate_schema( + data, + networks.NOVA_NETWORK_CONFIGURATION) + class NeutronNetworkConfigurationValidator(NetworkConfigurationValidator): @@ -182,6 +187,9 @@ class NeutronNetworkConfigurationValidator(NetworkConfigurationValidator): @classmethod def additional_network_validation(cls, data, cluster): if 'networking_parameters' in data: + cls.validate_schema( + data, + networks.NEUTRON_NETWORK_CONFIGURATION) cls.validate_neutron_params( jsonutils.dumps(data), cluster_id=cluster.id @@ -475,8 +483,6 @@ class NetAssignmentValidator(BasicValidator): class NetworkGroupValidator(BasicValidator): - single_schema = ng_scheme.NETWORK_GROUP - @classmethod def validate(cls, data): d = cls.validate_json(data) diff --git a/nailgun/nailgun/test/base.py b/nailgun/nailgun/test/base.py index c7c7a1d40c..9ebe29ddd2 100644 --- a/nailgun/nailgun/test/base.py +++ b/nailgun/nailgun/test/base.py @@ -1455,8 +1455,11 @@ class BaseValidatorTest(TestCase): context = self.get_invalid_data_context(obj) self.assertIn( - "Additional properties are not allowed (u'{0}' " - "was unexpected)".format(key), + "Additional properties are not allowed".format(key), + context.exception.message) + + self.assertIn( + "'{0}' was unexpected".format(key), context.exception.message) def assertRaisesRequiredProperty(self, obj, key): @@ -1479,7 +1482,7 @@ class BaseValidatorTest(TestCase): "{0} is not of type {1}".format(value, expected_value), context.exception.message) - def assertRaisesInvalidAnyOf(self, obj, expected_value): + def assertRaisesInvalidAnyOf(self, obj, passed_value, instance): context = self.get_invalid_data_context(obj) self.assertIn( "Failed validating 'anyOf' in schema", @@ -1487,7 +1490,12 @@ class BaseValidatorTest(TestCase): err_msg = "{0} is not valid under any of the given schemas" self.assertIn( - err_msg.format(expected_value), context.exception.message) + err_msg.format(passed_value), + context.exception.message) + + self.assertIn( + "On instance{0}".format(instance), + context.exception.message) def assertRaisesInvalidEnum(self, obj, value, expected_value): context = self.get_invalid_data_context(obj) diff --git a/nailgun/nailgun/test/integration/test_network_models.py b/nailgun/nailgun/test/integration/test_network_models.py index de502f1ba8..33bdeb1e9c 100644 --- a/nailgun/nailgun/test/integration/test_network_models.py +++ b/nailgun/nailgun/test/integration/test_network_models.py @@ -97,7 +97,7 @@ class TestNetworkModels(BaseIntegrationTest): test_network_params = copy.deepcopy(test_nets['networking_parameters']) # change something from 'networking_parameters' test_nets['networking_parameters']['dns_nameservers'] = \ - ['one.dns', 'two.dns'] + ['8.8.8.8', '8.8.4.4'] # let's change for example management network test_network_name = consts.NETWORKS.management diff --git a/nailgun/nailgun/test/integration/test_network_validation.py b/nailgun/nailgun/test/integration/test_network_validation.py index 23f279c5ef..17a288c1c6 100644 --- a/nailgun/nailgun/test/integration/test_network_validation.py +++ b/nailgun/nailgun/test/integration/test_network_validation.py @@ -311,8 +311,7 @@ class TestNovaHandlers(TestNetworkChecking): self.nets['networking_parameters']['fixed_networks_cidr'] = \ "10.10.0.0/28" self.nets['networking_parameters']['fixed_networks_amount'] = 1 - self.nets['networking_parameters']['fixed_network_size'] = \ - "256" + self.nets['networking_parameters']['fixed_network_size'] = 256 task = self.update_nova_networks_success(self.cluster.id, self.nets) self.assertEqual(task['status'], consts.TASK_STATUSES.ready) @@ -323,8 +322,7 @@ class TestNovaHandlers(TestNetworkChecking): self.nets['networking_parameters']['fixed_networks_cidr'] = \ "10.10.0.0/24" self.nets['networking_parameters']['fixed_networks_amount'] = 8 - self.nets['networking_parameters']['fixed_network_size'] = \ - "32" + self.nets['networking_parameters']['fixed_network_size'] = 32 self.update_nova_networks_success(self.cluster.id, self.nets) self.nets['networking_parameters']['fixed_networks_amount'] = 32 diff --git a/nailgun/nailgun/test/unit/test_network_configuration_validator.py b/nailgun/nailgun/test/unit/test_network_configuration_validator.py index aaaf7ec629..631177dffc 100644 --- a/nailgun/nailgun/test/unit/test_network_configuration_validator.py +++ b/nailgun/nailgun/test/unit/test_network_configuration_validator.py @@ -14,9 +14,10 @@ import mock -from oslo_serialization import jsonutils - from nailgun.api.v1.validators.network import NetworkConfigurationValidator +from nailgun.api.v1.validators.network import \ + NeutronNetworkConfigurationValidator +from nailgun.api.v1.validators.network import NovaNetworkConfigurationValidator from nailgun.db.sqlalchemy.models import Cluster from nailgun.db.sqlalchemy.models import NetworkGroup from nailgun.errors import errors @@ -24,7 +25,27 @@ from nailgun.network.neutron import NeutronManager from nailgun.test import base -class TestNetworkConfigurationValidatorProtocol(base.BaseValidatorTest): +class BaseNetworkConfigurationValidatorProtocolTest(base.BaseValidatorTest): + + def get_invalid_data_context(self, obj): + """The method is used by assertRaises* methods of base class + and should be overridden because by default it calls + validator with only one argument. + """ + with self.assertRaises(errors.InvalidData) as context: + with mock.patch('nailgun.db.sqlalchemy.models.Cluster.is_locked', + new_callable=mock.PropertyMock, + return_value=False): + cluster_mock = Cluster() + self.validator(obj, cluster_mock) + + return context + + +class TestNetworkConfigurationValidatorProtocol( + BaseNetworkConfigurationValidatorProtocolTest +): + validator = NetworkConfigurationValidator.validate_networks_update def setUp(self): @@ -57,22 +78,6 @@ class TestNetworkConfigurationValidatorProtocol(base.BaseValidatorTest): ] } - # This method is used by assertRaises* methods of base class - # and should be overridden because by default it calls - # validator with only one argument. - def get_invalid_data_context(self, obj): - json_obj = jsonutils.dumps(obj) - - with self.assertRaises(errors.InvalidData) as context: - with mock.patch('nailgun.db.sqlalchemy.models.Cluster.is_locked', - new_callable=mock.PropertyMock) \ - as mocked_property: - mocked_property.return_value = False - cluster_mock = Cluster() - self.validator(json_obj, cluster_mock) - - return context - # networks def test_required_property_networks(self): self.nc['test_key'] = self.nc.pop('networks') @@ -96,19 +101,24 @@ class TestNetworkConfigurationValidatorProtocol(base.BaseValidatorTest): def test_networks_invalid_type_group_id(self): self.nc['networks'][0]['group_id'] = 'x' - self.assertRaisesInvalidAnyOf(self.nc, "u'x'") + self.assertRaisesInvalidAnyOf( + self.nc, + "'x'", + "['networks'][0]['group_id']") def test_networks_invalid_type_gateway(self): self.nc['networks'][0]['gateway'] = [] - self.assertRaisesInvalidAnyOf(self.nc, []) + self.assertRaisesInvalidAnyOf( + self.nc, [], "['networks'][0]['gateway']") def test_networks_invalid_type_cidr(self): self.nc['networks'][0]['cidr'] = 1 - self.assertRaisesInvalidAnyOf(self.nc, 1) + self.assertRaisesInvalidAnyOf(self.nc, 1, "['networks'][0]['cidr']") def test_networks_invalid_type_vlan_start(self): self.nc['networks'][0]['vlan_start'] = {} - self.assertRaisesInvalidAnyOf(self.nc, {}) + self.assertRaisesInvalidAnyOf( + self.nc, {}, "['networks'][0]['vlan_start']") def test_networks_invalid_type_ip_ranges(self): self.nc['networks'][0]['ip_ranges'] = {} @@ -129,11 +139,13 @@ class TestNetworkConfigurationValidatorProtocol(base.BaseValidatorTest): def test_networks_meta_invalid_type_gateway(self): self.nc['networks'][0]['meta']['gateway'] = {} - self.assertRaisesInvalidAnyOf(self.nc, {}) + self.assertRaisesInvalidAnyOf( + self.nc, {}, "['networks'][0]['meta']['gateway']") def test_networks_meta_invalid_type_cidr(self): self.nc['networks'][0]['meta']['cidr'] = {} - self.assertRaisesInvalidAnyOf(self.nc, {}) + self.assertRaisesInvalidAnyOf( + self.nc, {}, "['networks'][0]['meta']['cidr']") # networks.meta.ip_range def test_networks_meta_ip_range(self): @@ -147,28 +159,30 @@ class TestNetworkConfigurationValidatorProtocol(base.BaseValidatorTest): ["1.1.1.1", "1.1.1.2", "1.1.1.3"] self.assertRaisesTooLong( self.nc, - "[u'1.1.1.1', u'1.1.1.2', u'1.1.1.3']") + "['1.1.1.1', '1.1.1.2', '1.1.1.3']") self.nc['networks'][0]['meta']['ip_range'] = ["1.1.1.1"] - self.assertRaisesTooShort(self.nc, "[u'1.1.1.1']") + self.assertRaisesTooShort(self.nc, "['1.1.1.1']") self.nc['networks'][0]['meta']['ip_range'] = ['1.2.3.4', '1.2.3.4'] - self.assertRaisesNonUnique(self.nc, "[u'1.2.3.4', u'1.2.3.4']") + self.assertRaisesNonUnique(self.nc, "['1.2.3.4', '1.2.3.4']") self.nc['networks'][0]['meta']['ip_range'] = ["1.1.1.1", "1.2.3.x"] - self.assertRaisesInvalidAnyOf(self.nc, "u'1.2.3.x'") + self.assertRaisesInvalidAnyOf( + self.nc, "'1.2.3.x'", "['networks'][0]['meta']['ip_range']") def test_networks_meta_invalid_type_vlan_start(self): self.nc['networks'][0]['meta']['vlan_start'] = {} - self.assertRaisesInvalidAnyOf(self.nc, {}) + self.assertRaisesInvalidAnyOf( + self.nc, {}, "['networks'][0]['meta']['vlan_start']") def test_networks_meta_invalid_type_seg_type(self): self.nc['networks'][0]['meta']['seg_type'] = 'x' - self.assertRaisesInvalidEnum(self.nc, "u'x'", "['vlan', 'gre', 'tun']") + self.assertRaisesInvalidEnum(self.nc, "'x'", "['vlan', 'gre', 'tun']") def test_networks_invalid_type_neutron_vlan_range(self): self.nc['networks'][0]['meta']['neutron_vlan_range'] = 'z' - self.assertRaisesInvalidType(self.nc, "u'z'", "'boolean'") + self.assertRaisesInvalidType(self.nc, "'z'", "'boolean'") def test_networks_meta_invalid_type_use_gateway(self): self.nc['networks'][0]['meta']['use_gateway'] = {} @@ -177,7 +191,7 @@ class TestNetworkConfigurationValidatorProtocol(base.BaseValidatorTest): def test_networks_invalid_type_notation(self): self.nc['networks'][0]['meta']['notation'] = 'x' self.assertRaisesInvalidEnum( - self.nc, "u'x'", "['cidr', 'ip_ranges', None]") + self.nc, "'x'", "['cidr', 'ip_ranges', None]") def test_networks_invalid_type_render_type(self): self.nc['networks'][0]['meta']['render_type'] = 1 @@ -197,7 +211,7 @@ class TestNetworkConfigurationValidatorProtocol(base.BaseValidatorTest): def test_networks_meta_invalid_type_configurable(self): self.nc['networks'][0]['meta']['configurable'] = 'hello' - self.assertRaisesInvalidType(self.nc, "u'hello'", "'boolean'") + self.assertRaisesInvalidType(self.nc, "'hello'", "'boolean'") def test_networks_meta_invalid_type_floating_range_var(self): self.nc['networks'][0]['meta']['floating_range_var'] = {} @@ -216,10 +230,10 @@ class TestNetworkConfigurationValidatorProtocol(base.BaseValidatorTest): self.assertRaisesInvalidType(self.nc, "1", "'string'") self.nc['networks'][0]['meta']['vips'] = ['vip_a', 'vip_a'] - self.assertRaisesNonUnique(self.nc, "[u'vip_a', u'vip_a']") + self.assertRaisesNonUnique(self.nc, "['vip_a', 'vip_a']") self.nc['networks'][0]['meta']['vips'] = ["a", "b", "c1"] - self.assertRaisesNotMatchPattern(self.nc, "u'c1'") + self.assertRaisesNotMatchPattern(self.nc, "'c1'") class TestNetworkConfigurationValidator(base.BaseIntegrationTest): @@ -246,10 +260,9 @@ class TestNetworkConfigurationValidator(base.BaseIntegrationTest): return net def get_context_of_validation_error(self): - config = jsonutils.dumps(self.config) with self.assertRaises(errors.InvalidData) as exc_context: - self.validator.validate_networks_update(config, - self.cluster) + self.validator.validate_networks_update( + self.config, self.cluster) return exc_context def assertRaisesInvalidData(self, message): @@ -337,3 +350,114 @@ class TestNetworkConfigurationValidator(base.BaseIntegrationTest): result = NetworkConfigurationValidator._check_for_ip_conflicts( mgmt, self.cluster, 'ip_ranges', False) self.assertTrue(result) + + +class TestNovaNetworkConfigurationValidatorProtocol( + BaseNetworkConfigurationValidatorProtocolTest +): + + validator = NovaNetworkConfigurationValidator.additional_network_validation + + def setUp(self): + super(TestNovaNetworkConfigurationValidatorProtocol, self).setUp() + self.nc = { + "networking_parameters": { + "dns_nameservers": ["8.8.4.4", "8.8.8.8"], + "floating_ranges": [["172.16.0.130", "172.16.0.254"]], + "fixed_network_size": 1, + "fixed_networks_amount": 2, + "fixed_networks_cidr": "192.168.111.0/24", + "fixed_networks_vlan_start": 101, + "net_manager": "FlatDHCPManager", + + } + } + + # networking parameters + def test_networking_parameters_invalid_type(self): + self.nc['networking_parameters'] = 1 + self.assertRaisesInvalidType(self.nc, "1", "'object'") + + def test_dns_nameservers_ip_range(self): + self.nc['networking_parameters']['dns_nameservers'] = {} + self.assertRaisesInvalidType(self.nc, "{}", "'array'") + + self.nc['networking_parameters']['dns_nameservers'] = [1, 2] + self.assertRaisesInvalidType(self.nc, "1", "'string'") + + self.nc['networking_parameters']['dns_nameservers'] = \ + ["1.1.1.1", "1.1.1.2", "1.1.1.3"] + self.assertRaisesTooLong( + self.nc, + "['1.1.1.1', '1.1.1.2', '1.1.1.3']") + + self.nc['networking_parameters']['dns_nameservers'] = ["1.1.1.1"] + self.assertRaisesTooShort(self.nc, "['1.1.1.1']") + + self.nc['networking_parameters']['dns_nameservers'] =\ + ['1.2.3.4', '1.2.3.4'] + self.assertRaisesNonUnique(self.nc, "['1.2.3.4', '1.2.3.4']") + + self.nc['networking_parameters']['dns_nameservers'] = \ + ["1.1.1.1", "1.2.3.x"] + self.assertRaisesInvalidAnyOf( + self.nc, + "'1.2.3.x'", + "['networking_parameters']['dns_nameservers']") + + +class TestNeutronNetworkConfigurationValidatorProtocol( + BaseNetworkConfigurationValidatorProtocolTest +): + + validator = \ + NeutronNetworkConfigurationValidator.additional_network_validation + + def setUp(self): + super(TestNeutronNetworkConfigurationValidatorProtocol, self).setUp() + self.nc = { + "networking_parameters": { + "base_mac": "fa:16:3e:00:00:00", + "configuration_template": None, + "dns_nameservers": ["8.8.4.4", "8.8.8.8"], + "floating_ranges": [["172.16.0.130", "172.16.0.254"]], + "gre_id_range": [2, 65535], + "internal_cidr": "192.168.111.0/24", + "internal_gateway": "192.168.111.1", + "net_l23_provider": "ovs", + "segmentation_type": "gre", + "vlan_range": [1000, 1030] + } + } + + # networking parameters + def test_networking_parameters_invalid_type(self): + self.nc['networking_parameters'] = 1 + self.assertRaisesInvalidType(self.nc, "1", "'object'") + + def test_dns_nameservers_ip_range(self): + self.nc['networking_parameters']['dns_nameservers'] = {} + self.assertRaisesInvalidType(self.nc, "{}", "'array'") + + self.nc['networking_parameters']['dns_nameservers'] = [1, 2] + self.assertRaisesInvalidType(self.nc, "1", "'string'") + + self.nc['networking_parameters']['dns_nameservers'] = \ + ["1.1.1.1", "1.1.1.2", "1.1.1.3"] + self.assertRaisesTooLong( + self.nc, + "['1.1.1.1', '1.1.1.2', '1.1.1.3']") + + self.nc['networking_parameters']['dns_nameservers'] = ["1.1.1.1"] + self.assertRaisesTooShort(self.nc, "['1.1.1.1']") + + self.nc['networking_parameters']['dns_nameservers'] =\ + ['1.2.3.4', '1.2.3.4'] + self.assertRaisesNonUnique(self.nc, "['1.2.3.4', '1.2.3.4']") + + self.nc['networking_parameters']['dns_nameservers'] = \ + ["1.1.1.1", "1.2.3.x"] + self.assertRaisesInvalidAnyOf( + self.nc, + "'1.2.3.x'", + "['networking_parameters']['dns_nameservers']") diff --git a/nailgun/nailgun/test/unit/test_network_group_handler.py b/nailgun/nailgun/test/unit/test_network_group_handler.py index c6b7696523..b5459b2df5 100644 --- a/nailgun/nailgun/test/unit/test_network_group_handler.py +++ b/nailgun/nailgun/test/unit/test_network_group_handler.py @@ -87,7 +87,8 @@ class TestHandlers(BaseIntegrationTest): self.assertEqual(400, resp.status_code) self.assertEqual( resp.json_body["message"], - "notation: u'new' is not one of ['cidr', 'ip_ranges', None]") + "IPAddrRange object cannot be created for network " + "'external' with notation='new', ip_range='None'") resp = self._create_network_group( meta={"notation": "ip_ranges"}, @@ -106,7 +107,9 @@ class TestHandlers(BaseIntegrationTest): ) self.assertEqual(400, resp.status_code) self.assertEqual(resp.json_body["message"], - "ip_range: [u'10.3.0.33'] is too short") + "IPAddrRange object cannot be created for network " + "'external' with notation='ip_ranges', " + "ip_range='[u'10.3.0.33']'") def test_get_network_group(self): resp = self._create_network_group(name='test')