2026-02-05 18:05:06 -05:00

214 lines
6.0 KiB
Python

"""Service packages installation and OpenRC configuration."""
import shutil
from pathlib import Path
from .utils import info, success, error, run, emerge
# Packages to emerge for system services
SERVICE_PACKAGES = [
# System essentials
"app-admin/sysklogd",
"sys-process/cronie",
# Network
"net-misc/networkmanager",
"net-misc/chrony",
"net-firewall/iptables",
# Bluetooth
"net-wireless/bluez",
"net-wireless/blueman",
# Desktop services
"sys-fs/udisks",
"sys-power/power-profiles-daemon",
"sys-auth/rtkit",
# Display manager
"x11-misc/sddm",
"gui-libs/display-manager-init",
# Containers
"app-containers/podman",
"app-containers/podman-compose",
"app-containers/podman-tui",
# Backup
"app-backup/snapper",
]
# OpenRC boot runlevel services
BOOT_SERVICES = [
"dbus",
"elogind",
"dmcrypt",
]
# OpenRC default runlevel services
DEFAULT_SERVICES = [
"sysklogd",
"sshd",
"NetworkManager",
"chronyd",
"cronie",
"power-profiles-daemon",
"display-manager",
"bluetooth",
"iptables",
"ip6tables",
]
def emerge_services() -> None:
"""Emerge service packages."""
info("=== Emerging Service Packages ===")
print()
info("Packages to install:")
for pkg in SERVICE_PACKAGES:
print(f" - {pkg}")
print()
emerge(*SERVICE_PACKAGES)
success("Service packages installed.")
def configure_display_manager() -> None:
"""Configure SDDM as the display manager."""
info("=== Configuring Display Manager ===")
dm_conf = Path("/etc/conf.d/display-manager")
if dm_conf.exists():
content = dm_conf.read_text()
# Check if already configured correctly (idempotency)
if 'DISPLAYMANAGER="sddm"' in content:
info("SDDM already configured as display manager")
return
# Update existing config
lines = content.split("\n")
new_lines = []
found = False
for line in lines:
if line.startswith("DISPLAYMANAGER="):
new_lines.append('DISPLAYMANAGER="sddm"')
found = True
else:
new_lines.append(line)
if not found:
new_lines.append('DISPLAYMANAGER="sddm"')
dm_conf.write_text("\n".join(new_lines))
else:
dm_conf.write_text('DISPLAYMANAGER="sddm"\n')
success("SDDM configured as display manager.")
def copy_system_configs(source_dir: Path) -> None:
"""Copy system configuration files."""
info("=== Copying System Configuration ===")
# conf.d/ -> /etc/conf.d/
conf_d_src = source_dir / "conf.d"
if conf_d_src.is_dir():
conf_d_dst = Path("/etc/conf.d")
for f in conf_d_src.iterdir():
if f.is_file():
shutil.copy2(f, conf_d_dst / f.name)
success(f"Copied conf.d/{f.name}")
# iptables/ -> /etc/iptables/ (for reference)
# Also copy to /var/lib/iptables/ and /var/lib/ip6tables/ (OpenRC locations)
iptables_src = source_dir / "iptables"
if iptables_src.is_dir():
# Copy to /etc/iptables for reference
iptables_etc = Path("/etc/iptables")
iptables_etc.mkdir(parents=True, exist_ok=True)
for f in iptables_src.iterdir():
if f.is_file():
shutil.copy2(f, iptables_etc / f.name)
success(f"Copied iptables/{f.name}")
# Copy to OpenRC service locations
iptables_var = Path("/var/lib/iptables")
ip6tables_var = Path("/var/lib/ip6tables")
iptables_var.mkdir(parents=True, exist_ok=True)
ip6tables_var.mkdir(parents=True, exist_ok=True)
rules_v4 = iptables_src / "iptables.rules"
rules_v6 = iptables_src / "ip6tables.rules"
if rules_v4.exists():
shutil.copy2(rules_v4, iptables_var / "rules-save")
success("Installed iptables rules to /var/lib/iptables/rules-save")
if rules_v6.exists():
shutil.copy2(rules_v6, ip6tables_var / "rules-save")
success("Installed ip6tables rules to /var/lib/ip6tables/rules-save")
# udev/ -> /etc/udev/rules.d/
udev_src = source_dir / "udev"
if udev_src.is_dir():
udev_dst = Path("/etc/udev/rules.d")
udev_dst.mkdir(parents=True, exist_ok=True)
for f in udev_src.iterdir():
if f.is_file():
shutil.copy2(f, udev_dst / f.name)
success(f"Copied udev/{f.name}")
def setup_openrc_services() -> None:
"""Add services to OpenRC runlevels."""
info("=== Configuring OpenRC Services ===")
# Boot runlevel
info("Adding boot runlevel services...")
for service in BOOT_SERVICES:
result = run("rc-update", "add", service, "boot", check=False)
if result.ok:
success(f" Added {service} to boot")
else:
error(f" Warning: Could not add {service} (may already exist)")
# Default runlevel
info("Adding default runlevel services...")
for service in DEFAULT_SERVICES:
result = run("rc-update", "add", service, "default", check=False)
if result.ok:
success(f" Added {service} to default")
else:
error(f" Warning: Could not add {service} (may already exist)")
print()
info("Current runlevel configuration:")
run("rc-update", "show")
def setup_services(source_dir: Path | None = None) -> None:
"""Full services setup workflow."""
if source_dir is None:
# Assume config files are in /root/gentoo or similar
# This should be passed from setup.py
source_dir = Path("/root/gentoo")
emerge_services()
print()
configure_display_manager()
print()
copy_system_configs(source_dir)
print()
setup_openrc_services()
print()
success("=== Services Setup Complete ===")
print()
info("Next steps:")
print(" 1. Install kernel: emerge gentoo-kernel-bin (or gentoo-kernel)")
print(" 2. Configure bootloader")
print(" 3. Set root password: passwd")
print(" 4. Create user account")
print(" 5. Reboot and test")