Merge "Delete disassociated floating ips on external network deletion"
This commit is contained in:
commit
cf22dd2ff9
@ -25,6 +25,8 @@ from neutron.db import db_base_plugin_v2
|
|||||||
from neutron.db import model_base
|
from neutron.db import model_base
|
||||||
from neutron.db import models_v2
|
from neutron.db import models_v2
|
||||||
from neutron.extensions import external_net
|
from neutron.extensions import external_net
|
||||||
|
from neutron import manager
|
||||||
|
from neutron.plugins.common import constants as service_constants
|
||||||
|
|
||||||
|
|
||||||
DEVICE_OWNER_ROUTER_GW = l3_constants.DEVICE_OWNER_ROUTER_GW
|
DEVICE_OWNER_ROUTER_GW = l3_constants.DEVICE_OWNER_ROUTER_GW
|
||||||
@ -135,6 +137,12 @@ class External_net_db_mixin(object):
|
|||||||
network_id=net_id).delete()
|
network_id=net_id).delete()
|
||||||
net_data[external_net.EXTERNAL] = False
|
net_data[external_net.EXTERNAL] = False
|
||||||
|
|
||||||
|
def _process_l3_delete(self, context, network_id):
|
||||||
|
l3plugin = manager.NeutronManager.get_service_plugins().get(
|
||||||
|
service_constants.L3_ROUTER_NAT)
|
||||||
|
if l3plugin:
|
||||||
|
l3plugin.delete_disassociated_floatingips(context, network_id)
|
||||||
|
|
||||||
def _filter_nets_l3(self, context, nets, filters):
|
def _filter_nets_l3(self, context, nets, filters):
|
||||||
vals = filters and filters.get(external_net.EXTERNAL, [])
|
vals = filters and filters.get(external_net.EXTERNAL, [])
|
||||||
if not vals:
|
if not vals:
|
||||||
|
@ -798,6 +798,14 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
|||||||
marker_obj=marker_obj,
|
marker_obj=marker_obj,
|
||||||
page_reverse=page_reverse)
|
page_reverse=page_reverse)
|
||||||
|
|
||||||
|
def delete_disassociated_floatingips(self, context, network_id):
|
||||||
|
query = self._model_query(context, FloatingIP)
|
||||||
|
query = query.filter_by(floating_network_id=network_id,
|
||||||
|
fixed_port_id=None,
|
||||||
|
router_id=None)
|
||||||
|
for fip in query:
|
||||||
|
self.delete_floatingip(context, fip.id)
|
||||||
|
|
||||||
def get_floatingips_count(self, context, filters=None):
|
def get_floatingips_count(self, context, filters=None):
|
||||||
return self._get_collection_count(context, FloatingIP,
|
return self._get_collection_count(context, FloatingIP,
|
||||||
filters=filters)
|
filters=filters)
|
||||||
|
@ -615,18 +615,8 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
|
|||||||
|
|
||||||
# Validate args
|
# Validate args
|
||||||
orig_net = super(NeutronRestProxyV2, self).get_network(context, net_id)
|
orig_net = super(NeutronRestProxyV2, self).get_network(context, net_id)
|
||||||
|
|
||||||
filter = {'network_id': [net_id]}
|
|
||||||
ports = self.get_ports(context, filters=filter)
|
|
||||||
|
|
||||||
# check if there are any tenant owned ports in-use
|
|
||||||
auto_delete_port_owners = db_base_plugin_v2.AUTO_DELETE_PORT_OWNERS
|
|
||||||
only_auto_del = all(p['device_owner'] in auto_delete_port_owners
|
|
||||||
for p in ports)
|
|
||||||
|
|
||||||
if not only_auto_del:
|
|
||||||
raise exceptions.NetworkInUse(net_id=net_id)
|
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
|
self._process_l3_delete(context, net_id)
|
||||||
ret_val = super(NeutronRestProxyV2, self).delete_network(context,
|
ret_val = super(NeutronRestProxyV2, self).delete_network(context,
|
||||||
net_id)
|
net_id)
|
||||||
self._send_delete_network(orig_net, context)
|
self._send_delete_network(orig_net, context)
|
||||||
@ -1092,6 +1082,18 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
|
|||||||
port_id)
|
port_id)
|
||||||
self._send_floatingip_update(context)
|
self._send_floatingip_update(context)
|
||||||
|
|
||||||
|
# overriding method from l3_db as original method calls
|
||||||
|
# self.delete_floatingip() which in turn calls self.delete_port() which
|
||||||
|
# is locked with 'bsn-port-barrier'
|
||||||
|
def delete_disassociated_floatingips(self, context, network_id):
|
||||||
|
query = self._model_query(context, l3_db.FloatingIP)
|
||||||
|
query = query.filter_by(floating_network_id=network_id,
|
||||||
|
fixed_port_id=None,
|
||||||
|
router_id=None)
|
||||||
|
for fip in query:
|
||||||
|
context.session.delete(fip)
|
||||||
|
self._delete_port(context.elevated(), fip['floating_port_id'])
|
||||||
|
|
||||||
def _send_floatingip_update(self, context):
|
def _send_floatingip_update(self, context):
|
||||||
try:
|
try:
|
||||||
ext_net_id = self.get_external_network_id(context)
|
ext_net_id = self.get_external_network_id(context)
|
||||||
|
@ -318,6 +318,7 @@ class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
|
self._process_l3_delete(context, net_id)
|
||||||
result = super(BrocadePluginV2, self).delete_network(context,
|
result = super(BrocadePluginV2, self).delete_network(context,
|
||||||
net_id)
|
net_id)
|
||||||
# we must delete all ports in db first (foreign key constraint)
|
# we must delete all ports in db first (foreign key constraint)
|
||||||
|
@ -1111,6 +1111,8 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
# the network_binding record is deleted via cascade from
|
# the network_binding record is deleted via cascade from
|
||||||
# the network record, so explicit removal is not necessary
|
# the network record, so explicit removal is not necessary
|
||||||
self._send_delete_network_request(context, network)
|
self._send_delete_network_request(context, network)
|
||||||
|
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
super(N1kvNeutronPluginV2, self).delete_network(context, id)
|
super(N1kvNeutronPluginV2, self).delete_network(context, id)
|
||||||
LOG.debug(_("Deleted network: %s"), id)
|
LOG.debug(_("Deleted network: %s"), id)
|
||||||
|
|
||||||
|
@ -276,6 +276,7 @@ class HyperVNeutronPlugin(agents_db.AgentDbMixin,
|
|||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
binding = self._db.get_network_binding(session, id)
|
binding = self._db.get_network_binding(session, id)
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
super(HyperVNeutronPlugin, self).delete_network(context, id)
|
super(HyperVNeutronPlugin, self).delete_network(context, id)
|
||||||
p = self._network_providers_map[binding.network_type]
|
p = self._network_providers_map[binding.network_type]
|
||||||
p.delete_network(session, binding)
|
p.delete_network(session, binding)
|
||||||
|
@ -236,7 +236,11 @@ class SdnvePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
@_ha
|
@_ha
|
||||||
def delete_network(self, context, id):
|
def delete_network(self, context, id):
|
||||||
LOG.debug(_("Delete network in progress: %s"), id)
|
LOG.debug(_("Delete network in progress: %s"), id)
|
||||||
super(SdnvePluginV2, self).delete_network(context, id)
|
session = context.session
|
||||||
|
|
||||||
|
with session.begin(subtransactions=True):
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
|
super(SdnvePluginV2, self).delete_network(context, id)
|
||||||
|
|
||||||
(res, data) = self.sdnve_client.sdnve_delete('network', id)
|
(res, data) = self.sdnve_client.sdnve_delete('network', id)
|
||||||
if res not in constants.HTTP_ACCEPTABLE:
|
if res not in constants.HTTP_ACCEPTABLE:
|
||||||
|
@ -444,6 +444,7 @@ class LinuxBridgePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
binding = db.get_network_binding(session, id)
|
binding = db.get_network_binding(session, id)
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
super(LinuxBridgePluginV2, self).delete_network(context, id)
|
super(LinuxBridgePluginV2, self).delete_network(context, id)
|
||||||
if binding.vlan_id != constants.LOCAL_VLAN_ID:
|
if binding.vlan_id != constants.LOCAL_VLAN_ID:
|
||||||
db.release_network(session, binding.physical_network,
|
db.release_network(session, binding.physical_network,
|
||||||
|
@ -516,7 +516,9 @@ class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
LOG.debug(_("MidonetPluginV2.delete_network called: id=%r"), id)
|
LOG.debug(_("MidonetPluginV2.delete_network called: id=%r"), id)
|
||||||
self.client.delete_bridge(id)
|
self.client.delete_bridge(id)
|
||||||
try:
|
try:
|
||||||
super(MidonetPluginV2, self).delete_network(context, id)
|
with context.session.begin(subtransactions=True):
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
|
super(MidonetPluginV2, self).delete_network(context, id)
|
||||||
except Exception:
|
except Exception:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
LOG.error(_('Failed to delete neutron db, while Midonet '
|
LOG.error(_('Failed to delete neutron db, while Midonet '
|
||||||
|
@ -457,6 +457,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
|
|
||||||
# Get ports to auto-delete.
|
# Get ports to auto-delete.
|
||||||
ports = (session.query(models_v2.Port).
|
ports = (session.query(models_v2.Port).
|
||||||
enable_eagerloads(False).
|
enable_eagerloads(False).
|
||||||
|
@ -379,6 +379,7 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
binding = db.get_network_binding(session, net_id)
|
binding = db.get_network_binding(session, net_id)
|
||||||
|
self._process_l3_delete(context, net_id)
|
||||||
super(MellanoxEswitchPlugin, self).delete_network(context,
|
super(MellanoxEswitchPlugin, self).delete_network(context,
|
||||||
net_id)
|
net_id)
|
||||||
if binding.segmentation_id != constants.LOCAL_VLAN_ID:
|
if binding.segmentation_id != constants.LOCAL_VLAN_ID:
|
||||||
|
@ -373,17 +373,24 @@ class NECPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
tenant_id = net_db['tenant_id']
|
tenant_id = net_db['tenant_id']
|
||||||
ports = self.get_ports(context, filters={'network_id': [id]})
|
ports = self.get_ports(context, filters={'network_id': [id]})
|
||||||
|
|
||||||
# check if there are any tenant owned ports in-use
|
# check if there are any tenant owned ports in-use;
|
||||||
|
# consider ports owned by floating ips as auto_delete as if there are
|
||||||
|
# no other tenant owned ports, those floating ips are disassociated
|
||||||
|
# and will be auto deleted with self._process_l3_delete()
|
||||||
only_auto_del = all(p['device_owner'] in
|
only_auto_del = all(p['device_owner'] in
|
||||||
db_base_plugin_v2.AUTO_DELETE_PORT_OWNERS
|
db_base_plugin_v2.AUTO_DELETE_PORT_OWNERS or
|
||||||
|
p['device_owner'] == const.DEVICE_OWNER_FLOATINGIP
|
||||||
for p in ports)
|
for p in ports)
|
||||||
if not only_auto_del:
|
if not only_auto_del:
|
||||||
raise n_exc.NetworkInUse(net_id=id)
|
raise n_exc.NetworkInUse(net_id=id)
|
||||||
|
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
|
|
||||||
# Make sure auto-delete ports on OFC are deleted.
|
# Make sure auto-delete ports on OFC are deleted.
|
||||||
# If an error occurs during port deletion,
|
# If an error occurs during port deletion,
|
||||||
# delete_network will be aborted.
|
# delete_network will be aborted.
|
||||||
for port in ports:
|
for port in [p for p in ports if p['device_owner']
|
||||||
|
in db_base_plugin_v2.AUTO_DELETE_PORT_OWNERS]:
|
||||||
port = self.deactivate_port(context, port)
|
port = self.deactivate_port(context, port)
|
||||||
|
|
||||||
# delete all packet_filters of the network from the controller
|
# delete all packet_filters of the network from the controller
|
||||||
|
@ -305,11 +305,13 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
return net
|
return net
|
||||||
|
|
||||||
def delete_network(self, context, id):
|
def delete_network(self, context, id):
|
||||||
filter = {'network_id': [id]}
|
with context.session.begin(subtransactions=True):
|
||||||
subnets = self.get_subnets(context, filters=filter)
|
self._process_l3_delete(context, id)
|
||||||
for subnet in subnets:
|
filter = {'network_id': [id]}
|
||||||
self.delete_subnet(context, subnet['id'])
|
subnets = self.get_subnets(context, filters=filter)
|
||||||
super(NuagePlugin, self).delete_network(context, id)
|
for subnet in subnets:
|
||||||
|
self.delete_subnet(context, subnet['id'])
|
||||||
|
super(NuagePlugin, self).delete_network(context, id)
|
||||||
|
|
||||||
def _get_net_partition_for_subnet(self, context, subnet):
|
def _get_net_partition_for_subnet(self, context, subnet):
|
||||||
subn = subnet['subnet']
|
subn = subnet['subnet']
|
||||||
|
@ -221,6 +221,7 @@ class OneConvergencePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
#get all the subnets under the network to delete them
|
#get all the subnets under the network to delete them
|
||||||
subnets = self._get_subnets_by_network(context, net_id)
|
subnets = self._get_subnets_by_network(context, net_id)
|
||||||
|
|
||||||
|
self._process_l3_delete(context, net_id)
|
||||||
super(OneConvergencePluginV2, self).delete_network(context,
|
super(OneConvergencePluginV2, self).delete_network(context,
|
||||||
net_id)
|
net_id)
|
||||||
|
|
||||||
|
@ -526,6 +526,7 @@ class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
binding = ovs_db_v2.get_network_binding(session, id)
|
binding = ovs_db_v2.get_network_binding(session, id)
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
super(OVSNeutronPluginV2, self).delete_network(context, id)
|
super(OVSNeutronPluginV2, self).delete_network(context, id)
|
||||||
if binding.network_type in constants.TUNNEL_NETWORK_TYPES:
|
if binding.network_type in constants.TUNNEL_NETWORK_TYPES:
|
||||||
ovs_db_v2.release_tunnel(session, binding.segmentation_id,
|
ovs_db_v2.release_tunnel(session, binding.segmentation_id,
|
||||||
|
@ -156,6 +156,7 @@ class NeutronPluginPLUMgridV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
self).get_network(context, net_id)
|
self).get_network(context, net_id)
|
||||||
|
|
||||||
with context.session.begin(subtransactions=True):
|
with context.session.begin(subtransactions=True):
|
||||||
|
self._process_l3_delete(context, net_id)
|
||||||
# Plugin DB - Network Delete
|
# Plugin DB - Network Delete
|
||||||
super(NeutronPluginPLUMgridV2, self).delete_network(context,
|
super(NeutronPluginPLUMgridV2, self).delete_network(context,
|
||||||
net_id)
|
net_id)
|
||||||
|
@ -202,6 +202,7 @@ class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
session = context.session
|
session = context.session
|
||||||
with session.begin(subtransactions=True):
|
with session.begin(subtransactions=True):
|
||||||
self.tunnel_key.delete(session, id)
|
self.tunnel_key.delete(session, id)
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
super(RyuNeutronPluginV2, self).delete_network(context, id)
|
super(RyuNeutronPluginV2, self).delete_network(context, id)
|
||||||
|
|
||||||
def create_port(self, context, port):
|
def create_port(self, context, port):
|
||||||
|
@ -1033,7 +1033,10 @@ class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
|||||||
if not external:
|
if not external:
|
||||||
lswitch_ids = nsx_utils.get_nsx_switch_ids(
|
lswitch_ids = nsx_utils.get_nsx_switch_ids(
|
||||||
context.session, self.cluster, id)
|
context.session, self.cluster, id)
|
||||||
super(NsxPluginV2, self).delete_network(context, id)
|
with context.session.begin(subtransactions=True):
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
|
super(NsxPluginV2, self).delete_network(context, id)
|
||||||
|
|
||||||
# clean up network owned ports
|
# clean up network owned ports
|
||||||
for port in router_iface_ports:
|
for port in router_iface_ports:
|
||||||
try:
|
try:
|
||||||
|
@ -43,7 +43,10 @@ class Fake1(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
return net
|
return net
|
||||||
|
|
||||||
def delete_network(self, context, id):
|
def delete_network(self, context, id):
|
||||||
return super(Fake1, self).delete_network(context, id)
|
session = context.session
|
||||||
|
with session.begin(subtransactions=True):
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
|
return super(Fake1, self).delete_network(context, id)
|
||||||
|
|
||||||
def create_port(self, context, port):
|
def create_port(self, context, port):
|
||||||
port = super(Fake1, self).create_port(context, port)
|
port = super(Fake1, self).create_port(context, port)
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
import contextlib
|
import contextlib
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
|
import mock
|
||||||
import testtools
|
import testtools
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
@ -158,6 +159,18 @@ class ExtNetDBTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
|
|||||||
self.assertEqual(ext_net['network'][external_net.EXTERNAL],
|
self.assertEqual(ext_net['network'][external_net.EXTERNAL],
|
||||||
True)
|
True)
|
||||||
|
|
||||||
|
def test_delete_network_check_disassociated_floatingips(self):
|
||||||
|
with mock.patch.object(NeutronManager,
|
||||||
|
'get_service_plugins') as srv_plugins:
|
||||||
|
l3_mock = mock.Mock()
|
||||||
|
srv_plugins.return_value = {'L3_ROUTER_NAT': l3_mock}
|
||||||
|
with self.network(do_delete=False) as net:
|
||||||
|
req = self.new_delete_request('networks', net['network']['id'])
|
||||||
|
res = req.get_response(self.api)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
||||||
|
(l3_mock.delete_disassociated_floatingips
|
||||||
|
.assert_called_once_with(mock.ANY, net['network']['id']))
|
||||||
|
|
||||||
|
|
||||||
class ExtNetDBTestCaseXML(ExtNetDBTestCase):
|
class ExtNetDBTestCaseXML(ExtNetDBTestCase):
|
||||||
fmt = 'xml'
|
fmt = 'xml'
|
||||||
|
@ -238,6 +238,11 @@ class TestL3NatBasePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||||||
self._process_l3_update(context, net, network['network'])
|
self._process_l3_update(context, net, network['network'])
|
||||||
return net
|
return net
|
||||||
|
|
||||||
|
def delete_network(self, context, id):
|
||||||
|
with context.session.begin(subtransactions=True):
|
||||||
|
self._process_l3_delete(context, id)
|
||||||
|
super(TestL3NatBasePlugin, self).delete_network(context, id)
|
||||||
|
|
||||||
def delete_port(self, context, id, l3_port_check=True):
|
def delete_port(self, context, id, l3_port_check=True):
|
||||||
plugin = NeutronManager.get_service_plugins().get(
|
plugin = NeutronManager.get_service_plugins().get(
|
||||||
service_constants.L3_ROUTER_NAT)
|
service_constants.L3_ROUTER_NAT)
|
||||||
@ -1700,6 +1705,13 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
|
|||||||
s['subnet']['id'],
|
s['subnet']['id'],
|
||||||
None)
|
None)
|
||||||
|
|
||||||
|
def test_delete_ext_net_with_disassociated_floating_ips(self):
|
||||||
|
with self.network() as net:
|
||||||
|
net_id = net['network']['id']
|
||||||
|
self._set_net_external(net_id)
|
||||||
|
with self.subnet(network=net, do_delete=False):
|
||||||
|
self._make_floatingip(self.fmt, net_id)
|
||||||
|
|
||||||
|
|
||||||
class L3AgentDbTestCaseBase(L3NatTestCaseMixin):
|
class L3AgentDbTestCaseBase(L3NatTestCaseMixin):
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user