aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/install-with-disko
blob: 00bcd5d5267852ddf3f5bc505622bdef8cc601f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env nix-shell
#!nix-shell -i zsh --packages rsync zsh

setopt ERR_EXIT NO_UNSET PIPE_FAIL

# load module to parse command line arguments
zmodload zsh/zutil

# parse any possible additional drive declarations
zparseopts -D -E -A opts -- -skip-disko h x

# enable XTRACE shell option for full debugging output of scripts
if (( ${+opts[-x]} )); then
	set -x
fi

DIR="${0:h}"
TARGET_HOST="${1:-}"

if [[ -z "${TARGET_HOST}" ]] || (( ${+opts[-h]} )); then
	<<EOF >&2
usage: ${0:t} [ --skip-disko ] [ -h ] [ -x ] host

	--skip-disko	skip running presumably already run disko step
	-h		this message
	-x		enable shell debug
	host		the host to install from our flake
EOF
	exit 1
fi

if [[ "${USERNAME}" != "nixos" ]]; then
	echo "ERROR!  ${0:t} should be run as the nixos user from a NixOS installer." >&2
	exit 1
fi

if [[ -z "$TARGET_HOST" ]]; then
	echo "ERROR!  ${0:t} requires a hostname as the first argument." >&2
	exit 1
fi

if [[ ! -e "${DIR}/../hosts/${TARGET_HOST}/disks.nix" ]]; then
	echo "ERROR!  ${0:t} could not find the required ${DIR}/../hosts/${TARGET_HOST}/disks.nix." >&2
	exit 1
fi

# Check if the machine we're provisioning is using an encrypted pool.
# If it does, prompt for the passphrase, and write to a known location.
if grep -q "data.keyfile" "${DIR}/../hosts/${TARGET_HOST}/disks.nix"; then
	while true; do
		echo -en "\n${TARGET_HOST} uses ZFS encryption.  Enter a passphrase to encrypt your pool: "
		read -s pass
		echo

		if [[ "${#pass}" -lt 8 ]]; then
			echo 'ERROR!  Passphrase must be at least 8 characters.' >&2
			continue
		fi

		echo -n "Re-enter passphrase: "
		read -s pass2
		echo

		if [[ "${pass}" != "${pass2}" ]]; then
			echo 'ERROR!  Passphrases must match.' >&2
			continue
		else
			break
		fi
	done

	echo -n "${pass}" > /tmp/data.keyfile && chmod 00600 /tmp/data.keyfile
fi


<<EOF

++++++++	The disk(s) in ${TARGET_HOST} are about to get wiped!
WARNING!	NixOS will be re-installed on ${TARGET_HOST}.
++++++++	This is a destructive operation!!!

EOF

read -q '?Are you sure? [y/N] '
echo

if [[ "${REPLY}" == "y" ]]; then
	sudo true

	if (( ! ${+opts[--skip-disko]} )); then
		sudo nix run github:nix-community/disko \
			--extra-experimental-features "nix-command flakes" \
			--no-write-lock-file \
			-- \
			--mode zap_create_mount \
			"${DIR}/../hosts/${TARGET_HOST}/disks.nix"
	fi

	# rsync NixOS configuration to target host file system and install the system

	if [[ ! -d /mnt/etc/nixos ]]; then
		sudo mkdir -p /mnt/etc/nixos
	fi

	sudo rsync -a --delete --exclude .git "${DIR}/.." /mnt/etc/nixos
	cd /mnt/etc/nixos
	sudo nixos-install --flake ".#${TARGET_HOST}"

	if [[ "${?}" -eq 0 ]]; then
		cd

		for i in $(awk -F: '{if ($3 >= 1000 && $3 <= 30000) print $1}' /mnt/etc/passwd); do
			read -q "?Do you want to set a password for the user ${i}? [y/N] "
			echo
			if [[ "${REPLY}" == "y" ]]; then
				sudo chroot /mnt /$(find /mnt/nix/store/*-shadow-*/bin/passwd -executable -name passwd | cut -d/ -f3-) ${i}
			fi
			echo
		done

		echo 'Unmounting file systems...' >&2
		mount | grep -v zfs | awk '$3 ~ /^\/mnt\// {print $3}' | xargs -i{} sudo umount -lf {}
		echo 'Unmounting ZFS file systems...' >&2
		while ! sudo umount -t zfs -a; do echo 'attempting to umount all ZFS file systems' >&2; sleep 1; done
		echo 'Exporting zpool...' >&2
		while ! sudo zpool export -a; do echo 'attempting to export all zpools' >&2; sleep 1; done
		echo 'Type reboot when ready.' >&2
	fi
fi