Huge update to the disk selection method. Now support striped or mirrored boot disk(s), and up to 9 disks for data with automatic inclusion of up to 3 parity disks.
This commit is contained in:
+2
-1
@@ -1,3 +1,4 @@
|
||||
agents/
|
||||
ai-production/
|
||||
extra-files/
|
||||
extra-files/
|
||||
test.sh
|
||||
@@ -1,110 +0,0 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
# Boot disk
|
||||
system = {
|
||||
type = "disk";
|
||||
device = "${BOOT_DISK_1}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "1G";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted";
|
||||
settings = {
|
||||
allowDiscards = true;
|
||||
};
|
||||
content = {
|
||||
type = "lvm_pv";
|
||||
vg = "pool";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# First data disk
|
||||
data1 = {
|
||||
type = "disk";
|
||||
device = "${DATA_DISK_1}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-data-1";
|
||||
keyFile = "/run/secrets/disks/data-disk-1";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/data-1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Parity disk
|
||||
parity1 = {
|
||||
type = "disk";
|
||||
device = "${PARITY_DISK_1}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-parity-1";
|
||||
keyFile = "/run/secrets/disks/parity-disk-1";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/parity-1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Boot disk LVM configuration
|
||||
lvm_vg = {
|
||||
pool = {
|
||||
type = "lvm_vg";
|
||||
lvs = {
|
||||
root = {
|
||||
size = "100%FREE";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
swap = {
|
||||
size = "8G";
|
||||
content.type = "swap";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
# Boot disk
|
||||
system = {
|
||||
type = "disk";
|
||||
device = "${BOOT_DISK_1}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "1G";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted";
|
||||
settings = {
|
||||
allowDiscards = true;
|
||||
};
|
||||
content = {
|
||||
type = "lvm_pv";
|
||||
vg = "pool";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# First data disk
|
||||
data1 = {
|
||||
type = "disk";
|
||||
device = "${DATA_DISK_1}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-data-1";
|
||||
keyFile = "/run/secrets/disks/data-disk-1";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/data-1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Second data disk
|
||||
data2 = {
|
||||
type = "disk";
|
||||
device = "${DATA_DISK_2}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-data-2";
|
||||
keyFile = "/run/secrets/disks/data-disk-2";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/data-2";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Parity disk
|
||||
parity1 = {
|
||||
type = "disk";
|
||||
device = "${PARITY_DISK_1}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-parity-1";
|
||||
keyFile = "/run/secrets/disks/parity-disk-1";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/parity-1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Boot disk LVM configuration
|
||||
lvm_vg = {
|
||||
pool = {
|
||||
type = "lvm_vg";
|
||||
lvs = {
|
||||
root = {
|
||||
size = "100%FREE";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
swap = {
|
||||
size = "8G";
|
||||
content.type = "swap";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
# Boot disk
|
||||
system = {
|
||||
type = "disk";
|
||||
device = "${BOOT_DISK_1}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
size = "1G";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted";
|
||||
settings = {
|
||||
allowDiscards = true;
|
||||
};
|
||||
content = {
|
||||
type = "lvm_pv";
|
||||
vg = "pool";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# First data disk
|
||||
data1 = {
|
||||
type = "disk";
|
||||
device = "${DATA_DISK_1}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-data-1";
|
||||
keyFile = "/run/secrets/disks/data-disk-1";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/data-1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Second data disk
|
||||
data2 = {
|
||||
type = "disk";
|
||||
device = "${DATA_DISK_2}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-data-2";
|
||||
keyFile = "/run/secrets/disks/data-disk-2";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/data-2";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Third data disk
|
||||
data3 = {
|
||||
type = "disk";
|
||||
device = "${DATA_DISK_3}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-data-3";
|
||||
keyFile = "/run/secrets/disks/data-disk-3";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/data-3";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Parity disk
|
||||
parity1 = {
|
||||
type = "disk";
|
||||
device = "${PARITY_DISK_1}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-parity-1";
|
||||
keyFile = "/run/secrets/disks/parity-disk-1";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/parity-1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Boot disk LVM configuration
|
||||
lvm_vg = {
|
||||
pool = {
|
||||
type = "lvm_vg";
|
||||
lvs = {
|
||||
root = {
|
||||
size = "100%FREE";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
swap = {
|
||||
size = "8G";
|
||||
content.type = "swap";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,9 +1,27 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
disko.devices = {
|
||||
# Boot disk LVM configuration
|
||||
lvm_vg = {
|
||||
pool = {
|
||||
type = "lvm_vg";
|
||||
lvs = {
|
||||
root = {
|
||||
size = "100%FREE";
|
||||
content.type = "filesystem";
|
||||
content.format = "btrfs";
|
||||
content.mountpoint = "/";
|
||||
};
|
||||
swap = {
|
||||
size = "16G";
|
||||
content.type = "swap";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
disk = {
|
||||
# Boot disk
|
||||
system = {
|
||||
system-1 = {
|
||||
type = "disk";
|
||||
device = "${BOOT_DISK_1}";
|
||||
content = {
|
||||
@@ -35,28 +53,4 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Boot disk LVM configuration
|
||||
lvm_vg = {
|
||||
pool = {
|
||||
type = "lvm_vg";
|
||||
lvs = {
|
||||
root = {
|
||||
size = "100%FREE";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
swap = {
|
||||
size = "8G";
|
||||
content.type = "swap";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -2,8 +2,7 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
# Boot disk
|
||||
system = {
|
||||
system-1 = {
|
||||
type = "disk";
|
||||
device = "${BOOT_DISK_1}";
|
||||
content = {
|
||||
@@ -19,68 +18,56 @@
|
||||
mountOptions = [ "umask=0077" ];
|
||||
};
|
||||
};
|
||||
luks = {
|
||||
crypt_p1 = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted";
|
||||
name = "nixos-p1";
|
||||
settings = {
|
||||
allowDiscards = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
system-2 = {
|
||||
type = "disk";
|
||||
device = "${BOOT_DISK_2}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
crypt_p2 = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "nixos-p2";
|
||||
settings = {
|
||||
allowDiscards = true;
|
||||
};
|
||||
content = {
|
||||
type = "lvm_pv";
|
||||
vg = "pool";
|
||||
type = "btrfs";
|
||||
extraArgs = [
|
||||
"-d raid1"
|
||||
"/dev/mapper/nixos-p1"
|
||||
];
|
||||
subvolumes = {
|
||||
"/root" = {
|
||||
mountpoint = "/";
|
||||
mountOptions = [
|
||||
"rw"
|
||||
"relatime"
|
||||
"ssd"
|
||||
];
|
||||
};
|
||||
"/swap" = {
|
||||
mountpoint = "none";
|
||||
swap.size = "16G";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# First data disk
|
||||
data1 = {
|
||||
type = "disk";
|
||||
device = "${DATA_DISK_1}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-data-1";
|
||||
keyFile = "/run/secrets/disks/data-disk-1";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/data-1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Boot disk LVM configuration
|
||||
lvm_vg = {
|
||||
pool = {
|
||||
type = "lvm_vg";
|
||||
lvs = {
|
||||
root = {
|
||||
size = "100%FREE";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
swap = {
|
||||
size = "8G";
|
||||
content.type = "swap";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
data-${DISK_NUMBER} = {
|
||||
type = "disk";
|
||||
device = "${DISK_PATH}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-data-${DISK_NUMBER}";
|
||||
keyFile = "/run/secrets/disks/data-disk-${DISK_NUMBER}";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/data-${DISK_NUMBER}";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
parity-${DISK_NUMBER} = {
|
||||
type = "disk";
|
||||
device = "${DISK_PATH}";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "luks";
|
||||
name = "crypted-parity-${DISK_NUMBER}";
|
||||
keyFile = "/run/secrets/disks/parity-disk-${DISK_NUMBER}";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "xfs";
|
||||
mountpoint = "/mnt/parity-${DISK_NUMBER}";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1,11 +1,13 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p gum openssl sops ssh-to-age age sshpass envsubst
|
||||
|
||||
prerun_action() {
|
||||
echo -e "$1"
|
||||
SETUP_ANSWER="$(gum input --placeholder "Type 'done' when you have finished.")"
|
||||
SETUP_ANSWER="$(gum input --placeholder 'Type "done" when you have finished.')"
|
||||
if [[ "$SETUP_ANSWER" == "done" ]]; then
|
||||
:
|
||||
else
|
||||
echo " Aborting - you did not type 'done'."
|
||||
echo ' ❌ Aborting - you did not type "done".'
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
@@ -65,14 +67,27 @@ necessary_credentials_with_config() {
|
||||
fi
|
||||
}
|
||||
|
||||
setup_ssh() {
|
||||
REMOTE_PASS=$(gum input --password --placeholder "Enter password for 'nixos' on '$TARGET_HOST'")
|
||||
if [ -z "$REMOTE_PASS" ]; then
|
||||
echo " ❌ Password is required to proceed. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\n\n ➡️ Copying SSH key to target host 'nixos@$TARGET_HOST'..."
|
||||
if sshpass -p "$REMOTE_PASS" ssh-copy-id -o StrictHostKeyChecking=no -i "extra-files/home/numbus-admin/.ssh/id_ed25519.pub" "nixos@$TARGET_HOST"; then
|
||||
echo " ✅ SSH key copied successfully."
|
||||
else
|
||||
echo " ❌ Failed to copy SSH key. Please check the host IP and password."
|
||||
exit 1
|
||||
fi
|
||||
export REMOTE_PASS
|
||||
}
|
||||
|
||||
ssh_to_host() {
|
||||
ssh -i "extra-files/home/numbus-admin/.ssh/id_ed25519.pub" "nixos@$TARGET_HOST" "$1"
|
||||
}
|
||||
|
||||
hardware_detection() {
|
||||
echo -e "\n\n ➡️ Please provide the password of the target host :"
|
||||
ssh-copy-id -i extra-files/home/numbus-admin/.ssh/id_ed25519.pub nixos@$TARGET_HOST
|
||||
|
||||
ssh_to_host() {
|
||||
ssh -i extra-files/home/numbus-admin/.ssh/id_ed25519 nixos@$TARGET_HOST "$1"
|
||||
}
|
||||
|
||||
echo -e "\n\n 🔎 Detecting graphics card on target host..."
|
||||
VGA_INFO=$(ssh_to_host "lspci -nn | grep -i 'vga'")
|
||||
if echo "$VGA_INFO" | grep -iq "intel"; then
|
||||
@@ -127,11 +142,11 @@ files_generation() {
|
||||
mkdir -p extra-files/mnt/data-storage/immich
|
||||
|
||||
echo -e "\n\n ✅ Generating new SSH for numbus-admin..."
|
||||
ssh-keygen -t ed25519 -C numbus-admin@numbus-server -f extra-files/home/numbus-admin/.ssh/id_ed25519 -N "" -q
|
||||
ssh-keygen -t "ed25519" -C "numbus-admin@numbus-server" -f "extra-files/home/numbus-admin/.ssh/id_ed25519" -N "" -q
|
||||
|
||||
echo -e "\n\n ✅ Generating sops-nix keys..."
|
||||
nix run nixpkgs#ssh-to-age -- -private-key -i extra-files/home/numbus-admin/.ssh/id_ed25519 > extra-files/var/lib/sops-nix/key.txt
|
||||
SOPS_PUBLIC_KEY=$(nix shell nixpkgs#age -c age-keygen -y extra-files/var/lib/sops-nix/key.txt)
|
||||
ssh-to-age -private-key -i extra-files/home/numbus-admin/.ssh/id_ed25519 > extra-files/var/lib/sops-nix/key.txt
|
||||
SOPS_PUBLIC_KEY=$(age-keygen -y extra-files/var/lib/sops-nix/key.txt)
|
||||
|
||||
echo -e "\n\n ✅ Generating sops-nix configuration files..."
|
||||
envsubst < config-files/sops-nix/.sops.yaml > extra-files/etc/nixos/.sops.yaml
|
||||
@@ -230,103 +245,205 @@ files_generation() {
|
||||
}
|
||||
|
||||
disk_config_generation() {
|
||||
ssh_to_host() {
|
||||
ssh -i extra-files/home/numbus-admin/.ssh/id_ed25519 nixos@$TARGET_HOST "$1"
|
||||
}
|
||||
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "
|
||||
⚠️ $(gum style --foreground 212 'WARNING:') You will choose the disks to install NixOS on.
|
||||
!! PLEASE MAKE SURE YOU BACKED UP ANY IMPORTANT DATA !!
|
||||
!! ALL DATA WILL BE WIPED ON THE DISKS YOU CHOOSE !!
|
||||
Please press CTRL+C to abort.
|
||||
"
|
||||
gum confirm "Do you understand and wish to proceed?" || { echo " ❌ Aborting."; exit 1; }
|
||||
|
||||
echo -e "\n\n ⚠️ WARNING: you will choose the disks you want to install NixOS on."
|
||||
echo -e " !! PLEASE MAKE SURE YOU BACKED UP ANY IMPORTANT DATA !!"
|
||||
echo -e " !! ALL DATA WILL BE WIPED ON THE DISKS YOU CHOOSE !!"
|
||||
echo -e " Press CTRL+C to abort."
|
||||
echo -e "\n\n 🔎 Fetching and analyzing disks from target host... (This may take a moment)"
|
||||
|
||||
SETUP_ANSWER="$(gum input --placeholder "Type 'understood' once you have read the warning.")"
|
||||
if [[ "$SETUP_ANSWER" == "understood" ]]; then
|
||||
:
|
||||
else
|
||||
echo " Aborting - you did not type 'understood'."
|
||||
declare -A DISK_INFO_MAP
|
||||
declare -A DISK_SIZE_MAP
|
||||
declare -A DISK_BY_ID_MAP
|
||||
declare -A DISK_LABEL_MAP
|
||||
DISK_OPTIONS=()
|
||||
|
||||
DISK_NAMES=$(ssh_to_host "lsblk -d -n -o NAME,TYPE | awk '\$2==\"disk\" {print \$1}'")
|
||||
|
||||
for name in $DISK_NAMES; do
|
||||
details=$(echo "$REMOTE_PASS" | ssh_to_host "
|
||||
set -e
|
||||
devpath=/dev/$name
|
||||
rota=1 # Default to rotational (HDD)
|
||||
[ -f /sys/block/$name/queue/rotational ] && rota=\$(cat /sys/block/$name/queue/rotational)
|
||||
tran=\$(lsblk -d -n -o TRAN \"\$devpath\" || echo 'unknown')
|
||||
health=\$(sudo -S smartctl -H \"\$devpath\" 2>/dev/null | grep 'self-assessment' | awk '{print \$6}')
|
||||
by_id=\$(ls -l /dev/disk/by-id | grep -m 1 \"../../$name\$\" | awk '{print \"/dev/disk/by-id/\"\$9}')
|
||||
|
||||
# Determine type
|
||||
if [[ \"\$name\" == nvme* ]]; then type=\"NVMe\"; # Check for NVMe first
|
||||
elif [[ \"\$rota\" == \"0\" ]]; then type=\"SSD\";
|
||||
elif [[ \"\$tran\" == \"usb\" ]]; then type=\"USB\";
|
||||
else type=\"HDD\"; fi
|
||||
|
||||
# Fallback for health and by-id
|
||||
[[ -z \"\$health\" || \"\$health\" == \"\" ]] && health=\"N/A\"
|
||||
[ -z \"\$by_id\" ] && by_id=\"\$devpath\"
|
||||
|
||||
# Get size last, after other commands that might fail
|
||||
size=\$(lsblk -b -d -n -o SIZE \"\$devpath\")
|
||||
echo \"\$size:::\$type:::\$health:::\$by_id\"
|
||||
")
|
||||
|
||||
mapfile -t parts < <(echo "$details" | tr ':' '\n')
|
||||
size="${parts[0]}"
|
||||
disk_type="${parts[3]}"
|
||||
health="${parts[6]}"
|
||||
by_id="${parts[9]}"
|
||||
|
||||
human_size=$(numfmt --to=iec-i --suffix=B "$size")
|
||||
label=$(printf "%-12s %-12s %-12s %-12s %s" "$name" "$disk_type" "$human_size" "$health" "$by_id")
|
||||
|
||||
DISK_OPTIONS+=("$label")
|
||||
DISK_INFO_MAP["$label"]="$name"
|
||||
DISK_SIZE_MAP["$name"]="$size"
|
||||
DISK_BY_ID_MAP["$name"]="$by_id"
|
||||
DISK_LABEL_MAP["$name"]="$label"
|
||||
done
|
||||
|
||||
if [ ${#DISK_OPTIONS[@]} -eq 0 ]; then
|
||||
echo " ❌ No disks found on the target host. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n\n 🔎 Fetching disks from target host..."
|
||||
HEADER=$(printf " %-12s %-12s %-12s %-12s %s" "Device" "Type" "Size" "SMART" "ID")
|
||||
gum style --foreground 212 " ➡️ Please choose one (stripe) or two (mirror) disks for your NixOS boot installation:"
|
||||
echo -e ""
|
||||
mapfile -t SELECTED_BOOT_LABELS < <(gum choose --limit 2 --header "$HEADER" "${DISK_OPTIONS[@]}")
|
||||
|
||||
DISK_JSON=$(ssh_to_host "lsblk -d --json -o NAME,ROTA,SIZE,PATH")
|
||||
BY_ID_RAW=$(ssh_to_host "ls -l /dev/disk/by-id/")
|
||||
if [ -z "$DISK_JSON" ]; then
|
||||
echo " ❌ Could not find any disks on the target host. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
if [ ${#SELECTED_BOOT_LABELS[@]} -eq 0 ]; then echo " ❌ No boot disk selected. Aborting."; exit 1; fi
|
||||
|
||||
declare -A BY_ID_MAP
|
||||
|
||||
while read -r line; do
|
||||
if [[ "$line" =~ "-> ../../"(.*)$ ]]; then
|
||||
dev_name="${BASH_REMATCH[1]}"
|
||||
by_id_path="/dev/disk/by-id/$(echo "$line" | awk '{print $9}')"
|
||||
if [[ ! -v "BY_ID_MAP[$dev_name]" && ! "$by_id_path" =~ -part ]]; then
|
||||
BY_ID_MAP["$dev_name"]="$by_id_path"
|
||||
fi
|
||||
fi
|
||||
done <<< "$BY_ID_RAW"
|
||||
|
||||
declare -A DISK_MAP
|
||||
declare -a DISK_OPTIONS
|
||||
|
||||
while read -r name type size; do
|
||||
by_id=${BY_ID_MAP[$name]}
|
||||
if [ -z "$by_id" ]; then continue; fi
|
||||
option=$(printf "%-8s %-5s %-8s (%s)" "$name" "$type" "$size" "$by_id")
|
||||
DISK_OPTIONS+=("$option")
|
||||
DISK_MAP["$option"]="$by_id"
|
||||
done < <(echo "$DISK_JSON" | jq -r '.blockdevices[] | "\(.name) \(if .name | test("^nvme") then "NVMe" else (if .rota == "0" then "SSD" else "HDD" end) end) \(.size)"')
|
||||
echo -e "\n\n ➡️ Please choose one (stripe) or two (mirror) disks for your NixOS boot installation:"
|
||||
mapfile -t SELECTED_BOOT_OPTIONS < <(gum choose --limit 2 "${DISK_OPTIONS[@]}")
|
||||
if [ ${#SELECTED_BOOT_OPTIONS[@]} -eq 0 ]; then
|
||||
echo " ❌ No boot disk selected. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NUMBER_OF_BOOT_DISKS=${#SELECTED_BOOT_OPTIONS[@]}
|
||||
BOOT_DISK_1=${DISK_MAP["${SELECTED_BOOT_OPTIONS[0]}"]}
|
||||
|
||||
if [ "$NUMBER_OF_BOOT_DISKS" -eq 2 ]; then
|
||||
BOOT_DISK_2=${DISK_MAP["${SELECTED_BOOT_OPTIONS[1]}"]}
|
||||
BOOT_DISK_1_NAME=${DISK_INFO_MAP["${SELECTED_BOOT_LABELS[0]}"]}
|
||||
BOOT_DISK_1=${DISK_BY_ID_MAP[$BOOT_DISK_1_NAME]}
|
||||
BOOT_DISK_2=""
|
||||
if [ ${#SELECTED_BOOT_LABELS[@]} -eq 2 ]; then
|
||||
BOOT_DISK_2_NAME=${DISK_INFO_MAP["${SELECTED_BOOT_LABELS[1]}"]}
|
||||
BOOT_DISK_2=${DISK_BY_ID_MAP[$BOOT_DISK_2_NAME]}
|
||||
fi
|
||||
|
||||
REMAINING_DISKS=()
|
||||
for option in "${DISK_OPTIONS[@]}"; do
|
||||
for label in "${DISK_OPTIONS[@]}"; do
|
||||
is_boot_disk=false
|
||||
for selected in "${SELECTED_BOOT_OPTIONS[@]}"; do
|
||||
if [[ "$option" == "$selected" ]]; then
|
||||
is_boot_disk=true
|
||||
break
|
||||
fi
|
||||
for selected in "${SELECTED_BOOT_LABELS[@]}"; do
|
||||
if [[ "$label" == "$selected" ]]; then is_boot_disk=true; break; fi
|
||||
done
|
||||
if ! $is_boot_disk; then
|
||||
REMAINING_DISKS+=("$option")
|
||||
fi
|
||||
if ! $is_boot_disk; then REMAINING_DISKS+=("$label"); fi
|
||||
done
|
||||
|
||||
if [ ${#REMAINING_DISKS[@]} -gt 0 ]; then
|
||||
echo -e "\n\n ➡️ Please choose your data disks (up to 4):"
|
||||
mapfile -t SELECTED_DATA_OPTIONS < <(gum choose --limit 4 "${REMAINING_DISKS[@]}")
|
||||
NUMBER_OF_DATA_DISKS=${#SELECTED_DATA_OPTIONS[@]}
|
||||
for i in $(seq 0 $(($NUMBER_OF_DATA_DISKS - 1))); do
|
||||
declare "DATA_DISK_$(($i + 1))"="${DISK_MAP["${SELECTED_DATA_OPTIONS[$i]}"]}"
|
||||
done
|
||||
echo -e ""
|
||||
gum style --foreground 212 " ➡️ Please choose your data and parity disks (up to 9 total)."
|
||||
mapfile -t SELECTED_DATA_LABELS < <(gum choose --limit 9 --header "$HEADER" "${REMAINING_DISKS[@]}")
|
||||
|
||||
if [ ${#SELECTED_DATA_LABELS[@]} -gt 0 ]; then
|
||||
selected_data_names=()
|
||||
for label in "${SELECTED_DATA_LABELS[@]}"; do
|
||||
selected_data_names+=("${DISK_INFO_MAP[$label]}")
|
||||
done
|
||||
|
||||
num_selected=${#selected_data_names[@]}
|
||||
num_parity=0
|
||||
if (( num_selected > 0 )); then
|
||||
num_parity=$(( (num_selected - 1) / 3 + 1 ))
|
||||
fi
|
||||
|
||||
# Sort selected disks by size (largest first)
|
||||
sorted_disks=($(
|
||||
for name in "${selected_data_names[@]}"; do
|
||||
echo "${DISK_SIZE_MAP[$name]} $name"
|
||||
done | sort -rn | awk '{print $2}'
|
||||
))
|
||||
|
||||
# Assign parity disks (the largest ones)
|
||||
parity_disks_final=()
|
||||
for i in $(seq 0 $((num_parity - 1))); do
|
||||
[[ -n "${sorted_disks[$i]}" ]] && parity_disks_final+=("${DISK_BY_ID_MAP[${sorted_disks[$i]}]}")
|
||||
done
|
||||
|
||||
# Assign data disks (the remaining ones)
|
||||
data_disks_final=()
|
||||
for i in $(seq $num_parity $((num_selected - 1))); do
|
||||
[[ -n "${sorted_disks[$i]}" ]] && data_disks_final+=("${DISK_BY_ID_MAP[${sorted_disks[$i]}]}")
|
||||
done
|
||||
|
||||
# Set exported variables (up to 9 data disks and 2 parity disks)
|
||||
for i in {0..8}; do export "DATA_DISK_$((i+1))"="${data_disks_final[$i]:-}"; done
|
||||
for i in {0..2}; do export "PARITY_DISK_$((i+1))"="${parity_disks_final[$i]:-}"; done
|
||||
fi
|
||||
else
|
||||
echo -e "\n\n ℹ️ No remaining disks available for data storage."
|
||||
NUMBER_OF_DATA_DISKS=0
|
||||
echo -e "\nℹ️ No remaining disks to select for data."
|
||||
fi
|
||||
|
||||
DISK_CONFIG_TEMPLATE="config-files/disks/boot-${NUMBER_OF_BOOT_DISKS}-data-${NUMBER_OF_DATA_DISKS}.nix"
|
||||
# --- Final Recap ---
|
||||
NUMBER_OF_BOOT_DISKS=0
|
||||
[[ -n "$BOOT_DISK_1" ]] && NUMBER_OF_BOOT_DISKS=$((NUMBER_OF_BOOT_DISKS + 1))
|
||||
[[ -n "$BOOT_DISK_2" ]] && NUMBER_OF_BOOT_DISKS=$((NUMBER_OF_BOOT_DISKS + 1))
|
||||
|
||||
if [[ -f "$DISK_CONFIG_TEMPLATE" ]]; then
|
||||
echo -e "\n\n ✅ Generating disk configuration from template: $DISK_CONFIG_TEMPLATE"
|
||||
envsubst < "$DISK_CONFIG_TEMPLATE" > disk-config.nix
|
||||
else
|
||||
echo -e "\n\n ❌ Error: No disk configuration template found for $NUMBER_OF_BOOT_DISKS boot disk(s) and $NUMBER_OF_DATA_DISKS data disk(s)."
|
||||
echo " Looked for: $DISK_CONFIG_TEMPLATE"
|
||||
exit 1
|
||||
NUMBER_OF_DATA_DISKS=0
|
||||
for i in {1..9}; do
|
||||
disk_var="DATA_DISK_$i"
|
||||
[[ -n "${!disk_var}" ]] && NUMBER_OF_DATA_DISKS=$((NUMBER_OF_DATA_DISKS + 1))
|
||||
done
|
||||
|
||||
NUMBER_OF_PARITY_DISKS=0
|
||||
for i in {1..3}; do
|
||||
disk_var="PARITY_DISK_$i"
|
||||
[[ -n "${!disk_var}" ]] && NUMBER_OF_PARITY_DISKS=$((NUMBER_OF_PARITY_DISKS + 1))
|
||||
done
|
||||
|
||||
RECAP_CONTENT=$(cat <<EOF
|
||||
### Disk Configuration Summary
|
||||
|
||||
Please review the selected disk layout before proceeding.
|
||||
|
||||
**Boot Disks ($NUMBER_OF_BOOT_DISKS):**
|
||||
* **Boot 1:** \`$BOOT_DISK_1\`
|
||||
$( [[ -n "$BOOT_DISK_2" ]] && echo "* **Boot 2:** \`$BOOT_DISK_2\`" || echo "* **Boot 2:** *Not configured*")
|
||||
|
||||
**Data Disks ($NUMBER_OF_DATA_DISKS):**
|
||||
$(for i in {1..9}; do disk_var="DATA_DISK_$i"; [[ -n "${!disk_var}" ]] && echo "* **Data $i:** \`${!disk_var}\`"; done)
|
||||
$( [[ $NUMBER_OF_DATA_DISKS -eq 0 ]] && echo "* *Not configured*")
|
||||
|
||||
**Parity Disks ($NUMBER_OF_PARITY_DISKS):**
|
||||
$(for i in {1..3}; do disk_var="PARITY_DISK_$i"; [[ -n "${!disk_var}" ]] && echo "* **Parity $i:** \`${!disk_var}\`"; done)
|
||||
$( [[ $NUMBER_OF_PARITY_DISKS -eq 0 ]] && echo "* *Not configured*")
|
||||
EOF
|
||||
)
|
||||
|
||||
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "$(gum format <<< "$RECAP_CONTENT")"
|
||||
gum confirm "Proceed with this disk configuration?" || { echo " ❌ Aborting as requested."; exit 1; }
|
||||
|
||||
echo -e "\n\n ⚙️ Generating disko configuration from templates..."
|
||||
template_file="config-files/disks/boot-${NUMBER_OF_BOOT_DISKS}.nix"
|
||||
(envsubst < "$template_file") > disk-config.nix
|
||||
echo " ✅ Generated boot disk configuration."
|
||||
|
||||
for i in $(seq 1 $NUMBER_OF_DATA_DISKS); do
|
||||
disk_var="DATA_DISK_$i"
|
||||
export DISK_NUMBER=$i
|
||||
export DISK_PATH=${!disk_var}
|
||||
(envsubst < "config-files/disks/data.nix") >> disk-config.nix
|
||||
done
|
||||
[[ "$NUMBER_OF_DATA_DISKS" -gt 0 ]] && echo " ✅ Generated $NUMBER_OF_DATA_DISKS data disk configuration(s)."
|
||||
|
||||
for i in $(seq 1 $NUMBER_OF_PARITY_DISKS); do
|
||||
disk_var="PARITY_DISK_$i"
|
||||
export DISK_NUMBER=$i
|
||||
export DISK_PATH=${!disk_var}
|
||||
(envsubst < "config-files/disks/parity.nix") >> disk-config.nix
|
||||
done
|
||||
[[ "$NUMBER_OF_PARITY_DISKS" -gt 0 ]] && echo " ✅ Generated $NUMBER_OF_PARITY_DISKS parity disk configuration(s)."
|
||||
|
||||
# Close the imports block
|
||||
cat <<'EOF' >> disk-config.nix
|
||||
};
|
||||
};
|
||||
}
|
||||
EOF
|
||||
echo -e " ✅ Final disko configuration created at 'disk-config.nix'."
|
||||
}
|
||||
|
||||
deploy() {
|
||||
@@ -338,7 +455,7 @@ deploy() {
|
||||
--chown "/home/numbus-admin/" 1000:1000 \
|
||||
--target-host nixos@$TARGET_HOST
|
||||
|
||||
echo -e "\n\n ✅ Installation successfull !!"
|
||||
echo -e "\n\n ✅ Installation successfull !"
|
||||
sleep 1
|
||||
}
|
||||
|
||||
@@ -375,18 +492,6 @@ EOF
|
||||
|
||||
sleep 1
|
||||
|
||||
# Pre-run checks
|
||||
if ! command -v gum &> /dev/null; then
|
||||
echo " ❌ 'gum' is not installed. Please install it to use the interactive TUI."
|
||||
echo " Add 'gum' to your configuration.nix in the system packages section."
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v openssl &> /dev/null; then
|
||||
echo " ❌ 'openssl' is not installed."
|
||||
echo " Add 'openssl' to your configuration.nix in the system packages section."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Choose the action
|
||||
ACTION_ANSWER=$(gum choose "[1] 🌐 Deploy NixOS on a remote machine" "[2] 💽 Deploy NixOS on a remote machine with a file configuration" "[3] 🛠️ Update a NixOS remote machine")
|
||||
echo $ACTION_ANSWER
|
||||
@@ -395,16 +500,20 @@ if [[ "$ACTION_ANSWER" == "[1] 🌐 Deploy NixOS on a remote machine" ]]; then
|
||||
echo -e "\n ➡️ Proceeding with deployment…"
|
||||
prerun_action "\n\n ➡️ On the target host : start the computer and boot into the NixOS iso.\n Launch a console and set up a new user password."
|
||||
necessary_credentials
|
||||
setup_ssh
|
||||
hardware_detection
|
||||
files_generation
|
||||
disk_config_generation
|
||||
generate_disko_config
|
||||
elif [[ "$ACTION_ANSWER" == "[2] 💽 Deploy NixOS on a remote machine with a file configuration" ]]; then
|
||||
echo -e "\n ➡️ Proceeding with deployment using a config file…"
|
||||
prerun_action "\n\n ➡️ On the target host : start the computer and boot into the NixOS iso.\n Launch a console and set up a new user password."
|
||||
necessary_credentials_with_config
|
||||
setup_ssh
|
||||
hardware_detection
|
||||
files_generation
|
||||
disk_config_generation
|
||||
generate_disko_config
|
||||
elif [[ "$ACTION_ANSWER" == "[3] 🛠️ Update a NixOS remote machine" ]]; then
|
||||
echo -e "\n ➡️ Proceeding with update…"
|
||||
prerun_action "\n\n ➡️ On the target host : make sure the NixOS installation you want to update is up-and-running, accessible with SSH."
|
||||
|
||||
Reference in New Issue
Block a user