summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Qiao <liyong.qiao@intel.com>2014-08-19 11:16:56 +0800
committerEli Qiao <liyong.qiao@intel.com>2015-03-13 11:06:13 +0800
commit78f7c744f675d618048968850259422338dd4955 (patch)
tree3c305844cdb33ba5fd61ecfd681212771f78fa3d
parent4465710f7f546e7a163bec71289e1c6e79fb58be (diff)
downloadnova-78f7c744f675d618048968850259422338dd4955.tar.gz
Handle exception when attaching interface failed
Currently, when attaching interface to an instance, nova doesn't handle the exception when calling `driver.attach_interface`, so the network info will leak when exception happened. This patch deallocates port when attaching interface failed, and give warn messages when deallocate port failed. Change-Id: I4fe67b5ce1b5ed41412d824a8c10b9a5e4fb325f Closes-bug: #1338551 Co-authored-by: Alex Xu <hejie.xu@intel.com>
-rw-r--r--nova/compute/manager.py18
-rw-r--r--nova/tests/unit/compute/test_compute.py28
2 files changed, 45 insertions, 1 deletions
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 0a5601acb4..a03bb32fb2 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -4894,7 +4894,23 @@ class ComputeManager(manager.Manager):
image_meta = compute_utils.get_image_metadata(
context, self.image_api, image_ref, instance)
- self.driver.attach_interface(instance, image_meta, network_info[0])
+ try:
+ self.driver.attach_interface(instance, image_meta, network_info[0])
+ except exception.NovaException as ex:
+ port_id = network_info[0].get('id')
+ LOG.warn(_LW("attach interface failed , try to deallocate "
+ "port %(port_id)s, reason: %(msg)s"),
+ {'port_id': port_id, 'msg': ex},
+ instance=instance)
+ try:
+ self.network_api.deallocate_port_for_instance(
+ context, instance, port_id)
+ except Exception:
+ LOG.warn(_LW("deallocate port %(port_id)s failed"),
+ {'port_id': port_id}, instance=instance)
+ raise exception.InterfaceAttachFailed(
+ instance_uuid=instance.uuid)
+
return network_info[0]
@object_compat
diff --git a/nova/tests/unit/compute/test_compute.py b/nova/tests/unit/compute/test_compute.py
index 667bccebf0..179f6f85f7 100644
--- a/nova/tests/unit/compute/test_compute.py
+++ b/nova/tests/unit/compute/test_compute.py
@@ -9146,6 +9146,34 @@ class ComputeAPITestCase(BaseTestCase):
self.assertEqual(vif['id'], network_id)
return nwinfo, port_id
+ def test_attach_interface_failed(self):
+ new_type = flavors.get_flavor_by_flavor_id('4')
+ sys_meta = flavors.save_flavor_info({}, new_type)
+ instance = objects.Instance(uuid='fake_id', image_ref='foo',
+ system_metadata=sys_meta)
+ nwinfo = [fake_network_cache_model.new_vif()]
+ network_id = nwinfo[0]['network']['id']
+ port_id = nwinfo[0]['id']
+ req_ip = '1.2.3.4'
+
+ with contextlib.nested(
+ mock.patch.object(self.compute.driver, 'attach_interface'),
+ mock.patch.object(self.compute.network_api,
+ 'allocate_port_for_instance'),
+ mock.patch.object(self.compute.network_api,
+ 'deallocate_port_for_instance')) as (
+ mock_attach, mock_allocate, mock_deallocate):
+
+ mock_allocate.return_value = nwinfo
+ mock_attach.side_effect = exception.NovaException("attach_failed")
+ self.assertRaises(exception.InterfaceAttachFailed,
+ self.compute.attach_interface, self.context,
+ instance, network_id, port_id, req_ip)
+ mock_allocate.assert_called_once_with(self.context, instance,
+ network_id, port_id, req_ip)
+ mock_deallocate.assert_called_once_with(self.context, instance,
+ port_id)
+
def test_detach_interface(self):
nwinfo, port_id = self.test_attach_interface()
self.stubs.Set(self.compute.network_api,