Handle over quota exception from Neutron

When using the floating IP in Nova with Neutron, and
a quota limit is exceeded in Neutron, the exception from
the Neutron client results in Nova generating a 500 error.
This is unhelpful to user, and not consistent with nova-networking
Return FloatingIPExceedLimit exception when quota exceeded.

Change I8788993578ac872da9f676fe3e2fb8f98414289d at neutronclient
add OverQuotaClient exception and it is used in this patch

Change-Id: Ieb90521cf231acae8b5a9920acf6c77f2e34ef67
Closes-Bug: #1210598
Closes-Bug: #1301117
This commit is contained in:
Huang Rui 2013-12-16 22:14:55 -05:00 committed by jichenjc
parent b8e3902881
commit 9f06c76645
4 changed files with 43 additions and 3 deletions

View File

@ -163,6 +163,12 @@ class FloatingIPController(object):
else:
msg = _("No more floating ips available.")
raise webob.exc.HTTPNotFound(explanation=msg)
except exception.FloatingIpLimitExceeded:
if pool:
msg = _("IP allocation over quota in pool %s.") % pool
else:
msg = _("IP allocation over quota.")
raise webob.exc.HTTPForbidden(explanation=msg)
return _translate_floating_ip_view(ip)

View File

@ -975,15 +975,15 @@ class API(base_api.NetworkAPI):
pool = pool or CONF.default_floating_pool
pool_id = self._get_floating_ip_pool_id_by_name_or_id(client, pool)
# TODO(amotoki): handle exception during create_floatingip()
# At this timing it is ensured that a network for pool exists.
# quota error may be returned.
param = {'floatingip': {'floating_network_id': pool_id}}
try:
fip = client.create_floatingip(param)
except (neutron_client_exc.IpAddressGenerationFailureClient,
neutron_client_exc.ExternalIpAddressExhaustedClient) as e:
raise exception.NoMoreFloatingIps(unicode(e))
except neutron_client_exc.OverQuotaClient as e:
raise exception.FloatingIpLimitExceeded(unicode(e))
return fip['floatingip']['floating_ip_address']
def _get_floating_ip_by_address(self, client, address):

View File

@ -325,6 +325,25 @@ class FloatingIpTest(test.TestCase):
self.assertIn('No more floating ips in pool non_existent_pool',
ex.explanation)
@mock.patch('nova.network.api.API.allocate_floating_ip',
side_effect=exception.FloatingIpLimitExceeded())
def test_floating_ip_allocate_over_quota(self, allocate_mock):
req = fakes.HTTPRequest.blank('/v2/fake/os-floating-ips')
ex = self.assertRaises(webob.exc.HTTPForbidden,
self.controller.create, req)
self.assertIn('IP allocation over quota', ex.explanation)
@mock.patch('nova.network.api.API.allocate_floating_ip',
side_effect=exception.FloatingIpLimitExceeded())
def test_floating_ip_allocate_quota_exceed_in_pool(self, allocate_mock):
req = fakes.HTTPRequest.blank('/v2/fake/os-floating-ips')
ex = self.assertRaises(webob.exc.HTTPForbidden,
self.controller.create, req, {'pool': 'non_existent_pool'})
self.assertIn('IP allocation over quota in pool non_existent_pool.',
ex.explanation)
def test_floating_ip_allocate(self):
def fake1(*args, **kwargs):
pass

View File

@ -2311,6 +2311,21 @@ class TestNeutronv2WithMock(test.TestCase):
list_ports_mock.assert_called_once_with(**list_port_mock_params)
def test_allocate_floating_ip_exceed_limit(self):
# Verify that the correct exception is thrown when quota exceed
pool_name = 'dummy'
api = neutronapi.API()
with contextlib.nested(
mock.patch.object(client.Client, 'create_floatingip'),
mock.patch.object(api,
'_get_floating_ip_pool_id_by_name_or_id')) as (
create_mock, get_mock):
create_mock.side_effect = neutronv2.exceptions.OverQuotaClient()
self.assertRaises(exception.FloatingIpLimitExceeded,
api.allocate_floating_ip,
self.context, pool_name)
class TestNeutronv2ModuleMethods(test.TestCase):