Handle PortLimitExceeded in POST /servers/{server_id}/os-interface

When attaching an interface to a server, if an existing port is not
specified, nova-compute will attempt to create a port on either the
user-specified network or the network that is available to the tenant.

If the tenant exceeds their port quota in neutron, a PortLimitExceeded
exception is raised up from nova-compute [1] which is not being handled
in the API controller code - which is fixed in this change.

Note that this is one of the few synchronous RPC call operations [2]
in the compute API so exceptions from the compute service will leak
back to the API like in this case and need to be handled to avoid a
500 response to the user.

The 403 response used here matches how PortLimitExceeded is handled in
the server create API [3].

[1] https://github.com/openstack/nova/blob/6ebb2c4ca/nova/network/neutronv2/api.py#L565
[2] https://github.com/openstack/nova/blob/6ebb2c4ca/nova/compute/rpcapi.py#L489
[3] https://github.com/openstack/nova/blob/6ebb2c4ca/nova/api/openstack/compute/servers.py#L688

Change-Id: I5687480a22542eea31d299442837bd64bf731285
Closes-Bug: #1823203
This commit is contained in:
Matt Riedemann 2019-04-04 14:44:02 -04:00
parent 6ebb2c4cae
commit 8ff0fae42b
2 changed files with 18 additions and 1 deletions

View File

@ -133,7 +133,7 @@ class InterfaceAttachmentController(wsgi.Controller):
context, port_info['port'],
show_tag=api_version_request.is_supported(req, '2.70'))}
@wsgi.expected_errors((400, 404, 409, 500, 501))
@wsgi.expected_errors((400, 403, 404, 409, 500, 501))
@validation.schema(attach_interfaces.create, '2.0', '2.48')
@validation.schema(attach_interfaces.create_v249, '2.49')
def create(self, req, server_id, body):
@ -183,6 +183,8 @@ class InterfaceAttachmentController(wsgi.Controller):
except (exception.PortNotFound,
exception.NetworkNotFound) as e:
raise exc.HTTPNotFound(explanation=e.format_message())
except exception.PortLimitExceeded as e:
raise exc.HTTPForbidden(explanation=e.format_message())
except exception.InterfaceAttachFailed as e:
raise webob.exc.HTTPInternalServerError(
explanation=e.format_message())

View File

@ -14,6 +14,7 @@
# under the License.
import mock
import six
from webob import exc
from nova.api.openstack import common
@ -308,6 +309,20 @@ class InterfaceAttachTestsV21(test.NoDBTestCase):
self.attachments.create, self.req, FAKE_UUID1,
body=body)
def test_attach_interface_port_limit_exceeded(self):
"""Tests the scenario where nova-compute attempts to create a port to
attach but the tenant port quota is exceeded and PortLimitExceeded
is raised from the neutron API code which results in a 403 response.
"""
with mock.patch.object(self.attachments.compute_api,
'attach_interface',
side_effect=exception.PortLimitExceeded):
body = {'interfaceAttachment': {}}
ex = self.assertRaises(
exc.HTTPForbidden, self.attachments.create,
self.req, FAKE_UUID1, body=body)
self.assertIn('Maximum number of ports exceeded', six.text_type(ex))
def test_detach_interface_with_invalid_state(self):
def fake_detach_interface_invalid_state(*args, **kwargs):
raise exception.InstanceInvalidState(