diff --git a/nova/api/openstack/compute/attach_interfaces.py b/nova/api/openstack/compute/attach_interfaces.py index 91040781e887..a027b33664bb 100644 --- a/nova/api/openstack/compute/attach_interfaces.py +++ b/nova/api/openstack/compute/attach_interfaces.py @@ -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()) diff --git a/nova/tests/unit/api/openstack/compute/test_attach_interfaces.py b/nova/tests/unit/api/openstack/compute/test_attach_interfaces.py index 5492b1aac187..c1d61679828c 100644 --- a/nova/tests/unit/api/openstack/compute/test_attach_interfaces.py +++ b/nova/tests/unit/api/openstack/compute/test_attach_interfaces.py @@ -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(