From 3c14c0c27c5b5f7da60be9e13c483b3d9b6ef094 Mon Sep 17 00:00:00 2001 From: Radek Vykydal Date: Mon, 23 Sep 2024 11:39:11 +0200 Subject: [PATCH] home reuse: reuse mount options of reused mountpoins --- pyanaconda/modules/storage/devicetree/root.py | 29 ++++++++++++--- .../automatic/automatic_partitioning.py | 14 ++++++- .../modules/storage/test_model.py | 37 +++++++++++++++++++ 3 files changed, 73 insertions(+), 7 deletions(-) diff --git a/pyanaconda/modules/storage/devicetree/root.py b/pyanaconda/modules/storage/devicetree/root.py index da97baed016..05fe5cefb69 100644 --- a/pyanaconda/modules/storage/devicetree/root.py +++ b/pyanaconda/modules/storage/devicetree/root.py @@ -124,7 +124,7 @@ def _find_existing_installations(devicetree): continue architecture, product, version = get_release_string(chroot=sysroot) - (mounts, devices) = _parse_fstab(devicetree, chroot=sysroot) + (mounts, devices, mountopts) = _parse_fstab(devicetree, chroot=sysroot) blivet_util.umount(mountpoint=sysroot) if not mounts and not devices: @@ -137,6 +137,7 @@ def _find_existing_installations(devicetree): arch=architecture, devices=devices, mounts=mounts, + mountopts=mountopts, )) return roots @@ -249,16 +250,17 @@ def _parse_fstab(devicetree, chroot): :param devicetree: a device tree :param chroot: a path to the target OS installation - :return: a tuple of a mount dict and a device list + :return: a tuple of a mount dict, device list, mount options """ mounts = {} devices = [] + mountopts = {} path = "%s/etc/fstab" % chroot if not os.access(path, os.R_OK): # XXX should we raise an exception instead? log.info("cannot open %s for read", path) - return mounts, devices + return mounts, devices, mountopts blkid_tab = BlkidTab(chroot=chroot) try: @@ -306,17 +308,18 @@ def _parse_fstab(devicetree, chroot): if fstype != "swap": mounts[mountpoint] = device + mountopts[mountpoint] = options devices.append(device) - return mounts, devices + return mounts, devices, mountopts class Root(object): """A root represents an existing OS installation.""" def __init__(self, name=None, product=None, version=None, arch=None, devices=None, - mounts=None): + mounts=None, mountopts=None): """Create a new OS representation. :param name: a name of the OS or None @@ -325,6 +328,7 @@ def __init__(self, name=None, product=None, version=None, arch=None, devices=Non :param arch: a machine's architecture or None :param devices: a list of all devices :param mounts: a dictionary of mount points and devices + :param mountopts: a dictionary of mount points and its mount options """ self._name = name self._product = product @@ -332,6 +336,7 @@ def __init__(self, name=None, product=None, version=None, arch=None, devices=Non self._arch = arch self._devices = devices or [] self._mounts = mounts or {} + self._mountopts = mountopts or {} @property def name(self): @@ -377,6 +382,14 @@ def mounts(self): """ return self._mounts + @property + def mountopts(self): + """Mount point options of mount points defined by the OS. + + :return: a dictionary of mount points and their mount options + """ + return self._mountopts + def copy(self, storage): """Create a copy with devices of the given storage model. @@ -392,6 +405,12 @@ def _get_mount(i): m, d = i[0], _get_device(i[1]) return (m, d) if m and d else None + def _get_mount_opt(i): + m, d = i[0], _get_device(i[1]) + return (m, self._mountopts[m]) if m and d and m in self._mountopts else None + new_root._devices = list(filter(None, map(_get_device, new_root._devices))) new_root._mounts = dict(filter(None, map(_get_mount, new_root._mounts.items()))) + new_root._mountopts = dict(filter(None, map(_get_mount_opt, + new_root._mounts.items()))) return new_root diff --git a/pyanaconda/modules/storage/partitioning/automatic/automatic_partitioning.py b/pyanaconda/modules/storage/partitioning/automatic/automatic_partitioning.py index 8a1ed282ac6..8a47b1487b3 100644 --- a/pyanaconda/modules/storage/partitioning/automatic/automatic_partitioning.py +++ b/pyanaconda/modules/storage/partitioning/automatic/automatic_partitioning.py @@ -83,6 +83,12 @@ def _get_mountpoint_device(self, storage, mountpoint, required=True): return devices[0] + def _get_mountpoint_options(self, storage, mountpoint): + for root in storage.roots: + if mountpoint in root.mountopts: + return root.mountopts[mountpoint] + return None + def _reused_devices_mountpoints(self, request): return request.reused_mount_points + request.reformatted_mount_points @@ -173,9 +179,13 @@ def _check_reused_scheme(self, storage, request): def _schedule_reused_mountpoint(self, storage, mountpoint): device = self._get_mountpoint_device(storage, mountpoint) - log.debug("add mount device request for reused mountpoint: %s device: %s", - mountpoint, device) + mountopts = self._get_mountpoint_options(storage, mountpoint) + log.debug("add mount device request for reused mountpoint: %s device: %s " + "with mountopts: %s", + mountpoint, device, mountopts) device.format.mountpoint = mountpoint + if mountopts: + device.format.options = mountopts def _schedule_reformatted_mountpoint(self, storage, mountpoint): old_device = self._get_mountpoint_device(storage, mountpoint) diff --git a/tests/unit_tests/pyanaconda_tests/modules/storage/test_model.py b/tests/unit_tests/pyanaconda_tests/modules/storage/test_model.py index 63bcf3cc87c..f375f34ffd7 100644 --- a/tests/unit_tests/pyanaconda_tests/modules/storage/test_model.py +++ b/tests/unit_tests/pyanaconda_tests/modules/storage/test_model.py @@ -149,3 +149,40 @@ def test_copy_roots(self): assert len(root2_copy.mounts) == 2 assert "/" in root2_copy.mounts assert "/home" in root2_copy.mounts + + def test_copy_mountopts(self): + """Test the copy of mount options.""" + dev1 = StorageDevice("dev1") + self._add_device(dev1) + + dev2 = StorageDevice("dev2") + self._add_device(dev2) + + dev3 = StorageDevice("dev3") + self._add_device(dev3) + + root1 = Root( + name="Linux 1", + devices=[dev2], + mounts={"/": dev2}, + ) + self.storage.roots.append(root1) + + root2 = Root( + name="Linux 2", + devices=[dev1, dev3], + mounts={"/": dev1, "/home": dev3}, + mountopts={"/home": "opt1"} + ) + self.storage.roots.append(root2) + + storage_copy = self.storage.copy() + assert len(storage_copy.roots) == 2 + + root1_copy = storage_copy.roots[0] + assert root1_copy.name == "Linux 1" + assert len(root1_copy.mountopts) == 0 + + root2_copy = storage_copy.roots[1] + assert root2_copy.name == "Linux 2" + assert len(root2_copy.mountopts) == 1