Add api extension for new network fields.

This uses the existing api extension to implement the actual control
of the fields, but the check is based on a new dummy extension
called os-extended-networks.

Api sample tests added for new extension.

DocImpact: Adds an extension that enables extra fields for network
create. The new fields are:
  mtu: int (default flag) if set, nova sets the mtu on bridge. This
       allows network_device_mtu flag to be set per network.
  dhcp_server: ip (default == gateway) if different from gateway, sets
                nova to assume gateway is external.
  enable_dhcp: bool (default true) false will disable dhcp on network.
  share_address: bool (default flag) if specifed, network will have
                 the same dhcp ip on every host. This allows
                 share_dhcp_address flag to be set per network.
  allowed_start: ip if specified, reserves all ips before allowed_start.
  allowed_end: ip if specified, reserves all ips after allowed_end.

Partially-implements blueprint better-support-for-multiple-networks

Change-Id: I577fe5f6560be50106f345a42a826e97d5e7d64c
This commit is contained in:
Vishvananda Ishaya 2014-05-09 13:04:46 -07:00
parent 7d61239dfe
commit 71fabdc8dc
25 changed files with 849 additions and 29 deletions

View File

@ -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 ",

View File

@ -129,6 +129,9 @@
<extension alias="os-extended-hypervisors" updated="2014-01-04T00:00:00Z" namespace="http://docs.openstack.org/compute/ext/extended_hypervisors/api/v1.1" name="ExtendedHypervisors">
<description>Extended hypervisors support.</description>
</extension>
<extension alias="os-extended-networks" updated="2014-05-09T00:00:00Z" namespace="http://docs.openstack.org/compute/ext/extended_networks/api/v2" name="ExtendedNetworks">
<description>Adds additional fields to networks</description>
</extension>
<extension alias="os-extended-quotas" updated="2013-06-09T00:00:00Z" namespace="http://docs.openstack.org/compute/ext/extended_quotas/api/v1.1" name="ExtendedQuotas">
<description>Adds ability for admins to delete quota
and optionally force the update Quota command.

View File

@ -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"
}
}

View File

@ -0,0 +1,10 @@
<network>
<label>new net 111</label>
<cidr>10.20.105.0/24</cidr>
<mtu>9000</mtu>
<dhcp_server>10.20.105.2</dhcp_server>
<enable_dhcp>False</enable_dhcp>
<share_address>True</share_address>
<allowed_start>10.20.105.10</allowed_start>
<allowed_end>10.20.105.200</allowed_end>
</network>

View File

@ -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
}
}

View File

@ -0,0 +1,35 @@
<?xml version='1.0' encoding='UTF-8'?>
<network>
<bridge>None</bridge>
<vpn_public_port>None</vpn_public_port>
<dhcp_start>10.20.105.2</dhcp_start>
<bridge_interface>None</bridge_interface>
<share_address>True</share_address>
<updated_at>None</updated_at>
<id>a931ead3-4c5c-4b85-a90e-b248ffa71134</id>
<cidr_v6>None</cidr_v6>
<deleted_at>None</deleted_at>
<gateway>10.20.105.1</gateway>
<rxtx_base>None</rxtx_base>
<label>new net 111</label>
<priority>None</priority>
<project_id>None</project_id>
<vpn_private_address>None</vpn_private_address>
<deleted>False</deleted>
<vlan>None</vlan>
<broadcast>10.20.105.255</broadcast>
<netmask>255.255.255.0</netmask>
<injected>None</injected>
<cidr>10.20.105.0/24</cidr>
<vpn_public_address>None</vpn_public_address>
<multi_host>None</multi_host>
<enable_dhcp>False</enable_dhcp>
<dns2>None</dns2>
<created_at>None</created_at>
<host>None</host>
<mtu>9000</mtu>
<gateway_v6>None</gateway_v6>
<netmask_v6>None</netmask_v6>
<dhcp_server>10.20.105.2</dhcp_server>
<dns1>None</dns1>
</network>

View File

@ -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
}
}

View File

@ -0,0 +1,35 @@
<?xml version='1.0' encoding='UTF-8'?>
<network>
<bridge>br100</bridge>
<vpn_public_port>1000</vpn_public_port>
<dhcp_start>10.0.0.3</dhcp_start>
<bridge_interface>eth0</bridge_interface>
<share_address>False</share_address>
<updated_at>2011-08-16 09:26:13.048257</updated_at>
<id>20c8acc0-f747-4d71-a389-46d078ebf047</id>
<cidr_v6>None</cidr_v6>
<deleted_at>None</deleted_at>
<gateway>10.0.0.1</gateway>
<rxtx_base>None</rxtx_base>
<label>mynet_0</label>
<priority>None</priority>
<project_id>1234</project_id>
<vpn_private_address>10.0.0.2</vpn_private_address>
<deleted>False</deleted>
<vlan>100</vlan>
<broadcast>10.0.0.7</broadcast>
<netmask>255.255.255.248</netmask>
<injected>False</injected>
<cidr>10.0.0.0/29</cidr>
<vpn_public_address>127.0.0.1</vpn_public_address>
<multi_host>False</multi_host>
<enable_dhcp>True</enable_dhcp>
<dns2>None</dns2>
<created_at>2011-08-15 06:19:19.387525</created_at>
<host>nsokolov-desktop</host>
<mtu>None</mtu>
<gateway_v6>None</gateway_v6>
<netmask_v6>None</netmask_v6>
<dhcp_server>10.0.0.1</dhcp_server>
<dns1>None</dns1>
</network>

View File

@ -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
}
]
}

View File

@ -0,0 +1,71 @@
<?xml version='1.0' encoding='UTF-8'?>
<networks>
<network>
<bridge>br100</bridge>
<vpn_public_port>1000</vpn_public_port>
<dhcp_start>10.0.0.3</dhcp_start>
<bridge_interface>eth0</bridge_interface>
<share_address>False</share_address>
<updated_at>2011-08-16 09:26:13.048257</updated_at>
<id>20c8acc0-f747-4d71-a389-46d078ebf047</id>
<cidr_v6>None</cidr_v6>
<deleted_at>None</deleted_at>
<gateway>10.0.0.1</gateway>
<rxtx_base>None</rxtx_base>
<label>mynet_0</label>
<priority>None</priority>
<project_id>1234</project_id>
<vpn_private_address>10.0.0.2</vpn_private_address>
<deleted>False</deleted>
<vlan>100</vlan>
<broadcast>10.0.0.7</broadcast>
<netmask>255.255.255.248</netmask>
<injected>False</injected>
<cidr>10.0.0.0/29</cidr>
<vpn_public_address>127.0.0.1</vpn_public_address>
<multi_host>False</multi_host>
<enable_dhcp>True</enable_dhcp>
<dns2>None</dns2>
<created_at>2011-08-15 06:19:19.387525</created_at>
<host>nsokolov-desktop</host>
<mtu>None</mtu>
<gateway_v6>None</gateway_v6>
<netmask_v6>None</netmask_v6>
<dhcp_server>10.0.0.1</dhcp_server>
<dns1>None</dns1>
</network>
<network>
<bridge>br101</bridge>
<vpn_public_port>1001</vpn_public_port>
<dhcp_start>10.0.0.11</dhcp_start>
<bridge_interface>eth0</bridge_interface>
<share_address>False</share_address>
<updated_at>None</updated_at>
<id>20c8acc0-f747-4d71-a389-46d078ebf000</id>
<cidr_v6>None</cidr_v6>
<deleted_at>None</deleted_at>
<gateway>10.0.0.9</gateway>
<rxtx_base>None</rxtx_base>
<label>mynet_1</label>
<priority>None</priority>
<project_id>None</project_id>
<vpn_private_address>10.0.0.10</vpn_private_address>
<deleted>False</deleted>
<vlan>101</vlan>
<broadcast>10.0.0.15</broadcast>
<netmask>255.255.255.248</netmask>
<injected>False</injected>
<cidr>10.0.0.10/29</cidr>
<vpn_public_address>None</vpn_public_address>
<multi_host>False</multi_host>
<enable_dhcp>True</enable_dhcp>
<dns2>None</dns2>
<created_at>2011-08-15 06:19:19.885495</created_at>
<host>None</host>
<mtu>None</mtu>
<gateway_v6>None</gateway_v6>
<netmask_v6>None</netmask_v6>
<dhcp_server>10.0.0.9</dhcp_server>
<dns1>None</dns1>
</network>
</networks>

View File

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

View File

@ -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]

View File

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

View File

@ -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')

View File

@ -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",

View File

@ -174,6 +174,9 @@
<extension alias="os-quota-class-sets" updated="%(isotime)s" namespace="http://docs.openstack.org/compute/ext/quota-classes-sets/api/v1.1" name="QuotaClasses">
<description>%(text)s</description>
</extension>
<extension alias="os-extended-networks" updated="%(isotime)s" namespace="http://docs.openstack.org/compute/ext/extended_networks/api/v2" name="ExtendedNetworks">
<description>%(text)s</description>
</extension>
<extension alias="os-extended-quotas" updated="%(isotime)s" namespace="http://docs.openstack.org/compute/ext/extended_quotas/api/v1.1" name="ExtendedQuotas">
<description>%(text)s</description>
</extension>

View File

@ -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"
}
}

View File

@ -0,0 +1,10 @@
<network>
<label>new net 111</label>
<cidr>10.20.105.0/24</cidr>
<mtu>9000</mtu>
<dhcp_server>10.20.105.2</dhcp_server>
<enable_dhcp>False</enable_dhcp>
<share_address>True</share_address>
<allowed_start>10.20.105.10</allowed_start>
<allowed_end>10.20.105.200</allowed_end>
</network>

View File

@ -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
}
}

View File

@ -0,0 +1,34 @@
<network>
<bridge>None</bridge>
<vpn_public_port>None</vpn_public_port>
<dhcp_start>%(ip)s</dhcp_start>
<bridge_interface>None</bridge_interface>
<updated_at>None</updated_at>
<id>%(id)s</id>
<cidr_v6>None</cidr_v6>
<deleted_at>None</deleted_at>
<gateway>%(ip)s</gateway>
<rxtx_base>None</rxtx_base>
<label>new net 111</label>
<priority>None</priority>
<project_id>None</project_id>
<vpn_private_address>None</vpn_private_address>
<deleted>False</deleted>
<vlan>None</vlan>
<broadcast>%(ip)s</broadcast>
<netmask>%(ip)s</netmask>
<injected>None</injected>
<cidr>10.20.105.0/24</cidr>
<vpn_public_address>None</vpn_public_address>
<multi_host>None</multi_host>
<dns2>None</dns2>
<created_at>None</created_at>
<host>None</host>
<gateway_v6>None</gateway_v6>
<netmask_v6>None</netmask_v6>
<dns1>None</dns1>
<mtu>9000</mtu>
<dhcp_server>10.20.105.2</dhcp_server>
<enable_dhcp>False</enable_dhcp>
<share_address>True</share_address>
</network>

View File

@ -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
}
}

View File

@ -0,0 +1,35 @@
<?xml version='1.0' encoding='UTF-8'?>
<network>
<bridge>br100</bridge>
<vpn_public_port>1000</vpn_public_port>
<dhcp_start>%(ip)s</dhcp_start>
<bridge_interface>eth0</bridge_interface>
<updated_at>%(xmltime)s</updated_at>
<id>%(id)s</id>
<cidr_v6>None</cidr_v6>
<deleted_at>None</deleted_at>
<gateway>%(ip)s</gateway>
<rxtx_base>None</rxtx_base>
<label>mynet_0</label>
<priority>None</priority>
<project_id>1234</project_id>
<vpn_private_address>%(ip)s</vpn_private_address>
<deleted>False</deleted>
<vlan>100</vlan>
<broadcast>%(ip)s</broadcast>
<netmask>%(ip)s</netmask>
<injected>False</injected>
<cidr>10.0.0.0/29</cidr>
<vpn_public_address>%(ip)s</vpn_public_address>
<multi_host>False</multi_host>
<dns2>None</dns2>
<created_at>%(xmltime)s</created_at>
<host>nsokolov-desktop</host>
<gateway_v6>None</gateway_v6>
<netmask_v6>None</netmask_v6>
<dns1>None</dns1>
<mtu>None</mtu>
<dhcp_server>%(ip)s</dhcp_server>
<enable_dhcp>True</enable_dhcp>
<share_address>False</share_address>
</network>

View File

@ -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
}
]
}

View File

@ -0,0 +1,71 @@
<?xml version='1.0' encoding='UTF-8'?>
<networks>
<network>
<bridge>br100</bridge>
<vpn_public_port>1000</vpn_public_port>
<dhcp_start>%(ip)s</dhcp_start>
<bridge_interface>eth0</bridge_interface>
<updated_at>%(xmltime)s</updated_at>
<id>%(id)s</id>
<cidr_v6>None</cidr_v6>
<deleted_at>None</deleted_at>
<gateway>%(ip)s</gateway>
<rxtx_base>None</rxtx_base>
<label>mynet_0</label>
<priority>None</priority>
<project_id>1234</project_id>
<vpn_private_address>%(ip)s</vpn_private_address>
<deleted>False</deleted>
<vlan>100</vlan>
<broadcast>%(ip)s</broadcast>
<netmask>%(ip)s</netmask>
<injected>False</injected>
<cidr>10.0.0.0/29</cidr>
<vpn_public_address>%(ip)s</vpn_public_address>
<multi_host>False</multi_host>
<dns2>None</dns2>
<created_at>%(xmltime)s</created_at>
<host>nsokolov-desktop</host>
<gateway_v6>None</gateway_v6>
<netmask_v6>None</netmask_v6>
<dns1>None</dns1>
<mtu>None</mtu>
<dhcp_server>%(ip)s</dhcp_server>
<enable_dhcp>True</enable_dhcp>
<share_address>False</share_address>
</network>
<network>
<bridge>br101</bridge>
<vpn_public_port>1001</vpn_public_port>
<dhcp_start>%(ip)s</dhcp_start>
<bridge_interface>eth0</bridge_interface>
<updated_at>None</updated_at>
<id>%(id)s</id>
<cidr_v6>None</cidr_v6>
<deleted_at>None</deleted_at>
<gateway>%(ip)s</gateway>
<rxtx_base>None</rxtx_base>
<label>mynet_1</label>
<priority>None</priority>
<project_id>None</project_id>
<vpn_private_address>%(ip)s</vpn_private_address>
<deleted>False</deleted>
<vlan>101</vlan>
<broadcast>%(ip)s</broadcast>
<netmask>%(ip)s</netmask>
<injected>False</injected>
<cidr>10.0.0.10/29</cidr>
<vpn_public_address>None</vpn_public_address>
<multi_host>False</multi_host>
<dns2>None</dns2>
<created_at>%(xmltime)s</created_at>
<host>None</host>
<gateway_v6>None</gateway_v6>
<netmask_v6>None</netmask_v6>
<dns1>None</dns1>
<mtu>None</mtu>
<dhcp_server>%(ip)s</dhcp_server>
<enable_dhcp>True</enable_dhcp>
<share_address>False</share_address>
</network>
</networks>

View File

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