Handle neutron exception on bad floating ip create request
This commit adds a new nova exception to handle a floating ip create failure with a BadRequest exception from neutronclient. This is then used in all 3 nova api implementations to ensure a 400 response is returned just as neutron is returning to nova. Change-Id: I36e8ef0113ae91e3b15c846c6d10e0b766cf2a37 Closes-Bug: #1482816
This commit is contained in:
parent
19810750b4
commit
f500f99aad
|
@ -616,6 +616,7 @@ class Executor(wsgi.Application):
|
|||
except (exception.CannotDisassociateAutoAssignedFloatingIP,
|
||||
exception.FloatingIpAssociated,
|
||||
exception.FloatingIpNotFound,
|
||||
exception.FloatingIpBadRequest,
|
||||
exception.ImageNotActive,
|
||||
exception.InvalidInstanceIDMalformed,
|
||||
exception.InvalidVolumeIDMalformed,
|
||||
|
|
|
@ -118,7 +118,7 @@ class FloatingIPController(object):
|
|||
|
||||
return _translate_floating_ips_view(floating_ips)
|
||||
|
||||
@extensions.expected_errors((403, 404))
|
||||
@extensions.expected_errors((400, 403, 404))
|
||||
def create(self, req, body=None):
|
||||
context = req.environ['nova.context']
|
||||
authorize(context)
|
||||
|
@ -143,6 +143,8 @@ class FloatingIPController(object):
|
|||
raise webob.exc.HTTPForbidden(explanation=msg)
|
||||
except exception.FloatingIpPoolNotFound as e:
|
||||
raise webob.exc.HTTPNotFound(explanation=e.format_message())
|
||||
except exception.FloatingIpBadRequest as e:
|
||||
raise webob.exc.HTTPBadRequest(explanation=e.format_message())
|
||||
|
||||
return _translate_floating_ip_view(ip)
|
||||
|
||||
|
|
|
@ -128,6 +128,8 @@ class FloatingIPController(object):
|
|||
raise webob.exc.HTTPForbidden(explanation=msg)
|
||||
except exception.FloatingIpPoolNotFound as e:
|
||||
raise webob.exc.HTTPNotFound(explanation=e.format_message())
|
||||
except exception.FloatingIpBadRequest as e:
|
||||
raise webob.exc.HTTPBadRequest(explanation=e.format_message())
|
||||
|
||||
return _translate_floating_ip_view(ip)
|
||||
|
||||
|
|
|
@ -900,6 +900,11 @@ class FloatingIpAssociateFailed(NovaException):
|
|||
msg_fmt = _("Floating IP %(address)s association has failed.")
|
||||
|
||||
|
||||
class FloatingIpBadRequest(Invalid):
|
||||
ec2_code = "UnsupportedOperation"
|
||||
msg_fmt = _("The floating IP request failed with a BadRequest")
|
||||
|
||||
|
||||
class CannotDisassociateAutoAssignedFloatingIP(NovaException):
|
||||
ec2_code = "UnsupportedOperation"
|
||||
msg_fmt = _("Cannot disassociate auto assigned floating ip")
|
||||
|
|
|
@ -1399,6 +1399,8 @@ class API(base_api.NetworkAPI):
|
|||
raise exception.NoMoreFloatingIps(six.text_type(e))
|
||||
except neutron_client_exc.OverQuotaClient as e:
|
||||
raise exception.FloatingIpLimitExceeded(six.text_type(e))
|
||||
except neutron_client_exc.BadRequest as e:
|
||||
raise exception.FloatingIpBadRequest(six.text_type(e))
|
||||
|
||||
return fip['floatingip']['floating_ip_address']
|
||||
|
||||
|
|
|
@ -150,6 +150,13 @@ class ExecutorTestCase(test.NoDBTestCase):
|
|||
self.assertIn('vol-00000005', self._extract_message(result))
|
||||
self.assertEqual('InvalidVolume.NotFound', self._extract_code(result))
|
||||
|
||||
def test_floating_ip_bad_create_request(self):
|
||||
def bad_request(context):
|
||||
raise exception.FloatingIpBadRequest()
|
||||
result = self._execute(bad_request)
|
||||
self.assertIn('BadRequest', self._extract_message(result))
|
||||
self.assertEqual('UnsupportedOperation', self._extract_code(result))
|
||||
|
||||
|
||||
class FakeResponse(object):
|
||||
reason = "Test Reason"
|
||||
|
|
|
@ -18,6 +18,7 @@ import contextlib
|
|||
import uuid
|
||||
|
||||
import mock
|
||||
import six
|
||||
import webob
|
||||
|
||||
from nova.api.openstack.compute import floating_ips as fips_v21
|
||||
|
@ -428,6 +429,18 @@ class FloatingIpTestV21(test.TestCase):
|
|||
self.assertIn('No more floating ips in pool non_existent_pool',
|
||||
ex.explanation)
|
||||
|
||||
@mock.patch.object(network.api.API, 'allocate_floating_ip',
|
||||
side_effect=exception.FloatingIpBadRequest(
|
||||
'Bad floatingip request: Network '
|
||||
'c8f0e88f-ae41-47cb-be6c-d8256ba80576 does not contain any '
|
||||
'IPv4 subnet'))
|
||||
def test_floating_ip_allocate_no_ipv4_subnet(self, allocate_mock):
|
||||
ex = self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.create, self.fake_req,
|
||||
{'pool': 'non_existent_pool'})
|
||||
self.assertIn("does not contain any IPv4 subnet",
|
||||
six.text_type(ex))
|
||||
|
||||
@mock.patch('nova.network.api.API.allocate_floating_ip',
|
||||
side_effect=exception.FloatingIpLimitExceeded())
|
||||
def test_floating_ip_allocate_over_quota(self, allocate_mock):
|
||||
|
|
|
@ -3018,6 +3018,22 @@ class TestNeutronv2WithMock(test.TestCase):
|
|||
api.allocate_floating_ip,
|
||||
self.context, pool_name)
|
||||
|
||||
def test_allocate_floating_ip_no_ipv4_subnet(self):
|
||||
api = neutronapi.API()
|
||||
net_id = uuid.uuid4()
|
||||
error_msg = ('Bad floatingip request: Network %s does not contain '
|
||||
'any IPv4 subnet' % net_id)
|
||||
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 = exceptions.BadRequest(error_msg)
|
||||
|
||||
self.assertRaises(exception.FloatingIpBadRequest,
|
||||
api.allocate_floating_ip, self.context,
|
||||
'ext_net')
|
||||
|
||||
def test_create_port_for_instance_no_more_ip(self):
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
net = {'id': 'my_netid1',
|
||||
|
|
Loading…
Reference in New Issue