summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorAlessio Ababilov <aababilov@griddynamics.com>2012-07-16 14:07:29 +0300
committerAlessio Ababilov <aababilov@griddynamics.com>2012-08-21 16:10:24 +0300
commite00a398f84562f1a0da69c8c0fd33db538365dc3 (patch)
tree0a2c00928d6c42397b6c8dbbf1b617c92498dc32 /nova
parent0272c063bbc32f1ff39f2baa8ae3f0764723ef73 (diff)
downloadnova-e00a398f84562f1a0da69c8c0fd33db538365dc3.tar.gz
nova-e00a398f84562f1a0da69c8c0fd33db538365dc3.tar.xz
nova-e00a398f84562f1a0da69c8c0fd33db538365dc3.zip
Implement network creation in compute API
Implements blueprint os-api-network-create The ability to create new networks is currently only exposed by the nova-manage CLI. Here we add support for network creation in the os-networks API extension. With the exception of num_networks and network_size, all the parameters supported by 'nova-manage network create' are supported. Only a single network may be created by each API call. To avoid code duplication, the nova-manage code is refactored and moved into NetworkManager so that it can be re-used by the API. DocImpact Change-Id: I682d498ab35ea43b553b64e13e677fe9eeb8e08b
Diffstat (limited to 'nova')
-rw-r--r--nova/api/openstack/compute/contrib/networks.py29
-rw-r--r--nova/network/manager.py90
-rw-r--r--nova/network/quantum/nova_ipam_lib.py2
-rw-r--r--nova/tests/api/openstack/compute/contrib/test_networks.py62
-rw-r--r--nova/tests/fake_flags.py1
-rw-r--r--nova/tests/network/test_linux_net.py1
-rw-r--r--nova/tests/test_nova_manage.py4
7 files changed, 180 insertions, 9 deletions
diff --git a/nova/api/openstack/compute/contrib/networks.py b/nova/api/openstack/compute/contrib/networks.py
index fb1d3d77e..f673bf43a 100644
--- a/nova/api/openstack/compute/contrib/networks.py
+++ b/nova/api/openstack/compute/contrib/networks.py
@@ -16,7 +16,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-
+import netaddr
import webob
from webob import exc
@@ -111,8 +111,31 @@ class NetworkController(object):
raise exc.HTTPNotFound(_("Network not found"))
return exc.HTTPAccepted()
- def create(self, req, id, body=None):
- raise exc.HTTPNotImplemented()
+ def create(self, req, body):
+ context = req.environ['nova.context']
+ authorize(context)
+
+ def bad(e):
+ return exc.HTTPUnprocessableEntity(explanation=e)
+
+ if not (body and body.get("network")):
+ raise bad(_("Missing network in body"))
+
+ params = body["network"]
+ if not params.get("label"):
+ raise bad(_("Network label is required"))
+
+ cidr = params.get("cidr") or params.get("cidr_v6")
+ if not cidr:
+ raise bad(_("Network cidr or cidr_v6 is required"))
+
+ LOG.debug(_("Creating network with label %s") % params["label"])
+
+ params["num_networks"] = 1
+ params["network_size"] = netaddr.IPNetwork(cidr).size
+
+ network = self.network_api.create(context, **params)[0]
+ return {"network": network_dict(context, network)}
def add(self, req, body):
context = req.environ['nova.context']
diff --git a/nova/network/manager.py b/nova/network/manager.py
index c1f3a6418..862fb6f78 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -769,6 +769,8 @@ class NetworkManager(manager.SchedulerDependentManager):
timeout_fixed_ips = True
+ required_create_args = []
+
def __init__(self, network_driver=None, *args, **kwargs):
if not network_driver:
network_driver = FLAGS.network_driver
@@ -1348,10 +1350,86 @@ class NetworkManager(manager.SchedulerDependentManager):
if not fixed_ip['allocated']:
self.db.fixed_ip_disassociate(context, address)
- def create_networks(self, context, label, cidr, multi_host, num_networks,
- network_size, cidr_v6, gateway, gateway_v6, bridge,
- bridge_interface, dns1=None, dns2=None,
+ def create_networks(self, context,
+ label, cidr=None, multi_host=None, num_networks=None,
+ network_size=None, cidr_v6=None,
+ gateway=None, gateway_v6=None, bridge=None,
+ bridge_interface=None, dns1=None, dns2=None,
fixed_cidr=None, **kwargs):
+ arg_names = ("label", "cidr", "multi_host", "num_networks",
+ "network_size", "cidr_v6",
+ "gateway", "gateway_v6", "bridge",
+ "bridge_interface", "dns1", "dns2",
+ "fixed_cidr")
+ for name in arg_names:
+ kwargs[name] = locals()[name]
+ int_args = ("network_size", "num_networks",
+ "vlan_start", "vpn_start")
+ for key in int_args:
+ try:
+ kwargs[key] = int(kwargs[key])
+ except ValueError:
+ raise ValueError(_("%s must be an integer") % key)
+ except KeyError:
+ pass
+
+ # check for certain required inputs
+ label = kwargs["label"]
+ if not label:
+ raise exception.NetworkNotCreated(req="label")
+
+ # Size of "label" column in nova.networks is 255, hence the restriction
+ if len(label) > 255:
+ raise ValueError(_("Maximum allowed length for 'label' is 255."))
+
+ if not (kwargs["cidr"] or kwargs["cidr_v6"]):
+ raise exception.NetworkNotCreated(req="cidr or cidr_v6")
+
+ kwargs["bridge"] = kwargs["bridge"] or FLAGS.flat_network_bridge
+ kwargs["bridge_interface"] = (kwargs["bridge_interface"] or
+ FLAGS.flat_interface)
+
+ for fld in self.required_create_args:
+ if not kwargs[fld]:
+ raise exception.NetworkNotCreated(req=fld)
+
+ num_networks = kwargs["num_networks"] or FLAGS.num_networks
+ network_size = kwargs["network_size"]
+ cidr = kwargs["cidr"]
+ if not network_size and cidr:
+ fixnet = netaddr.IPNetwork(cidr)
+ each_subnet_size = fixnet.size / num_networks
+ if each_subnet_size > FLAGS.network_size:
+ network_size = FLAGS.network_size
+ subnet = 32 - int(math.log(network_size, 2))
+ oversize_msg = _(
+ 'Subnet(s) too large, defaulting to /%s.'
+ ' To override, specify network_size flag.') % subnet
+ LOG.warn(oversize_msg)
+ else:
+ network_size = fixnet.size
+ kwargs["num_networks"] = num_networks
+ kwargs["network_size"] = network_size
+
+ kwargs["multi_host"] = (FLAGS.multi_host
+ if kwargs["multi_host"] is None
+ else
+ utils.bool_from_str(kwargs["multi_host"]))
+ kwargs["vlan_start"] = kwargs.get("vlan_start") or FLAGS.vlan_start
+ kwargs["vpn_start"] = kwargs.get("vpn_start") or FLAGS.vpn_start
+ kwargs["dns1"] = kwargs["dns1"] or FLAGS.flat_network_dns
+ kwargs["network_size"] = kwargs["network_size"] or FLAGS.network_size
+
+ if kwargs["fixed_cidr"]:
+ kwargs["fixed_cidr"] = netaddr.IPNetwork(kwargs["fixed_cidr"])
+
+ return self._do_create_networks(context, **kwargs)
+
+ def _do_create_networks(self, context,
+ label, cidr, multi_host, num_networks,
+ network_size, cidr_v6, gateway, gateway_v6, bridge,
+ bridge_interface, dns1=None, dns2=None,
+ fixed_cidr=None, **kwargs):
"""Create networks based on parameters."""
# NOTE(jkoelker): these are dummy values to make sure iter works
# TODO(tr3buchet): disallow carving up networks
@@ -1719,6 +1797,8 @@ class FlatManager(NetworkManager):
timeout_fixed_ips = False
+ required_create_args = ['bridge']
+
def _allocate_fixed_ips(self, context, instance_id, host, networks,
**kwargs):
"""Calls allocate_fixed_ip once for each network."""
@@ -1793,6 +1873,7 @@ class FlatDHCPManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
SHOULD_CREATE_BRIDGE = True
DHCP = True
+ required_create_args = ['bridge']
def init_host(self):
"""Do any initialization that needs to be run if this is a
@@ -1862,6 +1943,7 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
SHOULD_CREATE_BRIDGE = True
SHOULD_CREATE_VLAN = True
DHCP = True
+ required_create_args = ['bridge_interface']
def init_host(self):
"""Do any initialization that needs to be run if this is a
@@ -1941,6 +2023,8 @@ class VlanManager(RPCAllocateFixedIP, FloatingIP, NetworkManager):
'%(num_networks)s. Network size is %(network_size)s') %
kwargs)
+ kwargs['bridge_interface'] = (kwargs.get('bridge_interface') or
+ FLAGS.vlan_interface)
return NetworkManager.create_networks(
self, context, vpn=True, **kwargs)
diff --git a/nova/network/quantum/nova_ipam_lib.py b/nova/network/quantum/nova_ipam_lib.py
index f398815e5..02157bf7c 100644
--- a/nova/network/quantum/nova_ipam_lib.py
+++ b/nova/network/quantum/nova_ipam_lib.py
@@ -59,7 +59,7 @@ class QuantumNovaIPAMLib(object):
"""
admin_context = context.elevated()
subnet_size = len(netaddr.IPNetwork(cidr))
- networks = manager.FlatManager.create_networks(self.net_manager,
+ networks = manager.FlatManager._do_create_networks(self.net_manager,
admin_context, label, cidr,
False, 1, subnet_size, cidr_v6, gateway,
gateway_v6, quantum_net_id, None, dns1, dns2,
diff --git a/nova/tests/api/openstack/compute/contrib/test_networks.py b/nova/tests/api/openstack/compute/contrib/test_networks.py
index efbb7ceba..808493f1b 100644
--- a/nova/tests/api/openstack/compute/contrib/test_networks.py
+++ b/nova/tests/api/openstack/compute/contrib/test_networks.py
@@ -15,6 +15,10 @@
# under the License.
import copy
+import itertools
+import math
+import netaddr
+import uuid
import webob
@@ -23,6 +27,11 @@ from nova import exception
from nova import test
from nova.tests.api.openstack import fakes
+from nova import flags
+
+
+FLAGS = flags.FLAGS
+
FAKE_NETWORKS = [
{
@@ -75,6 +84,15 @@ FAKE_USER_NETWORKS = [
},
]
+NEW_NETWORK = {
+ "network": {
+ "bridge_interface": "eth0",
+ "cidr": "10.20.105.0/24",
+ "label": "new net 111",
+ "vlan_start": 111,
+ }
+}
+
class FakeNetworkAPI(object):
@@ -117,6 +135,32 @@ class FakeNetworkAPI(object):
return network
raise exception.NetworkNotFound()
+ def create(self, context, **kwargs):
+ subnet_bits = int(math.ceil(math.log(kwargs.get(
+ 'network_size', FLAGS.network_size), 2)))
+ fixed_net_v4 = netaddr.IPNetwork(kwargs['cidr'])
+ prefixlen_v4 = 32 - subnet_bits
+ subnets_v4 = list(fixed_net_v4.subnet(
+ prefixlen_v4,
+ count=kwargs.get('num_networks', FLAGS.num_networks)))
+ new_networks = []
+ new_id = max((net['id'] for net in self.networks))
+ for index, subnet_v4 in enumerate(subnets_v4):
+ new_id += 1
+ net = {'id': new_id, 'uuid': str(uuid.uuid4())}
+
+ net['cidr'] = str(subnet_v4)
+ net['netmask'] = str(subnet_v4.netmask)
+ net['gateway'] = kwargs.get('gateway') or str(subnet_v4[1])
+ net['broadcast'] = str(subnet_v4.broadcast)
+ net['dhcp_start'] = str(subnet_v4[2])
+
+ for key in FAKE_NETWORKS[0].iterkeys():
+ net.setdefault(key, kwargs.get(key))
+ new_networks.append(net)
+ self.networks += new_networks
+ return new_networks
+
class NetworksTest(test.TestCase):
@@ -204,3 +248,21 @@ class NetworksTest(test.TestCase):
req.environ["nova.context"].is_admin = True
res_dict = self.controller.show(req, uuid)
self.assertEqual(res_dict['network']['project_id'], 'fake')
+
+ def test_network_create(self):
+ req = fakes.HTTPRequest.blank('/v2/1234/os-networks')
+ res_dict = self.controller.create(req, NEW_NETWORK)
+ self.assertTrue('network' in res_dict)
+ uuid = res_dict['network']['id']
+ req = fakes.HTTPRequest.blank('/v2/1234/os-networks/%s' % uuid)
+ res_dict = self.controller.show(req, uuid)
+ self.assertTrue(res_dict['network']['label'].
+ startswith(NEW_NETWORK['network']['label']))
+
+ def test_network_create_large(self):
+ req = fakes.HTTPRequest.blank('/v2/1234/os-networks')
+ large_network = copy.deepcopy(NEW_NETWORK)
+ large_network['network']['cidr'] = '128.0.0.0/4'
+ res_dict = self.controller.create(req, large_network)
+ self.assertEqual(res_dict['network']['cidr'],
+ large_network['network']['cidr'])
diff --git a/nova/tests/fake_flags.py b/nova/tests/fake_flags.py
index f6d9496b1..f0fde3588 100644
--- a/nova/tests/fake_flags.py
+++ b/nova/tests/fake_flags.py
@@ -39,6 +39,7 @@ def set_defaults(conf):
conf.set_default('iscsi_num_targets', 8)
conf.set_default('network_size', 8)
conf.set_default('num_networks', 2)
+ conf.set_default('vlan_interface', 'eth0')
conf.set_default('rpc_backend', 'nova.openstack.common.rpc.impl_fake')
conf.set_default('sql_connection', "sqlite://")
conf.set_default('sqlite_synchronous', False)
diff --git a/nova/tests/network/test_linux_net.py b/nova/tests/network/test_linux_net.py
index 94b2ac8d9..47b853a8a 100644
--- a/nova/tests/network/test_linux_net.py
+++ b/nova/tests/network/test_linux_net.py
@@ -373,6 +373,7 @@ class LinuxNetworkTestCase(test.TestCase):
"bridge_interface": "base_interface",
"vlan": "fake"
}
+ self.flags(vlan_interface="")
driver.plug(network, "fakemac")
self.assertEqual(info['passed_interface'], "base_interface")
self.flags(vlan_interface="override_interface")
diff --git a/nova/tests/test_nova_manage.py b/nova/tests/test_nova_manage.py
index 805ac8e0d..6cadeb2ef 100644
--- a/nova/tests/test_nova_manage.py
+++ b/nova/tests/test_nova_manage.py
@@ -171,13 +171,13 @@ class NetworkCommandsTestCase(test.TestCase):
fake_create_networks)
self.commands.create(
label='Test',
- fixed_range_v4='10.2.0.0/24',
+ cidr='10.2.0.0/24',
num_networks=1,
network_size=256,
multi_host='F',
vlan_start=200,
vpn_start=2000,
- fixed_range_v6='fd00:2::/120',
+ cidr_v6='fd00:2::/120',
gateway='10.2.0.1',
gateway_v6='fd00:2::22',
bridge='br200',