diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index 0a87205e8e..cd876b32b4 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -691,6 +691,7 @@ def _create_test_instance(): 'root_gb': 10, 'ephemeral_gb': 20, 'system_metadata': { + 'image_base_image_ref': '155d900f-4e14-4e4c-a73d-069cbf4541e6', 'image_disk_format': 'raw' }, 'instance_type_id': flavor.id, @@ -2902,6 +2903,48 @@ class LibvirtConnTestCase(test.NoDBTestCase, self.assertEqual(meta.ports.ports[1].ips[1].ip_type, 'fixed') self.assertEqual(meta.ports.ports[1].ips[1].ip_version, 6) + def test_get_guest_config_meta_building_image_id(self): + test_instance = copy.deepcopy(self.test_instance) + test_instance["vm_state"] = "building" + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) + idm = drvr.get_instance_driver_metadata( + objects.Instance(**test_instance), + _fake_network_info(self)) + meta = drvr._get_guest_config_meta(idm) + + self.assertEqual("image", meta.roottype) + self.assertEqual("155d900f-4e14-4e4c-a73d-069cbf4541e6", + meta.rootid) + + def test_get_guest_config_meta_no_base_image_ref_image_id(self): + test_instance = copy.deepcopy(self.test_instance) + test_instance["system_metadata"] = {"image_disk_format": "raw"} + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) + idm = drvr.get_instance_driver_metadata( + objects.Instance(**test_instance), + _fake_network_info(self)) + meta = drvr._get_guest_config_meta(idm) + + self.assertEqual("image", meta.roottype) + self.assertEqual("155d900f-4e14-4e4c-a73d-069cbf4541e6", + meta.rootid) + + def test_get_guest_config_meta_unshelve_image_id(self): + test_instance = copy.deepcopy(self.test_instance) + test_instance["vm_state"] = "shelved_offloaded" + test_instance["system_metadata"]["image_base_image_ref"] = ( + "85daefce-4e20-4d2b-a4f3-11d3765f2a8f") + drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) + idm = drvr.get_instance_driver_metadata( + objects.Instance(**test_instance), + _fake_network_info(self)) + meta = drvr._get_guest_config_meta(idm) + + self.assertEqual("image", meta.roottype) + self.assertEqual(test_instance["system_metadata"][ + "image_base_image_ref"], + meta.rootid) + @mock.patch.object(time, "time") def test_get_guest_config(self, time_mock): """Generate a "standard" guest with minimal configuration. diff --git a/nova/virt/driver.py b/nova/virt/driver.py index 5998838bac..8f99b0834b 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -394,7 +394,14 @@ class ComputeDriver(object): flavor=flavor, image=image, root_type = 'image' if instance.image_ref else 'volume', - root_id = instance.image_ref, + # NOTE(callumdickinson): Once an image-backed instance has + # been shelved, instance.image_ref changes to the ID of the + # temporary image storing the root volume while shelved. + # Prefer base_image_ref from the system metadata, if available, + # to ensure that the ID of the original image the instance was + # booted from is used for the driver metadata. + root_id=system_meta.get('image_base_image_ref', + instance.image_ref), creation_time = time.time(), network_info=network_info ) diff --git a/releasenotes/notes/bug-2100588-fix-image-id-xml-after-unshelve-e5f6116043ba1c41.yaml b/releasenotes/notes/bug-2100588-fix-image-id-xml-after-unshelve-e5f6116043ba1c41.yaml new file mode 100644 index 0000000000..d713420ed5 --- /dev/null +++ b/releasenotes/notes/bug-2100588-fix-image-id-xml-after-unshelve-e5f6116043ba1c41.yaml @@ -0,0 +1,12 @@ +--- +fixes: + - | + When an instance booted from local storage is unshelved, + the image ID published to the libvirt domain metadata was + the ID for the temporary Glance image generated to store + the instance state, instead of the original image as intended. + Since the temporary image is removed after the instance is + unshelved, this results in an invalid image ID being stored + in the libvirt domain metadata. This issue has now been fixed. + Affected instances will need to be shutdown, restarted, cold + migrated or shelved-and-unshelved to update the metadata.