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")