From e5c9b7ecc62e1b9400d20540c7d5c10982506d3a Mon Sep 17 00:00:00 2001 From: "Alexey I. Froloff" Date: Tue, 22 Sep 2015 14:39:40 +0300 Subject: [PATCH] Fix more inconsistency between Nova-Net and Neutron The commit c62f698ef1f1e69bd5eb3c6544ee305f96488d42 fixed one incosistency between Nova-Net and Neutron, when Neutron returns 404 error for list_floatingip and Nova translates it into 500 computeFault. However, there are two other places where list_floatingips is called. Move common code into private helper function, where 404 Error from Neutron is gracefully handled, and use it where appropriate. Closes-Bug: #1498443 Related-Bug: #1163670 Change-Id: I9229d882712df1ad57afbda7477fa4d72f4fd83c --- nova/network/neutronv2/api.py | 34 ++++++++++-------- nova/tests/unit/network/test_neutronv2.py | 42 +++++++++++++++++++++-- 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/nova/network/neutronv2/api.py b/nova/network/neutronv2/api.py index 0782d48dcc92..f2e6c36f04ee 100644 --- a/nova/network/neutronv2/api.py +++ b/nova/network/neutronv2/api.py @@ -1400,7 +1400,9 @@ class API(base_api.NetworkAPI): def get_floating_ips_by_project(self, context): client = get_client(context) project_id = context.project_id - fips = client.list_floatingips(tenant_id=project_id)['floatingips'] + fips = self._safe_get_floating_ips(client, tenant_id=project_id) + if not fips: + return [] pool_dict = self._setup_pools_dict(client) port_dict = self._setup_ports_dict(client, project_id) return [self._format_floating_ip_model(fip, pool_dict, port_dict) @@ -1458,12 +1460,25 @@ class API(base_api.NetworkAPI): return fip['floatingip']['floating_ip_address'] + def _safe_get_floating_ips(self, client, **kwargs): + """Get floatingip gracefully handling 404 from Neutron.""" + try: + return client.list_floatingips(**kwargs)['floatingips'] + # If a neutron plugin does not implement the L3 API a 404 from + # list_floatingips will be raised. + except neutron_client_exc.NotFound: + return [] + except neutron_client_exc.NeutronClientException: + with excutils.save_and_reraise_exception(): + LOG.exception(_LE('Unable to access floating IP for %s'), + ', '.join(['%s %s' % (k, v) + for k, v in six.iteritems(kwargs)])) + def _get_floating_ip_by_address(self, client, address): """Get floatingip from floating ip address.""" if not address: raise exception.FloatingIpNotFoundForAddress(address=address) - data = client.list_floatingips(floating_ip_address=address) - fips = data['floatingips'] + fips = self._safe_get_floating_ips(client, floating_ip_address=address) if len(fips) == 0: raise exception.FloatingIpNotFoundForAddress(address=address) elif len(fips) > 1: @@ -1472,19 +1487,8 @@ class API(base_api.NetworkAPI): def _get_floating_ips_by_fixed_and_port(self, client, fixed_ip, port): """Get floatingips from fixed ip and port.""" - try: - data = client.list_floatingips(fixed_ip_address=fixed_ip, + return self._safe_get_floating_ips(client, fixed_ip_address=fixed_ip, port_id=port) - # If a neutron plugin does not implement the L3 API a 404 from - # list_floatingips will be raised. - except neutron_client_exc.NeutronClientException as e: - if e.status_code == 404: - return [] - with excutils.save_and_reraise_exception(): - LOG.exception(_LE('Unable to access floating IP %(fixed_ip)s ' - 'for port %(port_id)s'), - {'fixed_ip': fixed_ip, 'port_id': port}) - return data['floatingips'] def release_floating_ip(self, context, address, affect_auto_assigned=False): diff --git a/nova/tests/unit/network/test_neutronv2.py b/nova/tests/unit/network/test_neutronv2.py index 5161f0d983c6..a457394de0fb 100644 --- a/nova/tests/unit/network/test_neutronv2.py +++ b/nova/tests/unit/network/test_neutronv2.py @@ -2335,8 +2335,7 @@ class TestNeutronv2(TestNeutronv2Base): def test_list_floating_ips_without_l3_support(self): api = neutronapi.API() - NeutronNotFound = exceptions.NeutronClientException( - status_code=404) + NeutronNotFound = exceptions.NotFound() self.moxed_client.list_floatingips( fixed_ip_address='1.1.1.1', port_id=1).AndRaise(NeutronNotFound) self.mox.ReplayAll() @@ -3560,6 +3559,45 @@ class TestNeutronv2WithMock(test.TestCase): mock.sentinel.ctx, mock_inst, requested_networks=nw_req) + @mock.patch('nova.network.neutronv2.api.get_client') + def test_get_floating_ip_by_address_not_found_neutron_not_found(self, + mock_ntrn): + mock_nc = mock.Mock() + mock_ntrn.return_value = mock_nc + mock_nc.list_floatingips.side_effect = exceptions.NotFound() + address = '172.24.4.227' + self.assertRaises(exception.FloatingIpNotFoundForAddress, + self.api.get_floating_ip_by_address, + self.context, address) + + @mock.patch('nova.network.neutronv2.api.get_client') + def test_get_floating_ip_by_address_not_found_neutron_raises_non404(self, + mock_ntrn): + mock_nc = mock.Mock() + mock_ntrn.return_value = mock_nc + mock_nc.list_floatingips.side_effect = exceptions.InternalServerError() + address = '172.24.4.227' + self.assertRaises(exceptions.InternalServerError, + self.api.get_floating_ip_by_address, + self.context, address) + + @mock.patch('nova.network.neutronv2.api.get_client') + def test_get_floating_ips_by_project_not_found(self, mock_ntrn): + mock_nc = mock.Mock() + mock_ntrn.return_value = mock_nc + mock_nc.list_floatingips.side_effect = exceptions.NotFound() + fips = self.api.get_floating_ips_by_project(self.context) + self.assertEqual([], fips) + + @mock.patch('nova.network.neutronv2.api.get_client') + def test_get_floating_ips_by_project_raises_non404(self, mock_ntrn): + mock_nc = mock.Mock() + mock_ntrn.return_value = mock_nc + mock_nc.list_floatingips.side_effect = exceptions.InternalServerError() + self.assertRaises(exceptions.InternalServerError, + self.api.get_floating_ips_by_project, + self.context) + class TestNeutronv2ModuleMethods(test.NoDBTestCase):