diff --git a/iridium_installer/backend/network_logging.py b/iridium_installer/backend/network_logging.py index 3fafb44..79c8a55 100644 --- a/iridium_installer/backend/network_logging.py +++ b/iridium_installer/backend/network_logging.py @@ -2,6 +2,7 @@ import logging import requests import threading import time +import os from datetime import datetime logger = logging.getLogger(__name__ + ".network_logging") @@ -41,7 +42,7 @@ def flush_logs(): def send_full_log(): - """Sends the entire session log as one or more messages at the end.""" + """Sends the entire session log as a text file attachment at the end.""" if not ENABLED: return @@ -55,25 +56,23 @@ def send_full_log(): return def send_sync(): + temp_file = "/tmp/iridium_install_log.txt" try: - # send_discord_message("--- FULL SESSION LOG START ---") - content = "```\n" - for log in logs_to_send: - ts = log["timestamp"][:19].replace("T", " ") - line = f"[{ts}] [{log['level']}] [{log['module']}] {log['message']}\n" - - if len(content) + len(line) > 1900: - content += "```" - send_discord_message(content) - content = "```\n" - - content += line + with open(temp_file, "w") as f: + for log in logs_to_send: + ts = log["timestamp"][:19].replace("T", " ") + line = f"[{ts}] [{log['level']}] [{log['module']}] {log['message']}\n" + f.write(line) - content += "```" - send_discord_message(content) - # send_discord_message("--- FULL SESSION LOG END ---") + with open(temp_file, "rb") as f: + files = {"file": ("iridium_install_log.txt", f)} + requests.post(DISCORD_WEBHOOK_URL, files=files, timeout=30) + except Exception as e: - print(f"Failed to send full log to Discord: {e}") + print(f"Failed to send full log file to Discord: {e}") + finally: + if os.path.exists(temp_file): + os.remove(temp_file) # For full log, we run it in a thread but wait for it t = threading.Thread(target=send_sync) @@ -84,9 +83,7 @@ def send_full_log(): def send_discord_message(content: str): try: payload = {"content": content} - response = requests.post(DISCORD_WEBHOOK_URL, json=payload, timeout=5) - if response.status_code not in [200, 204]: - print(f"Discord webhook error: {response.status_code} - {response.text}") + requests.post(DISCORD_WEBHOOK_URL, json=payload, timeout=5) except Exception as e: print(f"Discord webhook error: {e}") diff --git a/iridium_installer/backend/os_install.py b/iridium_installer/backend/os_install.py index 1168dab..cc5e36b 100644 --- a/iridium_installer/backend/os_install.py +++ b/iridium_installer/backend/os_install.py @@ -150,9 +150,9 @@ 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): +def configure_system(mount_root, partition_info, user_info=None): """ - Basic configuration: fstab and systemd-boot. + Basic configuration: fstab, systemd-boot, and user creation. """ logger.info("Configuring system...") log_os_install("CONFIGURE", "start", f"Configuring system in {mount_root}") @@ -179,7 +179,22 @@ UUID={efi_uuid} /boot vfat defaults 0 2 with open(os.path.join(mount_root, "etc/fstab"), "w") as f: f.write(fstab_content) - # 2. Configure systemd-boot + # 2. Configure User + if user_info: + logger.info(f"Creating user {user_info['username']}...") + with mount_pseudo_fs(mount_root): + # Create user and add to wheel group (sudoer) + run_command(["chroot", mount_root, "useradd", "-m", "-G", "wheel", user_info["username"]]) + + # Set password + p = subprocess.Popen(["chroot", mount_root, "chpasswd"], stdin=subprocess.PIPE, text=True) + p.communicate(input=f"{user_info['username']}:{user_info['password']}") + + # Set hostname + with open(os.path.join(mount_root, "etc/hostname"), "w") as f: + f.write(user_info["hostname"] + "\n") + + # 3. Configure systemd-boot with mount_pseudo_fs(mount_root): # Ensure machine-id exists for kernel-install if not os.path.exists(os.path.join(mount_root, "etc/machine-id")): @@ -191,7 +206,8 @@ UUID={efi_uuid} /boot vfat defaults 0 2 f.write(f"root=UUID={root_uuid} rw quiet\n") # Install systemd-boot to the ESP (mounted at /boot) - run_command(["chroot", mount_root, "bootctl", "install"]) + # Use --path=/boot to be explicit, though standard behavior usually finds it. + run_command(["chroot", mount_root, "bootctl", "install", "--path=/boot"]) # Add kernel entries modules_dir = os.path.join(mount_root, "lib/modules") @@ -199,17 +215,24 @@ UUID={efi_uuid} /boot vfat defaults 0 2 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" - # In Fedora, the initrd is usually created in /boot/initramfs-.img - # During installation, dnf should have triggered dracut. - initrd_path = f"/boot/initramfs-{kver}.img" - + # kernel-install add [initrd] cmd = ["chroot", mount_root, "kernel-install", "add", kver, kernel_image] - if os.path.exists(os.path.join(mount_root, initrd_path.lstrip("/"))): - cmd.append(initrd_path) + if os.path.exists(os.path.join(mount_root, initrd_arg.lstrip("/"))): + cmd.append(initrd_arg) run_command(cmd) logger.info("System configuration complete.") - log_os_install("CONFIGURE", "complete", "systemd-boot configured successfully") + log_os_install("CONFIGURE", "complete", "systemd-boot and user configured successfully") diff --git a/iridium_installer/main.py b/iridium_installer/main.py index 152a17d..320fc03 100644 --- a/iridium_installer/main.py +++ b/iridium_installer/main.py @@ -57,7 +57,14 @@ def main(): print("Step 4: Configuring Bootloader...") logger.info("INSTALLER_BOOTLOADER: Configuring bootloader") - configure_system(mount_root, parts) + + # Default user for CLI install (since we don't have user input in CLI args yet) + user_info = { + "username": "admin", + "password": "password", # Insecure default for CLI dev testing + "hostname": "iridium-cli" + } + configure_system(mount_root, parts, user_info) logger.info("INSTALLER_BOOTLOADER_COMPLETE: Bootloader configured") print("Installation complete! You can now reboot.") diff --git a/iridium_installer/ui/window.py b/iridium_installer/ui/window.py index 31b7cbf..cbe308c 100644 --- a/iridium_installer/ui/window.py +++ b/iridium_installer/ui/window.py @@ -306,13 +306,13 @@ class InstallerWindow(Adw.ApplicationWindow): logging.info("Step 4: Configuration...") nlog( "INSTALL_PROGRESS", - f"Session: {self.session_id} - Configuring bootloader", + f"Session: {self.session_id} - Configuring bootloader and user", "installer", ) - configure_system(mount_root, parts) + configure_system(mount_root, parts, user_info) nlog( "INSTALL_PROGRESS", - f"Session: {self.session_id} - Bootloader configuration complete", + f"Session: {self.session_id} - Configuration complete", "installer", )