Raise NotFound if attach interface with invalid net id or port id

When posting an 'attach interface' request to Nova with an invalid
network id or port id, Nova returns HTTP 500 which indicates the
attach operation fails. In fact, Nova get an empty network list or
PortNotFound exception from Neutron due to incorrect input. Nova
should address the error and raise NotFound in order to inform the
user to correct the request.

Change-Id: I3c5e07d5d6920a750d25398da8388a39b76a2944
Closes-Bug: 1370359
Closes-Bug: 1382343
This commit is contained in:
Qin Zhao
2014-09-17 16:36:35 +08:00
parent efa9120872
commit e57412c05e
2 changed files with 49 additions and 4 deletions

View File

@@ -367,7 +367,10 @@ class API(base_api.NetworkAPI):
if requested_networks:
for request in requested_networks:
if request.port_id:
port = neutron.show_port(request.port_id)['port']
try:
port = neutron.show_port(request.port_id)['port']
except neutron_client_exc.PortNotFoundClient:
raise exception.PortNotFound(port_id=request.port_id)
if port.get('device_id'):
raise exception.PortInUse(port_id=request.port_id)
if hypervisor_macs is not None:
@@ -390,8 +393,16 @@ class API(base_api.NetworkAPI):
nets = self._get_available_networks(context, instance.project_id,
net_ids, neutron=neutron)
if not nets:
LOG.debug("No network configured", instance=instance)
return network_model.NetworkInfo([])
# NOTE(chaochin): If user specifies a network id and the network
# can not be found, raise NetworkNotFound error.
if requested_networks:
for request in requested_networks:
if not request.port_id and request.network_id:
raise exception.NetworkNotFound(
network_id=request.network_id)
else:
LOG.debug("No network configured", instance=instance)
return network_model.NetworkInfo([])
# if this function is directly called without a requested_network param
# or if it is indirectly called through allocate_port_for_instance()

View File

@@ -244,9 +244,12 @@ class TestNeutronv2Base(test.TestCase):
self.nets7.append(self.nets1[0])
# A network request with only external network
self.nets8 = [self.nets5[1]]
# An empty network
self.nets9 = []
self.nets = [self.nets1, self.nets2, self.nets3, self.nets4,
self.nets5, self.nets6, self.nets7, self.nets8]
self.nets5, self.nets6, self.nets7, self.nets8,
self.nets9]
self.port_address = '10.0.1.2'
self.port_data1 = [{'network_id': 'my_netid1',
@@ -411,6 +414,11 @@ class TestNeutronv2Base(test.TestCase):
request.network_id = 'my_netid1'
if macs is not None:
macs.discard('my_mac1')
elif request.port_id == 'invalid_id':
PortNotFound = exceptions.PortNotFoundClient(
status_code=404)
self.moxed_client.show_port(request.port_id
).AndRaise(PortNotFound)
else:
self.moxed_client.show_port(request.port_id).AndReturn(
{'port': {'id': 'my_portid1',
@@ -449,6 +457,10 @@ class TestNeutronv2Base(test.TestCase):
self.moxed_client.list_networks(
**mox_list_params).AndReturn({'networks': []})
if kwargs.get('_break') == 'post_list_networks':
self.mox.ReplayAll()
return api
if (('requested_networks' not in kwargs or
kwargs['requested_networks'].as_tuples() == [(None, None, None)])
and len(nets) > 1):
@@ -965,6 +977,17 @@ class TestNeutronv2(TestNeutronv2Base):
self._allocate_for_instance(net_idx=3,
requested_networks=requested_networks)
def test_allocate_for_instance_with_invalid_network_id(self):
requested_networks = objects.NetworkRequestList(
objects=[objects.NetworkRequest(network_id='invalid_id')])
api = self._stub_allocate_for_instance(net_idx=9,
requested_networks=requested_networks,
_break='post_list_networks')
self.assertRaises(exception.NetworkNotFound,
api.allocate_for_instance,
self.context, self.instance,
requested_networks=requested_networks)
def test_allocate_for_instance_with_requested_networks_with_fixedip(self):
# specify only first and last network
requested_networks = objects.NetworkRequestList(
@@ -1138,6 +1161,17 @@ class TestNeutronv2(TestNeutronv2Base):
api.allocate_for_instance, self.context,
self.instance, requested_networks=requested_networks)
def test_allocate_for_instance_port_not_found(self):
# If a port is not found, an exception should be raised.
requested_networks = objects.NetworkRequestList(
objects=[objects.NetworkRequest(port_id='invalid_id')])
api = self._stub_allocate_for_instance(
requested_networks=requested_networks,
_break='pre_list_networks')
self.assertRaises(exception.PortNotFound,
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.