forked from Fediversity/Fediversity
133 lines
3.4 KiB
Bash
Executable file
133 lines
3.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# nixos-deploy deploys a nixos-instantiate-generated drvPath to a target host
|
|
#
|
|
# Usage: nixos-deploy.sh <drvPath> <host> <switch-action> [<build-opts>] ignoreme
|
|
set -euo pipefail
|
|
|
|
### Defaults ###
|
|
|
|
buildArgs=(
|
|
--option extra-binary-caches https://cache.nixos.org/
|
|
)
|
|
profile=/nix/var/nix/profiles/system
|
|
# will be set later
|
|
sshOpts=(
|
|
-o "ControlMaster=auto"
|
|
-o "ControlPersist=60"
|
|
# Avoid issues with IP re-use. This disable TOFU security.
|
|
-o "StrictHostKeyChecking=no"
|
|
-o "UserKnownHostsFile=/dev/null"
|
|
-o "GlobalKnownHostsFile=/dev/null"
|
|
# interactive authentication is not possible
|
|
-o "BatchMode=yes"
|
|
# verbose output for easier debugging
|
|
-v
|
|
)
|
|
|
|
### Argument parsing ###
|
|
|
|
drvPath="$1"
|
|
outPath="$2"
|
|
targetHost="$3"
|
|
targetPort="$4"
|
|
buildOnTarget="$5"
|
|
sshPrivateKey="$6"
|
|
action="$7"
|
|
deleteOlderThan="$8"
|
|
shift 8
|
|
|
|
# remove the last argument
|
|
set -- "${@:1:$(($# - 1))}"
|
|
buildArgs+=("$@")
|
|
|
|
sshOpts+=( -p "${targetPort}" )
|
|
|
|
workDir=$(mktemp -d)
|
|
trap 'rm -rf "$workDir"' EXIT
|
|
|
|
if [[ -n "${sshPrivateKey}" && "${sshPrivateKey}" != "-" ]]; then
|
|
sshPrivateKeyFile="$workDir/ssh_key"
|
|
echo "$sshPrivateKey" > "$sshPrivateKeyFile"
|
|
chmod 0700 "$sshPrivateKeyFile"
|
|
sshOpts+=( -o "IdentityFile=${sshPrivateKeyFile}" )
|
|
fi
|
|
|
|
### Functions ###
|
|
|
|
log() {
|
|
echo "--- $*" >&2
|
|
}
|
|
|
|
copyToTarget() {
|
|
NIX_SSHOPTS="${sshOpts[*]}" nix-copy-closure --to "$targetHost" "$@"
|
|
}
|
|
|
|
# assumes that passwordless sudo is enabled on the server
|
|
targetHostCmd() {
|
|
# ${*@Q} escapes the arguments losslessly into space-separted quoted strings.
|
|
# `ssh` did not properly maintain the array nature of the command line,
|
|
# erroneously splitting arguments with internal spaces, even when using `--`.
|
|
# Tested with OpenSSH_7.9p1.
|
|
#
|
|
# shellcheck disable=SC2029
|
|
ssh "${sshOpts[@]}" "$targetHost" "./maybe-sudo.sh ${*@Q}"
|
|
}
|
|
|
|
# Setup a temporary ControlPath for this session. This speeds-up the
|
|
# operations by not re-creating SSH sessions between each command. At the end
|
|
# of the run, the session is forcefully terminated.
|
|
setupControlPath() {
|
|
sshOpts+=(
|
|
-o "ControlPath=$workDir/ssh_control"
|
|
)
|
|
cleanupControlPath() {
|
|
local ret=$?
|
|
# Avoid failing during the shutdown
|
|
set +e
|
|
# Close ssh multiplex-master process gracefully
|
|
log "closing persistent ssh-connection"
|
|
ssh "${sshOpts[@]}" -O stop "$targetHost"
|
|
rm -rf "$workDir"
|
|
exit "$ret"
|
|
}
|
|
trap cleanupControlPath EXIT
|
|
}
|
|
|
|
### Main ###
|
|
|
|
setupControlPath
|
|
|
|
if [[ "${buildOnTarget:-false}" == true ]]; then
|
|
|
|
# Upload derivation
|
|
log "uploading derivations"
|
|
copyToTarget "$drvPath" --gzip --use-substitutes
|
|
|
|
# Build remotely
|
|
log "building on target"
|
|
set -x
|
|
targetHostCmd "nix-store" "--realize" "$drvPath" "${buildArgs[@]}"
|
|
|
|
else
|
|
|
|
# Build derivation
|
|
log "building on deployer"
|
|
outPath=$(nix-store --realize "$drvPath" "${buildArgs[@]}")
|
|
|
|
# Upload build results
|
|
log "uploading build results"
|
|
copyToTarget "$outPath" --gzip --use-substitutes
|
|
|
|
fi
|
|
|
|
# Activate
|
|
log "activating configuration"
|
|
targetHostCmd nix-env --profile "$profile" --set "$outPath"
|
|
targetHostCmd "$outPath/bin/switch-to-configuration" "$action"
|
|
|
|
# Cleanup previous generations
|
|
log "collecting old nix derivations"
|
|
# Deliberately not quoting $deleteOlderThan so the user can configure something like "1 2 3"
|
|
# to keep generations with those numbers
|
|
targetHostCmd "nix-env" "--profile" "$profile" "--delete-generations" $deleteOlderThan
|
|
targetHostCmd "nix-store" "--gc"
|