aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/bootstrap-host.sh
diff options
context:
space:
mode:
authorGravatar Tom van der Lee <tom@vanderlee.io>2026-09-17 11:05:45 +0200
committerGravatar Tom van der Lee <tom@vanderlee.io>2026-09-17 11:05:45 +0200
commitf793f76e26b461c3228c69926d82bf950aaac671 (patch)
treeaffac98593ff0de3bb24fcd8aa64f6ef8ed9dc19 /scripts/bootstrap-host.sh
parentae3fa667bda75f11881c9209dc67226f98bcfd95 (diff)
downloaddesktop-flake-f793f76e26b461c3228c69926d82bf950aaac671.tar.gz
desktop-flake-f793f76e26b461c3228c69926d82bf950aaac671.tar.bz2
desktop-flake-f793f76e26b461c3228c69926d82bf950aaac671.zip
Add scripted host bootstrapping with directory-driven discovery
nixosConfigurations now auto-discovers hosts/<name>/ directories instead of a hand-maintained attrset, and scripts/bootstrap-host.sh (exposed as `nix run .#bootstrap-host`) scaffolds a new host from the template. The script always requires an explicit --root for hardware-configuration.nix so a live-installer run can never read the live ISO's own /etc/nixos by accident. Also records the belated task-11.1 checkbox update for the prior change's already-committed state.
Diffstat (limited to 'scripts/bootstrap-host.sh')
-rw-r--r--scripts/bootstrap-host.sh146
1 files changed, 146 insertions, 0 deletions
diff --git a/scripts/bootstrap-host.sh b/scripts/bootstrap-host.sh
new file mode 100644
index 0000000..afb4e14
--- /dev/null
+++ b/scripts/bootstrap-host.sh
@@ -0,0 +1,146 @@
1#!/usr/bin/env bash
2set -euo pipefail
3
4usage() {
5 cat <<'EOF'
6Usage: bootstrap-host <hostname> --root <path> --state-version <version> [--system <system>] [--force]
7
8Scaffolds hosts/<hostname>/ from hosts/template, ready to be picked up
9automatically as nixosConfigurations.<hostname> — no flake.nix edit needed.
10Must be run from the root of the nix-config checkout.
11
12 --root <path> Required. Where to read hardware-configuration.nix
13 from: <path>/etc/nixos/hardware-configuration.nix.
14 Use /mnt when running from a NixOS live/installer
15 environment against a freshly mounted install
16 target; use / when adopting an already-installed
17 system. There is no default — this is always
18 explicit so the live environment's own /etc/nixos
19 is never read by accident.
20 --state-version <ver> Required, e.g. 24.05. Never change this after the
21 host's first install.
22 --system <system> Optional. Defaults to x86_64-linux.
23 --force Overwrite an existing hosts/<hostname> directory.
24EOF
25}
26
27hostname=""
28root=""
29state_version=""
30system="x86_64-linux"
31force=0
32
33while [ $# -gt 0 ]; do
34 case "$1" in
35 --root)
36 root="$2"
37 shift 2
38 ;;
39 --state-version)
40 state_version="$2"
41 shift 2
42 ;;
43 --system)
44 system="$2"
45 shift 2
46 ;;
47 --force)
48 force=1
49 shift
50 ;;
51 -h | --help)
52 usage
53 exit 0
54 ;;
55 -*)
56 echo "Error: unknown flag '$1'." >&2
57 usage >&2
58 exit 1
59 ;;
60 *)
61 if [ -n "$hostname" ]; then
62 echo "Error: unexpected extra argument '$1'." >&2
63 exit 1
64 fi
65 hostname="$1"
66 shift
67 ;;
68 esac
69done
70
71if [ -z "$hostname" ]; then
72 echo "Error: <hostname> is required." >&2
73 usage >&2
74 exit 1
75fi
76
77if [[ ! "$hostname" =~ ^[a-zA-Z0-9][a-zA-Z0-9-]*$ ]]; then
78 echo "Error: '$hostname' is not a valid hostname (letters, digits, hyphens; must not start with a hyphen)." >&2
79 exit 1
80fi
81
82if [ -z "$root" ]; then
83 echo "Error: --root is required (e.g. --root /mnt for a fresh install, --root / to adopt the running system)." >&2
84 exit 1
85fi
86
87if [ -z "$state_version" ]; then
88 echo "Error: --state-version is required (e.g. --state-version 24.05)." >&2
89 exit 1
90fi
91
92repo_root="$(pwd)"
93template_dir="$repo_root/hosts/template"
94host_dir="$repo_root/hosts/$hostname"
95
96if [ ! -d "$template_dir" ]; then
97 echo "Error: hosts/template not found under the current directory ($repo_root)." >&2
98 echo "Run this from the root of the nix-config checkout." >&2
99 exit 1
100fi
101
102if [ -e "$host_dir" ] && [ "$force" -ne 1 ]; then
103 echo "Error: $host_dir already exists. Pass --force to overwrite." >&2
104 exit 1
105fi
106
107rm -rf "$host_dir"
108cp -r "$template_dir" "$host_dir"
109
110sed -i.bak \
111 -e "s/networking.hostName = \"CHANGEME\";/networking.hostName = \"$hostname\";/" \
112 -e "s/system.stateVersion = \"CHANGEME\";/system.stateVersion = \"$state_version\";/" \
113 "$host_dir/configuration.nix"
114rm -f "$host_dir/configuration.nix.bak"
115
116printf '%s' "$system" >"$host_dir/system"
117
118# Always read from <root>/etc/nixos, never bare /etc/nixos — this is what
119# keeps a live-installer run from picking up the live ISO's own hardware
120# config instead of the freshly mounted install target's.
121hw_config_src="$root/etc/nixos/hardware-configuration.nix"
122
123if [ ! -f "$hw_config_src" ] && command -v nixos-generate-config >/dev/null 2>&1; then
124 echo "No hardware-configuration.nix found at $hw_config_src — generating it with 'nixos-generate-config --root $root' ..."
125 nixos-generate-config --root "$root"
126fi
127
128if [ ! -f "$hw_config_src" ]; then
129 echo "Error: could not find or generate hardware-configuration.nix at $hw_config_src." >&2
130 echo "Generate it yourself (e.g. 'nixos-generate-config --root $root') and re-run." >&2
131 exit 1
132fi
133
134cp "$hw_config_src" "$host_dir/hardware-configuration.nix"
135
136cat <<EOF
137
138Host '$hostname' scaffolded at hosts/$hostname
139
140Next steps:
141 1. Review hosts/$hostname/configuration.nix (boot loader choice, etc.)
142 2. git -C "$repo_root" add "hosts/$hostname"
143 3. Install or rebuild using <flake>#<host> syntax:
144 Fresh install: nixos-install --root $root --flake "$repo_root#$hostname"
145 Existing system: sudo nixos-rebuild switch --flake "$repo_root#$hostname"
146EOF