Improve 'attach interface' exception handling

Previously, if a user attempted to launch an instance and specified a
port that belonged to a different tenant, a HTTP 500 Server
Error was returned to the user. This patch changes that to a
more informative HTTPBadRequest exception.

Change-Id: I4a4017407ac7358490974cbffc5b7dbb7a200f44
Closes-bug: #1409617
This commit is contained in:
liyingjun 2015-02-10 15:24:13 +08:00
parent 5ce9ca28cd
commit c4f353b112
5 changed files with 50 additions and 5 deletions

View File

@ -127,7 +127,8 @@ class InterfaceAttachmentController(object):
exception.NoMoreFixedIps,
exception.PortInUse,
exception.NetworkDuplicated,
exception.NetworkAmbiguous) as e:
exception.NetworkAmbiguous,
exception.PortNotUsable) as e:
raise exc.HTTPBadRequest(explanation=e.format_message())
except exception.InstanceIsLocked as e:
raise exc.HTTPConflict(explanation=e.format_message())

View File

@ -117,7 +117,8 @@ class InterfaceAttachmentController(wsgi.Controller):
instance, network_id, port_id, req_ip)
except (exception.NetworkDuplicated,
exception.NetworkAmbiguous,
exception.NoMoreFixedIps) as e:
exception.NoMoreFixedIps,
exception.PortNotUsable) as e:
raise exc.HTTPBadRequest(explanation=e.format_message())
except (exception.InstanceIsLocked,
exception.FixedIpAlreadyInUse,

View File

@ -399,6 +399,9 @@ class API(base_api.NetworkAPI):
port = neutron.show_port(request.port_id)['port']
except neutron_client_exc.PortNotFoundClient:
raise exception.PortNotFound(port_id=request.port_id)
if port['tenant_id'] != instance.project_id:
raise exception.PortNotUsable(port_id=request.port_id,
instance=instance.uuid)
if port.get('device_id'):
raise exception.PortInUse(port_id=request.port_id)
if hypervisor_macs is not None:

View File

@ -131,6 +131,7 @@ class InterfaceAttachTestsV21(test.NoDBTestCase):
validate_exc = exception.ValidationError
in_use_exc = exc.HTTPConflict
not_found_exc = exc.HTTPNotFound
not_usable_exc = exc.HTTPBadRequest
def setUp(self):
super(InterfaceAttachTestsV21, self).setUp()
@ -372,6 +373,27 @@ class InterfaceAttachTestsV21(test.NoDBTestCase):
want_objects=True,
expected_attrs=None)
@mock.patch.object(compute_api.API, 'get')
@mock.patch.object(compute_api.API, 'attach_interface')
def test_attach_interface_port_not_usable(self,
attach_mock,
get_mock):
fake_instance = objects.Instance(uuid=FAKE_UUID1)
get_mock.return_value = fake_instance
attach_mock.side_effect = exception.PortNotUsable(
port_id=FAKE_PORT_ID1,
instance=fake_instance.uuid)
body = {}
self.assertRaises(self.not_usable_exc,
self.attachments.create, self.req, FAKE_UUID1,
body=body)
ctxt = self.req.environ['nova.context']
attach_mock.assert_called_once_with(ctxt, fake_instance, None,
None, None)
get_mock.assert_called_once_with(ctxt, FAKE_UUID1,
want_objects=True,
expected_attrs=None)
@mock.patch.object(compute_api.API, 'get')
@mock.patch.object(compute_api.API, 'attach_interface')
def test_attach_interface_no_more_fixed_ips(self,

View File

@ -201,14 +201,15 @@ class TestNeutronv2Base(test.NoDBTestCase):
setattr(self.context,
'auth_token',
'bff4a5a6b9eb4ea2a6efec6eefb77936')
self.instance = {'project_id': '9d049e4b60b64716978ab415e6fbd5c0',
self.tenant_id = '9d049e4b60b64716978ab415e6fbd5c0'
self.instance = {'project_id': self.tenant_id,
'uuid': str(uuid.uuid4()),
'display_name': 'test_instance',
'availability_zone': 'nova',
'host': 'some_host',
'info_cache': {'network_info': []},
'security_groups': []}
self.instance2 = {'project_id': '9d049e4b60b64716978ab415e6fbd5c0',
self.instance2 = {'project_id': self.tenant_id,
'uuid': str(uuid.uuid4()),
'display_name': 'test_instance2',
'availability_zone': 'nova',
@ -260,6 +261,7 @@ class TestNeutronv2Base(test.NoDBTestCase):
self.port_address = '10.0.1.2'
self.port_data1 = [{'network_id': 'my_netid1',
'device_id': self.instance2['uuid'],
'tenant_id': self.tenant_id,
'device_owner': 'compute:nova',
'id': 'my_portid1',
'binding:vnic_type': model.VNIC_TYPE_NORMAL,
@ -280,6 +282,7 @@ class TestNeutronv2Base(test.NoDBTestCase):
self.port_data2.append(self.port_data1[0])
self.port_data2.append({'network_id': 'my_netid2',
'device_id': self.instance['uuid'],
'tenant_id': self.tenant_id,
'admin_state_up': True,
'status': 'ACTIVE',
'device_owner': 'compute:nova',
@ -296,6 +299,7 @@ class TestNeutronv2Base(test.NoDBTestCase):
'floating_ip_address': '172.0.2.2'})
self.port_data3 = [{'network_id': 'my_netid1',
'device_id': 'device_id3',
'tenant_id': self.tenant_id,
'status': 'DOWN',
'admin_state_up': True,
'device_owner': 'compute:nova',
@ -427,6 +431,7 @@ class TestNeutronv2Base(test.NoDBTestCase):
).AndReturn(
{'port': {'id': 'my_portid3',
'network_id': 'my_netid1',
'tenant_id': self.tenant_id,
'mac_address': 'my_mac1',
'device_id': kwargs.get('_device') and
self.instance2.uuid or
@ -446,6 +451,7 @@ class TestNeutronv2Base(test.NoDBTestCase):
self.moxed_client.show_port(request.port_id).AndReturn(
{'port': {'id': 'my_portid1',
'network_id': 'my_netid1',
'tenant_id': self.tenant_id,
'mac_address': 'my_mac1',
'device_id': kwargs.get('_device') and
self.instance2.uuid or
@ -1212,6 +1218,17 @@ class TestNeutronv2(TestNeutronv2Base):
api.allocate_for_instance, self.context,
self.instance, requested_networks=requested_networks)
def test_allocate_for_instance_port_invalid_tenantid(self):
self.tenant_id = 'invalid_id'
requested_networks = objects.NetworkRequestList(
objects=[objects.NetworkRequest(port_id='my_portid1')])
api = self._stub_allocate_for_instance(
requested_networks=requested_networks,
_break='pre_list_networks')
self.assertRaises(exception.PortNotUsable,
api.allocate_for_instance, self.context,
self.instance, requested_networks=requested_networks)
def test_allocate_for_instance_with_externalnet_forbidden(self):
"""Only one network is available, it's external, and the client
is unauthorized to use it.
@ -3266,7 +3283,8 @@ class TestNeutronv2WithMock(test.NoDBTestCase):
mock_nc = mock.Mock()
def show_port(port_id):
return {'port': {'network_id': 'net-1', 'id': port_id}}
return {'port': {'network_id': 'net-1', 'id': port_id,
'tenant_id': 'proj-1'}}
mock_nc.show_port = show_port
mock_ntrn.return_value = mock_nc