Merge "Raise exception for network delete with subnets presents"
This commit is contained in:
commit
0ed990b617
@ -1040,6 +1040,10 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
network = self.get_network(context, id)
|
network = self.get_network(context, id)
|
||||||
|
if network['subnets']:
|
||||||
|
msg = _("Cannot delete network '%s', "
|
||||||
|
"delete the associated subnet first") % network['name']
|
||||||
|
raise n_exc.InvalidInput(error_message=msg)
|
||||||
if n1kv_db_v2.is_trunk_member(session, id):
|
if n1kv_db_v2.is_trunk_member(session, id):
|
||||||
msg = _("Cannot delete network '%s' "
|
msg = _("Cannot delete network '%s' "
|
||||||
"that is member of a trunk segment") % network['name']
|
"that is member of a trunk segment") % network['name']
|
||||||
|
@ -15,8 +15,10 @@
|
|||||||
# @author: Juergen Brendel, Cisco Systems Inc.
|
# @author: Juergen Brendel, Cisco Systems Inc.
|
||||||
# @author: Abhishek Raut, Cisco Systems Inc.
|
# @author: Abhishek Raut, Cisco Systems Inc.
|
||||||
# @author: Sourabh Patwardhan, Cisco Systems Inc.
|
# @author: Sourabh Patwardhan, Cisco Systems Inc.
|
||||||
|
# @author: Marga Millet, Cisco Systems Inc.
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
import webob.exc
|
||||||
|
|
||||||
from neutron.api import extensions as neutron_extensions
|
from neutron.api import extensions as neutron_extensions
|
||||||
from neutron.api.v2 import attributes
|
from neutron.api.v2 import attributes
|
||||||
@ -570,6 +572,14 @@ class TestN1kvPorts(test_plugin.TestPortsV2,
|
|||||||
VIF_TYPE = portbindings.VIF_TYPE_OVS
|
VIF_TYPE = portbindings.VIF_TYPE_OVS
|
||||||
HAS_PORT_FILTER = False
|
HAS_PORT_FILTER = False
|
||||||
|
|
||||||
|
_unsupported = ('test_delete_network_if_port_exists',
|
||||||
|
'test_requested_subnet_id_v4_and_v6')
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
if self._testMethodName in self._unsupported:
|
||||||
|
self.skipTest("Unsupported test case")
|
||||||
|
super(TestN1kvPorts, self).setUp()
|
||||||
|
|
||||||
def test_create_port_with_default_n1kv_policy_profile_id(self):
|
def test_create_port_with_default_n1kv_policy_profile_id(self):
|
||||||
"""Test port create without passing policy profile id."""
|
"""Test port create without passing policy profile id."""
|
||||||
with self.port() as port:
|
with self.port() as port:
|
||||||
@ -795,11 +805,63 @@ class TestN1kvNetworks(test_plugin.TestNetworksV2,
|
|||||||
self.assertFalse(n1kv_db_v2.get_vxlan_allocation(db_session,
|
self.assertFalse(n1kv_db_v2.get_vxlan_allocation(db_session,
|
||||||
10000).allocated)
|
10000).allocated)
|
||||||
|
|
||||||
|
def test_delete_network(self):
|
||||||
|
"""Regular test case of network deletion. Should return successful."""
|
||||||
|
res = self._create_network(self.fmt, name='net', admin_state_up=True)
|
||||||
|
network = self.deserialize(self.fmt, res)
|
||||||
|
req = self.new_delete_request('networks', network['network']['id'])
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
def test_delete_network_with_subnet(self):
|
||||||
|
"""Network deletion fails when a subnet is present on the network."""
|
||||||
|
with self.subnet() as subnet:
|
||||||
|
net_id = subnet['subnet']['network_id']
|
||||||
|
req = self.new_delete_request('networks', net_id)
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEqual(res.status_int, webob.exc.HTTPBadRequest.code)
|
||||||
|
|
||||||
|
def test_update_network_set_not_shared_multi_tenants2_returns_409(self):
|
||||||
|
"""
|
||||||
|
Verifies that updating a network which cannot be shared,
|
||||||
|
returns a conflict error.
|
||||||
|
"""
|
||||||
|
with self.network(shared=True) as network:
|
||||||
|
res = self._create_port(self.fmt, network['network']['id'],
|
||||||
|
webob.exc.HTTPCreated.code,
|
||||||
|
tenant_id='somebody_else',
|
||||||
|
set_context=True)
|
||||||
|
data = {'network': {'shared': False}}
|
||||||
|
req = self.new_update_request('networks', data,
|
||||||
|
network['network']['id'])
|
||||||
|
self.assertEqual(req.get_response(self.api).status_int,
|
||||||
|
webob.exc.HTTPConflict.code)
|
||||||
|
port = self.deserialize(self.fmt, res)
|
||||||
|
self._delete('ports', port['port']['id'])
|
||||||
|
|
||||||
|
def test_delete_network_if_port_exists(self):
|
||||||
|
"""Verify that a network with a port attached cannot be removed."""
|
||||||
|
res = self._create_network(self.fmt, name='net1', admin_state_up=True)
|
||||||
|
network = self.deserialize(self.fmt, res)
|
||||||
|
net_id = network['network']['id']
|
||||||
|
res = self._create_port(self.fmt, net_id,
|
||||||
|
webob.exc.HTTPCreated.code)
|
||||||
|
req = self.new_delete_request('networks', net_id)
|
||||||
|
self.assertEqual(req.get_response(self.api).status_int,
|
||||||
|
webob.exc.HTTPConflict.code)
|
||||||
|
|
||||||
|
|
||||||
class TestN1kvSubnets(test_plugin.TestSubnetsV2,
|
class TestN1kvSubnets(test_plugin.TestSubnetsV2,
|
||||||
N1kvPluginTestCase):
|
N1kvPluginTestCase):
|
||||||
|
|
||||||
|
_unsupported = (
|
||||||
|
'test_delete_network',
|
||||||
|
'test_create_subnets_bulk_emulated',
|
||||||
|
'test_create_subnets_bulk_emulated_plugin_failure')
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
if self._testMethodName in self._unsupported:
|
||||||
|
self.skipTest("Unsupported test")
|
||||||
super(TestN1kvSubnets, self).setUp()
|
super(TestN1kvSubnets, self).setUp()
|
||||||
|
|
||||||
def test_create_subnet_with_invalid_parameters(self):
|
def test_create_subnet_with_invalid_parameters(self):
|
||||||
@ -815,6 +877,113 @@ class TestN1kvSubnets(test_plugin.TestSubnetsV2,
|
|||||||
# Subnet creation should fail due to invalid network name
|
# Subnet creation should fail due to invalid network name
|
||||||
self.assertEqual(subnet_resp.status_int, 400)
|
self.assertEqual(subnet_resp.status_int, 400)
|
||||||
|
|
||||||
|
def test_update_subnet_adding_additional_host_routes_and_dns(self):
|
||||||
|
host_routes = [{'destination': '172.16.0.0/24',
|
||||||
|
'nexthop': '10.0.2.2'}]
|
||||||
|
with self.network() as network:
|
||||||
|
data = {'subnet': {'network_id': network['network']['id'],
|
||||||
|
'cidr': '10.0.2.0/24',
|
||||||
|
'ip_version': 4,
|
||||||
|
'dns_nameservers': ['192.168.0.1'],
|
||||||
|
'host_routes': host_routes,
|
||||||
|
'tenant_id': network['network']['tenant_id']}}
|
||||||
|
req = self.new_create_request('subnets', data)
|
||||||
|
subnet = self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
|
|
||||||
|
host_routes = [{'destination': '172.16.0.0/24',
|
||||||
|
'nexthop': '10.0.2.2'},
|
||||||
|
{'destination': '192.168.0.0/24',
|
||||||
|
'nexthop': '10.0.2.3'}]
|
||||||
|
|
||||||
|
dns_nameservers = ['192.168.0.1', '192.168.0.2']
|
||||||
|
data = {'subnet': {'host_routes': host_routes,
|
||||||
|
'dns_nameservers': dns_nameservers}}
|
||||||
|
req = self.new_update_request('subnets', data,
|
||||||
|
subnet['subnet']['id'])
|
||||||
|
subnet = self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
|
self.assertEqual(sorted(subnet['subnet']['host_routes']),
|
||||||
|
sorted(host_routes))
|
||||||
|
self.assertEqual(sorted(subnet['subnet']['dns_nameservers']),
|
||||||
|
sorted(dns_nameservers))
|
||||||
|
# In N1K we need to delete the subnet before the network
|
||||||
|
req = self.new_delete_request('subnets', subnet['subnet']['id'])
|
||||||
|
self.assertEqual(req.get_response(self.api).status_int,
|
||||||
|
webob.exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
def test_subnet_with_allocation_range(self):
|
||||||
|
with self.network() as network:
|
||||||
|
net_id = network['network']['id']
|
||||||
|
data = {'subnet': {'network_id': net_id,
|
||||||
|
'cidr': '10.0.0.0/24',
|
||||||
|
'ip_version': 4,
|
||||||
|
'gateway_ip': '10.0.0.1',
|
||||||
|
'tenant_id': network['network']['tenant_id'],
|
||||||
|
'allocation_pools': [{'start': '10.0.0.100',
|
||||||
|
'end': '10.0.0.120'}]}}
|
||||||
|
req = self.new_create_request('subnets', data)
|
||||||
|
subnet = self.deserialize(self.fmt, req.get_response(self.api))
|
||||||
|
# Check fixed IP not in allocation range
|
||||||
|
kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id'],
|
||||||
|
'ip_address': '10.0.0.10'}]}
|
||||||
|
res = self._create_port(self.fmt, net_id=net_id, **kwargs)
|
||||||
|
self.assertEqual(res.status_int, webob.exc.HTTPCreated.code)
|
||||||
|
port = self.deserialize(self.fmt, res)
|
||||||
|
# delete the port
|
||||||
|
self._delete('ports', port['port']['id'])
|
||||||
|
# Check when fixed IP is gateway
|
||||||
|
kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id'],
|
||||||
|
'ip_address': '10.0.0.1'}]}
|
||||||
|
res = self._create_port(self.fmt, net_id=net_id, **kwargs)
|
||||||
|
self.assertEqual(res.status_int, webob.exc.HTTPCreated.code)
|
||||||
|
port = self.deserialize(self.fmt, res)
|
||||||
|
# delete the port
|
||||||
|
self._delete('ports', port['port']['id'])
|
||||||
|
req = self.new_delete_request('subnets', subnet['subnet']['id'])
|
||||||
|
self.assertEqual(req.get_response(self.api).status_int,
|
||||||
|
webob.exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
def test_requested_subnet_id_v4_and_v6(self):
|
||||||
|
with self.network() as network:
|
||||||
|
net_id = network['network']['id']
|
||||||
|
res = self._create_subnet(self.fmt, tenant_id='tenant1',
|
||||||
|
net_id=net_id, cidr='10.0.0.0/24',
|
||||||
|
ip_version=4,
|
||||||
|
gateway_ip=attributes.ATTR_NOT_SPECIFIED)
|
||||||
|
subnet1 = self.deserialize(self.fmt, res)
|
||||||
|
res = self._create_subnet(self.fmt, tenant_id='tenant1',
|
||||||
|
net_id=net_id,
|
||||||
|
cidr='2607:f0d0:1002:51::/124',
|
||||||
|
ip_version=6,
|
||||||
|
gateway_ip=attributes.ATTR_NOT_SPECIFIED)
|
||||||
|
subnet2 = self.deserialize(self.fmt, res)
|
||||||
|
kwargs = {"fixed_ips": [{'subnet_id': subnet1['subnet']['id']},
|
||||||
|
{'subnet_id': subnet2['subnet']['id']}]}
|
||||||
|
res = self._create_port(self.fmt, net_id=net_id, **kwargs)
|
||||||
|
port3 = self.deserialize(self.fmt, res)
|
||||||
|
ips = port3['port']['fixed_ips']
|
||||||
|
self.assertEqual(len(ips), 2)
|
||||||
|
self.assertEqual(ips[0]['ip_address'], '10.0.0.2')
|
||||||
|
self.assertEqual(ips[0]['subnet_id'], subnet1['subnet']['id'])
|
||||||
|
self.assertEqual(ips[1]['ip_address'], '2607:f0d0:1002:51::2')
|
||||||
|
self.assertEqual(ips[1]['subnet_id'], subnet2['subnet']['id'])
|
||||||
|
res = self._create_port(self.fmt, net_id=net_id)
|
||||||
|
port4 = self.deserialize(self.fmt, res)
|
||||||
|
# Check that a v4 and a v6 address are allocated
|
||||||
|
ips = port4['port']['fixed_ips']
|
||||||
|
self.assertEqual(len(ips), 2)
|
||||||
|
self.assertEqual(ips[0]['ip_address'], '10.0.0.3')
|
||||||
|
self.assertEqual(ips[0]['subnet_id'], subnet1['subnet']['id'])
|
||||||
|
self.assertEqual(ips[1]['ip_address'], '2607:f0d0:1002:51::3')
|
||||||
|
self.assertEqual(ips[1]['subnet_id'], subnet2['subnet']['id'])
|
||||||
|
self._delete('ports', port3['port']['id'])
|
||||||
|
self._delete('ports', port4['port']['id'])
|
||||||
|
req = self.new_delete_request('subnets', subnet1['subnet']['id'])
|
||||||
|
self.assertEqual(req.get_response(self.api).status_int,
|
||||||
|
webob.exc.HTTPNoContent.code)
|
||||||
|
req = self.new_delete_request('subnets', subnet2['subnet']['id'])
|
||||||
|
self.assertEqual(req.get_response(self.api).status_int,
|
||||||
|
webob.exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
|
||||||
class TestN1kvL3Test(test_l3_plugin.L3NatExtensionTestCase):
|
class TestN1kvL3Test(test_l3_plugin.L3NatExtensionTestCase):
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user