Files
spinifex/scripts/iac/spinifex-test.sh
T
2026-04-07 10:56:16 +10:00

224 lines
5.6 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TOFU_DIR="$SCRIPT_DIR/proxmox"
CLUSTERS_DIR="$TOFU_DIR/clusters"
usage() {
cat <<'USAGE'
Usage: spinifex-test.sh <command> <cluster_name> [options]
Commands:
up Provision VMs with OpenTofu
configure Clone repo, build, form cluster, start services
test Run smoke tests against the cluster
down Destroy VMs and clean up state
full up → configure → test → down (preserves test exit code)
status Show cluster health and node IPs
ssh <N> SSH to node N (1-based)
Options:
--node-count=N Number of VMs (default: 3)
--memory-mb=N Memory per VM in MB (default: 16384)
--cpu-cores=N CPU cores per VM (default: 4)
--disk-size-gb=N Disk size per VM in GB (default: 32)
Examples:
./scripts/iac/spinifex-test.sh up spinifex-test1
./scripts/iac/spinifex-test.sh configure spinifex-test1
./scripts/iac/spinifex-test.sh test spinifex-test1
./scripts/iac/spinifex-test.sh status spinifex-test1
./scripts/iac/spinifex-test.sh ssh spinifex-test1 2
./scripts/iac/spinifex-test.sh down spinifex-test1
./scripts/iac/spinifex-test.sh full spinifex-test1 --node-count=3
USAGE
exit 1
}
[ $# -lt 2 ] && usage
COMMAND="$1"
CLUSTER_NAME="$2"
shift 2
# Parse options
NODE_COUNT=3
MEMORY_MB=16384
CPU_CORES=4
DISK_SIZE_GB=32
SSH_NODE=""
for arg in "$@"; do
case "$arg" in
--node-count=*) NODE_COUNT="${arg#*=}" ;;
--memory-mb=*) MEMORY_MB="${arg#*=}" ;;
--cpu-cores=*) CPU_CORES="${arg#*=}" ;;
--disk-size-gb=*) DISK_SIZE_GB="${arg#*=}" ;;
[0-9]*) SSH_NODE="$arg" ;;
*) echo "Unknown option: $arg"; usage ;;
esac
done
STATE_DIR="$CLUSTERS_DIR/$CLUSTER_NAME"
STATE_FILE="$STATE_DIR/terraform.tfstate"
tofu_cmd() {
tofu -chdir="$TOFU_DIR" "$@"
}
get_inventory() {
tofu_cmd output -json -state="$STATE_FILE" inventory 2>/dev/null
}
get_node_ip() {
local index=$1
get_inventory | jq -r ".nodes[$((index - 1))].management"
}
get_ssh_key() {
get_inventory | jq -r ".ssh_key_path"
}
get_node_count() {
get_inventory | jq -r ".node_count"
}
cmd_up() {
echo "==> Provisioning cluster '$CLUSTER_NAME' ($NODE_COUNT nodes, ${MEMORY_MB}MB RAM, ${CPU_CORES} cores)"
mkdir -p "$STATE_DIR"
tofu_cmd init
tofu_cmd apply \
-state="$STATE_FILE" \
-var="cluster_name=$CLUSTER_NAME" \
-var="node_count=$NODE_COUNT" \
-var="memory_mb=$MEMORY_MB" \
-var="cpu_cores=$CPU_CORES" \
-var="disk_size_gb=$DISK_SIZE_GB" \
-auto-approve
echo ""
echo "==> Cluster '$CLUSTER_NAME' provisioned"
echo ""
get_inventory | jq '.nodes[] | {name, management, data}'
}
cmd_configure() {
echo "==> Configuring cluster '$CLUSTER_NAME'"
if [ ! -f "$STATE_FILE" ]; then
echo "Error: No state file found at $STATE_FILE. Run 'up' first."
exit 1
fi
"$SCRIPT_DIR/configure-cluster.sh" "$CLUSTER_NAME" "$STATE_FILE"
}
cmd_test() {
echo "==> Testing cluster '$CLUSTER_NAME'"
if [ ! -f "$STATE_FILE" ]; then
echo "Error: No state file found at $STATE_FILE. Run 'up' first."
exit 1
fi
"$SCRIPT_DIR/test-cluster.sh" "$CLUSTER_NAME" "$STATE_FILE"
}
cmd_down() {
echo "==> Destroying cluster '$CLUSTER_NAME'"
if [ ! -f "$STATE_FILE" ]; then
echo "Error: No state file found at $STATE_FILE."
exit 1
fi
tofu_cmd destroy \
-state="$STATE_FILE" \
-var="cluster_name=$CLUSTER_NAME" \
-var="node_count=$NODE_COUNT" \
-var="memory_mb=$MEMORY_MB" \
-var="cpu_cores=$CPU_CORES" \
-var="disk_size_gb=$DISK_SIZE_GB" \
-auto-approve
rm -rf "$STATE_DIR"
echo "==> Cluster '$CLUSTER_NAME' destroyed"
}
cmd_full() {
cmd_up
cmd_configure
local test_exit=0
cmd_test || test_exit=$?
cmd_down
exit $test_exit
}
cmd_status() {
if [ ! -f "$STATE_FILE" ]; then
echo "Error: No state file found at $STATE_FILE."
exit 1
fi
local inventory
inventory=$(get_inventory)
local count
count=$(echo "$inventory" | jq -r '.node_count')
local ssh_key
ssh_key=$(echo "$inventory" | jq -r '.ssh_key_path')
echo "==> Cluster '$CLUSTER_NAME' status ($count nodes)"
echo ""
for i in $(seq 1 "$count"); do
local ip
ip=$(echo "$inventory" | jq -r ".nodes[$((i - 1))].management")
local data_ip
data_ip=$(echo "$inventory" | jq -r ".nodes[$((i - 1))].data")
local name
name=$(echo "$inventory" | jq -r ".nodes[$((i - 1))].name")
printf " %-20s mgmt=%-16s data=%-16s " "$name" "$ip" "$data_ip"
local health
if health=$(curl -sk --connect-timeout 3 "https://$ip:4432/health" 2>/dev/null); then
echo "health=$health"
else
echo "health=unreachable"
fi
done
}
cmd_ssh() {
if [ -z "$SSH_NODE" ]; then
echo "Usage: spinifex-test.sh ssh <cluster_name> <node_number>"
exit 1
fi
local ip
ip=$(get_node_ip "$SSH_NODE")
local ssh_key
ssh_key=$(get_ssh_key)
echo "==> SSH to $CLUSTER_NAME node $SSH_NODE ($ip)"
ssh -i "$(eval echo "$ssh_key")" \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
"tf-user@$ip"
}
case "$COMMAND" in
up) cmd_up ;;
configure) cmd_configure ;;
test) cmd_test ;;
down) cmd_down ;;
full) cmd_full ;;
status) cmd_status ;;
ssh) cmd_ssh ;;
*) echo "Unknown command: $COMMAND"; usage ;;
esac