Redo backend installer logic to support BIOS/MBR boot on older devices and switch to GRUB2
This commit is contained in:
@@ -110,6 +110,10 @@ def mount_pseudo_fs(mount_root):
|
||||
logger.warning(f"Failed to unmount {path}: {e}")
|
||||
|
||||
|
||||
def is_uefi():
|
||||
return os.path.exists("/sys/firmware/efi")
|
||||
|
||||
|
||||
def install_minimal_os(mount_root, releasever="43"):
|
||||
"""
|
||||
Installs minimal Fedora packages to mount_root.
|
||||
@@ -117,22 +121,29 @@ def install_minimal_os(mount_root, releasever="43"):
|
||||
logger.info(f"Installing minimal Fedora {releasever} to {mount_root}...")
|
||||
log_os_install("INSTALL", "start", f"Target: {mount_root}, Release: {releasever}")
|
||||
|
||||
uefi = is_uefi()
|
||||
|
||||
packages = [
|
||||
"basesystem",
|
||||
"bash",
|
||||
"coreutils",
|
||||
"kernel",
|
||||
"systemd",
|
||||
"systemd-boot-unsigned",
|
||||
"dnf",
|
||||
"shadow-utils",
|
||||
"util-linux",
|
||||
"efibootmgr",
|
||||
"passwd",
|
||||
"rootfiles",
|
||||
"vim-minimal",
|
||||
"grub2-tools",
|
||||
"grubby",
|
||||
]
|
||||
|
||||
if uefi:
|
||||
packages += ["grub2-efi-x64", "shim-x64", "efibootmgr"]
|
||||
else:
|
||||
packages += ["grub2-pc"]
|
||||
|
||||
# Offline installation logic
|
||||
possible_repos = [
|
||||
"/run/install/repo",
|
||||
@@ -175,7 +186,7 @@ def install_minimal_os(mount_root, releasever="43"):
|
||||
"--cacheonly",
|
||||
]
|
||||
else:
|
||||
logger.warning("ISO repository not found in common locations. DNF might try to use network.")
|
||||
logger.warning("ISO repository not found. DNF might try to use network.")
|
||||
dnf_args = []
|
||||
|
||||
cmd = [
|
||||
@@ -200,56 +211,48 @@ def install_minimal_os(mount_root, releasever="43"):
|
||||
log_os_install("INSTALL", "complete", f"Installed to {mount_root}")
|
||||
|
||||
|
||||
def configure_system(mount_root, partition_info, user_info=None):
|
||||
def configure_system(mount_root, partition_info, user_info=None, disk_device=None):
|
||||
"""
|
||||
Basic configuration: fstab, systemd-boot, and user creation.
|
||||
Basic configuration: fstab, grub2, and user creation.
|
||||
"""
|
||||
logger.info("Configuring system...")
|
||||
log_os_install("CONFIGURE", "start", f"Configuring system in {mount_root}")
|
||||
|
||||
uefi = is_uefi()
|
||||
|
||||
# 1. Generate fstab
|
||||
def get_uuid(dev):
|
||||
res = run_command(["blkid", "-s", "UUID", "-o", "value", dev])
|
||||
return res.stdout.strip()
|
||||
|
||||
root_uuid = get_uuid(partition_info["root"])
|
||||
efi_uuid = get_uuid(partition_info["efi"])
|
||||
|
||||
fstab_lines = [f"UUID={root_uuid} / ext4 defaults 1 1"]
|
||||
|
||||
if uefi and partition_info.get("efi"):
|
||||
efi_uuid = get_uuid(partition_info["efi"])
|
||||
fstab_lines.append(f"UUID={efi_uuid} /boot/efi vfat defaults 0 2")
|
||||
|
||||
swap_entry = ""
|
||||
if partition_info.get("swap"):
|
||||
swap_uuid = get_uuid(partition_info["swap"])
|
||||
swap_entry = f"UUID={swap_uuid} none swap defaults 0 0\n"
|
||||
fstab_lines.append(f"UUID={swap_uuid} none swap defaults 0 0")
|
||||
|
||||
fstab_content = f"""
|
||||
UUID={root_uuid} / ext4 defaults 1 1
|
||||
UUID={efi_uuid} /boot vfat defaults 0 2
|
||||
{swap_entry}
|
||||
"""
|
||||
os.makedirs(os.path.join(mount_root, "etc"), exist_ok=True)
|
||||
with open(os.path.join(mount_root, "etc/fstab"), "w") as f:
|
||||
f.write(fstab_content)
|
||||
f.write("\n".join(fstab_lines) + "\n")
|
||||
|
||||
with mount_pseudo_fs(mount_root):
|
||||
# 2. Configure User
|
||||
if user_info:
|
||||
logger.info(f"Creating user {user_info['username']}...")
|
||||
# Create user and add to wheel group (sudoer)
|
||||
run_command(["chroot", mount_root, "useradd", "-m", "-G", "wheel", user_info["username"]])
|
||||
|
||||
# Ensure changes to /etc/passwd and /etc/shadow are flushed
|
||||
run_command(["sync"])
|
||||
|
||||
# Ensure wheel group has sudo privileges
|
||||
sudoers_dir = os.path.join(mount_root, "etc/sudoers.d")
|
||||
os.makedirs(sudoers_dir, exist_ok=True)
|
||||
with open(os.path.join(sudoers_dir, "wheel"), "w") as f:
|
||||
f.write("%wheel ALL=(ALL) ALL\n")
|
||||
os.chmod(os.path.join(sudoers_dir, "wheel"), 0o440)
|
||||
# Set hostname
|
||||
with open(os.path.join(mount_root, "etc/hostname"), "w") as f:
|
||||
f.write(user_info["hostname"] + "\n")
|
||||
|
||||
# Set user and root password using hashed passwords and usermod
|
||||
# Set passwords
|
||||
try:
|
||||
logger.info(f"Setting hashed passwords for {user_info['username']} and root...")
|
||||
# Generate SHA512 hash using openssl on the host
|
||||
res = subprocess.run(
|
||||
["openssl", "passwd", "-6", user_info["password"]],
|
||||
capture_output=True,
|
||||
@@ -257,64 +260,38 @@ UUID={efi_uuid} /boot vfat defaults 0 2
|
||||
check=True
|
||||
)
|
||||
hashed_pass = res.stdout.strip()
|
||||
|
||||
# Apply hash to user and root using usermod -p (takes encrypted password)
|
||||
run_command(["chroot", mount_root, "usermod", "-p", hashed_pass, user_info["username"]])
|
||||
run_command(["chroot", mount_root, "usermod", "-p", hashed_pass, "root"])
|
||||
|
||||
run_command(["sync"])
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to set passwords: {e}")
|
||||
raise e
|
||||
|
||||
# Set hostname
|
||||
with open(os.path.join(mount_root, "etc/hostname"), "w") as f:
|
||||
f.write(user_info["hostname"] + "\n")
|
||||
|
||||
# 3. Configure systemd-boot
|
||||
# Ensure machine-id exists for kernel-install
|
||||
if not os.path.exists(os.path.join(mount_root, "etc/machine-id")):
|
||||
run_command(["chroot", mount_root, "systemd-machine-id-setup"])
|
||||
|
||||
# Set kernel command line
|
||||
os.makedirs(os.path.join(mount_root, "etc/kernel"), exist_ok=True)
|
||||
with open(os.path.join(mount_root, "etc/kernel/cmdline"), "w") as f:
|
||||
f.write(f"root=UUID={root_uuid} rw quiet\n")
|
||||
# 3. Configure GRUB2
|
||||
logger.info("Configuring GRUB2...")
|
||||
|
||||
# Set kernel layout to BLS for systemd-boot
|
||||
with open(os.path.join(mount_root, "etc/kernel/layout"), "w") as f:
|
||||
f.write("bls\n")
|
||||
# Ensure /etc/default/grub exists
|
||||
grub_default = os.path.join(mount_root, "etc/default/grub")
|
||||
if not os.path.exists(grub_default):
|
||||
with open(grub_default, "w") as f:
|
||||
f.write('GRUB_TIMEOUT=5\nGRUB_DISTRIBUTOR="$(sed \'s, release .*$,,g\' /etc/system-release)"\nGRUB_DEFAULT=saved\nGRUB_DISABLE_SUBMENU=true\nGRUB_TERMINAL_OUTPUT="console"\nGRUB_CMDLINE_LINUX="rhgb quiet"\nGRUB_DISABLE_RECOVERY="true"\nGRUB_ENABLE_BLSCFG=true\n')
|
||||
|
||||
# Install systemd-boot to the ESP (mounted at /boot)
|
||||
# Note: removed --force as it's not supported by all bootctl versions
|
||||
run_command(["chroot", mount_root, "bootctl", "install", "--path=/boot"])
|
||||
if uefi:
|
||||
run_command(["chroot", mount_root, "grub2-install", "--target=x86_64-efi", "--efi-directory=/boot/efi", "--bootloader-id=iridium", "--recheck"])
|
||||
run_command(["chroot", mount_root, "grub2-mkconfig", "-o", "/boot/efi/EFI/iridium/grub.cfg"])
|
||||
# Fedora compatibility link
|
||||
fedora_dir = os.path.join(mount_root, "boot/efi/EFI/fedora")
|
||||
os.makedirs(fedora_dir, exist_ok=True)
|
||||
with open(os.path.join(fedora_dir, "grub.cfg"), "w") as f:
|
||||
f.write(f"configfile /EFI/iridium/grub.cfg\n")
|
||||
else:
|
||||
if not disk_device:
|
||||
# Try to guess disk device from root partition
|
||||
disk_device = partition_info["root"].rstrip("0123456789")
|
||||
if disk_device.endswith("p"): disk_device = disk_device[:-1]
|
||||
|
||||
logger.info(f"Installing GRUB to {disk_device} (BIOS)")
|
||||
run_command(["chroot", mount_root, "grub2-install", "--target=i386-pc", disk_device])
|
||||
run_command(["chroot", mount_root, "grub2-mkconfig", "-o", "/boot/grub2/grub.cfg"])
|
||||
|
||||
# Add kernel entries
|
||||
modules_dir = os.path.join(mount_root, "lib/modules")
|
||||
if os.path.exists(modules_dir):
|
||||
kvers = [d for d in os.listdir(modules_dir) if os.path.isdir(os.path.join(modules_dir, d))]
|
||||
for kver in kvers:
|
||||
logger.info(f"Adding kernel entry for {kver}...")
|
||||
|
||||
# Ensure initramfs exists. If not, generate it.
|
||||
initrd_path_rel = f"boot/initramfs-{kver}.img"
|
||||
initrd_full_path = os.path.join(mount_root, initrd_path_rel)
|
||||
|
||||
if not os.path.exists(initrd_full_path):
|
||||
logger.info(f"Generating initramfs for {kver}...")
|
||||
run_command(["chroot", mount_root, "dracut", "--force", f"/boot/initramfs-{kver}.img", kver])
|
||||
|
||||
kernel_image = f"/lib/modules/{kver}/vmlinuz"
|
||||
initrd_arg = f"/boot/initramfs-{kver}.img"
|
||||
|
||||
# kernel-install add <version> <image> [initrd]
|
||||
cmd = ["chroot", mount_root, "kernel-install", "add", kver, kernel_image]
|
||||
if os.path.exists(os.path.join(mount_root, initrd_arg.lstrip("/"))):
|
||||
cmd.append(initrd_arg)
|
||||
|
||||
run_command(cmd)
|
||||
|
||||
# Ensure all data is synced to disk
|
||||
run_command(["sync"])
|
||||
|
||||
logger.info("System configuration complete.")
|
||||
|
||||
Reference in New Issue
Block a user