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:
parent
5ce9ca28cd
commit
c4f353b112
|
@ -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())
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue