nixos-anywhere/src/nixos-remote.sh

241 lines
6.5 KiB
Bash
Raw Normal View History

2022-11-10 16:42:06 +03:00
showUsage() {
cat <<USAGE
Usage: nixos-remote [options] ssh-host
2022-11-10 16:42:06 +03:00
Options:
* -f, --flake flake
set the flake to install the system from
2022-12-07 18:06:02 +03:00
* -s, --store-paths
set the store paths to the disko-script and nixos-system directly
if this is give, flake is not needed
2022-12-07 18:06:20 +03:00
* --no-ssh-copy
skip copying ssh-keys to target system
* --no-reboot
do not reboot after installation, allowing further customization of the target installation.
* --kexec url
use another kexec tarball to bootstrap NixOS
2022-12-27 21:43:41 +03:00
* --stop-after-disko
exit after disko formating, you can then proceed to install manually or some other way
2022-12-23 20:22:25 +03:00
* --extra-files files
files to copy into the new nixos installation
* --disk-encryption-keys remote_path local_path
copy the contents of the file or pipe in local_path to remote_path in the installer environment,
after kexec but before installation. Can be repeated.
* --debug
enable debug output
2022-11-10 16:42:06 +03:00
USAGE
}
abort() {
echo "aborted: $*" >&2
exit 1
}
2022-12-14 15:25:31 +03:00
kexec_url=https://github.com/nix-community/nixos-images/releases/download/nixos-22.11/nixos-kexec-installer-x86_64-linux.tar.gz
enable_debug=""
maybereboot="reboot"
2022-11-10 16:42:06 +03:00
declare -A disk_encryption_keys
2022-11-10 16:42:06 +03:00
while [[ $# -gt 0 ]]; do
case "$1" in
-f | --flake)
flake=$2
shift
;;
2022-12-07 18:06:02 +03:00
-s | --store-paths)
disko_script=$(readlink -f "$2")
nixos_system=$(readlink -f "$3")
2022-12-07 18:06:02 +03:00
shift
shift
;;
2022-11-10 16:42:06 +03:00
--help)
showUsage
exit 0
;;
--kexec)
kexec_url=$2
shift
;;
--no-ssh-copy-id)
no_ssh_copy=y
;;
--debug)
enable_debug="-x"
set -x
;;
2022-12-23 20:22:25 +03:00
--extra-files)
extra_files=$2
shift
;;
2022-12-28 17:19:23 +03:00
--disk-encryption-keys)
disk_encryption_keys["$2"]="$3"
shift
2022-12-28 17:19:23 +03:00
shift
;;
2022-12-27 21:43:41 +03:00
--stop-after-disko)
stop_after_disko=y
;;
2022-12-30 13:24:26 +03:00
--no-reboot)
maybereboot=""
2022-12-30 13:24:26 +03:00
;;
2022-11-10 16:42:06 +03:00
*)
if [[ -z ${ssh_connection:-} ]]; then
2022-12-29 19:18:46 +03:00
ssh_connection="$1"
2022-11-10 16:42:06 +03:00
else
showUsage
exit 1
fi
;;
esac
shift
done
2022-12-09 18:20:48 +03:00
2022-11-10 16:42:06 +03:00
# ssh wrapper
2022-11-10 18:45:14 +03:00
timeout_ssh_() {
2022-11-10 17:31:43 +03:00
timeout 10 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$ssh_connection" "$@"
2022-11-10 16:42:06 +03:00
}
2022-11-10 18:45:14 +03:00
ssh_() {
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$ssh_connection" "$@"
}
nixCopy() {
NIX_SSHOPTS='-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' nix copy --extra-experimental-features nix-command "$@"
}
nix_build() {
nix \
--experimental-features flakes build \
--extra-experimental-features nix-command \
--no-write-lock-file \
--print-out-paths \
"$@"
}
if [[ -z ${ssh_connection:-} ]]; then
2022-12-09 18:20:48 +03:00
abort "ssh-host must be set"
fi
# parse flake nixos-install style syntax, get the system attr
if [[ -n "${flake:-}" ]]; then
if [[ $flake =~ ^(.*)\#([^\#\"]*)$ ]]; then
flake="${BASH_REMATCH[1]}"
flakeAttr="${BASH_REMATCH[2]}"
fi
if [[ -z "${flakeAttr:-}" ]]; then
echo "Please specify the name of the NixOS configuration to be installed, as a URI fragment in the flake-uri."
echo "For example, to use the output nixosConfigurations.foo from the flake.nix, append \"#foo\" to the flake-uri."
exit 1
fi
disko_script=$(nix_build "${flake}#nixosConfigurations.${flakeAttr}.config.system.build.disko")
nixos_system=$(nix_build "${flake}#nixosConfigurations.${flakeAttr}.config.system.build.toplevel")
elif [[ -n "${disko_script:-}" ]] && [[ -n "${nixos_system:-}" ]]; then
2022-12-07 18:06:02 +03:00
if [[ ! -e "${disko_script}" ]] || [[ ! -e "${nixos_system}" ]]; then
echo "${disko_script} and ${nixos_system} must be existing store-paths"
exit 1
fi
:
else
abort "flake must be set"
fi
# wait for machine to become reachable (possibly forever)
# TODO we probably need an architecture detection here
2022-12-30 20:51:46 +03:00
# TODO if we have specified a user here but we are already booted into the
# installer, than the user might not work anymore
until facts=$(ssh_ -o ConnectTimeout=10 -- <<SSH
set -efu ${enable_debug}
has(){
command -v tar >/dev/null && echo "y" || echo "n"
}
cat <<FACTS
is_os=\$(uname)
is_kexec=\$(if test -f /etc/is_kexec; then echo "y"; else echo "n"; fi)
has_tar=\$(has tar)
has_sudo=\$(has sudo)
has_wget=\$(has wget)
has_curl=\$(has curl)
FACTS
SSH
); do
2023-01-03 15:31:26 +03:00
sleep 5
done
2023-01-03 15:31:26 +03:00
# make facts available in script
# shellcheck disable=SC2046
2023-01-03 15:31:26 +03:00
export $(echo "$facts" | grep -E '^(has|is)_[a-z0-9_]+=\S+' | xargs)
2022-11-10 16:42:06 +03:00
if [[ ${has_tar-n} == "n" ]]; then
abort "no tar command found, but required to unpack kexec tarball"
fi
maybesudo=""
if [[ ${has_sudo-n} == "y" ]]; then
maybesudo="sudo"
2022-11-10 19:15:00 +03:00
fi
if [[ ${is_os-n} != "Linux" ]]; then
abort "This script requires Linux as the operating system, but got $is_os"
fi
if [[ ${is_kexec-n} != "y" ]] && [[ ${no_ssh_copy-n} != "y" ]]; then
ssh-copy-id -o ConnectTimeout=10 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$ssh_connection"
fi
if [[ ${is_kexec-n} == "n" ]]; then
ssh_ << SSH
set -efu ${enable_debug}
"${maybesudo}" rm -rf /root/kexec
"${maybesudo}" mkdir -p /root/kexec
SSH
if [[ -f "$kexec_url" ]]; then
2022-12-30 20:51:46 +03:00
ssh_ "${maybesudo} tar -C /root/kexec -xvzf-" < "$kexec_url"
elif [[ ${has_curl-n} == "y" ]]; then
ssh_ "curl --fail -Ss -L '${kexec_url}' | ${maybesudo} tar -C /root/kexec -xvzf-"
elif [[ ${has_wget-n} == "y" ]]; then
ssh_ "wget '${kexec_url}' -O- | ${maybesudo} tar -C /root/kexec -xvzf-"
2022-11-10 16:42:06 +03:00
else
curl --fail -Ss -L "${kexec_url}" | ssh_ "${maybesudo} tar -C /root/kexec -xvzf-"
2022-11-10 16:42:06 +03:00
fi
2022-11-12 13:47:17 +03:00
ssh_ << SSH
TMPDIR=/root/kexec setsid ${maybesudo} /root/kexec/kexec/run
2022-11-10 16:42:06 +03:00
SSH
2022-11-10 16:42:06 +03:00
# wait for machine to become unreachable
2022-11-10 18:45:14 +03:00
while timeout_ssh_ -- exit 0; do sleep 1; done
2022-11-10 16:42:06 +03:00
2022-12-30 20:51:46 +03:00
# After kexec we explicitly set the user to root@
ssh_connection="root@${ssh_connection#*@}"
2022-11-10 16:42:06 +03:00
# watiting for machine to become available again
2022-11-10 17:31:43 +03:00
until ssh_ -o ConnectTimeout=10 -- exit 0; do sleep 5; done
2022-11-10 16:42:06 +03:00
fi
for path in "${!disk_encryption_keys[@]}"
do
echo "Uploading ${disk_encryption_keys[$path]} to $path"
ssh_ "umask 077; cat > $path" < "${disk_encryption_keys[$path]}"
done
2022-12-28 17:19:23 +03:00
2022-12-29 19:18:46 +03:00
nixCopy --to "ssh://$ssh_connection" "$disko_script"
2022-12-21 15:57:39 +03:00
ssh_ "$disko_script"
2022-11-10 16:42:06 +03:00
2022-12-27 21:43:41 +03:00
if [[ ${stop_after_disko-n} == "y" ]]; then
exit 0
fi
2022-12-29 19:18:46 +03:00
nixCopy --to "ssh://$ssh_connection?remote-store=local?root=/mnt" "$nixos_system"
2022-12-23 20:22:25 +03:00
if [[ -n ${extra_files:-} ]]; then
if [[ -d "$extra_files" ]]; then
extra_files="$extra_files/"
fi
rsync -vrlF -e "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" "$extra_files" "${ssh_connection}:/mnt/"
2022-12-23 20:22:25 +03:00
fi
2022-12-30 13:24:26 +03:00
ssh_ <<SSH
set -efu ${enable_debug}
2022-12-28 17:19:23 +03:00
# needed for installation if initrd-secrets are used
mkdir -m777 -p /mnt/tmp
nixos-install --no-root-passwd --no-channel-copy --system "$nixos_system"
${maybereboot}
SSH