# shellcheck shell=bash usage() { echo "Usage: $0 flake -m install|repair -h host [-k key] [-p password_file] [-c] [-r]" echo echo "Options:" echo " flake Directory containing the flake.nix file." echo " -m mode Mode: 'install' or 'repair'." echo " -h host Host to configure." echo " -k key Key file to copy to user config." echo " -p password_file LUKS password file to use for encryption." echo " -c Copy configuration to target." echo " -r Reboot after completion." exit 1 } check_root() { if [[ "$EUID" -ne 0 ]]; then echo "Please run the script as root." exit 1 fi } check_network() { if ! ping -c 1 google.com &>/dev/null; then echo "Connect to a network before proceeding." exit 1 fi } check_flake() { if [[ ! -f "$flake/flake.nix" ]]; then echo "flake.nix not found in $flake." exit 1 fi } check_host() { if ! nix flake show --quiet --json "$flake" 2>/dev/null | jq -e ".nixosConfigurations[\"$host\"]" &>/dev/null; then echo "Host '$host' not found in flake." exit 1 fi } check_key() { if [[ -n "$key" ]] && [[ ! -f "$flake/secrets/$key/key.txt" ]]; then echo "Key '$key' not found." exit 1 fi } set_password_file() { if [[ -n "$password_file" ]]; then if [[ ! -f "$password_file" ]]; then echo "LUKS key file '$password_file' not found." exit 1 fi ln -sf "$(realpath "$password_file")" /tmp/installer.key else echo "Enter password for LUKS encryption:" IFS= read -r -s password echo "Enter password again to confirm: " IFS= read -r -s password_check [ "$password" != "$password_check" ] echo -n "$password" > /tmp/installer.key unset password password_check fi } prepare_disk() { local disko_mode="$1" mkdir -p /mnt root=$(mktemp -d /mnt/install.XXXXXX) disko -m "$disko_mode" --yes-wipe-all-disks --root-mountpoint "$root" "$flake/hosts/$host/format.nix" } copy_keys() { mkdir -p "$root/persist/etc/ssh" cp "$flake/hosts/$host/secrets/ssh_host_ed25519_key" "$root/persist/etc/ssh/ssh_host_ed25519_key" for path in "$flake/hosts/$host/users"/*; do if [[ -z "$key" ]]; then continue fi local user user=$(basename "$path") mkdir -p "$root/persist/home/$user/.config/sops-nix" cp "$flake/secrets/$key/key.txt" "$root/persist/home/$user/.config/sops-nix/key.txt" chown -R "$(cat "$flake/hosts/$host/users/$user/uid"):100" "$root/persist/home/$user" done } install() { nixos-install --root "$root" --flake "$flake#$host" --no-root-passwd } copy_config() { echo "Copying configuration..." rm -rf "$root/persist/etc/nixos" cp -r "$flake" "$root/persist/etc/nixos" } finish() { echo "Rebooting system..." trap - EXIT cleanup reboot } cleanup() { rm -f /tmp/installer.key if [[ -n "$host" ]]; then disko -m "unmount" "$flake/hosts/$host/format.nix"; fi if [[ -d "$root" ]]; then rmdir "$root"; fi } check_root check_network if [[ "$#" -lt 1 ]]; then usage fi flake="$(realpath "$1")" check_flake shift mode="" host="" key="" password_file="" copy_config_flag="false" reboot_flag="false" while getopts "m:h:k:p:cr" opt; do case "$opt" in m) mode="$OPTARG" ;; h) host="$OPTARG" ;; k) key="$OPTARG" ;; p) password_file="$OPTARG" ;; c) copy_config_flag="true" ;; r) reboot_flag="true" ;; *) usage ;; esac done if [[ -z "$mode" || -z "$host" ]]; then usage fi check_host check_key until set_password_file; do echo "Passwords did not match, please try again."; done case "$mode" in install) prepare_disk "destroy,format,mount" copy_keys install if [[ "$copy_config_flag" == "true" ]]; then copy_config; fi if [[ "$reboot_flag" == "true" ]]; then finish; fi ;; repair) prepare_disk "mount" install if [[ "$reboot_flag" == "true" ]]; then finish; fi ;; *) echo "Invalid mode: $mode" usage ;; esac