Skip to content

Commit

Permalink
home reuse: reuse mount options of reused mountpoins
Browse files Browse the repository at this point in the history
  • Loading branch information
rvykydal committed Sep 23, 2024
1 parent b2a4e21 commit ffa8298
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 7 deletions.
29 changes: 24 additions & 5 deletions pyanaconda/modules/storage/devicetree/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -137,6 +137,7 @@ def _find_existing_installations(devicetree):
arch=architecture,
devices=devices,
mounts=mounts,
mountopts=mountopts,
))

return roots
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -325,13 +328,15 @@ 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
self._version = version
self._arch = arch
self._devices = devices or []
self._mounts = mounts or {}
self._mountopts = mountopts or {}

@property
def name(self):
Expand Down Expand Up @@ -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.
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -172,9 +178,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)
Expand Down
37 changes: 37 additions & 0 deletions tests/unit_tests/pyanaconda_tests/modules/storage/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit ffa8298

Please sign in to comment.