Send logs as file, create sudoer user, and improve bootloader reliability
This commit is contained in:
@@ -2,6 +2,7 @@ import logging
|
|||||||
import requests
|
import requests
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
logger = logging.getLogger(__name__ + ".network_logging")
|
logger = logging.getLogger(__name__ + ".network_logging")
|
||||||
@@ -41,7 +42,7 @@ def flush_logs():
|
|||||||
|
|
||||||
|
|
||||||
def send_full_log():
|
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:
|
if not ENABLED:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -55,25 +56,23 @@ def send_full_log():
|
|||||||
return
|
return
|
||||||
|
|
||||||
def send_sync():
|
def send_sync():
|
||||||
|
temp_file = "/tmp/iridium_install_log.txt"
|
||||||
try:
|
try:
|
||||||
# send_discord_message("--- FULL SESSION LOG START ---")
|
with open(temp_file, "w") as f:
|
||||||
content = "```\n"
|
|
||||||
for log in logs_to_send:
|
for log in logs_to_send:
|
||||||
ts = log["timestamp"][:19].replace("T", " ")
|
ts = log["timestamp"][:19].replace("T", " ")
|
||||||
line = f"[{ts}] [{log['level']}] [{log['module']}] {log['message']}\n"
|
line = f"[{ts}] [{log['level']}] [{log['module']}] {log['message']}\n"
|
||||||
|
f.write(line)
|
||||||
|
|
||||||
if len(content) + len(line) > 1900:
|
with open(temp_file, "rb") as f:
|
||||||
content += "```"
|
files = {"file": ("iridium_install_log.txt", f)}
|
||||||
send_discord_message(content)
|
requests.post(DISCORD_WEBHOOK_URL, files=files, timeout=30)
|
||||||
content = "```\n"
|
|
||||||
|
|
||||||
content += line
|
|
||||||
|
|
||||||
content += "```"
|
|
||||||
send_discord_message(content)
|
|
||||||
# send_discord_message("--- FULL SESSION LOG END ---")
|
|
||||||
except Exception as e:
|
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
|
# For full log, we run it in a thread but wait for it
|
||||||
t = threading.Thread(target=send_sync)
|
t = threading.Thread(target=send_sync)
|
||||||
@@ -84,9 +83,7 @@ def send_full_log():
|
|||||||
def send_discord_message(content: str):
|
def send_discord_message(content: str):
|
||||||
try:
|
try:
|
||||||
payload = {"content": content}
|
payload = {"content": content}
|
||||||
response = requests.post(DISCORD_WEBHOOK_URL, json=payload, timeout=5)
|
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}")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Discord webhook error: {e}")
|
print(f"Discord webhook error: {e}")
|
||||||
|
|
||||||
|
|||||||
@@ -150,9 +150,9 @@ def install_minimal_os(mount_root, releasever="43"):
|
|||||||
log_os_install("INSTALL", "complete", f"Installed to {mount_root}")
|
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...")
|
logger.info("Configuring system...")
|
||||||
log_os_install("CONFIGURE", "start", f"Configuring system in {mount_root}")
|
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:
|
with open(os.path.join(mount_root, "etc/fstab"), "w") as f:
|
||||||
f.write(fstab_content)
|
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):
|
with mount_pseudo_fs(mount_root):
|
||||||
# Ensure machine-id exists for kernel-install
|
# Ensure machine-id exists for kernel-install
|
||||||
if not os.path.exists(os.path.join(mount_root, "etc/machine-id")):
|
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")
|
f.write(f"root=UUID={root_uuid} rw quiet\n")
|
||||||
|
|
||||||
# Install systemd-boot to the ESP (mounted at /boot)
|
# 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
|
# Add kernel entries
|
||||||
modules_dir = os.path.join(mount_root, "lib/modules")
|
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))]
|
kvers = [d for d in os.listdir(modules_dir) if os.path.isdir(os.path.join(modules_dir, d))]
|
||||||
for kver in kvers:
|
for kver in kvers:
|
||||||
logger.info(f"Adding kernel entry for {kver}...")
|
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"
|
kernel_image = f"/lib/modules/{kver}/vmlinuz"
|
||||||
|
initrd_arg = f"/boot/initramfs-{kver}.img"
|
||||||
|
|
||||||
# In Fedora, the initrd is usually created in /boot/initramfs-<version>.img
|
# kernel-install add <version> <image> [initrd]
|
||||||
# During installation, dnf should have triggered dracut.
|
|
||||||
initrd_path = f"/boot/initramfs-{kver}.img"
|
|
||||||
|
|
||||||
cmd = ["chroot", mount_root, "kernel-install", "add", kver, kernel_image]
|
cmd = ["chroot", mount_root, "kernel-install", "add", kver, kernel_image]
|
||||||
if os.path.exists(os.path.join(mount_root, initrd_path.lstrip("/"))):
|
if os.path.exists(os.path.join(mount_root, initrd_arg.lstrip("/"))):
|
||||||
cmd.append(initrd_path)
|
cmd.append(initrd_arg)
|
||||||
|
|
||||||
run_command(cmd)
|
run_command(cmd)
|
||||||
|
|
||||||
logger.info("System configuration complete.")
|
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")
|
||||||
|
|||||||
@@ -57,7 +57,14 @@ def main():
|
|||||||
|
|
||||||
print("Step 4: Configuring Bootloader...")
|
print("Step 4: Configuring Bootloader...")
|
||||||
logger.info("INSTALLER_BOOTLOADER: 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")
|
logger.info("INSTALLER_BOOTLOADER_COMPLETE: Bootloader configured")
|
||||||
|
|
||||||
print("Installation complete! You can now reboot.")
|
print("Installation complete! You can now reboot.")
|
||||||
|
|||||||
@@ -306,13 +306,13 @@ class InstallerWindow(Adw.ApplicationWindow):
|
|||||||
logging.info("Step 4: Configuration...")
|
logging.info("Step 4: Configuration...")
|
||||||
nlog(
|
nlog(
|
||||||
"INSTALL_PROGRESS",
|
"INSTALL_PROGRESS",
|
||||||
f"Session: {self.session_id} - Configuring bootloader",
|
f"Session: {self.session_id} - Configuring bootloader and user",
|
||||||
"installer",
|
"installer",
|
||||||
)
|
)
|
||||||
configure_system(mount_root, parts)
|
configure_system(mount_root, parts, user_info)
|
||||||
nlog(
|
nlog(
|
||||||
"INSTALL_PROGRESS",
|
"INSTALL_PROGRESS",
|
||||||
f"Session: {self.session_id} - Bootloader configuration complete",
|
f"Session: {self.session_id} - Configuration complete",
|
||||||
"installer",
|
"installer",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user