2025-09-14 00:48:55 +02:00
#!/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> [--type cpx11] [--region nbg1] [--role web] [--image ubuntu-24.04] [--user admin]
#
# 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"
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; ;
*) 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 "
ok " Inventory updated: $NAME → inventory/servers.yaml "
# --- Decrypt Hetzner token and apply Terraform ---
2025-09-14 00:11:27 +00:00
HCLOUD_TOKEN = " $( sops -d --extract '["hetzner"]["token"]' secrets/hetzner-token.sops.yaml 2>/dev/null) "
[ [ -n " $HCLOUD_TOKEN " ] ] || fail "Could not decrypt ops.hcloud_token from secrets/hetzner-token.sops.yaml. Ensure SOPS_AGE_KEY or keys.txt is set and token exists."
2025-09-14 00:48:55 +02:00
pushd terraform/hetzner >/dev/null
terraform init -upgrade
export HCLOUD_TOKEN
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."