Add installer teardown for LUKS and LVM layouts
This commit is contained in:
parent
c4d68855cb
commit
ea64876595
|
|
@ -118,6 +118,14 @@ def lvm_vol_change(vol: LvmVolume, activate: bool) -> None:
|
|||
SysCommand(cmd)
|
||||
|
||||
|
||||
def lvm_vg_change(vg: LvmVolumeGroup, activate: bool) -> None:
|
||||
active_flag = 'y' if activate else 'n'
|
||||
cmd = ['vgchange', '-a', active_flag, vg.name]
|
||||
|
||||
debug(f'vgchange volume group: {" ".join(cmd)}')
|
||||
SysCommand(cmd)
|
||||
|
||||
|
||||
def lvm_export_vg(vg: LvmVolumeGroup) -> None:
|
||||
cmd = f'vgexport {vg.name}'
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import subprocess
|
|||
import textwrap
|
||||
import time
|
||||
from collections.abc import Callable
|
||||
from contextlib import suppress
|
||||
from pathlib import Path
|
||||
from subprocess import CalledProcessError
|
||||
from types import TracebackType
|
||||
|
|
@ -16,7 +17,7 @@ from archinstall.lib.bootloader.utils import validate_bootloader_layout
|
|||
from archinstall.lib.command import SysCommand, run
|
||||
from archinstall.lib.disk.fido import Fido2
|
||||
from archinstall.lib.disk.luks import Luks2, unlock_luks2_dev
|
||||
from archinstall.lib.disk.lvm import lvm_import_vg, lvm_pvseg_info, lvm_vol_change
|
||||
from archinstall.lib.disk.lvm import lvm_import_vg, lvm_pvseg_info, lvm_vg_change, lvm_vol_change
|
||||
from archinstall.lib.disk.utils import (
|
||||
get_lsblk_by_mountpoint,
|
||||
get_lsblk_info,
|
||||
|
|
@ -24,6 +25,8 @@ from archinstall.lib.disk.utils import (
|
|||
get_unique_path_for_device,
|
||||
mount,
|
||||
swapon,
|
||||
udev_sync,
|
||||
umount,
|
||||
)
|
||||
from archinstall.lib.exceptions import DiskError, HardwareIncompatibilityError, RequirementError, ServiceException, SysCallError
|
||||
from archinstall.lib.hardware import SysInfo
|
||||
|
|
@ -131,45 +134,51 @@ class Installer:
|
|||
|
||||
self._zram_enabled = False
|
||||
self._disable_fstrim = False
|
||||
|
||||
self._layout_teardown_required = False
|
||||
self.pacman = Pacman(self.target, silent)
|
||||
|
||||
def __enter__(self) -> Self:
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None) -> bool | None:
|
||||
if exc_type is not None:
|
||||
error(str(exc_value))
|
||||
try:
|
||||
if exc_type is not None:
|
||||
error(str(exc_value))
|
||||
|
||||
self.sync_log_to_install_medium()
|
||||
self.sync_log_to_install_medium()
|
||||
|
||||
# We avoid printing /mnt/<log path> because that might confuse people if they note it down
|
||||
# and then reboot, and an identical log file will be found in the ISO medium anyway.
|
||||
print(tr('[!] A log file has been created here: {}').format(logger.path))
|
||||
print(tr('Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues'))
|
||||
# We avoid printing /mnt/<log path> because that might confuse people if they note it down
|
||||
# and then reboot, and an identical log file will be found in the ISO medium anyway.
|
||||
print(tr('[!] A log file has been created here: {}').format(logger.path))
|
||||
print(tr('Please submit this issue (and file) to https://github.com/archlinux/archinstall/issues'))
|
||||
|
||||
# Return None to propagate the exception
|
||||
return None
|
||||
# Return None to propagate the exception
|
||||
return None
|
||||
|
||||
info(tr('Syncing the system...'))
|
||||
os.sync()
|
||||
info(tr('Syncing the system...'))
|
||||
os.sync()
|
||||
|
||||
if not (missing_steps := self.post_install_check()):
|
||||
msg = f'Installation completed without any errors.\nLog files temporarily available at {logger.directory}.\nYou may reboot when ready.\n'
|
||||
log(msg, fg='green')
|
||||
self.sync_log_to_install_medium()
|
||||
return True
|
||||
else:
|
||||
warn('Some required steps were not successfully installed/configured before leaving the installer:')
|
||||
if not (missing_steps := self.post_install_check()):
|
||||
msg = f'Installation completed without any errors.\nLog files temporarily available at {logger.directory}.\nYou may reboot when ready.\n'
|
||||
log(msg, fg='green')
|
||||
self.sync_log_to_install_medium()
|
||||
return True
|
||||
else:
|
||||
warn('Some required steps were not successfully installed/configured before leaving the installer:')
|
||||
|
||||
for step in missing_steps:
|
||||
warn(f' - {step}')
|
||||
for step in missing_steps:
|
||||
warn(f' - {step}')
|
||||
|
||||
warn(f'Detailed error logs can be found at: {logger.directory}')
|
||||
warn('Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues')
|
||||
warn(f'Detailed error logs can be found at: {logger.directory}')
|
||||
warn('Submit this zip file as an issue to https://github.com/archlinux/archinstall/issues')
|
||||
|
||||
self.sync_log_to_install_medium()
|
||||
return False
|
||||
self.sync_log_to_install_medium()
|
||||
return False
|
||||
finally:
|
||||
try:
|
||||
self.teardown()
|
||||
except Exception as err:
|
||||
warn(f'Failed to teardown installation target: {err}')
|
||||
|
||||
def remove_mod(self, mod: str) -> None:
|
||||
if mod in self._modules:
|
||||
|
|
@ -257,6 +266,7 @@ class Installer:
|
|||
|
||||
def mount_ordered_layout(self) -> None:
|
||||
debug('Mounting ordered layout')
|
||||
self._layout_teardown_required = True
|
||||
|
||||
luks_handlers: dict[Any, Luks2] = {}
|
||||
|
||||
|
|
@ -438,6 +448,110 @@ class Installer:
|
|||
options = mount_options + [f'subvol={subvol.name}']
|
||||
mount(dev_path, mountpoint, options=options)
|
||||
|
||||
def teardown(self) -> None:
|
||||
if not self._layout_teardown_required:
|
||||
debug('No mounted layout registered for teardown')
|
||||
return
|
||||
|
||||
info('Tearing down installation target')
|
||||
|
||||
with suppress(Exception):
|
||||
os.sync()
|
||||
|
||||
self._swapoff_layout()
|
||||
|
||||
with suppress(SysCallError, DiskError):
|
||||
umount(self.target, recursive=True)
|
||||
|
||||
match self._disk_encryption.encryption_type:
|
||||
case EncryptionType.LUKS:
|
||||
self._teardown_luks_partitions()
|
||||
|
||||
case EncryptionType.LUKS_ON_LVM:
|
||||
self._teardown_luks_lvm()
|
||||
self._teardown_lvm()
|
||||
|
||||
case EncryptionType.LVM_ON_LUKS:
|
||||
self._teardown_lvm()
|
||||
self._teardown_luks_partitions()
|
||||
|
||||
case EncryptionType.NO_ENCRYPTION:
|
||||
self._teardown_lvm()
|
||||
|
||||
with suppress(SysCallError):
|
||||
udev_sync()
|
||||
|
||||
self._layout_teardown_required = False
|
||||
|
||||
def _swapoff_path(self, path: Path | None) -> None:
|
||||
if path is None:
|
||||
return
|
||||
|
||||
with suppress(SysCallError, DiskError):
|
||||
SysCommand(['swapoff', str(path)])
|
||||
|
||||
def _swapoff_layout(self) -> None:
|
||||
for mod in self._disk_config.device_modifications:
|
||||
for part in mod.partitions:
|
||||
if part.is_swap():
|
||||
self._swapoff_path(part.dev_path)
|
||||
|
||||
if part.mapper_name:
|
||||
self._swapoff_path(Path('/dev/mapper') / part.mapper_name)
|
||||
|
||||
if not self._disk_config.lvm_config:
|
||||
return
|
||||
|
||||
for vol in self._disk_config.lvm_config.get_all_volumes():
|
||||
if vol.fs_type == FilesystemType.LINUX_SWAP:
|
||||
self._swapoff_path(vol.dev_path)
|
||||
|
||||
if vol.mapper_name:
|
||||
self._swapoff_path(Path('/dev/mapper') / vol.mapper_name)
|
||||
|
||||
def _teardown_lvm(self) -> None:
|
||||
lvm_config = self._disk_config.lvm_config
|
||||
|
||||
if not lvm_config:
|
||||
return
|
||||
|
||||
for vg in reversed(lvm_config.vol_groups):
|
||||
for vol in reversed(vg.volumes):
|
||||
if not vol.dev_path:
|
||||
continue
|
||||
|
||||
with suppress(SysCallError, DiskError):
|
||||
lvm_vol_change(vol, False)
|
||||
|
||||
with suppress(SysCallError, DiskError):
|
||||
lvm_vg_change(vg, False)
|
||||
|
||||
def _teardown_luks_partitions(self) -> None:
|
||||
for part_mod in reversed(self._disk_encryption.partitions):
|
||||
if not part_mod.dev_path or not part_mod.mapper_name:
|
||||
continue
|
||||
|
||||
luks_handler = Luks2(
|
||||
part_mod.dev_path,
|
||||
mapper_name=part_mod.mapper_name,
|
||||
)
|
||||
|
||||
with suppress(SysCallError, DiskError):
|
||||
luks_handler.lock()
|
||||
|
||||
def _teardown_luks_lvm(self) -> None:
|
||||
for vol in reversed(self._disk_encryption.lvm_volumes):
|
||||
if not vol.dev_path or not vol.mapper_name:
|
||||
continue
|
||||
|
||||
luks_handler = Luks2(
|
||||
vol.dev_path,
|
||||
mapper_name=vol.mapper_name,
|
||||
)
|
||||
|
||||
with suppress(SysCallError, DiskError):
|
||||
luks_handler.lock()
|
||||
|
||||
def generate_key_files(self) -> None:
|
||||
match self._disk_encryption.encryption_type:
|
||||
case EncryptionType.LUKS:
|
||||
|
|
|
|||
Loading…
Reference in New Issue