railiance-infra/scripts/hcloud_new_server.sh
codex b93af8cc78
Some checks failed
CI Smoke / source-contract (push) Failing after 2s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Implement reproducible S1 handoff contracts
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02994-7685-7940-bf34-3555b8256018
2026-08-23 12:02:23 +02:00

105 lines
3 KiB
Bash
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# hcloud_new_server.sh — Add a host to inventory and provision it on Hetzner
# Usage:
# scripts/hcloud_new_server.sh <NAME> [options] [--apply]
#
# Prereqs:
# - age + SOPS installed, with access to decrypt your Hetzner token
# - terraform installed
# - Python3 + PyYAML (for scripts/new_host.py)
#
set -euo pipefail
fail() { echo "$*" >&2; exit 1; }
ok() { echo "$*"; }
info() { echo " $*"; }
# --- Parse args ---
NAME="${1:-}"
shift || true
TYPE="cpx21"
REGION="nbg1"
ROLE="generic"
IMAGE="ubuntu-24.04"
USER="admin"
APPLY=false
while [[ $# -gt 0 ]]; do
case "$1" in
--type) TYPE="$2"; shift 2;;
--region) REGION="$2"; shift 2;;
--role) ROLE="$2"; shift 2;;
--image) IMAGE="$2"; shift 2;;
--user) USER="$2"; shift 2;;
--apply) APPLY=true; shift;;
*) fail "Unknown arg: $1 (usage: scripts/hcloud_new_server.sh <NAME> [--type cpx11] [--region nbg1] [--role web] [--image ubuntu-24.04] [--user admin])";;
esac
done
[[ -n "$NAME" ]] || fail "Missing NAME. Usage: scripts/hcloud_new_server.sh <NAME> [--type ...] ..."
# --- Sanity checks ---
command -v terraform >/dev/null || fail "terraform not found"
command -v sops >/dev/null || fail "sops not found"
command -v python3 >/dev/null || fail "python3 not found"
python3 -c "import yaml" 2>/dev/null || fail "PyYAML not installed for python3 (pip install pyyaml)"
if [[ ! -f "scripts/new_host.py" ]]; then
fail "scripts/new_host.py not found (expected in repo)."
fi
if [[ ! -f "keys/admin_ssh.pub" ]]; then
info "keys/admin_ssh.pub missing. Hetzner will still inject your project key if configured, but you may want to add one."
fi
# --- Add host to inventory ---
python3 scripts/new_host.py \
--name "$NAME" \
--type "$TYPE" \
--region "$REGION" \
--role "$ROLE" \
--image "$IMAGE" \
--user "$USER" \
--reuse-existing
ok "Inventory updated: $NAME → inventory/servers.yaml"
# --- Decrypt Hetzner token and apply Terraform ---
HCLOUD_TOKEN="$(sops -d --extract '["hetzner"]["token"]' secrets/hetzner-token.yaml 2>/dev/null)"
[[ -n "$HCLOUD_TOKEN" ]] || fail "Could not decrypt hetzner.token from secrets/hetzner-token.yaml. Ensure SOPS_AGE_KEY or keys.txt is set."
pushd terraform/hetzner >/dev/null
terraform init -upgrade
export TF_VAR_hcloud_token="$HCLOUD_TOKEN"
terraform plan
if [[ "$APPLY" != true ]]; then
info "Plan complete; no provider mutation performed. Re-run with --apply only after review and approval."
popd >/dev/null
exit 0
fi
terraform apply -auto-approve
# Try to show IP of the created host
if command -v jq >/dev/null; then
IP="$(terraform output -json servers | jq -r --arg n "$NAME" '.[$n] // empty')"
if [[ -n "$IP" && "$IP" != "null" ]]; then
ok "Server $NAME IPv4: $IP"
echo ""
echo "SSH quick check (if admin key injected):"
echo " ssh admin@$IP"
else
info "Could not extract IP for $NAME (jq path empty). Full outputs:"
terraform output
fi
else
info "jq not found. Terraform outputs:"
terraform output
fi
popd >/dev/null
ok "Provisioning complete."