diff --git a/doc/api_samples/all_extensions/extensions-get-resp.json b/doc/api_samples/all_extensions/extensions-get-resp.json index 81df655de3..b8fac5f559 100644 --- a/doc/api_samples/all_extensions/extensions-get-resp.json +++ b/doc/api_samples/all_extensions/extensions-get-resp.json @@ -296,6 +296,14 @@ "namespace": "http://docs.openstack.org/compute/ext/extended_hypervisors/api/v1.1", "updated": "2014-01-04T00:00:00Z" }, + { + "alias": "os-extended-networks", + "description": "Adds additional fields to networks", + "links": [], + "name": "ExtendedNetworks", + "namespace": "http://docs.openstack.org/compute/ext/extended_networks/api/v2", + "updated": "2014-05-09T00:00:00Z" + }, { "alias": "os-extended-quotas", "description": "Adds ability for admins to delete quota\n and optionally force the update Quota command.\n ", diff --git a/doc/api_samples/all_extensions/extensions-get-resp.xml b/doc/api_samples/all_extensions/extensions-get-resp.xml index 77fde4d58b..fb56dd8f4b 100644 --- a/doc/api_samples/all_extensions/extensions-get-resp.xml +++ b/doc/api_samples/all_extensions/extensions-get-resp.xml @@ -129,6 +129,9 @@ Extended hypervisors support. + + Adds additional fields to networks + Adds ability for admins to delete quota and optionally force the update Quota command. diff --git a/doc/api_samples/os-extended-networks/network-create-req.json b/doc/api_samples/os-extended-networks/network-create-req.json new file mode 100644 index 0000000000..18515bd6c4 --- /dev/null +++ b/doc/api_samples/os-extended-networks/network-create-req.json @@ -0,0 +1,12 @@ +{ + "network": { + "label": "new net 111", + "cidr": "10.20.105.0/24", + "mtu": 9000, + "dhcp_server": "10.20.105.2", + "enable_dhcp": false, + "share_address": true, + "allowed_start": "10.20.105.10", + "allowed_end": "10.20.105.200" + } +} diff --git a/doc/api_samples/os-extended-networks/network-create-req.xml b/doc/api_samples/os-extended-networks/network-create-req.xml new file mode 100644 index 0000000000..3cc79bd837 --- /dev/null +++ b/doc/api_samples/os-extended-networks/network-create-req.xml @@ -0,0 +1,10 @@ + + + 10.20.105.0/24 + 9000 + 10.20.105.2 + False + True + 10.20.105.10 + 10.20.105.200 + diff --git a/doc/api_samples/os-extended-networks/network-create-resp.json b/doc/api_samples/os-extended-networks/network-create-resp.json new file mode 100644 index 0000000000..4364e50b2d --- /dev/null +++ b/doc/api_samples/os-extended-networks/network-create-resp.json @@ -0,0 +1,36 @@ +{ + "network": { + "bridge": null, + "bridge_interface": null, + "broadcast": "10.20.105.255", + "cidr": "10.20.105.0/24", + "cidr_v6": null, + "created_at": null, + "deleted": null, + "deleted_at": null, + "dhcp_server": "10.20.105.2", + "dhcp_start": "10.20.105.2", + "dns1": null, + "dns2": null, + "enable_dhcp": false, + "gateway": "10.20.105.1", + "gateway_v6": null, + "host": null, + "id": "d7a17c0c-457e-4ab4-a99c-4fa1762f5359", + "injected": null, + "label": "new net 111", + "mtu": 9000, + "multi_host": null, + "netmask": "255.255.255.0", + "netmask_v6": null, + "priority": null, + "project_id": null, + "rxtx_base": null, + "share_address": true, + "updated_at": null, + "vlan": null, + "vpn_private_address": null, + "vpn_public_address": null, + "vpn_public_port": null + } +} \ No newline at end of file diff --git a/doc/api_samples/os-extended-networks/network-create-resp.xml b/doc/api_samples/os-extended-networks/network-create-resp.xml new file mode 100644 index 0000000000..9f16171ed7 --- /dev/null +++ b/doc/api_samples/os-extended-networks/network-create-resp.xml @@ -0,0 +1,35 @@ + + + None + None + 10.20.105.2 + None + True + None + a931ead3-4c5c-4b85-a90e-b248ffa71134 + None + None + 10.20.105.1 + None + + None + None + None + False + None + 10.20.105.255 + 255.255.255.0 + None + 10.20.105.0/24 + None + None + False + None + None + None + 9000 + None + None + 10.20.105.2 + None + \ No newline at end of file diff --git a/doc/api_samples/os-extended-networks/network-show-resp.json b/doc/api_samples/os-extended-networks/network-show-resp.json new file mode 100644 index 0000000000..9741395c63 --- /dev/null +++ b/doc/api_samples/os-extended-networks/network-show-resp.json @@ -0,0 +1,36 @@ +{ + "network": { + "bridge": "br100", + "bridge_interface": "eth0", + "broadcast": "10.0.0.7", + "cidr": "10.0.0.0/29", + "cidr_v6": null, + "created_at": "2011-08-15T06:19:19.387525", + "deleted": false, + "deleted_at": null, + "dhcp_server": "10.0.0.1", + "dhcp_start": "10.0.0.3", + "dns1": null, + "dns2": null, + "enable_dhcp": true, + "gateway": "10.0.0.1", + "gateway_v6": null, + "host": "nsokolov-desktop", + "id": "20c8acc0-f747-4d71-a389-46d078ebf047", + "injected": false, + "label": "mynet_0", + "mtu": null, + "multi_host": false, + "netmask": "255.255.255.248", + "netmask_v6": null, + "priority": null, + "project_id": "1234", + "rxtx_base": null, + "share_address": false, + "updated_at": "2011-08-16T09:26:13.048257", + "vlan": 100, + "vpn_private_address": "10.0.0.2", + "vpn_public_address": "127.0.0.1", + "vpn_public_port": 1000 + } +} \ No newline at end of file diff --git a/doc/api_samples/os-extended-networks/network-show-resp.xml b/doc/api_samples/os-extended-networks/network-show-resp.xml new file mode 100644 index 0000000000..2f3176fbc3 --- /dev/null +++ b/doc/api_samples/os-extended-networks/network-show-resp.xml @@ -0,0 +1,35 @@ + + + br100 + 1000 + 10.0.0.3 + eth0 + False + 2011-08-16 09:26:13.048257 + 20c8acc0-f747-4d71-a389-46d078ebf047 + None + None + 10.0.0.1 + None + + None + 1234 + 10.0.0.2 + False + 100 + 10.0.0.7 + 255.255.255.248 + False + 10.0.0.0/29 + 127.0.0.1 + False + True + None + 2011-08-15 06:19:19.387525 + nsokolov-desktop + None + None + None + 10.0.0.1 + None + \ No newline at end of file diff --git a/doc/api_samples/os-extended-networks/networks-list-resp.json b/doc/api_samples/os-extended-networks/networks-list-resp.json new file mode 100644 index 0000000000..49bdad5826 --- /dev/null +++ b/doc/api_samples/os-extended-networks/networks-list-resp.json @@ -0,0 +1,72 @@ +{ + "networks": [ + { + "bridge": "br100", + "bridge_interface": "eth0", + "broadcast": "10.0.0.7", + "cidr": "10.0.0.0/29", + "cidr_v6": null, + "created_at": "2011-08-15T06:19:19.387525", + "deleted": false, + "deleted_at": null, + "dhcp_server": "10.0.0.1", + "dhcp_start": "10.0.0.3", + "dns1": null, + "dns2": null, + "enable_dhcp": true, + "gateway": "10.0.0.1", + "gateway_v6": null, + "host": "nsokolov-desktop", + "id": "20c8acc0-f747-4d71-a389-46d078ebf047", + "injected": false, + "label": "mynet_0", + "mtu": null, + "multi_host": false, + "netmask": "255.255.255.248", + "netmask_v6": null, + "priority": null, + "project_id": "1234", + "rxtx_base": null, + "share_address": false, + "updated_at": "2011-08-16T09:26:13.048257", + "vlan": 100, + "vpn_private_address": "10.0.0.2", + "vpn_public_address": "127.0.0.1", + "vpn_public_port": 1000 + }, + { + "bridge": "br101", + "bridge_interface": "eth0", + "broadcast": "10.0.0.15", + "cidr": "10.0.0.10/29", + "cidr_v6": null, + "created_at": "2011-08-15T06:19:19.885495", + "deleted": false, + "deleted_at": null, + "dhcp_server": "10.0.0.9", + "dhcp_start": "10.0.0.11", + "dns1": null, + "dns2": null, + "enable_dhcp": true, + "gateway": "10.0.0.9", + "gateway_v6": null, + "host": null, + "id": "20c8acc0-f747-4d71-a389-46d078ebf000", + "injected": false, + "label": "mynet_1", + "mtu": null, + "multi_host": false, + "netmask": "255.255.255.248", + "netmask_v6": null, + "priority": null, + "project_id": null, + "rxtx_base": null, + "share_address": false, + "updated_at": null, + "vlan": 101, + "vpn_private_address": "10.0.0.10", + "vpn_public_address": null, + "vpn_public_port": 1001 + } + ] +} \ No newline at end of file diff --git a/doc/api_samples/os-extended-networks/networks-list-resp.xml b/doc/api_samples/os-extended-networks/networks-list-resp.xml new file mode 100644 index 0000000000..b3b6e8885f --- /dev/null +++ b/doc/api_samples/os-extended-networks/networks-list-resp.xml @@ -0,0 +1,71 @@ + + + + br100 + 1000 + 10.0.0.3 + eth0 + False + 2011-08-16 09:26:13.048257 + 20c8acc0-f747-4d71-a389-46d078ebf047 + None + None + 10.0.0.1 + None + + None + 1234 + 10.0.0.2 + False + 100 + 10.0.0.7 + 255.255.255.248 + False + 10.0.0.0/29 + 127.0.0.1 + False + True + None + 2011-08-15 06:19:19.387525 + nsokolov-desktop + None + None + None + 10.0.0.1 + None + + + br101 + 1001 + 10.0.0.11 + eth0 + False + None + 20c8acc0-f747-4d71-a389-46d078ebf000 + None + None + 10.0.0.9 + None + + None + None + 10.0.0.10 + False + 101 + 10.0.0.15 + 255.255.255.248 + False + 10.0.0.10/29 + None + False + True + None + 2011-08-15 06:19:19.885495 + None + None + None + None + 10.0.0.9 + None + + \ No newline at end of file diff --git a/nova/api/openstack/compute/contrib/extended_networks.py b/nova/api/openstack/compute/contrib/extended_networks.py new file mode 100644 index 0000000000..f5021a48dc --- /dev/null +++ b/nova/api/openstack/compute/contrib/extended_networks.py @@ -0,0 +1,26 @@ +# Copyright 2014 Nebula, Inc. +# All Rights Reserved. +# +# 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 nova.api.openstack import extensions + + +class Extended_networks(extensions.ExtensionDescriptor): + """Adds additional fields to networks.""" + + name = "ExtendedNetworks" + alias = "os-extended-networks" + namespace = ("http://docs.openstack.org/compute/ext/extended_networks" + "/api/v2") + updated = "2014-05-09T00:00:00Z" diff --git a/nova/api/openstack/compute/contrib/os_networks.py b/nova/api/openstack/compute/contrib/os_networks.py index 2cbb46ff4e..cbb30e68ea 100644 --- a/nova/api/openstack/compute/contrib/os_networks.py +++ b/nova/api/openstack/compute/contrib/os_networks.py @@ -30,9 +30,10 @@ LOG = logging.getLogger(__name__) authorize = extensions.extension_authorizer('compute', 'networks') authorize_view = extensions.extension_authorizer('compute', 'networks:view') +extended_fields = ('mtu', 'dhcp_server', 'enable_dhcp', 'share_address') -def network_dict(context, network): +def network_dict(context, network, extended): fields = ('id', 'cidr', 'netmask', 'gateway', 'broadcast', 'dns1', 'dns2', 'cidr_v6', 'gateway_v6', 'label', 'netmask_v6') admin_fields = ('created_at', 'updated_at', 'deleted_at', 'deleted', @@ -46,6 +47,8 @@ def network_dict(context, network): # are only visible if they are an admin. if context.is_admin: fields += admin_fields + if extended: + fields += extended_fields result = dict((field, network.get(field)) for field in fields) uuid = network.get('uuid') if uuid: @@ -57,14 +60,19 @@ def network_dict(context, network): class NetworkController(wsgi.Controller): - def __init__(self, network_api=None): + def __init__(self, network_api=None, ext_mgr=None): self.network_api = network_api or network.API() + if ext_mgr: + self.extended = ext_mgr.is_loaded('os-extended-networks') + else: + self.extended = False def index(self, req): context = req.environ['nova.context'] authorize_view(context) networks = self.network_api.get_all(context) - result = [network_dict(context, net_ref) for net_ref in networks] + result = [network_dict(context, net_ref, self.extended) + for net_ref in networks] return {'networks': result} @wsgi.action("disassociate") @@ -93,7 +101,7 @@ class NetworkController(wsgi.Controller): except exception.NetworkNotFound: msg = _("Network not found") raise exc.HTTPNotFound(explanation=msg) - return {'network': network_dict(context, network)} + return {'network': network_dict(context, network, self.extended)} def delete(self, req, id): context = req.environ['nova.context'] @@ -113,7 +121,7 @@ class NetworkController(wsgi.Controller): authorize(context) def bad(e): - return exc.HTTPUnprocessableEntity(explanation=e) + return exc.HTTPBadRequest(explanation=e) if not (body and body.get("network")): raise bad(_("Missing network in body")) @@ -126,13 +134,31 @@ class NetworkController(wsgi.Controller): if not cidr: raise bad(_("Network cidr or cidr_v6 is required")) + if params.get("project_id") == "": + params["project_id"] = None + LOG.debug("Creating network with label %s", params["label"]) - params["num_networks"] = 1 - params["network_size"] = netaddr.IPNetwork(cidr).size + try: + params["num_networks"] = 1 + try: + params["network_size"] = netaddr.IPNetwork(cidr).size + except netaddr.AddrFormatError: + raise exception.InvalidCidr(cidr=cidr) + if not self.extended: + create_params = ('allowed_start', 'allowed_end') + for field in extended_fields + create_params: + if field in params: + del params[field] - network = self.network_api.create(context, **params)[0] - return {"network": network_dict(context, network)} + network = self.network_api.create(context, **params)[0] + except exception.NovaException as ex: + if ex.code == 400: + raise bad(ex.format_message()) + elif ex.code == 409: + raise exc.HTTPConflict(explanation=ex.format_message()) + raise + return {"network": network_dict(context, network, self.extended)} def add(self, req, body): context = req.environ['nova.context'] @@ -177,7 +203,7 @@ class Os_networks(extensions.ExtensionDescriptor): collection_actions = {'add': 'POST'} res = extensions.ResourceExtension( 'os-networks', - NetworkController(), + NetworkController(ext_mgr=self.ext_mgr), member_actions=member_actions, collection_actions=collection_actions) return [res] diff --git a/nova/exception.py b/nova/exception.py index d3677ac9af..1a1923dbca 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -590,32 +590,27 @@ class NetworkInUse(NovaException): msg_fmt = _("Network %(network_id)s is still in use.") -class InvalidNetworkParam(Invalid): - # NOTE(vish) base class for network create param errors - code = 422 - - -class NetworkNotCreated(InvalidNetworkParam): +class NetworkNotCreated(Invalid): msg_fmt = _("%(req)s is required to create a network.") -class LabelTooLong(InvalidNetworkParam): +class LabelTooLong(Invalid): msg_fmt = _("Maximum allowed length for 'label' is 255.") -class InvalidIntValue(InvalidNetworkParam): +class InvalidIntValue(Invalid): msg_fmt = _("%(key)s must be an integer.") -class InvalidCidr(InvalidNetworkParam): +class InvalidCidr(Invalid): msg_fmt = _("%(cidr)s is not a valid ip network.") -class InvalidAddress(InvalidNetworkParam): +class InvalidAddress(Invalid): msg_fmt = _("%(address)s is not a valid ip address.") -class AddressOutOfRange(InvalidNetworkParam): +class AddressOutOfRange(Invalid): msg_fmt = _("%(address)s is not within %(cidr)s.") diff --git a/nova/tests/api/openstack/compute/contrib/test_networks.py b/nova/tests/api/openstack/compute/contrib/test_networks.py index 48fe473217..5b9a8a1a2d 100644 --- a/nova/tests/api/openstack/compute/contrib/test_networks.py +++ b/nova/tests/api/openstack/compute/contrib/test_networks.py @@ -27,8 +27,11 @@ import webob from nova.api.openstack.compute.contrib import networks_associate from nova.api.openstack.compute.contrib import os_networks as networks from nova.api.openstack.compute.contrib import os_tenant_networks as tnet +from nova.api.openstack import extensions import nova.context from nova import exception +from nova.network import manager +from nova import objects from nova import test from nova.tests.api.openstack import fakes import nova.utils @@ -52,6 +55,8 @@ FAKE_NETWORKS = [ 'dns1': None, 'dns2': None, 'host': 'nsokolov-desktop', 'gateway_v6': None, 'netmask_v6': None, 'priority': None, 'created_at': datetime.datetime(2011, 8, 15, 6, 19, 19, 387525), + 'mtu': None, 'dhcp_server': '10.0.0.1', 'enable_dhcp': True, + 'share_address': False, }, { 'bridge': 'br101', 'vpn_public_port': 1001, @@ -67,6 +72,8 @@ FAKE_NETWORKS = [ 'multi_host': False, 'dns1': None, 'dns2': None, 'host': None, 'gateway_v6': None, 'netmask_v6': None, 'priority': None, 'created_at': datetime.datetime(2011, 8, 15, 6, 19, 19, 885495), + 'mtu': None, 'dhcp_server': '10.0.0.9', 'enable_dhcp': True, + 'share_address': False, }, ] @@ -198,13 +205,83 @@ class FakeNetworkAPI(object): return new_networks +# NOTE(vish): tests that network create Exceptions actually return +# the proper error responses +class NetworkCreateExceptionsTest(test.TestCase): + + def setUp(self): + super(NetworkCreateExceptionsTest, self).setUp() + ext_mgr = extensions.ExtensionManager() + ext_mgr.extensions = {'os-extended-networks': 'fake'} + + class PassthroughAPI(): + def __init__(self): + self.network_manager = manager.FlatDHCPManager() + + def create(self, *args, **kwargs): + return self.network_manager.create_networks(*args, **kwargs) + + self.controller = networks.NetworkController( + PassthroughAPI(), ext_mgr) + fakes.stub_out_networking(self.stubs) + fakes.stub_out_rate_limiting(self.stubs) + + def test_network_create_bad_vlan(self): + req = fakes.HTTPRequest.blank('/v2/1234/os-networks') + net = copy.deepcopy(NEW_NETWORK) + net['network']['vlan_start'] = 'foo' + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.create, req, net) + + def test_network_create_no_cidr(self): + req = fakes.HTTPRequest.blank('/v2/1234/os-networks') + net = copy.deepcopy(NEW_NETWORK) + net['network']['cidr'] = '' + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.create, req, net) + + def test_network_create_invalid_fixed_cidr(self): + req = fakes.HTTPRequest.blank('/v2/1234/os-networks') + net = copy.deepcopy(NEW_NETWORK) + net['network']['fixed_cidr'] = 'foo' + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.create, req, net) + + def test_network_create_invalid_start(self): + req = fakes.HTTPRequest.blank('/v2/1234/os-networks') + net = copy.deepcopy(NEW_NETWORK) + net['network']['allowed_start'] = 'foo' + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.create, req, net) + + def test_network_create_cidr_conflict(self): + + @staticmethod + def get_all(context): + ret = objects.NetworkList(context=context, objects=[]) + net = objects.Network(cidr='10.0.0.0/23') + ret.objects.append(net) + return ret + + self.stubs.Set(objects.NetworkList, 'get_all', get_all) + + req = fakes.HTTPRequest.blank('/v2/1234/os-networks') + net = copy.deepcopy(NEW_NETWORK) + net['network']['cidr'] = '10.0.0.0/24' + self.assertRaises(webob.exc.HTTPConflict, + self.controller.create, req, net) + + class NetworksTest(test.NoDBTestCase): def setUp(self): super(NetworksTest, self).setUp() self.fake_network_api = FakeNetworkAPI() + ext_mgr = extensions.ExtensionManager() + ext_mgr.extensions = {'os-extended-networks': 'fake'} self.controller = networks.NetworkController( - self.fake_network_api) + self.fake_network_api, + ext_mgr) self.associate_controller = networks_associate\ .NetworkAssociateActionController(self.fake_network_api) fakes.stub_out_networking(self.stubs) @@ -313,13 +390,6 @@ class NetworksTest(test.NoDBTestCase): self.assertRaises(webob.exc.HTTPConflict, self.controller.delete, req, -1) - def test_network_add_vlan_disabled(self): - self.fake_network_api.disable_vlan() - uuid = FAKE_NETWORKS[1]['uuid'] - req = fakes.HTTPRequest.blank('/v2/1234/os-networks/add') - self.assertRaises(webob.exc.HTTPNotImplemented, - self.controller.add, req, {'id': uuid}) - def test_network_add(self): uuid = FAKE_NETWORKS[1]['uuid'] req = fakes.HTTPRequest.blank('/v2/1234/os-networks/add') @@ -359,6 +429,29 @@ class NetworksTest(test.NoDBTestCase): self.assertEqual(res_dict['network']['cidr'], large_network['network']['cidr']) + def test_network_create_not_extended(self): + self.stubs.Set(self.controller, 'extended', False) + + # NOTE(vish): Verify that new params are not passed through if + # extension is not enabled. + def no_mtu(*args, **kwargs): + if 'mtu' in kwargs: + raise test.TestingException("mtu should not pass through") + return [{}] + + self.stubs.Set(self.controller.network_api, 'create', no_mtu) + req = fakes.HTTPRequest.blank('/v2/1234/os-networks') + net = copy.deepcopy(NEW_NETWORK) + net['network']['mtu'] = 9000 + self.controller.create(req, net) + + def test_network_create_bad_cidr(self): + req = fakes.HTTPRequest.blank('/v2/1234/os-networks') + net = copy.deepcopy(NEW_NETWORK) + net['network']['cidr'] = '128.0.0.0/900' + self.assertRaises(webob.exc.HTTPBadRequest, + self.controller.create, req, net) + def test_network_neutron_associate_not_implemented(self): uuid = FAKE_NETWORKS[1]['uuid'] self.flags(network_api_class='nova.network.neutronv2.api.API') diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl index c7e4783743..6830422bff 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl @@ -488,6 +488,14 @@ "namespace": "http://docs.openstack.org/compute/ext/quota-classes-sets/api/v1.1", "updated": "%(isotime)s" }, + { + "alias": "os-extended-networks", + "description": "%(text)s", + "links": [], + "name": "ExtendedNetworks", + "namespace": "http://docs.openstack.org/compute/ext/extended_networks/api/v2", + "updated": "%(isotime)s" + }, { "alias": "os-extended-quotas", "description": "%(text)s", diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl index ef98730514..9cacb12676 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl @@ -174,6 +174,9 @@ %(text)s + + %(text)s + %(text)s diff --git a/nova/tests/integrated/api_samples/os-extended-networks/network-create-req.json.tpl b/nova/tests/integrated/api_samples/os-extended-networks/network-create-req.json.tpl new file mode 100644 index 0000000000..18515bd6c4 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-networks/network-create-req.json.tpl @@ -0,0 +1,12 @@ +{ + "network": { + "label": "new net 111", + "cidr": "10.20.105.0/24", + "mtu": 9000, + "dhcp_server": "10.20.105.2", + "enable_dhcp": false, + "share_address": true, + "allowed_start": "10.20.105.10", + "allowed_end": "10.20.105.200" + } +} diff --git a/nova/tests/integrated/api_samples/os-extended-networks/network-create-req.xml.tpl b/nova/tests/integrated/api_samples/os-extended-networks/network-create-req.xml.tpl new file mode 100644 index 0000000000..3cc79bd837 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-networks/network-create-req.xml.tpl @@ -0,0 +1,10 @@ + + + 10.20.105.0/24 + 9000 + 10.20.105.2 + False + True + 10.20.105.10 + 10.20.105.200 + diff --git a/nova/tests/integrated/api_samples/os-extended-networks/network-create-resp.json.tpl b/nova/tests/integrated/api_samples/os-extended-networks/network-create-resp.json.tpl new file mode 100644 index 0000000000..5cf155b13f --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-networks/network-create-resp.json.tpl @@ -0,0 +1,36 @@ +{ + "network": { + "bridge": null, + "vpn_public_port": null, + "dhcp_start": "%(ip)s", + "bridge_interface": null, + "updated_at": null, + "id": "%(id)s", + "cidr_v6": null, + "deleted_at": null, + "gateway": "%(ip)s", + "rxtx_base": null, + "label": "new net 111", + "priority": null, + "project_id": null, + "vpn_private_address": null, + "deleted": null, + "vlan": null, + "broadcast": "%(ip)s", + "netmask": "%(ip)s", + "injected": null, + "cidr": "10.20.105.0/24", + "vpn_public_address": null, + "multi_host": null, + "dns2": null, + "created_at": null, + "host": null, + "gateway_v6": null, + "netmask_v6": null, + "dns1": null, + "mtu": 9000, + "dhcp_server": "10.20.105.2", + "enable_dhcp": false, + "share_address": true + } +} diff --git a/nova/tests/integrated/api_samples/os-extended-networks/network-create-resp.xml.tpl b/nova/tests/integrated/api_samples/os-extended-networks/network-create-resp.xml.tpl new file mode 100644 index 0000000000..3a757c5f2f --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-networks/network-create-resp.xml.tpl @@ -0,0 +1,34 @@ + + None + None + %(ip)s + None + None + %(id)s + None + None + %(ip)s + None + + None + None + None + False + None + %(ip)s + %(ip)s + None + 10.20.105.0/24 + None + None + None + None + None + None + None + None + 9000 + 10.20.105.2 + False + True + diff --git a/nova/tests/integrated/api_samples/os-extended-networks/network-show-resp.json.tpl b/nova/tests/integrated/api_samples/os-extended-networks/network-show-resp.json.tpl new file mode 100644 index 0000000000..ac75fe7fb1 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-networks/network-show-resp.json.tpl @@ -0,0 +1,37 @@ +{ + "network": + { + "bridge": "br100", + "bridge_interface": "eth0", + "broadcast": "%(ip)s", + "cidr": "10.0.0.0/29", + "cidr_v6": null, + "created_at": "%(strtime)s", + "deleted": false, + "deleted_at": null, + "dhcp_start": "%(ip)s", + "dns1": null, + "dns2": null, + "gateway": "%(ip)s", + "gateway_v6": null, + "host": "nsokolov-desktop", + "id": "%(id)s", + "injected": false, + "label": "mynet_0", + "multi_host": false, + "netmask": "%(ip)s", + "netmask_v6": null, + "priority": null, + "project_id": "1234", + "rxtx_base": null, + "updated_at": "%(strtime)s", + "vlan": 100, + "vpn_private_address": "%(ip)s", + "vpn_public_address": "%(ip)s", + "vpn_public_port": 1000, + "mtu": null, + "dhcp_server": "%(ip)s", + "enable_dhcp": true, + "share_address": false + } +} diff --git a/nova/tests/integrated/api_samples/os-extended-networks/network-show-resp.xml.tpl b/nova/tests/integrated/api_samples/os-extended-networks/network-show-resp.xml.tpl new file mode 100644 index 0000000000..3139ca88a8 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-networks/network-show-resp.xml.tpl @@ -0,0 +1,35 @@ + + + br100 + 1000 + %(ip)s + eth0 + %(xmltime)s + %(id)s + None + None + %(ip)s + None + + None + 1234 + %(ip)s + False + 100 + %(ip)s + %(ip)s + False + 10.0.0.0/29 + %(ip)s + False + None + %(xmltime)s + nsokolov-desktop + None + None + None + None + %(ip)s + True + False + diff --git a/nova/tests/integrated/api_samples/os-extended-networks/networks-list-resp.json.tpl b/nova/tests/integrated/api_samples/os-extended-networks/networks-list-resp.json.tpl new file mode 100644 index 0000000000..ccdd586a0f --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-networks/networks-list-resp.json.tpl @@ -0,0 +1,72 @@ +{ + "networks": [ + { + "bridge": "br100", + "bridge_interface": "eth0", + "broadcast": "%(ip)s", + "cidr": "10.0.0.0/29", + "cidr_v6": null, + "created_at": "%(strtime)s", + "deleted": false, + "deleted_at": null, + "dhcp_start": "%(ip)s", + "dns1": null, + "dns2": null, + "gateway": "%(ip)s", + "gateway_v6": null, + "host": "nsokolov-desktop", + "id": "%(id)s", + "injected": false, + "label": "mynet_0", + "multi_host": false, + "netmask": "%(ip)s", + "netmask_v6": null, + "priority": null, + "project_id": "1234", + "rxtx_base": null, + "updated_at": "%(strtime)s", + "vlan": 100, + "vpn_private_address": "%(ip)s", + "vpn_public_address": "%(ip)s", + "vpn_public_port": 1000, + "mtu": null, + "dhcp_server": "%(ip)s", + "enable_dhcp": true, + "share_address": false + }, + { + "bridge": "br101", + "bridge_interface": "eth0", + "broadcast": "%(ip)s", + "cidr": "10.0.0.10/29", + "cidr_v6": null, + "created_at": "%(strtime)s", + "deleted": false, + "deleted_at": null, + "dhcp_start": "%(ip)s", + "dns1": null, + "dns2": null, + "gateway": "%(ip)s", + "gateway_v6": null, + "host": null, + "id": "%(id)s", + "injected": false, + "label": "mynet_1", + "multi_host": false, + "netmask": "%(ip)s", + "netmask_v6": null, + "priority": null, + "project_id": null, + "rxtx_base": null, + "updated_at": null, + "vlan": 101, + "vpn_private_address": "%(ip)s", + "vpn_public_address": null, + "vpn_public_port": 1001, + "mtu": null, + "dhcp_server": "%(ip)s", + "enable_dhcp": true, + "share_address": false + } + ] +} diff --git a/nova/tests/integrated/api_samples/os-extended-networks/networks-list-resp.xml.tpl b/nova/tests/integrated/api_samples/os-extended-networks/networks-list-resp.xml.tpl new file mode 100644 index 0000000000..0b7f456402 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-networks/networks-list-resp.xml.tpl @@ -0,0 +1,71 @@ + + + + br100 + 1000 + %(ip)s + eth0 + %(xmltime)s + %(id)s + None + None + %(ip)s + None + + None + 1234 + %(ip)s + False + 100 + %(ip)s + %(ip)s + False + 10.0.0.0/29 + %(ip)s + False + None + %(xmltime)s + nsokolov-desktop + None + None + None + None + %(ip)s + True + False + + + br101 + 1001 + %(ip)s + eth0 + None + %(id)s + None + None + %(ip)s + None + + None + None + %(ip)s + False + 101 + %(ip)s + %(ip)s + False + 10.0.0.10/29 + None + False + None + %(xmltime)s + None + None + None + None + None + %(ip)s + True + False + + diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py index 4707a74889..0ccb3b0823 100644 --- a/nova/tests/integrated/test_api_samples.py +++ b/nova/tests/integrated/test_api_samples.py @@ -2669,6 +2669,50 @@ class NetworksXmlTests(NetworksJsonTests): ctype = 'xml' +class ExtendedNetworksJsonTests(ApiSampleTestBaseV2): + extends_name = ("nova.api.openstack.compute.contrib." + "os_networks.Os_networks") + extension_name = ("nova.api.openstack.compute.contrib." + "extended_networks.Extended_networks") + + def setUp(self): + super(ExtendedNetworksJsonTests, self).setUp() + fake_network_api = test_networks.FakeNetworkAPI() + self.stubs.Set(network_api.API, "get_all", + fake_network_api.get_all) + self.stubs.Set(network_api.API, "get", + fake_network_api.get) + self.stubs.Set(network_api.API, "associate", + fake_network_api.associate) + self.stubs.Set(network_api.API, "delete", + fake_network_api.delete) + self.stubs.Set(network_api.API, "create", + fake_network_api.create) + self.stubs.Set(network_api.API, "add_network_to_project", + fake_network_api.add_network_to_project) + + def test_network_list(self): + response = self._do_get('os-networks') + subs = self._get_regexes() + self._verify_response('networks-list-resp', subs, response, 200) + + def test_network_show(self): + uuid = test_networks.FAKE_NETWORKS[0]['uuid'] + response = self._do_get('os-networks/%s' % uuid) + subs = self._get_regexes() + self._verify_response('network-show-resp', subs, response, 200) + + def test_network_create(self): + response = self._do_post("os-networks", + 'network-create-req', {}) + subs = self._get_regexes() + self._verify_response('network-create-resp', subs, response, 200) + + +class ExtendedNetworksXmlTests(ExtendedNetworksJsonTests): + ctype = 'xml' + + class NetworksAssociateJsonTests(ApiSampleTestBaseV2): extension_name = ("nova.api.openstack.compute.contrib" ".networks_associate.Networks_associate")