Merge "Add API schema for v2.1 networks API"
This commit is contained in:
commit
5c2c5eb122
@ -17,8 +17,10 @@
|
||||
import netaddr
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack.compute.schemas.v3 import networks as schema
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api import validation
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova import network
|
||||
@ -133,33 +135,17 @@ class NetworkController(wsgi.Controller):
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
@extensions.expected_errors((400, 409, 501))
|
||||
@validation.schema(schema.create)
|
||||
def create(self, req, body):
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
|
||||
def bad(e):
|
||||
return exc.HTTPBadRequest(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"))
|
||||
|
||||
if params.get("project_id") == "":
|
||||
params["project_id"] = None
|
||||
|
||||
params["num_networks"] = 1
|
||||
try:
|
||||
params["network_size"] = netaddr.IPNetwork(cidr).size
|
||||
except netaddr.AddrFormatError:
|
||||
msg = _('%s is not a valid ip network') % cidr
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
params["network_size"] = netaddr.IPNetwork(cidr).size
|
||||
|
||||
try:
|
||||
network = self.network_api.create(context, **params)[0]
|
||||
|
68
nova/api/openstack/compute/schemas/v3/networks.py
Normal file
68
nova/api/openstack/compute/schemas/v3/networks.py
Normal file
@ -0,0 +1,68 @@
|
||||
# Copyright 2015 NEC Corporation. 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.validation import parameter_types
|
||||
|
||||
|
||||
create = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'network': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'label': {
|
||||
'type': 'string', 'maxLength': 255
|
||||
},
|
||||
'ipam': parameter_types.boolean,
|
||||
'cidr': parameter_types.cidr,
|
||||
'cidr_v6': parameter_types.cidr,
|
||||
'project_id': parameter_types.project_id,
|
||||
'multi_host': parameter_types.boolean,
|
||||
'gateway': parameter_types.ipv4,
|
||||
'gateway_v6': parameter_types.ipv6,
|
||||
'bridge': {
|
||||
'type': 'string',
|
||||
},
|
||||
'bridge_interface': {
|
||||
'type': 'string',
|
||||
},
|
||||
# NOTE: In _extract_subnets(), dns1, dns2 dhcp_server are
|
||||
# used only for IPv4, not IPv6.
|
||||
'dns1': parameter_types.ipv4,
|
||||
'dns2': parameter_types.ipv4,
|
||||
'dhcp_server': parameter_types.ipv4,
|
||||
|
||||
'fixed_cidr': parameter_types.cidr,
|
||||
'allowed_start': parameter_types.ip_address,
|
||||
'allowed_end': parameter_types.ip_address,
|
||||
'enable_dhcp': parameter_types.boolean,
|
||||
'share_address': parameter_types.boolean,
|
||||
'mtu': parameter_types.positive_integer,
|
||||
'vlan': parameter_types.positive_integer,
|
||||
'vlan_start': parameter_types.positive_integer,
|
||||
'vpn_start': {
|
||||
'type': 'string',
|
||||
},
|
||||
},
|
||||
'required': ['label'],
|
||||
'oneOf': [
|
||||
{'required': ['cidr']},
|
||||
{'required': ['cidr_v6']}
|
||||
],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'required': ['network'],
|
||||
'additionalProperties': False,
|
||||
}
|
@ -189,3 +189,18 @@ ip_address = {
|
||||
{'format': 'ipv6'}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
ipv4 = {
|
||||
'type': 'string', 'format': 'ipv4'
|
||||
}
|
||||
|
||||
|
||||
ipv6 = {
|
||||
'type': 'string', 'format': 'ipv6'
|
||||
}
|
||||
|
||||
|
||||
cidr = {
|
||||
'type': 'string', 'format': 'cidr'
|
||||
}
|
||||
|
@ -1135,14 +1135,20 @@ class NetworkManager(manager.Manager):
|
||||
self._convert_int_args(kwargs)
|
||||
|
||||
# check for certain required inputs
|
||||
# NOTE: We can remove this check after v2.0 API code is removed because
|
||||
# jsonschema has checked already before this.
|
||||
label = kwargs["label"]
|
||||
if not label:
|
||||
raise exception.NetworkNotCreated(req="label")
|
||||
|
||||
# Size of "label" column in nova.networks is 255, hence the restriction
|
||||
# NOTE: We can remove this check after v2.0 API code is removed because
|
||||
# jsonschema has checked already before this.
|
||||
if len(label) > 255:
|
||||
raise exception.LabelTooLong()
|
||||
|
||||
# NOTE: We can remove this check after v2.0 API code is removed because
|
||||
# jsonschema has checked already before this.
|
||||
if not (kwargs["cidr"] or kwargs["cidr_v6"]):
|
||||
raise exception.NetworkNotCreated(req="cidr or cidr_v6")
|
||||
|
||||
|
@ -106,9 +106,7 @@ NEW_NETWORK = {
|
||||
"cidr": "10.20.105.0/24",
|
||||
"label": "new net 111",
|
||||
"vlan_start": 111,
|
||||
"injected": False,
|
||||
"multi_host": False,
|
||||
'mtu': None,
|
||||
'dhcp_server': '10.0.0.1',
|
||||
'enable_dhcp': True,
|
||||
'share_address': False,
|
||||
@ -194,6 +192,14 @@ class FakeNetworkAPI(object):
|
||||
def get(self, context, network_id):
|
||||
for network in self.networks:
|
||||
if network.get('uuid') == network_id:
|
||||
if 'injected' in network and network['injected'] is None:
|
||||
# NOTE: This is a workaround for passing unit tests.
|
||||
# When using nova-network, 'injected' value should be
|
||||
# boolean because of the definition of objects.Network().
|
||||
# However, 'injected' value can be None if neutron.
|
||||
# So here changes the value to False just for passing
|
||||
# following _from_db_object().
|
||||
network['injected'] = False
|
||||
return objects.Network._from_db_object(context,
|
||||
objects.Network(),
|
||||
network)
|
||||
@ -229,6 +235,7 @@ class FakeNetworkAPI(object):
|
||||
# NOTE(vish): tests that network create Exceptions actually return
|
||||
# the proper error responses
|
||||
class NetworkCreateExceptionsTestV21(test.TestCase):
|
||||
validation_error = exception.ValidationError
|
||||
|
||||
class PassthroughAPI(object):
|
||||
def __init__(self):
|
||||
@ -252,28 +259,39 @@ class NetworkCreateExceptionsTestV21(test.TestCase):
|
||||
|
||||
def test_network_create_bad_vlan(self):
|
||||
self.new_network['network']['vlan_start'] = 'foo'
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.create, self.req, self.new_network)
|
||||
self.assertRaises(self.validation_error,
|
||||
self.controller.create, self.req,
|
||||
body=self.new_network)
|
||||
|
||||
def test_network_create_no_cidr(self):
|
||||
self.new_network['network']['cidr'] = ''
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.create, self.req, self.new_network)
|
||||
self.assertRaises(self.validation_error,
|
||||
self.controller.create, self.req,
|
||||
body=self.new_network)
|
||||
|
||||
def test_network_create_invalid_fixed_cidr(self):
|
||||
self.new_network['network']['fixed_cidr'] = 'foo'
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.create, self.req, self.new_network)
|
||||
self.assertRaises(self.validation_error,
|
||||
self.controller.create, self.req,
|
||||
body=self.new_network)
|
||||
|
||||
def test_network_create_invalid_start(self):
|
||||
self.new_network['network']['allowed_start'] = 'foo'
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.create, self.req, self.new_network)
|
||||
self.assertRaises(self.validation_error,
|
||||
self.controller.create, self.req,
|
||||
body=self.new_network)
|
||||
|
||||
def test_network_create_bad_cidr(self):
|
||||
self.new_network['network']['cidr'] = '128.0.0.0/900'
|
||||
self.assertRaises(self.validation_error,
|
||||
self.controller.create, self.req,
|
||||
body=self.new_network)
|
||||
|
||||
def test_network_create_handle_network_not_created(self):
|
||||
self.new_network['network']['label'] = 'fail_NetworkNotCreated'
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.create, self.req, self.new_network)
|
||||
self.controller.create, self.req,
|
||||
body=self.new_network)
|
||||
|
||||
def test_network_create_cidr_conflict(self):
|
||||
|
||||
@ -288,10 +306,12 @@ class NetworkCreateExceptionsTestV21(test.TestCase):
|
||||
|
||||
self.new_network['network']['cidr'] = '10.0.0.0/24'
|
||||
self.assertRaises(webob.exc.HTTPConflict,
|
||||
self.controller.create, self.req, self.new_network)
|
||||
self.controller.create, self.req,
|
||||
body=self.new_network)
|
||||
|
||||
|
||||
class NetworkCreateExceptionsTestV2(NetworkCreateExceptionsTestV21):
|
||||
validation_error = webob.exc.HTTPBadRequest
|
||||
|
||||
def _setup(self):
|
||||
ext_mgr = extensions.ExtensionManager()
|
||||
@ -300,6 +320,11 @@ class NetworkCreateExceptionsTestV2(NetworkCreateExceptionsTestV21):
|
||||
self.controller = networks.NetworkController(
|
||||
self.PassthroughAPI(), ext_mgr)
|
||||
|
||||
def test_network_create_with_both_cidr_and_cidr_v6(self):
|
||||
# NOTE: v2.0 API cannot handle this case, so we need to just
|
||||
# skip it on the API.
|
||||
pass
|
||||
|
||||
|
||||
class NetworksTestV21(test.NoDBTestCase):
|
||||
|
||||
@ -428,15 +453,10 @@ class NetworksTestV21(test.NoDBTestCase):
|
||||
|
||||
def test_network_create_large(self):
|
||||
self.new_network['network']['cidr'] = '128.0.0.0/4'
|
||||
res_dict = self.controller.create(self.req, self.new_network)
|
||||
res_dict = self.controller.create(self.req, body=self.new_network)
|
||||
self.assertEqual(res_dict['network']['cidr'],
|
||||
self.new_network['network']['cidr'])
|
||||
|
||||
def test_network_create_bad_cidr(self):
|
||||
self.new_network['network']['cidr'] = '128.0.0.0/900'
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.create, self.req, self.new_network)
|
||||
|
||||
def test_network_neutron_disassociate_not_implemented(self):
|
||||
uuid = FAKE_NETWORKS[1]['uuid']
|
||||
self.flags(network_api_class='nova.network.neutronv2.api.API')
|
||||
@ -469,7 +489,7 @@ class NetworksTestV2(NetworksTestV21):
|
||||
|
||||
self.stubs.Set(self.controller.network_api, 'create', no_mtu)
|
||||
self.new_network['network']['mtu'] = 9000
|
||||
self.controller.create(self.req, self.new_network)
|
||||
self.controller.create(self.req, body=self.new_network)
|
||||
|
||||
|
||||
class NetworksAssociateTestV21(test.NoDBTestCase):
|
||||
|
Loading…
Reference in New Issue
Block a user