57 lines
2.4 KiB
Bash
Executable File
57 lines
2.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# The SSH client submits once and follows durable stages on workstation.
|
|
set -euo pipefail
|
|
: "${DEPLOY_HOST:?missing DEPLOY_HOST}"
|
|
: "${DEPLOY_USER:?missing DEPLOY_USER}"
|
|
: "${DEPLOY_KEY:?missing DEPLOY_SSH_KEY}"
|
|
: "${DEPLOY_KNOWN_HOSTS:?configure pinned DEPLOY_KNOWN_HOSTS}"
|
|
: "${DEPLOY_RUN_ID:?missing DEPLOY_RUN_ID}"
|
|
[[ "$DEPLOY_USER" =~ ^[A-Za-z_][A-Za-z0-9_.-]*$ ]] || exit 1
|
|
[[ "$DEPLOY_HOST" =~ ^[A-Za-z0-9_.:-]+$ ]] || exit 1
|
|
[[ "$DEPLOY_RUN_ID" =~ ^[0-9]+-[0-9]+$ ]] || exit 1
|
|
[[ "${DEPLOY_PORT:-22}" =~ ^[0-9]+$ ]] || exit 1
|
|
key_dir="$(mktemp -d "${RUNNER_TEMP:-/tmp}/homelab-deploy-key.XXXXXXXX")"
|
|
trap 'rm -rf "$key_dir"' EXIT
|
|
chmod 700 "$key_dir"
|
|
printf '%s\n' "$DEPLOY_KEY" >"$key_dir/key"
|
|
printf '%s\n' "$DEPLOY_KNOWN_HOSTS" >"$key_dir/known_hosts"
|
|
chmod 600 "$key_dir/key" "$key_dir/known_hosts"
|
|
ssh_opts=(-i "$key_dir/key" -p "${DEPLOY_PORT:-22}" -o BatchMode=yes -o StrictHostKeyChecking=yes
|
|
-o "UserKnownHostsFile=$key_dir/known_hosts" -o ConnectTimeout=15
|
|
-o ServerAliveInterval=15 -o ServerAliveCountMax=4)
|
|
controller=.local/lib/homelab-deploy/controller.py
|
|
case "${1:?start, apply, verify or smoke required}" in
|
|
start)
|
|
python3 - <<'PY' >"$key_dir/request.json"
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
release = json.loads(Path('release.json').read_text())
|
|
print(json.dumps({'release': release, 'mode': os.environ.get('DEPLOY_MODE', 'changed'),
|
|
'refresh_images': os.environ.get('REFRESH_IMAGES', 'false') == 'true'}))
|
|
PY
|
|
for attempt in 1 2 3; do
|
|
rc=0
|
|
# shellcheck disable=SC2029 # The run ID and operation are validated local arguments, not remote variables.
|
|
ssh "${ssh_opts[@]}" "$DEPLOY_USER@$DEPLOY_HOST" python3 "$controller" start "$DEPLOY_RUN_ID" <"$key_dir/request.json" || rc=$?
|
|
[ "$rc" -eq 0 ] && exit 0
|
|
[ "$rc" -eq 255 ] || exit "$rc"
|
|
sleep 5
|
|
done
|
|
exit "$rc"
|
|
;;
|
|
apply|verify|smoke)
|
|
for attempt in 1 2 3; do
|
|
rc=0
|
|
# shellcheck disable=SC2029 # The run ID and operation are validated local arguments, not remote variables.
|
|
ssh "${ssh_opts[@]}" "$DEPLOY_USER@$DEPLOY_HOST" python3 "$controller" follow "$DEPLOY_RUN_ID" "$1" || rc=$?
|
|
[ "$rc" -eq 0 ] && exit 0
|
|
[ "$rc" -eq 255 ] || exit "$rc"
|
|
echo "SSH disconnected; reconnecting to the existing deploy ($attempt/3)"
|
|
sleep 5
|
|
done
|
|
exit "$rc"
|
|
;;
|
|
*) echo "Unknown SSH operation: $1" >&2; exit 1 ;;
|
|
esac
|