Merge "Delete disassociated floating ips on external network deletion"
This commit is contained in:
commit
9218afc8cb
@ -25,6 +25,8 @@ from neutron.db import db_base_plugin_v2
|
||||
from neutron.db import model_base
|
||||
from neutron.db import models_v2
|
||||
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
|
||||
@ -135,6 +137,12 @@ class External_net_db_mixin(object):
|
||||
network_id=net_id).delete()
|
||||
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):
|
||||
vals = filters and filters.get(external_net.EXTERNAL, [])
|
||||
if not vals:
|
||||
|
@ -798,6 +798,14 @@ class L3_NAT_db_mixin(l3.RouterPluginBase):
|
||||
marker_obj=marker_obj,
|
||||
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):
|
||||
return self._get_collection_count(context, FloatingIP,
|
||||
filters=filters)
|
||||
|
@ -615,18 +615,8 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
|
||||
|
||||
# Validate args
|
||||
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):
|
||||
self._process_l3_delete(context, net_id)
|
||||
ret_val = super(NeutronRestProxyV2, self).delete_network(context,
|
||||
net_id)
|
||||
self._send_delete_network(orig_net, context)
|
||||
@ -1092,6 +1082,18 @@ class NeutronRestProxyV2(NeutronRestProxyV2Base,
|
||||
port_id)
|
||||
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):
|
||||
try:
|
||||
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):
|
||||
self._process_l3_delete(context, net_id)
|
||||
result = super(BrocadePluginV2, self).delete_network(context,
|
||||
net_id)
|
||||
# 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 record, so explicit removal is not necessary
|
||||
self._send_delete_network_request(context, network)
|
||||
|
||||
self._process_l3_delete(context, id)
|
||||
super(N1kvNeutronPluginV2, self).delete_network(context, id)
|
||||
LOG.debug(_("Deleted network: %s"), id)
|
||||
|
||||
|
@ -276,6 +276,7 @@ class HyperVNeutronPlugin(agents_db.AgentDbMixin,
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
binding = self._db.get_network_binding(session, id)
|
||||
self._process_l3_delete(context, id)
|
||||
super(HyperVNeutronPlugin, self).delete_network(context, id)
|
||||
p = self._network_providers_map[binding.network_type]
|
||||
p.delete_network(session, binding)
|
||||
|
@ -236,7 +236,11 @@ class SdnvePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
@_ha
|
||||
def delete_network(self, context, 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)
|
||||
if res not in constants.HTTP_ACCEPTABLE:
|
||||
|
@ -444,6 +444,7 @@ class LinuxBridgePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
binding = db.get_network_binding(session, id)
|
||||
self._process_l3_delete(context, id)
|
||||
super(LinuxBridgePluginV2, self).delete_network(context, id)
|
||||
if binding.vlan_id != constants.LOCAL_VLAN_ID:
|
||||
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)
|
||||
self.client.delete_bridge(id)
|
||||
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:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_('Failed to delete neutron db, while Midonet '
|
||||
|
@ -457,6 +457,8 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
while True:
|
||||
try:
|
||||
with session.begin(subtransactions=True):
|
||||
self._process_l3_delete(context, id)
|
||||
|
||||
# Get ports to auto-delete.
|
||||
ports = (session.query(models_v2.Port).
|
||||
enable_eagerloads(False).
|
||||
|
@ -379,6 +379,7 @@ class MellanoxEswitchPlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
binding = db.get_network_binding(session, net_id)
|
||||
self._process_l3_delete(context, net_id)
|
||||
super(MellanoxEswitchPlugin, self).delete_network(context,
|
||||
net_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']
|
||||
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
|
||||
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)
|
||||
if not only_auto_del:
|
||||
raise n_exc.NetworkInUse(net_id=id)
|
||||
|
||||
self._process_l3_delete(context, id)
|
||||
|
||||
# Make sure auto-delete ports on OFC are deleted.
|
||||
# If an error occurs during port deletion,
|
||||
# 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)
|
||||
|
||||
# delete all packet_filters of the network from the controller
|
||||
|
@ -305,11 +305,13 @@ class NuagePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
return net
|
||||
|
||||
def delete_network(self, context, id):
|
||||
filter = {'network_id': [id]}
|
||||
subnets = self.get_subnets(context, filters=filter)
|
||||
for subnet in subnets:
|
||||
self.delete_subnet(context, subnet['id'])
|
||||
super(NuagePlugin, self).delete_network(context, id)
|
||||
with context.session.begin(subtransactions=True):
|
||||
self._process_l3_delete(context, id)
|
||||
filter = {'network_id': [id]}
|
||||
subnets = self.get_subnets(context, filters=filter)
|
||||
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):
|
||||
subn = subnet['subnet']
|
||||
|
@ -221,6 +221,7 @@ class OneConvergencePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
#get all the subnets under the network to delete them
|
||||
subnets = self._get_subnets_by_network(context, net_id)
|
||||
|
||||
self._process_l3_delete(context, net_id)
|
||||
super(OneConvergencePluginV2, self).delete_network(context,
|
||||
net_id)
|
||||
|
||||
|
@ -526,6 +526,7 @@ class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
binding = ovs_db_v2.get_network_binding(session, id)
|
||||
self._process_l3_delete(context, id)
|
||||
super(OVSNeutronPluginV2, self).delete_network(context, id)
|
||||
if binding.network_type in constants.TUNNEL_NETWORK_TYPES:
|
||||
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)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
self._process_l3_delete(context, net_id)
|
||||
# Plugin DB - Network Delete
|
||||
super(NeutronPluginPLUMgridV2, self).delete_network(context,
|
||||
net_id)
|
||||
|
@ -202,6 +202,7 @@ class RyuNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
self.tunnel_key.delete(session, id)
|
||||
self._process_l3_delete(context, id)
|
||||
super(RyuNeutronPluginV2, self).delete_network(context, id)
|
||||
|
||||
def create_port(self, context, port):
|
||||
|
@ -1033,7 +1033,10 @@ class NsxPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
if not external:
|
||||
lswitch_ids = nsx_utils.get_nsx_switch_ids(
|
||||
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
|
||||
for port in router_iface_ports:
|
||||
try:
|
||||
|
@ -43,7 +43,10 @@ class Fake1(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
return net
|
||||
|
||||
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):
|
||||
port = super(Fake1, self).create_port(context, port)
|
||||
|
@ -18,6 +18,7 @@
|
||||
import contextlib
|
||||
import itertools
|
||||
|
||||
import mock
|
||||
import testtools
|
||||
from webob import exc
|
||||
|
||||
@ -158,6 +159,18 @@ class ExtNetDBTestCase(test_db_plugin.NeutronDbPluginV2TestCase):
|
||||
self.assertEqual(ext_net['network'][external_net.EXTERNAL],
|
||||
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):
|
||||
fmt = 'xml'
|
||||
|
@ -238,6 +238,11 @@ class TestL3NatBasePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
self._process_l3_update(context, net, network['network'])
|
||||
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):
|
||||
plugin = NeutronManager.get_service_plugins().get(
|
||||
service_constants.L3_ROUTER_NAT)
|
||||
@ -1700,6 +1705,13 @@ class L3NatTestCaseBase(L3NatTestCaseMixin):
|
||||
s['subnet']['id'],
|
||||
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):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user