Merge "Delete disassociated floating ips on external network deletion"

This commit is contained in:
Jenkins 2014-04-23 15:45:53 +00:00 committed by Gerrit Code Review
commit cf22dd2ff9
21 changed files with 99 additions and 23 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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:

View File

@ -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,

View File

@ -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 '

View File

@ -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).

View File

@ -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:

View File

@ -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

View File

@ -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']

View File

@ -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)

View File

@ -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,

View File

@ -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)

View File

@ -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):

View File

@ -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:

View File

@ -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)

View File

@ -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'

View File

@ -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):