Skip to content

Commit 353afbd

Browse files
authored
Merge pull request #74 from desultory/automount
add automounts
2 parents 96528bc + 07fed0d commit 353afbd

File tree

4 files changed

+51
-26
lines changed

4 files changed

+51
-26
lines changed

docs/configuration.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ destination = "/mnt/extra"
155155
label = "extra"
156156
```
157157

158+
##### auto_mounts
159+
160+
Paths added to `auto_mounts` will be auto-configured to mount before `init_main` is run.
161+
158162
#### ugrd.fs.fakeudev
159163

160164
This module is used to create fake udev entries for DM devices.

src/ugrd/crypto/cryptsetup.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,11 @@ def _validate_crypysetup_key(self, key_paramters: dict) -> None:
7070

7171

7272
@contains('validate', "Skipping cryptsetup configuration validation.", log_level=30)
73-
def _validate_cryptsetup_config(self, mapped_name: str, config: dict) -> None:
73+
def _validate_cryptsetup_config(self, mapped_name: str) -> None:
74+
try:
75+
config = self['cryptsetup'][mapped_name]
76+
except KeyError:
77+
raise KeyError("No cryptsetup configuration found for: %s" % mapped_name)
7478
self.logger.log(5, "[%s] Validating cryptsetup configuration: %s" % (mapped_name, config))
7579
for parameter in config:
7680
if parameter not in CRYPTSETUP_PARAMETERS:
@@ -92,7 +96,6 @@ def _validate_cryptsetup_config(self, mapped_name: str, config: dict) -> None:
9296
def _process_cryptsetup_multi(self, mapped_name: str, config: dict) -> None:
9397
""" Processes the cryptsetup configuration """
9498
config = _merge_cryptsetup(self, mapped_name, config) # Merge the config with the existing configuration
95-
_validate_cryptsetup_config(self, mapped_name, config) # Validate the configuration
9699
self.logger.debug("[%s] Processing cryptsetup configuration: %s" % (mapped_name, config))
97100
# Check if the key type is defined in the configuration, otherwise use the default, check if it's valid
98101
if key_type := config.get('key_type', self.get('cryptsetup_key_type')):
@@ -118,21 +121,21 @@ def _process_cryptsetup_multi(self, mapped_name: str, config: dict) -> None:
118121

119122

120123
@contains('validate', "Skipping cryptsetup configuration validation.", log_level=30)
121-
def _validate_luks_source(self, mapped_name: str) -> None:
122-
""" Checks that a LUKS source device is valid """
124+
def _validate_luks_config(self, mapped_name: str) -> None:
125+
""" Checks that a LUKS config portion is valid. """
123126
for _dm_info in self['_dm_info'].values():
124127
if _dm_info['name'] == mapped_name:
125-
dm_info = _dm_info
128+
dm_info = _dm_info # Get the device mapper information
126129
break
127130
else:
128131
raise ValueError("No device mapper information found for: %s" % mapped_name)
129132

130-
cryptsetup_info = self['cryptsetup'][mapped_name]
133+
cryptsetup_info = self['cryptsetup'][mapped_name] # Get the cryptsetup information
131134

132-
if not dm_info['uuid'].startswith('CRYPT-LUKS'):
135+
if not dm_info['uuid'].startswith('CRYPT-LUKS'): # Ensure the device is a crypt device
133136
raise ValueError("Device is not a crypt device: %s" % dm_info)
134137

135-
slave_source = dm_info['slaves'][0]
138+
slave_source = dm_info['slaves'][0] # Get the slave source
136139

137140
try:
138141
blkid_info = self['_blkid_info'][f'/dev/{slave_source}']
@@ -147,18 +150,19 @@ def _validate_luks_source(self, mapped_name: str) -> None:
147150
break
148151
else:
149152
raise ValueError("[%s] Unable to validate LUKS source: %s" % (mapped_name, cryptsetup_info))
153+
_validate_cryptsetup_config(self, mapped_name)
150154

151155

152156
def export_crypt_sources(self) -> list[str]:
153157
"""
154-
Validates the cryptsetup configuration.
158+
Validates the cryptsetup configuration (if enabled).
155159
Adds the cryptsetup source and token to the exports.
156160
Sets the token to the partuuid or uuid if it exists.
157161
Sets the SOURCE when using a path.
158162
Only allows using the path if validation is disabled.
159163
"""
160164
for name, parameters in self['cryptsetup'].items():
161-
_validate_luks_source(self, name)
165+
_validate_luks_config(self, name)
162166
if parameters.get('path'):
163167
if not self['validate']:
164168
self.logger.warning("Using device paths is unreliable and can result in boot failures. Consider using partuuid.")

src/ugrd/fs/mounts.py

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
__author__ = 'desultory'
2-
__version__ = '4.12.2'
2+
__version__ = '4.13.0'
33

44
from pathlib import Path
55
from zenlib.util import contains, pretty_print
@@ -443,25 +443,41 @@ def autodetect_root(self) -> None:
443443
root_dev = _resolve_root_dev(self)
444444
if root_dev not in self['_blkid_info']:
445445
get_blkid_info(self, root_dev)
446-
autodetect_mount_kmods(self, root_dev) # Get kmods for the root device
447-
448-
root_mount_info = self['_blkid_info'][root_dev]
449-
self.logger.debug("Detected root mount info: %s" % root_mount_info)
450-
mount_info = {'root': {'type': 'auto', 'base_mount': False}}
451-
452-
if mount_type := root_mount_info.get('type'): # Attempt to autodetect the root type
453-
self.logger.info("Autodetected root type: %s" % mount_type)
454-
mount_info['root']['type'] = mount_type.lower()
446+
self['mounts'] = _autodetect_mount(self, '/')
447+
448+
449+
def _autodetect_mount(self, mountpoint) -> dict:
450+
""" Returns mount config based on the mount at the specified mountpoint. """
451+
if mountpoint not in self['_mounts']:
452+
raise FileNotFoundError("auto_mount mountpointpoint not found in host mounts: %s" % mountpoint)
453+
if self['_mounts'][mountpoint]['device'] not in self['_blkid_info']:
454+
get_blkid_info(self, self['_mounts'][mountpoint]['device'])
455+
mount_device = self['_mounts'][mountpoint]['device']
456+
mount_info = self['_blkid_info'][mount_device]
457+
autodetect_mount_kmods(self, mount_device)
458+
mount_name = 'root' if mountpoint == '/' else mountpoint.removeprefix('/')
459+
mount_config = {mount_name: {'type': 'auto'}}
460+
if mount_type := mount_info.get('type'):
461+
self.logger.info("Autodetected mount type: %s" % mount_type)
462+
mount_config[mount_name]['type'] = mount_type.lower()
455463

456464
for source_type in SOURCE_TYPES:
457-
if source := root_mount_info.get(source_type):
458-
self.logger.info("Autodetected root source: %s=%s" % (source_type, source))
459-
mount_info['root'][source_type] = source
465+
if source := mount_info.get(source_type):
466+
self.logger.info("[%s] Autodetected mount source: %s=%s" % (mount_name, source_type, source))
467+
mount_config[mount_name][source_type] = source
460468
break
461469
else:
462-
raise ValueError("Failed to autodetect root mount source.")
470+
raise ValueError("[%s] Failed to autodetect mount source." % mountpoint)
471+
472+
return mount_config
463473

464-
self['mounts'] = mount_info
474+
475+
@contains('auto_mounts', "Skipping auto mounts, auto_mounts is empty.", log_level=10)
476+
@contains('hostonly', "Skipping mount autodetection, hostonly mode is enabled.", log_level=30)
477+
def autodetect_mounts(self) -> None:
478+
""" Configured the mount config for a device based on the host mount config. """
479+
for mountpoint in self['auto_mounts']:
480+
self['mounts'] = _autodetect_mount(self, mountpoint)
465481

466482

467483
def mount_base(self) -> list[str]:

src/ugrd/fs/mounts.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ late_fstab = "/etc/fstab.late"
2020
"ugrd.fs.mounts" = [ "_process_mounts_multi", "_process_late_mounts_multi", "_process_mount_timeout" ]
2121

2222
[imports.build_pre]
23-
"ugrd.fs.mounts" = [ "get_mounts_info", "get_dm_info", "get_blkid_info", "autodetect_root", "autodetect_root_dm" ]
23+
"ugrd.fs.mounts" = [ "get_mounts_info", "get_dm_info", "get_blkid_info", "autodetect_root", "autodetect_mounts", "autodetect_root_dm" ]
2424

2525
[imports.build_tasks]
2626
"ugrd.fs.mounts" = [ "autodetect_init_mount", "export_mount_info", "export_root_target" ]
@@ -44,6 +44,7 @@ late_fstab = "/etc/fstab.late"
4444
mounts = "dict" # Add the mounts property, used to define the mounts to be made in the fstab
4545
late_mounts = "dict" # Like mounts, but run after the root is mounted
4646
late_fstab = "str" # The path to the late_fstab file
47+
auto_mounts = "NoDupFlatList" # A list of mounts to be automatically added to the mounts list
4748
mount_wait = "bool" # Add the mount_wait property, if defined, user input will be required before attempting to mount entries
4849
mount_timeout = "float" # Add the mount_timeout property, used to define the timeout for mount_wait
4950
mount_retries = "int" # The number of times to re-attempt mounting the fstab

0 commit comments

Comments
 (0)