diff --git a/Cargo.lock b/Cargo.lock index ef13355..d4efc4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -130,12 +130,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itoa" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" - [[package]] name = "libc" version = "0.2.169" @@ -155,7 +149,6 @@ dependencies = [ "clap", "nix", "serde", - "serde_json", "toml", "yansi", ] @@ -190,12 +183,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - [[package]] name = "serde" version = "1.0.216" @@ -216,18 +203,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_json" -version = "1.0.135" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - [[package]] name = "serde_spanned" version = "0.6.8" diff --git a/Cargo.toml b/Cargo.toml index 490c9a6..8cff2a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,5 @@ edition = "2024" clap = { version = "4.5.23", features = ["cargo"] } nix = { version = "0.29.0", features = ["user"] } serde = { version = "1.0.216", features = ["derive"] } -serde_json = "1.0.135" toml = "0.8.19" yansi = "1.0.1" diff --git a/installs/desktop.toml b/installs/desktop.toml index c59366a..75c08ce 100644 --- a/installs/desktop.toml +++ b/installs/desktop.toml @@ -1,29 +1,59 @@ # Desktop Install Template +# Drive Selection for Install [drive] +# Device node for the EFI boot filesystem boot = "/dev/null" + +# Device node for the root filesystem root = "/dev/null" + +# Root filesystem encryption passphrase +# If this option is set the root filesystem will be encrypted with LUKS encryption = "password" +# General configuration [general] +# Preset mode = "Desktop" + +# System Locale locale = "de_DE.UTF-8" + +# Keymap keyboard_layout = "de" keyboard_variant = "mac" + +# Timezone timezone = "Europe/Berlin" + +# Hostname hostname = "navos" + +# Root password root_password = "root" + +# Enable Bluetooth bluetooth = true + +# GPU Video Drivers gpu_driver = "NVIDIA" -firewall = true [pkg] +# Additional packages pkg = [ "nano", "micro" ] +# User configuration +# The `[[user]]` directive can be repeated to create multiple users. [[user]] +# Username name = "u" + +# User password password = "pass" + +# Add user to wheel group wheel = true diff --git a/installs/full.toml b/installs/full.toml index 48c7839..85e39b8 100644 --- a/installs/full.toml +++ b/installs/full.toml @@ -15,10 +15,6 @@ encryption = "password" # General configuration [general] # Preset -# Available options: -# - `Base`: Basic Arch Linux Installation -# - `Desktop`: navOS Desktop Installation -# - `Server`: navOS Server Installation mode = "Desktop" # System Locale @@ -41,12 +37,8 @@ root_password = "root" bluetooth = true # GPU Video Drivers -# Available options: `NVIDIA`, `AMD`, `INTEL` gpu_driver = "NVIDIA" -# Enable firewall -firewall = true - [pkg] # Additional packages pkg = [ diff --git a/installs/min.toml b/installs/min.toml index 7b905c4..e2185ab 100644 --- a/installs/min.toml +++ b/installs/min.toml @@ -1,19 +1,38 @@ # Minimal Install Template +# Drive Selection for Install [drive] +# Device node for the EFI boot filesystem boot = "/dev/null" + +# Device node for the root filesystem root = "/dev/null" + +# Root filesystem encryption passphrase +# If this option is set the root filesystem will be encrypted with LUKS encryption = "password" +# General configuration [general] +# Preset mode = "Base" + +# System Locale locale = "de_DE.UTF-8" + +# Keymap keyboard_layout = "de" keyboard_variant = "mac" + +# Timezone timezone = "Europe/Berlin" + +# Hostname hostname = "navos_min" + +# Root password root_password = "root" -firewall = false [pkg] +# Additional packages pkg = [] diff --git a/installs/server.toml b/installs/server.toml index 58fec8a..67a33b4 100644 --- a/installs/server.toml +++ b/installs/server.toml @@ -1,36 +1,79 @@ # Server Install Template +# Drive Selection for Install [drive] +# Device node for the EFI boot filesystem boot = "/dev/null" + +# Device node for the root filesystem root = "/dev/null" + +# Root filesystem encryption passphrase +# If this option is set the root filesystem will be encrypted with LUKS encryption = "password" +# General configuration [general] +# Preset mode = "Server" + +# System Locale locale = "de_DE.UTF-8" + +# Keymap keyboard_layout = "de" keyboard_variant = "mac" + +# Timezone timezone = "Europe/Berlin" + +# Hostname hostname = "navos" + +# Root password root_password = "root" -firewall = true [pkg] +# Additional packages pkg = [] +# Enable virtualization virtualization = true + +# Enable docker docker = true +# User configuration +# The `[[user]]` directive can be repeated to create multiple users. [[user]] +# Username name = "u" + +# User password password = "pass" + +# Add user to wheel group wheel = true + +# Add user to Docker group docker = true + +# Add user to libvirt group virtualization = true +# SSH Configuration +# If `[ssh]` is set, openssh will be installed and enabled. [ssh] +# Config file for sshd +# This file will be copied to the new system sshd_config = "/etc/ssh/sshd_config" +# Install a SSH keys +# To set multiple keys, repeat the `[[ssh.key]]` directive. +# Every key will be installed in the users respective `authorized_keys` file. [[ssh.key]] +# The SSH Key key = "ssh-rsa ... user@host" + +# The users allowed to login with this key users = ["u", "root"] diff --git a/src/config.rs b/src/config.rs index 95372c2..2b4b301 100644 --- a/src/config.rs +++ b/src/config.rs @@ -88,16 +88,14 @@ pub struct GeneralConfig { // Enable Bluetooth pub bluetooth: Option, /// Install Video Driver - pub gpu_driver: Option, - // Eanble firewall - pub firewall: Option, + pub gpu_driver: Option } #[derive(Debug, Clone, Deserialize)] pub enum GPUVendor { AMD, NVIDIA, - INTEL, + INTEL } #[derive(Debug, Clone, Deserialize)] diff --git a/src/install/drives.rs b/src/install/drives.rs index 2d4160a..e95bde2 100644 --- a/src/install/drives.rs +++ b/src/install/drives.rs @@ -1,13 +1,10 @@ -use yansi::{Color, Paint}; - -use crate::{config::DriveConfig, linux::run_command, print_status}; +use crate::{config::DriveConfig, linux::run_command}; // TODO : Add support for using entire block device /// Format the drives with the given config pub fn format_drives(conf: &DriveConfig) { - disk_safe_check(&conf.root); - disk_safe_check(&conf.root); + // TODO : Safety checks !!! // EFI (BOOT) run_command(&["mkfs.vfat", "-F", "32", conf.boot.as_str()], None, false); @@ -55,59 +52,3 @@ pub fn mount_drives(conf: &DriveConfig) { false, ); } - -/// Format a disk with EFI and BOOT partitions. -pub fn partition_disk(dev: &str) { - disk_safe_check(dev); - print_status(&format!("Formatting disk {dev}")); - let cmd = vec!["fdisk", dev]; - let input = "g\nn\n1\n\n+1G\nt\n1\nn\n2\n\nw\n"; - run_command(&cmd, Some(input), false); -} - -/// Check if `dev` contains a filesystem and error if it does -pub fn disk_safe_check(dev: &str) { - if let Some(fs) = has_filesystem(dev) { - println!( - "{} Device {} already contains a filesystem {}", - "Error:".paint(Color::Red), - dev.paint(Color::Red), - fs.paint(Color::Blue) - ); - std::process::exit(1); - } -} - -pub fn has_filesystem(dev: &str) -> Option { - let blockdevs: serde_json::Value = - serde_json::from_str(&run_command(&["lsblk", "--fs", "--json"], None, false).0).unwrap(); - - // TODO : Follow if symlink from /dev/disks - let dev = dev.trim_start_matches("/dev/"); - - let dev_entry = blockdevs - .as_object() - .unwrap() - .get("blockdevices") - .unwrap() - .as_array() - .unwrap() - .iter() - .find(|x| { - x.as_object() - .unwrap() - .get("name") - .unwrap() - .as_str() - .unwrap() - == dev - }); - - if let Some(dev_entry) = dev_entry { - if let Some(fs) = dev_entry.as_object().unwrap().get("fstype") { - return Some(fs.to_string()); - } - } - - None -} diff --git a/src/install/firewall.rs b/src/install/firewall.rs deleted file mode 100644 index 0a48a73..0000000 --- a/src/install/firewall.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::{ - linux::{arch_chroot, systemd_service_enable}, - pkg::install_pkgs, - print_status, -}; - -/// Setup UFW -pub fn setup_firewall(ssh: bool) { - print_status("Enabling firewall"); - install_pkgs(&["ufw"]); - systemd_service_enable("ufw.service"); - - arch_chroot(&["ufw", "default", "deny"], None, false); - - if ssh { - arch_chroot(&["ufw", "allow", "22/tcp"], None, false); - - arch_chroot(&["ufw", "limit", "ssh"], None, false); - } - - arch_chroot(&["ufw", "enable"], None, false); -} diff --git a/src/install/firmware.rs b/src/install/firmware.rs index 5cd8fa6..7bbd09e 100644 --- a/src/install/firmware.rs +++ b/src/install/firmware.rs @@ -1,13 +1,11 @@ use crate::{linux::systemd_service_enable, pkg::install_pkgs, print_status}; -/// Setup firmware update daemon pub fn setup_fwupd() { print_status("Enabling firmware updates"); install_pkgs(&["fwupd"]); systemd_service_enable("fwupd-refresh.timer"); } -/// Setup CPU Microcode pub fn setup_microcode() { print_status("Installing CPU Microcode"); let cpuinfo = std::fs::read_to_string("/proc/cpuinfo").unwrap(); diff --git a/src/install/first_boot.rs b/src/install/first_boot.rs index bae4650..d59bcf6 100644 --- a/src/install/first_boot.rs +++ b/src/install/first_boot.rs @@ -45,14 +45,7 @@ pub fn first_boot_values(conf: &GeneralConfig) { print_status("Writing /etc/hostname"); std::fs::write("/mnt/etc/hostname", format!("{}\n", conf.hostname)).unwrap(); - install_file( - "/mnt/etc/hosts", - &format!( - "127.0.0.1 localhost\n::1 localhost\n127.0.1.1 {}\n", - conf.hostname - ), - 0o644, - ); + install_file("/mnt/etc/hosts", &format!("127.0.0.1 localhost\n::1 localhost\n127.0.1.1 {}\n", conf.hostname), 0o644); // LOCALE print_status("Setting locale"); diff --git a/src/install/gpu.rs b/src/install/gpu.rs index 9532dda..73e5cca 100644 --- a/src/install/gpu.rs +++ b/src/install/gpu.rs @@ -1,28 +1,15 @@ use crate::{config::GPUVendor, pkg::install_pkgs}; -/// Setup GPU video drivers pub fn setup_video_drivers(vendor: &GPUVendor) { match vendor { GPUVendor::AMD => { - install_pkgs(&[ - "xf86-video-amdgpu", - "mesa", - "lib32-mesa", - "vulkan-radeon", - "lib32-vulkan-radeon", - ]); - } + install_pkgs(&["xf86-video-amdgpu", "mesa", "lib32-mesa", "vulkan-radeon", "lib32-vulkan-radeon"]); + }, GPUVendor::NVIDIA => { install_pkgs(&["nvidia", "nvidia-utils", "lib32-nvidia-utils"]); - } + }, GPUVendor::INTEL => { - install_pkgs(&[ - "xf86-video-intel2", - "mesa", - "lib32-mesa", - "vulkan-intel", - "lib32-vulkan-intel", - ]); - } + install_pkgs(&["xf86-video-intel2", "mesa", "lib32-mesa", "vulkan-intel", "lib32-vulkan-intel"]); + }, } } diff --git a/src/install/kernel.rs b/src/install/kernel.rs index 539006b..c71c69b 100644 --- a/src/install/kernel.rs +++ b/src/install/kernel.rs @@ -6,7 +6,6 @@ use crate::{ print_status, }; -/// Setup initramfs pub fn setup_mkinitcpio(conf: &DriveConfig) { print_status("Writing /etc/mkinitcpio.d/linux.preset"); install_file( diff --git a/src/install/mod.rs b/src/install/mod.rs index b30de83..3ac2c15 100644 --- a/src/install/mod.rs +++ b/src/install/mod.rs @@ -1,5 +1,6 @@ // TODO : Autojoin docker swarm // TODO : Autojoin teleport +// TODO : Firewall // DRIVE SELECTION @@ -8,7 +9,6 @@ use boot::setup_bootloader; use desktop::setup_desktop; use docker::setup_docker; use drives::{format_drives, mount_drives}; -use firewall::setup_firewall; use firmware::{setup_fwupd, setup_microcode}; use first_boot::{first_boot_values, genfstab}; use gpu::setup_video_drivers; @@ -28,10 +28,7 @@ pub mod boot; pub mod desktop; pub mod docker; pub mod drives; -pub mod firewall; -pub mod firmware; pub mod first_boot; -pub mod gpu; pub mod kernel; pub mod navos; pub mod ollama; @@ -41,22 +38,14 @@ pub mod ssh; pub mod user; pub mod virt; pub mod zram; +pub mod firmware; +pub mod gpu; use crate::{ config::InstallConfig, pkg::{self, install_pkgs, pacstrap}, }; -/// Uncomment the first occurrence of a specified value in a file. -/// -/// This function searches for the first line in the specified file that contains -/// the given `value` string. If the line is commented out with a `#` symbol, -/// it removes the `#` and updates the file. -/// -/// # Arguments -/// -/// * `value` - A string that specifies the value to search for in the file. -/// * `file` - A string specifying the path to the file. pub fn uncomment_first_value_of(value: &str, file: &str) { // read in the file let content = std::fs::read_to_string(file).unwrap(); @@ -77,15 +66,6 @@ pub fn uncomment_first_value_of(value: &str, file: &str) { std::fs::write(file, new).unwrap(); } -/// Uncomment lines that start with a specified tag in a file. -/// -/// This function processes all lines in the specified file. For any line that starts -/// with the provided `tag`, it removes the `tag` and updates the file. -/// -/// # Arguments -/// -/// * `tag` - A string specifying the prefix tag to remove from matching lines. -/// * `file` - A string specifying the path to the file. pub fn uncomment_tag(tag: &str, file: &str) { // read in the file let content = std::fs::read_to_string(file).unwrap(); @@ -115,13 +95,15 @@ pub fn install(conf: InstallConfig) { pacstrap(&conf.pkg); genfstab(); - // Configuration + // System Setup first_boot_values(&conf.general); setup_skel(&conf.general); setup_users(&conf.user.as_ref().unwrap_or(&Vec::new())); + setup_ssh(&conf.ssh); - // Presets + setup_bootloader(); + match conf.general.mode { crate::config::InstallMode::Base => {} crate::config::InstallMode::Desktop => { @@ -136,8 +118,6 @@ pub fn install(conf: InstallConfig) { } } - // Applications - if conf.pkg.virtualization.unwrap_or_default() { setup_virtualization(&conf); } @@ -156,24 +136,18 @@ pub fn install(conf: InstallConfig) { setup_ollama(&ai); } - // Connectivity + setup_zram(); + if conf.general.bluetooth.unwrap_or_default() { setup_bluetooth(); } - if conf.general.firewall.unwrap_or(true) { - setup_firewall(conf.ssh.is_some()); - } - - // System - setup_zram(); setup_vm(); if let Some(gpu_vendor) = &conf.general.gpu_driver { setup_video_drivers(gpu_vendor); } setup_fwupd(); setup_microcode(); - setup_bootloader(); setup_mkinitcpio(&conf.drive); setup_secure_boot(); @@ -181,5 +155,5 @@ pub fn install(conf: InstallConfig) { setup_tpm_unlock(&conf.drive); } - println!("{}", "System install complete".bold().paint(Color::Green)); + println!("{}", "System install complete".paint(Color::Green)); } diff --git a/src/install/ollama.rs b/src/install/ollama.rs index 0210abe..1729105 100644 --- a/src/install/ollama.rs +++ b/src/install/ollama.rs @@ -1,9 +1,4 @@ -use crate::{ - config::OllamaConfig, - linux::{arch_chroot, systemd_service_enable}, - pkg::install_pkgs, - print_status, -}; +use crate::{config::OllamaConfig, linux::systemd_service_enable, pkg::install_pkgs}; /// Setup Ollama AI Service pub fn setup_ollama(conf: &OllamaConfig) { @@ -15,20 +10,7 @@ pub fn setup_ollama(conf: &OllamaConfig) { systemd_service_enable("ollama.service"); - print_status("Pulling Models"); - - let mut ollama_server = std::process::Command::new("arch-chroot") - .arg("/mnt") - .arg("runuser -u ollama -- env OLLAMA_MODELS=/var/lib/ollama HOME=/var/lib/ollama /usr/bin/ollama serve") - .stdout(Stdio::piped()) - .spawn() - .expect("Failed to start ollama server"); - - let models = conf.models.clone().unwrap_or_default(); - - for model in models { - arch_chroot(&["ollama", "pull", &model], None, true); + for model in conf.models.clone().unwrap_or_default() { + // TODO : Pull models } - - ollama_server.kill().unwrap(); } diff --git a/src/install/ssh.rs b/src/install/ssh.rs index 0af5f65..1157df9 100644 --- a/src/install/ssh.rs +++ b/src/install/ssh.rs @@ -1,9 +1,4 @@ -use crate::{ - config::SSHConfig, - linux::{install_file, systemd_service_enable}, - pkg::install_pkgs, - print_status, -}; +use crate::{config::SSHConfig, linux::install_file, pkg::install_pkgs, print_status}; use std::io::Write; /// Setup SSH on the system @@ -39,7 +34,5 @@ pub fn setup_ssh(conf: &Option) { writeln!(authorized_keys, "{}\n", key.key).unwrap(); } } - - systemd_service_enable("sshd.service"); } } diff --git a/src/install/user.rs b/src/install/user.rs index 3ff7ad7..b463a74 100644 --- a/src/install/user.rs +++ b/src/install/user.rs @@ -1,8 +1,5 @@ use crate::{ - config::UserConfig, - linux::{arch_chroot, install_file}, - pkg::install_pkgs, - print_status, + config::UserConfig, linux::{arch_chroot, install_file}, pkg::install_pkgs, print_status }; pub fn change_passwd(user: &str, pw: &str) { diff --git a/src/install/virt.rs b/src/install/virt.rs index 7ff0602..78757fe 100644 --- a/src/install/virt.rs +++ b/src/install/virt.rs @@ -1,8 +1,7 @@ use crate::{ config::{InstallConfig, InstallMode}, - linux::{arch_chroot, run_command, systemd_service_enable}, + linux::{arch_chroot, systemd_service_enable}, pkg::install_pkgs, - print_status, }; pub fn setup_virtualization(conf: &InstallConfig) { @@ -31,19 +30,6 @@ pub fn setup_virtualization(conf: &InstallConfig) { } } -/// Setup guest utils if running inside a VM pub fn setup_vm() { - let is_vm = run_command(&["systemd-detect-virt", "--vm"], None, false) - .0 - .trim(); - - match is_vm { - "qemu" | "kvm" => { - print_status("Detected KVM. Installing utils"); - install_pkgs(&["qemu-guest-agent", "spice-vdagent"]); - systemd_service_enable("qemu-guest-agent.service"); - systemd_service_enable("spice-vdagentd.service"); - } - _ => {} - } + // TODO : Install guest tools if in virt with systemd-detect-virt } diff --git a/src/linux.rs b/src/linux.rs index 5cfd3ef..3711f80 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -75,6 +75,7 @@ pub fn install_file(path: &str, content: &str, permissions: u32) { file.write_all(content.as_bytes()).unwrap(); let permissions = std::fs::Permissions::from_mode(permissions); - print_status(&format!("Wrote file {path} [{:o}]", permissions.mode())); + // TODO : Fix permission format + print_status(&format!("Wrote file {path} [{permissions:#?}]")); std::fs::set_permissions(path, permissions).unwrap(); } diff --git a/src/pkg.rs b/src/pkg.rs index 5604561..479412e 100644 --- a/src/pkg.rs +++ b/src/pkg.rs @@ -3,16 +3,18 @@ use crate::{ linux::{arch_chroot, run_command}, }; -pub const DESKTOP_PKG: [&str; 17] = [ +pub const DESKTOP_PKG: [&str; 16] = [ // Desktop "plasma", "sddm", + // Sound "pipewire", "pipewire-alsa", "pipewire-pulse", "pipewire-jack", "wireplumber", + // Applications "konsole", "dolphin", @@ -22,9 +24,9 @@ pub const DESKTOP_PKG: [&str; 17] = [ "gwenview", "ark", "flatpak", + // Misc - "navos/navos", - "man", + "navos/navos" ]; pub const SERVER_PKG: [&str; 2] = ["tmux", "navos/navos"]; @@ -58,6 +60,7 @@ pub fn pacstrap(conf: &PackageConfig) { "zsh", "zsh-completions", "zsh-autosuggestions", + "man" ]; cmd.extend( diff --git a/src/print.rs b/src/print.rs index 1719aa1..efa6877 100644 --- a/src/print.rs +++ b/src/print.rs @@ -65,20 +65,11 @@ pub fn print_config(conf: &InstallConfig) { } if let Some(vendor) = &conf.general.gpu_driver { match vendor { - crate::config::GPUVendor::AMD => { - general_info.add_str(format!("🟥 AMD GPU {}", "✔️".paint(Color::Green))) - } - crate::config::GPUVendor::INTEL => { - general_info.add_str(format!("🟦 Intel GPU {}", "✔️".paint(Color::Green))) - } - crate::config::GPUVendor::NVIDIA => { - general_info.add_str(format!("🟩 NVIDIA GPU {}", "✔️".paint(Color::Green))) - } + crate::config::GPUVendor::AMD => general_info.add_str(format!("🟥 AMD GPU {}", "✔️".paint(Color::Green))), + crate::config::GPUVendor::INTEL => general_info.add_str(format!("🟦 Intel GPU {}", "✔️".paint(Color::Green))), + crate::config::GPUVendor::NVIDIA => general_info.add_str(format!("🟩 NVIDIA GPU {}", "✔️".paint(Color::Green))), } } - if conf.general.firewall.unwrap_or(true) { - general_info.add_str(format!("🔥 Firewall {}", "✔️".paint(Color::Green))); - } root_info.add_tree("🔨 General", general_info);