Skip to content

Commit 50314cf

Browse files
JohnGarbuttjovial
authored andcommitted
Fix ironic instance rebuild with API >=2.93
When you attempt to rebuild an Ironic instance, using the CLI, it will pick the latest micversion, which triggers sending to the ironic driver: reimage_boot_volume = true The ironic driver then raises an exception, saying it is unable to rebuild a volume backed instance. This happens even when the instance is not volume backed, and rebuild would be fine. This patch ensures we only raise the "can't rebuild" exception when the instance is volume backed. Closes-Bug: #2127017 Change-Id: Ibb8e83a1d36506df34a324ca0da9e2f129a38cfa Signed-off-by: John Garbutt <john.garbutt@stackhpc.com> Assisted-By: Github Copilot Free (cherry picked from commit 2c8f0e0b3a9c42260e86b894c4e5344a16b187bc)
1 parent b4fde79 commit 50314cf

2 files changed

Lines changed: 33 additions & 10 deletions

File tree

nova/tests/unit/virt/ironic/test_driver.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2276,7 +2276,8 @@ def test_detach_interface(self, mock_uv):
22762276
@mock.patch.object(objects.Instance, 'save')
22772277
def _test_rebuild(self, mock_save, mock_add_instance_info,
22782278
mock_looping, mock_wait_active, mock_metadata,
2279-
preserve=False):
2279+
preserve=False, reimage_boot_volume=False,
2280+
block_device_info=None):
22802281
node_uuid = uuidutils.generate_uuid()
22812282
node = _get_cached_node(id=node_uuid, instance_id=self.instance_id)
22822283
self.mock_conn.get_node.return_value = node
@@ -2300,7 +2301,9 @@ def _test_rebuild(self, mock_save, mock_add_instance_info,
23002301
context=self.ctx, instance=instance, image_meta=image_meta,
23012302
injected_files=None, admin_password=None, allocations={},
23022303
bdms=None, detach_block_devices=None, attach_block_devices=None,
2303-
preserve_ephemeral=preserve)
2304+
preserve_ephemeral=preserve,
2305+
reimage_boot_volume=reimage_boot_volume,
2306+
block_device_info=block_device_info)
23042307

23052308
mock_save.assert_called_once_with(
23062309
expected_task_state=[task_states.REBUILDING])
@@ -2339,11 +2342,25 @@ def test_rebuild_no_preserve_ephemeral(self, mock_required_by,
23392342
def test_rebuild_with_configdrive(self, mock_required_by,
23402343
mock_configdrive):
23412344
mock_required_by.return_value = True
2342-
self._test_rebuild()
2345+
self._test_rebuild(reimage_boot_volume=True)
23432346
# assert configdrive was generated
23442347
mock_configdrive.assert_called_once_with(
23452348
self.ctx, mock.ANY, mock.ANY, mock.ANY, extra_md={}, files=None)
23462349

2350+
@mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive')
2351+
@mock.patch.object(configdrive, 'required_by')
2352+
def test_rebuild_bfv_fails(self, mock_required_by,
2353+
mock_configdrive):
2354+
mock_required_by.return_value = False
2355+
block_device_info = self._create_fake_block_device_info()
2356+
e = self.assertRaises(exception.NovaException,
2357+
self._test_rebuild,
2358+
reimage_boot_volume=True,
2359+
block_device_info=block_device_info)
2360+
self.assertEqual(
2361+
"Ironic doesn't support rebuilding volume backed instances.",
2362+
str(e))
2363+
23472364
@mock.patch.object(ironic_driver.IronicDriver,
23482365
'get_instance_driver_metadata')
23492366
@mock.patch.object(ironic_driver.IronicDriver, '_generate_configdrive')

nova/virt/ironic/driver.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -408,13 +408,16 @@ def failed_spawn_cleanup(self, instance):
408408
return
409409
self._cleanup_deploy(node, instance)
410410

411+
def _is_boot_from_volume(self, block_device_info):
412+
root_bdm = block_device.get_root_bdm(
413+
virt_driver.block_device_info_get_mapping(block_device_info))
414+
return root_bdm is not None
415+
411416
def _add_instance_info_to_node(self, node, instance, image_meta, flavor,
412417
metadata, preserve_ephemeral=None,
413418
block_device_info=None):
414419

415-
root_bdm = block_device.get_root_bdm(
416-
virt_driver.block_device_info_get_mapping(block_device_info))
417-
boot_from_volume = root_bdm is not None
420+
boot_from_volume = self._is_boot_from_volume(block_device_info)
418421
patch = patcher.create(node).get_deploy_patch(instance,
419422
image_meta,
420423
flavor,
@@ -1739,12 +1742,15 @@ def rebuild(self, context, instance, image_meta, injected_files,
17391742
:param preserve_ephemeral: Boolean value; if True the ephemeral
17401743
must be preserved on rebuild.
17411744
:param accel_uuids: Accelerator UUIDs. Ignored by this driver.
1742-
:param reimage_boot_volume: Re-image the volume backed instance.
1745+
:param reimage_boot_volume: Ironic driver raises when rebuild
1746+
of a boot from volume instance, as its not yet supported.
17431747
"""
17441748
if reimage_boot_volume:
1745-
raise exception.NovaException(
1746-
_("Ironic doesn't support rebuilding volume backed "
1747-
"instances."))
1749+
boot_from_volume = self._is_boot_from_volume(block_device_info)
1750+
if boot_from_volume:
1751+
raise exception.NovaException(
1752+
_("Ironic doesn't support rebuilding volume backed "
1753+
"instances."))
17481754

17491755
LOG.debug('Rebuild called for instance', instance=instance)
17501756

0 commit comments

Comments
 (0)