diff --git a/scripts/installer/auto-install.sh b/scripts/installer/auto-install.sh index 4d5c1ad..9b7d273 100755 --- a/scripts/installer/auto-install.sh +++ b/scripts/installer/auto-install.sh @@ -1,17 +1,20 @@ #!/usr/bin/env nix-shell -#!nix-shell -i bash -p jq disko nixos-install-tools +#!nix-shell -i bash -p jq disko nixos-install-tools zfs # shellcheck shell=bash # The only genuinely external tools this script calls directly: `jq` -# (parsing the `nix eval` host list) and `disko`/`nixos-install` (the -# install itself). Everything disko shells out to internally -# (parted/sgdisk/mkfs.*/zfs/...) is self-contained -- disko's own -# generated scripts hardcode absolute Nix store paths for those, they +# (parsing the `nix eval` host list), `disko`/`nixos-install` (the +# install itself), and `zpool` (exporting a ZFS root pool before reboot, +# see the comment above that call below). Everything disko shells out to +# internally (parted/sgdisk/mkfs.*/zfs/...) is self-contained -- disko's +# own generated scripts hardcode absolute Nix store paths for those, they # don't rely on this script's PATH at all (confirmed by inspecting a # generated system.build.formatScript). The built installer image -# (modules/installer/common.nix) already has all three in -# environment.systemPackages, so this nix-shell wrapper is a fast no-op -# there; it's what makes the script also work standalone (e.g. run -# directly from a checkout on a stock ISO), where they aren't. +# (modules/installer/common.nix, plus the upstream +# installation-cd-minimal.nix it imports via iso.nix) already has all +# four in environment.systemPackages, so this nix-shell wrapper is a +# fast no-op there; it's what makes the script also work standalone +# (e.g. run directly from a checkout on a stock ISO), where they aren't +# guaranteed. set -eux set -euo pipefail @@ -162,5 +165,24 @@ nixos-install \ # /etc/ssh/ssh_host_ed25519_key. Nothing NixOS-managed ever cleans this # up on its own since it was written imperatively, not declaratively. rm -rf /root/host-keys + + # disko's --mode ...,mount left any ZFS root pool imported (that's what + # let nixos-install write into /mnt). If we reboot with it still + # imported, it isn't just "not exported" -- it's stamped with *this* + # live installer environment's hostid, which almost never matches the + # target's own networking.hostId (see hosts/*/host.nix; the installer + # itself sets none). modules/services/zfs/enable-service.nix and + # modules/common/configuration.nix both set boot.zfs.forceImportRoot = + # false deliberately (the safe option per that setting's own docs), so + # the freshly-installed system's first real boot sees a pool "in use by + # another system" and refuses to import it without -f -- which is what + # makes boot stall waiting on the ZFS import. Exporting here (a no-op + # if the chosen host has no ZFS root, e.g. proxmox-*/linode-*) clears + # that in-use state so the next import, from any hostid, succeeds. + if [[ -n "$(zpool list -H -o name 2>/dev/null)" ]]; then + echo "Exporting ZFS pool(s) before reboot..." + zpool export -a + fi + sleep 10 reboot