Skip to content

Commit 43926eb

Browse files
committed
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 (cherry picked from commit 8ff0fae)
1 parent db40cc4 commit 43926eb

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

nova/api/openstack/compute/attach_interfaces.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def show(self, req, server_id, id):
133133
context, port_info['port'],
134134
show_tag=api_version_request.is_supported(req, '2.70'))}
135135

136-
@wsgi.expected_errors((400, 404, 409, 500, 501))
136+
@wsgi.expected_errors((400, 403, 404, 409, 500, 501))
137137
@validation.schema(attach_interfaces.create, '2.0', '2.48')
138138
@validation.schema(attach_interfaces.create_v249, '2.49')
139139
def create(self, req, server_id, body):
@@ -183,6 +183,8 @@ def create(self, req, server_id, body):
183183
except (exception.PortNotFound,
184184
exception.NetworkNotFound) as e:
185185
raise exc.HTTPNotFound(explanation=e.format_message())
186+
except exception.PortLimitExceeded as e:
187+
raise exc.HTTPForbidden(explanation=e.format_message())
186188
except exception.InterfaceAttachFailed as e:
187189
raise webob.exc.HTTPInternalServerError(
188190
explanation=e.format_message())

nova/tests/unit/api/openstack/compute/test_attach_interfaces.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# under the License.
1515

1616
import mock
17+
import six
1718
from webob import exc
1819

1920
from nova.api.openstack import common
@@ -308,6 +309,20 @@ def fake_attach_interface_invalid_state(*args, **kwargs):
308309
self.attachments.create, self.req, FAKE_UUID1,
309310
body=body)
310311

312+
def test_attach_interface_port_limit_exceeded(self):
313+
"""Tests the scenario where nova-compute attempts to create a port to
314+
attach but the tenant port quota is exceeded and PortLimitExceeded
315+
is raised from the neutron API code which results in a 403 response.
316+
"""
317+
with mock.patch.object(self.attachments.compute_api,
318+
'attach_interface',
319+
side_effect=exception.PortLimitExceeded):
320+
body = {'interfaceAttachment': {}}
321+
ex = self.assertRaises(
322+
exc.HTTPForbidden, self.attachments.create,
323+
self.req, FAKE_UUID1, body=body)
324+
self.assertIn('Maximum number of ports exceeded', six.text_type(ex))
325+
311326
def test_detach_interface_with_invalid_state(self):
312327
def fake_detach_interface_invalid_state(*args, **kwargs):
313328
raise exception.InstanceInvalidState(

0 commit comments

Comments
 (0)