Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make ssh host optional again in vm-test #382

Merged
merged 12 commits into from
Sep 16, 2024
91 changes: 56 additions & 35 deletions src/nixos-anywhere.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
set -euo pipefail

here=$(dirname "${BASH_SOURCE[0]}")
flake=""
flakeAttr=""
kexecUrl=""
kexecExtraFlags=""
enableDebug=""
diskoScript=""
nixosSystem=""
extraFiles=""
vmTest="n"
nixOptions=(
--extra-experimental-features 'nix-command flakes'
"--no-write-lock-file"
Expand All @@ -19,24 +23,38 @@ phases[disko]=1
phases[install]=1
phases[reboot]=1

substituteOnDestination=y
sshPrivateKeyFile=
if [ -t 0 ]; then # stdin is a tty, we allow interactive input to ssh i.e. passwords
sshTtyParam="-t"
else
sshTtyParam="-T"
fi
sshConnection=
postKexecSshPort=22
buildOnRemote=n
envPassword=
envPassword=n

# Facts set by get-facts.sh
isOs=
isArch=
isKexec=
isInstaller=
isContainer=
hasIpv6Only=
hasTar=
hasSudo=
hasDoas=
hasWget=
hasCurl=
hasSetsid=

sshKeyDir=$(mktemp -d)
trap 'rm -rf "$sshKeyDir"' EXIT
mkdir -p "$sshKeyDir"

declare -A diskEncryptionKeys
declare -a nixCopyOptions
declare -a sshArgs
declare -A diskEncryptionKeys=()
declare -a nixCopyOptions=()
declare -a sshArgs=()

showUsage() {
cat <<USAGE
Expand Down Expand Up @@ -208,7 +226,7 @@ parseArgs() {
nixOptions+=("--option" "$key" "$value")
;;
--no-substitute-on-destination)
substituteOnDestination=n
nixCopyOptions+=("--substitute-on-destination")
;;
--build-on-remote)
buildOnRemote=y
Expand All @@ -220,7 +238,7 @@ parseArgs() {
vmTest=y
;;
*)
if [[ -z ${sshConnection-} ]]; then
if [[ -z ${sshConnection} ]]; then
sshConnection="$1"
else
showUsage
Expand All @@ -235,20 +253,16 @@ parseArgs() {
nixOptions+=("-L")
fi

if [[ ${substituteOnDestination-n} == "y" ]]; then
nixCopyOptions+=("--substitute-on-destination")
fi

if [[ -z ${sshConnection-} ]]; then
if [[ $vmTest == "n" ]] && [[ -z ${sshConnection} ]]; then
abort "ssh-host must be set"
fi

if [[ -n ${flake-} ]]; then
if [[ -n ${flake} ]]; then
if [[ $flake =~ ^(.*)\#([^\#\"]*)$ ]]; then
flake="${BASH_REMATCH[1]}"
flakeAttr="${BASH_REMATCH[2]}"
fi
if [[ -z ${flakeAttr-} ]]; then
if [[ -z ${flakeAttr} ]]; then
echo "Please specify the name of the NixOS configuration to be installed, as a URI fragment in the flake-uri." >&2
echo 'For example, to use the output nixosConfigurations.foo from the flake.nix, append "#foo" to the flake-uri.' >&2
exit 1
Expand Down Expand Up @@ -280,7 +294,7 @@ nixBuild() {
}

runVmTest() {
if [[ -z ${flakeAttr-} ]]; then
if [[ -z ${flakeAttr} ]]; then
echo "--vm-test is not supported with --store-paths" >&2
echo "Please use --flake instead or build config.system.build.installTest of your nixos configuration manually" >&2
exit 1
Expand All @@ -290,15 +304,15 @@ runVmTest() {
echo "--vm-test is not supported with --build-on-remote" >&2
exit 1
fi
if [[ -n ${extraFiles-} ]]; then
if [[ -n ${extraFiles} ]]; then
echo "--vm-test is not supported with --extra-files" >&2
exit 1
fi
if [[ -n ${diskEncryptionKeys-} ]]; then
if [ ${#diskEncryptionKeys[@]} -gt 0 ]; then
echo "--vm-test is not supported with --disk-encryption-keys" >&2
exit 1
fi
exec nix build \
nix build \
--print-out-paths \
--no-link \
-L \
Expand All @@ -320,7 +334,7 @@ uploadSshKey() {

step Uploading install SSH keys
until
if [[ -n ${envPassword} ]]; then
if [[ ${envPassword} == y ]]; then
sshpass -e \
ssh-copy-id \
-i "$sshKeyDir"/nixos-anywhere.pub \
Expand Down Expand Up @@ -359,19 +373,25 @@ importFacts() {
# make facts available in script
# shellcheck disable=SC2046
export $(echo "$filteredFacts" | xargs)

for var in isOs isArch isKexec isInstaller isContainer hasIpv6Only hasTar hasSudo hasDoas hasWget hasCurl hasSetsid; do
if [[ -z ${!var} ]]; then
abort "Failed to retrieve fact $var from host"
fi
done
}

runKexec() {
if [[ ${isKexec-n} == "y" ]] || [[ ${isInstaller-n} == "y" ]]; then
if [[ ${isKexec} == "y" ]] || [[ ${isInstaller} == "y" ]]; then
return
fi

if [[ ${isContainer-none} != "none" ]]; then
if [[ ${isContainer} != "none" ]]; then
echo "WARNING: This script does not support running from a '${isContainer}' container. kexec will likely not work" >&2
fi

if [[ $kexecUrl == "" ]]; then
case "${isArch-unknown}" in
case "${isArch}" in
x86_64 | aarch64)
kexecUrl="https://github.com/nix-community/nixos-images/releases/download/nixos-24.05/nixos-kexec-installer-noninteractive-${isArch}-linux.tar.gz"
;;
Expand All @@ -389,15 +409,15 @@ $maybeSudo mkdir -p /root/kexec
SSH

# no way to reach global ipv4 destinations, use gh-v6.com automatically if github url
if [[ ${hasIpv6Only-n} == "y" ]] && [[ $kexecUrl == "https://github.com/"* ]]; then
if [[ ${hasIpv6Only} == "y" ]] && [[ $kexecUrl == "https://github.com/"* ]]; then
kexecUrl=${kexecUrl/"github.com"/"gh-v6.com"}
fi

if [[ -f $kexecUrl ]]; then
runSsh "${maybeSudo} tar -C /root/kexec -xvzf-" <"$kexecUrl"
elif [[ ${hasCurl-n} == "y" ]]; then
elif [[ ${hasCurl} == "y" ]]; then
runSsh "curl --fail -Ss -L '${kexecUrl}' | ${maybeSudo} tar -C /root/kexec -xvzf-"
elif [[ ${hasWget-n} == "y" ]]; then
elif [[ ${hasWget} == "y" ]]; then
runSsh "wget '${kexecUrl}' -O- | ${maybeSudo} tar -C /root/kexec -xvzf-"
else
curl --fail -Ss -L "${kexecUrl}" | runSsh "${maybeSudo} tar -C /root/kexec -xvzf-"
Expand Down Expand Up @@ -464,15 +484,15 @@ nixosInstall() {
)
fi

if [[ -n ${extraFiles-} ]]; then
if [[ -n ${extraFiles} ]]; then
step Copying extra files
tar -C "$extraFiles" -cpf- . | runSsh "${maybeSudo} tar -C /mnt -xf- --no-same-owner"
runSsh "chmod 755 /mnt" # tar also changes permissions of /mnt
fi

step Installing NixOS
maybeReboot=""
if [[ ${phases[reboot]-} == 1 ]]; then
if [[ ${phases[reboot]} == 1 ]]; then
maybeReboot="nohup sh -c 'sleep 6 && reboot' >/dev/null &"
fi
runSsh sh <<SSH
Expand Down Expand Up @@ -509,12 +529,13 @@ SSH
main() {
parseArgs "$@"

if [[ -n ${vmTest-} ]]; then
if [[ ${vmTest} == y ]]; then
runVmTest
exit 0
fi

# parse flake nixos-install style syntax, get the system attr
if [[ -n ${flake-} ]]; then
if [[ -n ${flake} ]]; then
if [[ ${buildOnRemote} == "n" ]]; then
diskoScript=$(nixBuild "${flake}#nixosConfigurations.\"${flakeAttr}\".config.system.build.diskoScript")
nixosSystem=$(nixBuild "${flake}#nixosConfigurations.\"${flakeAttr}\".config.system.build.toplevel")
Expand All @@ -527,7 +548,7 @@ main() {
abort "--flake or --store-paths must be set"
fi

if [[ -n ${SSH_PRIVATE_KEY} ]] && [[ -z ${sshPrivateKeyFile-} ]]; then
if [[ -n ${SSH_PRIVATE_KEY} ]] && [[ -z ${sshPrivateKeyFile} ]]; then
# $sshKeyDir is getting deleted on trap EXIT
sshPrivateKeyFile="$sshKeyDir/from-env"
(
Expand Down Expand Up @@ -559,11 +580,11 @@ main() {
maybeSudo="doas"
fi

if [[ ${isOs-n} != "Linux" ]]; then
if [[ ${isOs} != "Linux" ]]; then
abort "This script requires Linux as the operating system, but got $isOs"
fi

if [[ ${phases[kexec]-} == 1 ]]; then
if [[ ${phases[kexec]} == 1 ]]; then
runKexec
fi

Expand All @@ -575,15 +596,15 @@ main() {
sshConnection="root@${sshHost}"
fi

if [[ ${phases[disko]-} == 1 ]]; then
if [[ ${phases[disko]} == 1 ]]; then
runDisko "$diskoScript"
fi

if [[ ${phases[install]-} == 1 ]]; then
if [[ ${phases[install]} == 1 ]]; then
nixosInstall "$nixosSystem"
fi

if [[ ${phases[reboot]-} == 1 ]]; then
if [[ ${phases[reboot]} == 1 ]]; then
step Waiting for the machine to become unreachable due to reboot
while runSshTimeout -- exit 0; do sleep 1; done
fi
Expand Down
Loading