From e310049eab7dc3d05a25a37c68fec3b34d621c33 Mon Sep 17 00:00:00 2001 From: Sean Mooney Date: Fri, 6 Sep 2024 03:00:54 +0100 Subject: [PATCH] Add functional repoducer for ephemeral disks This commit add a functional repoducer for a regression in ephmeral disk image format validation When we changed to use the oslo.utils verison of the format_inspector we aquired a new inspector which can detect if a file has a partition table. As the qcow 2 backend does not know that ephemeral disk or swap disk are not boot able it requires that they also have partition tables. Related-Bug: #2079850 Change-Id: I26c6e8d2efbf7403542e99b8ac45e2a31f08afd1 --- bindep.txt | 2 + .../regressions/test_bug_2079850.py | 92 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 nova/tests/functional/regressions/test_bug_2079850.py diff --git a/bindep.txt b/bindep.txt index a0c54b7d7951..b843e358b7b7 100644 --- a/bindep.txt +++ b/bindep.txt @@ -2,6 +2,8 @@ # see https://docs.openstack.org/infra/bindep/ for additional information. build-essential [platform:dpkg test] +# required for mkfs.vfat +dosfstools [platform:dpkg test] # fonts-freefont-otf is needed for pdf docs builds with the 'xelatex' engine fonts-freefont-otf [pdf-docs] gcc [platform:rpm test] diff --git a/nova/tests/functional/regressions/test_bug_2079850.py b/nova/tests/functional/regressions/test_bug_2079850.py new file mode 100644 index 000000000000..4e9f1fcf65f7 --- /dev/null +++ b/nova/tests/functional/regressions/test_bug_2079850.py @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: Apache-2.0 +import functools +import os +import shutil + +import fixtures + +from oslo_utils.fixture import uuidsentinel as uuids +from oslo_utils.imageutils import format_inspector +from oslo_utils import units + +import nova.conf + +from nova import exception +from nova import objects +from nova import test +from nova.virt.libvirt import driver +from nova.virt.libvirt import imagebackend +from nova.virt.libvirt import utils as libvirt_utils + + +CONF = nova.conf.CONF + + +class TestBugBackingFilePartitionTables(test.NoDBTestCase): + """Regression test for nova created backing files + + This test case is for a bug that was discovered where nova was creating + backing files for swap and ephemeral disks. With the move to using the + image format inspector form oslo.utils we gained the ability to inspect + files for mbr and gpt partition tables. + + This is now a requirement for all backing files created by nova. + """ + + def setUp(self): + super(TestBugBackingFilePartitionTables, self).setUp() + self.base_dir = self.useFixture( + fixtures.TempDir()) + if shutil.which("qemu-img") is None: + self.skipTest("qemu-img not installed") + if shutil.which("mkfs.vfat") is None: + self.skipTest("mkfs.vfat not installed") + + def test_create_file(self): + """Test that files created files have partition tables + + This test will create a file and then inspect it to ensure + that it has a partition table so that it can be used as a + backing file. + """ + + file_path = os.path.join(self.base_dir.path, 'test_file') + libvirt_utils.create_image(file_path, 'raw', '64M') + self.assertTrue(os.path.exists(file_path)) + # nova should ensure that any file we create has a partition table + # inspector = format_inspector.GPTInspector.from_file(file_path) + # self.assertIsNotNone(inspector) + # inspector.safety_check() + + # however the libvirt_utils.create_image method does not create a + # partition table so we should expect this to fail + self.assertRaises( + format_inspector.ImageFormatError, + format_inspector.GPTInspector.from_file, file_path) + + def test_cache_file(self): + """Test the qcow2 cache interaction for ephemeral disks + + This test will create a file via the image backend cache function + and ensure that the backing file has a partition table + """ + _create_ephemeral = driver.LibvirtDriver._create_ephemeral + + self.flags(use_cow_images=True) + self.flags(instances_path=self.base_dir.path) + self.flags(group='libvirt', images_type='qcow2') + + backend_image = imagebackend.Backend(CONF.use_cow_images).backend() + instance = objects.Instance(uuid=uuids.instance) + image = backend_image(instance, 'test_image') + + fn = functools.partial( + _create_ephemeral, fs_label='ephemeral0', + os_type=None, is_block_dev=False) + # this need to be multiples of 1G + size = 1 * units.Gi + fname = "ephemeral_%s_%s" % (size, ".qcow") + e = self.assertRaises(exception.InvalidDiskInfo, + image.cache, fetch_func=fn, context=None, filename=fname, + size=size, ephemeral_size=1) + self.assertIn("Base image failed safety check", str(e))