diff options
author | Eli Qiao <liyong.qiao@intel.com> | 2014-08-19 11:16:56 +0800 |
---|---|---|
committer | Eli Qiao <liyong.qiao@intel.com> | 2015-03-13 11:06:13 +0800 |
commit | 78f7c744f675d618048968850259422338dd4955 (patch) | |
tree | 3c305844cdb33ba5fd61ecfd681212771f78fa3d | |
parent | 4465710f7f546e7a163bec71289e1c6e79fb58be (diff) | |
download | nova-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.py | 18 | ||||
-rw-r--r-- | nova/tests/unit/compute/test_compute.py | 28 |
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, |