Skip to content

Commit 410ce2f

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Return 409 Conflict to tenant user deleting port attached to FIP" into stable/yoga
2 parents 2544a20 + 3328be0 commit 410ce2f

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

neutron/db/l3_db.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@
8181
'port: %(port_id)s.')
8282

8383

84+
# TODO(froyo): Move this exception to neutron-lib as soon as possible, and when
85+
# a new release is created and pointed to in the requirements remove this code.
86+
class FipAssociated(n_exc.InUse):
87+
message = _('Unable to complete the operation on port "%(port_id)s" '
88+
'because the port still has an associated floating IP.')
89+
90+
8491
@registry.has_registry_receivers
8592
class L3_NAT_dbonly_mixin(l3.RouterPluginBase,
8693
base_services.WorkerBase,
@@ -1766,12 +1773,27 @@ def disassociate_floatingips(self, context, port_id, do_notify=True):
17661773
@return: set of router-ids that require notification updates
17671774
"""
17681775
with db_api.CONTEXT_WRITER.using(context):
1776+
# NOTE(froyo): Context is elevated to confirm the presence of at
1777+
# least one FIP associated to the port_id. Additional checks
1778+
# regarding the tenant's grants will be carried out in following
1779+
# lines.
17691780
if not l3_obj.FloatingIP.objects_exist(
1770-
context, fixed_port_id=port_id):
1781+
context.elevated(), fixed_port_id=port_id):
17711782
return []
17721783

17731784
floating_ip_objs = l3_obj.FloatingIP.get_objects(
17741785
context, fixed_port_id=port_id)
1786+
1787+
# NOTE(froyo): To ensure that a FIP assigned by an admin user
1788+
# cannot be disassociated by a tenant user, we raise exception to
1789+
# generate a 409 Conflict response message that prompts the tenant
1790+
# user to contact an admin, rather than a 500 error message.
1791+
if not context.is_admin:
1792+
floating_ip_objs_admin = l3_obj.FloatingIP.get_objects(
1793+
context.elevated(), fixed_port_id=port_id)
1794+
if floating_ip_objs_admin != floating_ip_objs:
1795+
raise FipAssociated(port_id=port_id)
1796+
17751797
router_ids = {fip.router_id for fip in floating_ip_objs}
17761798
old_fips = {fip.id: self._make_floatingip_dict(fip)
17771799
for fip in floating_ip_objs}

neutron/tests/unit/db/test_l3_db.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,27 @@ def test_prevent_l3_port_existing_floating_ip(self, gp):
328328

329329
self.db.prevent_l3_port_deletion(ctx, None)
330330

331+
@mock.patch.object(l3_obj.FloatingIP, 'objects_exist')
332+
@mock.patch.object(l3_obj.FloatingIP, 'get_objects')
333+
def test_disassociate_floatingips_conflict_by_fip_attached(self,
334+
get_objects,
335+
objects_exist):
336+
context_tenant = context.Context('tenant', 'tenant', is_admin=False)
337+
objects_exist.return_value = True
338+
get_objects.side_effect = [
339+
[],
340+
[{'id': 'floating_ip1', 'port_id': 'port_id'}]]
341+
self.assertRaises(l3_db.FipAssociated,
342+
self.db.disassociate_floatingips,
343+
context_tenant,
344+
'port_id')
345+
objects_exist.assert_called_once_with(
346+
mock.ANY, fixed_port_id='port_id')
347+
expected_calls = [
348+
mock.call(context_tenant, fixed_port_id='port_id'),
349+
mock.call(mock.ANY, fixed_port_id='port_id')]
350+
get_objects.assert_has_calls(expected_calls)
351+
331352
@mock.patch.object(directory, 'get_plugin')
332353
def test_subscribe_address_scope_of_subnetpool(self, gp):
333354
l3_db.L3RpcNotifierMixin()

0 commit comments

Comments
 (0)