ironic: Cleanup instance information when spawn fails
Instance information such as an instance_uuid set to an ironic node by
_add_driver_fields() is not cleared when spawning is aborted by an
exception raised before ironic starts deployment. Then, ironic node
stays AVAILABLE state with instance_uuid set. This information is not
cleared even if the instance is deleted. The ironic node cannot be
removed nor deployed again becuase instance_uuid remains.
This patch adds a method to remove the information. This method is
called if ironic doesn't need unprovisioning when an instance is
destroyed.
Change-Id: Idf5191aa1c990552ca2340856d5d5b6ac03f7539
Closes-Bug: 1596922
(cherry picked from commit 0e24e9e2ec
)
This commit is contained in:
parent
cc2105fc4b
commit
20ba099205
|
@ -957,6 +957,24 @@ class IronicDriverTestCase(test.NoDBTestCase):
|
|||
self.driver._add_driver_fields,
|
||||
node, instance, image_meta, flavor)
|
||||
|
||||
def _test_remove_driver_fields(self, mock_update):
|
||||
node = ironic_utils.get_test_node(driver='fake')
|
||||
instance = fake_instance.fake_instance_obj(self.ctx,
|
||||
node=node.uuid)
|
||||
self.driver._remove_driver_fields(node, instance)
|
||||
expected_patch = [{'path': '/instance_info', 'op': 'remove'},
|
||||
{'path': '/instance_uuid', 'op': 'remove'}]
|
||||
mock_update.assert_called_once_with(node.uuid, expected_patch)
|
||||
|
||||
@mock.patch.object(FAKE_CLIENT.node, 'update')
|
||||
def test_remove_driver_fields(self, mock_update):
|
||||
self._test_remove_driver_fields(mock_update)
|
||||
|
||||
@mock.patch.object(FAKE_CLIENT.node, 'update')
|
||||
def test_remove_driver_fields_fail(self, mock_update):
|
||||
mock_update.side_effect = ironic_exception.BadRequest()
|
||||
self._test_remove_driver_fields(mock_update)
|
||||
|
||||
@mock.patch.object(configdrive, 'required_by')
|
||||
@mock.patch.object(FAKE_CLIENT, 'node')
|
||||
def test_spawn_node_driver_validation_fail(self, mock_node,
|
||||
|
@ -1156,8 +1174,10 @@ class IronicDriverTestCase(test.NoDBTestCase):
|
|||
self.assertEqual('/dev/sda1', instance.default_ephemeral_device)
|
||||
|
||||
@mock.patch.object(FAKE_CLIENT, 'node')
|
||||
@mock.patch.object(ironic_driver.IronicDriver, '_remove_driver_fields')
|
||||
@mock.patch.object(ironic_driver.IronicDriver, '_cleanup_deploy')
|
||||
def _test_destroy(self, state, mock_cleanup_deploy, mock_node):
|
||||
def _test_destroy(self, state, mock_cleanup_deploy,
|
||||
mock_remove_driver_fields, mock_node):
|
||||
node_uuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
|
||||
network_info = 'foo'
|
||||
|
||||
|
@ -1181,8 +1201,10 @@ class IronicDriverTestCase(test.NoDBTestCase):
|
|||
if state in ironic_driver._UNPROVISION_STATES:
|
||||
mock_node.set_provision_state.assert_called_once_with(
|
||||
node_uuid, 'deleted')
|
||||
self.assertFalse(mock_remove_driver_fields.called)
|
||||
else:
|
||||
self.assertFalse(mock_node.set_provision_state.called)
|
||||
mock_remove_driver_fields.assert_called_once_with(node, instance)
|
||||
|
||||
def test_destroy(self):
|
||||
for state in ironic_states.PROVISION_STATE_LIST:
|
||||
|
|
|
@ -377,6 +377,18 @@ class IronicDriver(virt_driver.ComputeDriver):
|
|||
LOG.error(msg)
|
||||
raise exception.InstanceDeployFailure(msg)
|
||||
|
||||
def _remove_driver_fields(self, node, instance):
|
||||
patch = [{'path': '/instance_info', 'op': 'remove'},
|
||||
{'path': '/instance_uuid', 'op': 'remove'}]
|
||||
try:
|
||||
self.ironicclient.call('node.update', node.uuid, patch)
|
||||
except ironic.exc.BadRequest as e:
|
||||
LOG.warning(_LW("Failed to remove deploy parameters from node "
|
||||
"%(node)s when unprovisioning the instance "
|
||||
"%(instance)s: %(reason)s"),
|
||||
{'node': node.uuid, 'instance': instance.uuid,
|
||||
'reason': six.text_type(e)})
|
||||
|
||||
def _cleanup_deploy(self, node, instance, network_info):
|
||||
self._unplug_vifs(node, instance, network_info)
|
||||
self._stop_firewall(instance, network_info)
|
||||
|
@ -868,6 +880,8 @@ class IronicDriver(virt_driver.ComputeDriver):
|
|||
|
||||
if node.provision_state in _UNPROVISION_STATES:
|
||||
self._unprovision(instance, node)
|
||||
else:
|
||||
self._remove_driver_fields(node, instance)
|
||||
|
||||
self._cleanup_deploy(node, instance, network_info)
|
||||
LOG.info(_LI('Successfully unprovisioned Ironic node %s'),
|
||||
|
|
Loading…
Reference in New Issue