From 4815936beb1b3d4cb1dc23bd878d151def027757 Mon Sep 17 00:00:00 2001 From: Dima Shulyak Date: Wed, 5 Nov 2014 13:06:24 +0200 Subject: [PATCH] Add support for release network_metadata serialziation Patch adds support for release network metadata serialization, by adding additional handler on release//networks for PUT/GET requestss Proper validation for release networking data Why not to add another field in release handler: 1. networks_metadata it is ours internal naming 2. url release//networks makes more sense for client applications Change-Id: I205ec786f1a9d772905ff22e426c1ce8a6d4d6e7 Closes-Bug: 1381557 --- nailgun/nailgun/api/v1/handlers/release.py | 51 ++++++++++++++- nailgun/nailgun/api/v1/urls.py | 4 +- .../api/v1/validators/json_schema/networks.py | 63 +++++++++++++++++++ .../api/v1/validators/json_schema/node.py | 39 ++---------- .../api/v1/validators/json_schema/release.py | 46 ++++++++++++++ nailgun/nailgun/api/v1/validators/release.py | 15 +++++ .../test_release_networks_handler.py | 62 ++++++++++++++++++ .../test/unit/test_release_networks_schema.py | 30 +++++++++ 8 files changed, 274 insertions(+), 36 deletions(-) create mode 100644 nailgun/nailgun/api/v1/validators/json_schema/networks.py create mode 100644 nailgun/nailgun/api/v1/validators/json_schema/release.py create mode 100644 nailgun/nailgun/test/integration/test_release_networks_handler.py create mode 100644 nailgun/nailgun/test/unit/test_release_networks_schema.py diff --git a/nailgun/nailgun/api/v1/handlers/release.py b/nailgun/nailgun/api/v1/handlers/release.py index 3070908317..3dcc1e68ae 100644 --- a/nailgun/nailgun/api/v1/handlers/release.py +++ b/nailgun/nailgun/api/v1/handlers/release.py @@ -21,9 +21,8 @@ Handlers dealing with releases from nailgun.api.v1.handlers.base import CollectionHandler from nailgun.api.v1.handlers.base import content_json from nailgun.api.v1.handlers.base import SingleHandler - +from nailgun.api.v1.validators.release import ReleaseNetworksValidator from nailgun.api.v1.validators.release import ReleaseValidator - from nailgun.objects import Release from nailgun.objects import ReleaseCollection @@ -50,3 +49,51 @@ class ReleaseCollectionHandler(CollectionHandler): """ q = sorted(self.collection.all(), reverse=True) return self.collection.to_json(q) + + +class ReleaseNetworksHandler(SingleHandler): + """Release Handler for network metadata + """ + + single = Release + validator = ReleaseNetworksValidator + + @content_json + def GET(self, obj_id): + """Read release networks metadata + + :returns: Release networks metadata + :http: * 201 (object successfully created) + * 400 (invalid object data specified) + * 404 (release object not found) + """ + obj = self.get_object_or_404(self.single, obj_id) + return obj['networks_metadata'] + + @content_json + def PUT(self, obj_id): + """Updates release networks metadata + + :returns: Release networks metadata + :http: * 201 (object successfully created) + * 400 (invalid object data specified) + * 404 (release object not found) + """ + obj = self.get_object_or_404(self.single, obj_id) + data = self.checked_data() + self.single.update(obj, {'networks_metadata': data}) + return obj['networks_metadata'] + + def POST(self, obj_id): + """Creation of metadata disallowed + + :http: * 405 (method not supported) + """ + raise self.http(405, 'Create not supported for this entity') + + def DELETE(self, obj_id): + """Deletion of metadata disallowed + + :http: * 405 (method not supported) + """ + raise self.http(405, 'Delete not supported for this entity') diff --git a/nailgun/nailgun/api/v1/urls.py b/nailgun/nailgun/api/v1/urls.py index ebff320c9e..ef90afaaad 100644 --- a/nailgun/nailgun/api/v1/urls.py +++ b/nailgun/nailgun/api/v1/urls.py @@ -77,10 +77,10 @@ from nailgun.api.v1.handlers.orchestrator import DeploySelectedNodes from nailgun.api.v1.handlers.orchestrator import ProvisioningInfo from nailgun.api.v1.handlers.orchestrator import ProvisionSelectedNodes - from nailgun.api.v1.handlers.registration import FuelKeyHandler from nailgun.api.v1.handlers.release import ReleaseCollectionHandler from nailgun.api.v1.handlers.release import ReleaseHandler +from nailgun.api.v1.handlers.release import ReleaseNetworksHandler from nailgun.api.v1.handlers.tasks import TaskCollectionHandler from nailgun.api.v1.handlers.tasks import TaskHandler @@ -98,6 +98,8 @@ urls = ( ReleaseCollectionHandler, r'/releases/(?P\d+)/?$', ReleaseHandler, + r'/releases/(?P\d+)/networks/?$', + ReleaseNetworksHandler, r'/clusters/?$', ClusterCollectionHandler, diff --git a/nailgun/nailgun/api/v1/validators/json_schema/networks.py b/nailgun/nailgun/api/v1/validators/json_schema/networks.py new file mode 100644 index 0000000000..56fc68a621 --- /dev/null +++ b/nailgun/nailgun/api/v1/validators/json_schema/networks.py @@ -0,0 +1,63 @@ +# Copyright 2014 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. + + +# Non-complete JSON Schema for validating IP addresses. +# Use it for better readability in the main schema. +_IP_ADDRESS_SCHEMA = { + 'type': 'string', + 'format': 'ipv4', +} + + +# Non-complete JSON schema for validating NET addresses. +# Use it for better readability in the main schema. +_NET_ADDRESS_SCHEMA = { + 'type': 'string', + + # check for valid ip address and route prefix + # e.g: 192.168.0.0/24 + 'pattern': '^(({octet}\.){{3}}{octet})({prefix})?$'.format( + octet='(2(5[0-5]|[0-4][0-9])|[01]?[0-9][0-9]?)', + prefix='/(3[012]|[12]?[0-9])' + ), +} + + +# Non-complete JSON Schema for validating MAC addresses. +# Use it for better readability in the main schema. +_MAC_ADDRESS_SCHEMA = { + 'type': 'string', + 'pattern': '^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$', +} + + +NETWORK = { + 'type': 'object', + 'properties': { + 'name': {'type': 'string'}, + 'cidr': _NET_ADDRESS_SCHEMA, + 'gateway': _IP_ADDRESS_SCHEMA, + 'ip_range': {'type': 'array'}, + 'vlan_start': {'type': ['null', 'number']}, + 'use_gateway': {'type': 'boolean'}, + 'notation': {'type': ['string', 'null']}, + 'render_type': {'type': ['null', 'string']}, + 'map_priority': {'type': 'number'}, + 'configurable': {'type': 'boolean'}, + 'floating_range_var': {'type': 'string'}, + 'ext_net_data': {'type': 'array'}, + 'assign_vip': {'type': 'boolean'}}, + 'required': ['name'] +} diff --git a/nailgun/nailgun/api/v1/validators/json_schema/node.py b/nailgun/nailgun/api/v1/validators/json_schema/node.py index 6e0eba0c9b..bed9482013 100644 --- a/nailgun/nailgun/api/v1/validators/json_schema/node.py +++ b/nailgun/nailgun/api/v1/validators/json_schema/node.py @@ -14,34 +14,7 @@ # License for the specific language governing permissions and limitations # under the License. -# Non-complete JSON Schema for validating IP addresses. -# Use it for better readability in the main schema. -_IP_ADDRESS_SCHEMA = { - 'type': 'string', - 'format': 'ipv4', -} - - -# Non-complete JSON schema for validating NET addresses. -# Use it for better readability in the main schema. -_NET_ADDRESS_SCHEMA = { - 'type': 'string', - - # check for valid ip address and route prefix - # e.g: 192.168.0.0/24 - 'pattern': '^(({octet}\.){{3}}{octet})({prefix})?$'.format( - octet='(2(5[0-5]|[0-4][0-9])|[01]?[0-9][0-9]?)', - prefix='/(3[012]|[12]?[0-9])' - ), -} - - -# Non-complete JSON Schema for validating MAC addresses. -# Use it for better readability in the main schema. -_MAC_ADDRESS_SCHEMA = { - 'type': 'string', - 'pattern': '^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$', -} +from nailgun.api.v1.validators.json_schema import networks # TODO(@ikalnitsky): add `required` properties to all needed objects @@ -51,8 +24,8 @@ node_format_schema = { 'description': 'Object with node description', 'type': 'object', 'properties': { - 'mac': _MAC_ADDRESS_SCHEMA, - 'ip': _IP_ADDRESS_SCHEMA, + 'mac': networks._MAC_ADDRESS_SCHEMA, + 'ip': networks._IP_ADDRESS_SCHEMA, 'meta': { 'type': 'object', 'properties': { @@ -63,9 +36,9 @@ node_format_schema = { 'items': { 'type': 'object', 'properties': { - 'ip': _IP_ADDRESS_SCHEMA, - 'netmask': _NET_ADDRESS_SCHEMA, - 'mac': _MAC_ADDRESS_SCHEMA, + 'ip': networks._IP_ADDRESS_SCHEMA, + 'netmask': networks._NET_ADDRESS_SCHEMA, + 'mac': networks._MAC_ADDRESS_SCHEMA, 'state': {'type': 'string'}, 'name': {'type': 'string'}, } diff --git a/nailgun/nailgun/api/v1/validators/json_schema/release.py b/nailgun/nailgun/api/v1/validators/json_schema/release.py new file mode 100644 index 0000000000..b5e4f68e0b --- /dev/null +++ b/nailgun/nailgun/api/v1/validators/json_schema/release.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 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 networks + + +NOVA_NETWORK_SCHEMA = { + 'type': 'object', + 'properties': { + 'networks': { + 'type': 'array', + 'items': networks.NETWORK}, + 'config': {'type': 'object'}}, + 'required': ['networks', 'config'] +} + +NEUTRON_SCHEMA = { + 'type': 'object', + 'properties': { + 'networks': { + 'type': 'array', + 'items': networks.NETWORK}, + 'config': {'type': 'object'}}, + 'required': ['networks', 'config'] +} + +NETWORKS_SCHEMA = { + 'type': 'object', + 'properties': { + 'nova_network': NOVA_NETWORK_SCHEMA, + 'neutron': NEUTRON_SCHEMA, + }, + 'required': ['nova_network', 'neutron'] +} diff --git a/nailgun/nailgun/api/v1/validators/release.py b/nailgun/nailgun/api/v1/validators/release.py index 7150f18750..32ba6652f0 100644 --- a/nailgun/nailgun/api/v1/validators/release.py +++ b/nailgun/nailgun/api/v1/validators/release.py @@ -16,6 +16,7 @@ from sqlalchemy import not_ from nailgun.api.v1.validators.base import BasicValidator +from nailgun.api.v1.validators.json_schema import release from nailgun.db import db from nailgun.db.sqlalchemy.models import Release from nailgun.errors import errors @@ -126,3 +127,17 @@ class ReleaseValidator(BasicValidator): "Can't delete release with " "clusters assigned" ) + + +class ReleaseNetworksValidator(BasicValidator): + + @classmethod + def validate(cls, data): + parsed = super(ReleaseNetworksValidator, cls).validate(data) + cls.validate_schema(parsed) + return parsed + + @classmethod + def validate_schema(cls, data): + return super(ReleaseNetworksValidator, cls).validate_schema( + data, release.NETWORKS_SCHEMA) diff --git a/nailgun/nailgun/test/integration/test_release_networks_handler.py b/nailgun/nailgun/test/integration/test_release_networks_handler.py new file mode 100644 index 0000000000..3fdb3d4de6 --- /dev/null +++ b/nailgun/nailgun/test/integration/test_release_networks_handler.py @@ -0,0 +1,62 @@ +# Copyright 2014 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.openstack.common import jsonutils +from nailgun.test.base import BaseIntegrationTest +from nailgun.test.base import reverse + + +class TestReleaseNetworksHandlers(BaseIntegrationTest): + + def setUp(self): + super(TestReleaseNetworksHandlers, self).setUp() + self.release = self.env.create_release() + + def test_get(self): + resp = self.app.get( + reverse('ReleaseNetworksHandler', + kwargs={'obj_id': self.release.id}), + headers=self.default_headers + ) + self.assertEqual(resp.status_code, 200) + self.assertEqual(self.release['networks_metadata'], resp.json) + + def test_post(self): + resp = self.app.post( + reverse('ReleaseNetworksHandler', + kwargs={'obj_id': self.release.id}), + headers=self.default_headers, + expect_errors=True + ) + self.assertEqual(resp.status_code, 405) + + def test_delete(self): + resp = self.app.delete( + reverse('ReleaseNetworksHandler', + kwargs={'obj_id': self.release.id}), + headers=self.default_headers, + expect_errors=True + ) + self.assertEqual(resp.status_code, 405) + + def test_put(self): + data = jsonutils.dumps(self.release['networks_metadata']) + resp = self.app.put( + reverse('ReleaseNetworksHandler', + kwargs={'obj_id': self.release.id}), + data, + headers=self.default_headers + ) + self.assertEqual(resp.status_code, 200) diff --git a/nailgun/nailgun/test/unit/test_release_networks_schema.py b/nailgun/nailgun/test/unit/test_release_networks_schema.py new file mode 100644 index 0000000000..c1e479ae86 --- /dev/null +++ b/nailgun/nailgun/test/unit/test_release_networks_schema.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Copyright 2014 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. + +import jsonschema + +from nailgun.api.v1.validators.json_schema import release +from nailgun.test import base + + +class TestRelaseNetworksSchema(base.BaseTestCase): + + def test_networks_schema(self): + checker = jsonschema.FormatChecker() + release_data = self.env.create_release() + jsonschema.validate( + release_data['networks_metadata'], + release.NETWORKS_SCHEMA, + format_checker=checker)