From 33b45e7dd43d4a94ef3a20a96c157e3b14616cc2 Mon Sep 17 00:00:00 2001 From: Nachi Ueno Date: Thu, 25 Oct 2012 21:14:48 +0000 Subject: [PATCH] Make create_floatingip support transaction Fixes bug #1064748 Also added unit test Change-Id: I82b2031af0a87a92ace9a8b86f89772beaca5e8f --- quantum/db/l3_db.py | 39 +++++++++++++--------------- quantum/tests/unit/test_l3_plugin.py | 39 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/quantum/db/l3_db.py b/quantum/db/l3_db.py index d03d9501d..bd74a4d39 100644 --- a/quantum/db/l3_db.py +++ b/quantum/db/l3_db.py @@ -536,27 +536,26 @@ class L3_NAT_db_mixin(l3.RouterPluginBase): # This external port is never exposed to the tenant. # it is used purely for internal system and admin use when # managing floating IPs. - external_port = self.create_port(context.elevated(), { - 'port': - {'tenant_id': '', # tenant intentionally not set - 'network_id': f_net_id, - 'mac_address': attributes.ATTR_NOT_SPECIFIED, - 'fixed_ips': attributes.ATTR_NOT_SPECIFIED, - 'admin_state_up': True, - 'device_id': fip_id, - 'device_owner': DEVICE_OWNER_FLOATINGIP, - 'name': ''}}) - # Ensure IP addresses are allocated on external port - if not external_port['fixed_ips']: - msg = "Unable to find any IP address on external network" - # remove the external port - self.delete_port(context.elevated(), external_port['id'], - l3_port_check=False) - raise q_exc.BadRequest(resource='floatingip', msg=msg) - - floating_ip_address = external_port['fixed_ips'][0]['ip_address'] try: with context.session.begin(subtransactions=True): + external_port = self.create_port(context.elevated(), { + 'port': + {'tenant_id': '', # tenant intentionally not set + 'network_id': f_net_id, + 'mac_address': attributes.ATTR_NOT_SPECIFIED, + 'fixed_ips': attributes.ATTR_NOT_SPECIFIED, + 'admin_state_up': True, + 'device_id': fip_id, + 'device_owner': DEVICE_OWNER_FLOATINGIP, + 'name': ''}}) + # Ensure IP addresses are allocated on external port + if not external_port['fixed_ips']: + msg = "Unable to find any IP address on external network" + # remove the external port + raise q_exc.BadRequest(resource='floatingip', msg=msg) + + floating_fixed_ip = external_port['fixed_ips'][0] + floating_ip_address = floating_fixed_ip['ip_address'] floatingip_db = FloatingIP( id=fip_id, tenant_id=tenant_id, @@ -578,8 +577,6 @@ class L3_NAT_db_mixin(l3.RouterPluginBase): except Exception: LOG.exception("Floating IP association failed") # Remove the port created for internal purposes - self.delete_port(context.elevated(), external_port['id'], - l3_port_check=False) raise return self._make_floatingip_dict(floatingip_db) diff --git a/quantum/tests/unit/test_l3_plugin.py b/quantum/tests/unit/test_l3_plugin.py index 6482a9f3e..6133bcffd 100644 --- a/quantum/tests/unit/test_l3_plugin.py +++ b/quantum/tests/unit/test_l3_plugin.py @@ -31,6 +31,7 @@ from webob import exc from quantum.api.v2 import attributes from quantum.common import config +from quantum.common import exceptions as q_exc from quantum.common.test_lib import test_config from quantum.common import utils from quantum import context @@ -773,6 +774,44 @@ class L3NatDBTestCase(test_db_plugin.QuantumDbPluginV2TestCase): self._show('floatingips', fip['floatingip']['id'], expected_code=exc.HTTPNotFound.code) + def test_floatingip_with_assoc_fails(self): + fmt = 'json' + with self.subnet() as public_sub: + self._set_net_external(public_sub['subnet']['network_id']) + with self.port() as private_port: + with self.router() as r: + sid = private_port['port']['fixed_ips'][0]['subnet_id'] + private_sub = {'subnet': {'id': sid}} + self._add_external_gateway_to_router( + r['router']['id'], + public_sub['subnet']['network_id']) + self._router_interface_action('add', r['router']['id'], + private_sub['subnet']['id'], + None) + PLUGIN_CLASS = 'quantum.db.l3_db.L3_NAT_db_mixin' + METHOD = PLUGIN_CLASS + '._update_fip_assoc' + with mock.patch(METHOD) as pl: + pl.side_effect = q_exc.BadRequest( + resource='floatingip', + msg='fake_error') + res = self._create_floatingip( + fmt, + public_sub['subnet']['network_id'], + port_id=private_port['port']['id']) + self.assertEqual(res.status_int, 400) + + for p in self._list('ports')['ports']: + if p['device_owner'] == 'network:floatingip': + self.fail('garbage port is not deleted') + + self._remove_external_gateway_from_router( + r['router']['id'], + public_sub['subnet']['network_id']) + self._router_interface_action('remove', + r['router']['id'], + private_sub['subnet']['id'], + None) + def test_floatingip_update(self): with self.port() as p: private_sub = {'subnet': {'id': -- 2.45.2