summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2017-06-12 10:34:45 +0000
committerGerrit Code Review <review@openstack.org>2017-06-12 10:34:45 +0000
commit9fd1fd7f4314ed612e228586f7bfca9cd156f117 (patch)
tree9829f6ab50874176834f48607cb06a9d1ea1d563
parent7c30084d848bb45f713f5dd74988725578334150 (diff)
parent1052ad4d5adbb2cb2794f266f21961340c534b69 (diff)
Merge "Catch neutronclient.NotFound on floating deletion" into stable/ocata
-rw-r--r--nova/api/openstack/compute/floating_ips.py2
-rw-r--r--nova/network/neutronv2/api.py7
-rw-r--r--nova/tests/unit/api/openstack/compute/test_floating_ips.py38
-rw-r--r--nova/tests/unit/network/test_neutronv2.py20
4 files changed, 66 insertions, 1 deletions
diff --git a/nova/api/openstack/compute/floating_ips.py b/nova/api/openstack/compute/floating_ips.py
index db021e5..8275f94 100644
--- a/nova/api/openstack/compute/floating_ips.py
+++ b/nova/api/openstack/compute/floating_ips.py
@@ -201,6 +201,8 @@ class FloatingIPController(wsgi.Controller):
201 except exception.CannotDisassociateAutoAssignedFloatingIP: 201 except exception.CannotDisassociateAutoAssignedFloatingIP:
202 msg = _('Cannot disassociate auto assigned floating IP') 202 msg = _('Cannot disassociate auto assigned floating IP')
203 raise webob.exc.HTTPForbidden(explanation=msg) 203 raise webob.exc.HTTPForbidden(explanation=msg)
204 except exception.FloatingIpNotFoundForAddress as exc:
205 raise webob.exc.HTTPNotFound(explanation=exc.format_message())
204 206
205 207
206class FloatingIPActionController(wsgi.Controller): 208class FloatingIPActionController(wsgi.Controller):
diff --git a/nova/network/neutronv2/api.py b/nova/network/neutronv2/api.py
index ef1d4cc..6ae0e4f 100644
--- a/nova/network/neutronv2/api.py
+++ b/nova/network/neutronv2/api.py
@@ -2008,7 +2008,12 @@ class API(base_api.NetworkAPI):
2008 2008
2009 if raise_if_associated and fip['port_id']: 2009 if raise_if_associated and fip['port_id']:
2010 raise exception.FloatingIpAssociated(address=address) 2010 raise exception.FloatingIpAssociated(address=address)
2011 client.delete_floatingip(fip['id']) 2011 try:
2012 client.delete_floatingip(fip['id'])
2013 except neutron_client_exc.NotFound:
2014 raise exception.FloatingIpNotFoundForAddress(
2015 address=address
2016 )
2012 2017
2013 @base_api.refresh_cache 2018 @base_api.refresh_cache
2014 def disassociate_floating_ip(self, context, instance, address, 2019 def disassociate_floating_ip(self, context, instance, address,
diff --git a/nova/tests/unit/api/openstack/compute/test_floating_ips.py b/nova/tests/unit/api/openstack/compute/test_floating_ips.py
index d184769..d75cb4d 100644
--- a/nova/tests/unit/api/openstack/compute/test_floating_ips.py
+++ b/nova/tests/unit/api/openstack/compute/test_floating_ips.py
@@ -159,6 +159,44 @@ class FloatingIpTestNeutronV21(test.NoDBTestCase):
159 ex = exception.InvalidID(id=1) 159 ex = exception.InvalidID(id=1)
160 self._test_floatingip_delete_not_found(ex, webob.exc.HTTPBadRequest) 160 self._test_floatingip_delete_not_found(ex, webob.exc.HTTPBadRequest)
161 161
162 def _test_floatingip_delete_error_disassociate(self, raised_exc,
163 expected_exc):
164 """Ensure that various exceptions are correctly transformed.
165
166 Handle the myriad exceptions that could be raised from the
167 'disassociate_and_release_floating_ip' call.
168 """
169 req = fakes.HTTPRequest.blank('')
170 with mock.patch.object(self.controller.network_api,
171 'get_floating_ip',
172 return_value={'address': 'foo'}), \
173 mock.patch.object(self.controller.network_api,
174 'get_instance_id_by_floating_address',
175 return_value=None), \
176 mock.patch.object(self.controller.network_api,
177 'disassociate_and_release_floating_ip',
178 side_effect=raised_exc):
179 self.assertRaises(expected_exc,
180 self.controller.delete, req, 1)
181
182 def test_floatingip_delete_error_disassociate_1(self):
183 raised_exc = exception.Forbidden
184 expected_exc = webob.exc.HTTPForbidden
185 self._test_floatingip_delete_error_disassociate(raised_exc,
186 expected_exc)
187
188 def test_floatingip_delete_error_disassociate_2(self):
189 raised_exc = exception.CannotDisassociateAutoAssignedFloatingIP
190 expected_exc = webob.exc.HTTPForbidden
191 self._test_floatingip_delete_error_disassociate(raised_exc,
192 expected_exc)
193
194 def test_floatingip_delete_error_disassociate_3(self):
195 raised_exc = exception.FloatingIpNotFoundForAddress(address='1.1.1.1')
196 expected_exc = webob.exc.HTTPNotFound
197 self._test_floatingip_delete_error_disassociate(raised_exc,
198 expected_exc)
199
162 200
163class FloatingIpTestV21(test.TestCase): 201class FloatingIpTestV21(test.TestCase):
164 floating_ip = "10.10.10.10" 202 floating_ip = "10.10.10.10"
diff --git a/nova/tests/unit/network/test_neutronv2.py b/nova/tests/unit/network/test_neutronv2.py
index 33c9d32..9bd37d3 100644
--- a/nova/tests/unit/network/test_neutronv2.py
+++ b/nova/tests/unit/network/test_neutronv2.py
@@ -3516,6 +3516,26 @@ class TestNeutronv2WithMock(test.TestCase):
3516 api.allocate_floating_ip, self.context, 3516 api.allocate_floating_ip, self.context,
3517 'ext_net') 3517 'ext_net')
3518 3518
3519 @mock.patch('nova.network.neutronv2.api.get_client')
3520 @mock.patch('nova.network.neutronv2.api.API._get_floating_ip_by_address',
3521 return_value={'port_id': None, 'id': 'abc'})
3522 def test_release_floating_ip_not_found(self, mock_get_ip, mock_ntrn):
3523 """Ensure neutron's NotFound exception is correctly handled.
3524
3525 Sometimes, trying to delete a floating IP multiple times in a short
3526 delay can trigger an exception because the operation is not atomic. If
3527 neutronclient's call to delete fails with a NotFound error, then we
3528 should correctly handle this.
3529 """
3530 mock_nc = mock.Mock()
3531 mock_ntrn.return_value = mock_nc
3532 mock_nc.delete_floatingip.side_effect = exceptions.NotFound()
3533 address = '172.24.4.227'
3534
3535 self.assertRaises(exception.FloatingIpNotFoundForAddress,
3536 self.api.release_floating_ip,
3537 self.context, address)
3538
3519 @mock.patch.object(client.Client, 'create_port') 3539 @mock.patch.object(client.Client, 'create_port')
3520 def test_create_port_minimal_raise_no_more_ip(self, create_port_mock): 3540 def test_create_port_minimal_raise_no_more_ip(self, create_port_mock):
3521 instance = fake_instance.fake_instance_obj(self.context) 3541 instance = fake_instance.fake_instance_obj(self.context)