@thomas.solbjor her er "import" av tofu fra ditt repo med justeringer for å tilpasse patterns her. Også minimalisert til å kun opprette cluster, ingen managed services som postgres etc. Ta en titt. Co-authored-by: Danijel Simeunovic <danijel.simeunovic@fortedigital.com> Reviewed-on: #15 Reviewed-by: Danijel Simeunovic <danijel.simeunovic@fortedigital.com> Co-authored-by: Ghost <> Co-committed-by: Ghost <>
247 lines
8.8 KiB
Bash
247 lines
8.8 KiB
Bash
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
TOFU_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
PROJECT_ROOT="$(dirname "$TOFU_ROOT")"
|
|
|
|
# ─── Usage ────────────────────────────────────────────────────────────
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: $0 <cluster> [options]
|
|
|
|
Provision a Kubernetes cluster using OpenTofu.
|
|
Mirrors bootstrap.sh convention: cluster = <platform>-<env>
|
|
|
|
Clusters: aks-dev | aks-prod | eks-dev | eks-prod
|
|
gke-dev | gke-prod | upc-dev | upc-prod
|
|
<platform>-workload (for workload clusters)
|
|
|
|
Options:
|
|
--plan Plan only, don't apply
|
|
--destroy Destroy the cluster (use teardown-cluster.sh instead)
|
|
--auto Skip confirmation prompts
|
|
-h, --help Show this help
|
|
|
|
Examples:
|
|
$0 aks-dev
|
|
$0 eks-prod --plan
|
|
$0 upc-dev --auto
|
|
|
|
Prerequisites:
|
|
- tofu, kubectl, helm installed
|
|
- Platform credentials in .tofu/configs/<platform>.env
|
|
- Cluster config in clusters/<cluster>.yaml
|
|
|
|
After provisioning, run:
|
|
./bootstrap.sh <cluster>
|
|
EOF
|
|
exit "${1:-0}"
|
|
}
|
|
|
|
# ─── Parse arguments ──────────────────────────────────────────────────
|
|
CLUSTER=""
|
|
PLAN_ONLY=false
|
|
DESTROY=false
|
|
AUTO_APPROVE=false
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--plan) PLAN_ONLY=true; shift ;;
|
|
--destroy) DESTROY=true; shift ;;
|
|
--auto) AUTO_APPROVE=true; shift ;;
|
|
-h|--help) usage 0 ;;
|
|
-*) echo "Unknown option: $1"; usage 1 ;;
|
|
*)
|
|
if [[ -z "$CLUSTER" ]]; then
|
|
CLUSTER="$1"
|
|
else
|
|
echo "Error: unexpected argument '$1'"
|
|
usage 1
|
|
fi
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
[[ -z "$CLUSTER" ]] && { echo "Error: <cluster> argument required"; usage 1; }
|
|
|
|
# ─── Map cluster → platform + env ────────────────────────────────────
|
|
PLATFORM="${CLUSTER%%-*}" # aks-dev → aks
|
|
ENV="${CLUSTER#*-}" # aks-dev → dev
|
|
|
|
case "$PLATFORM" in
|
|
aks|eks|gke|upc) ;;
|
|
*) echo "Error: unknown platform '$PLATFORM'. Expected: aks, eks, gke, upc"; exit 1 ;;
|
|
esac
|
|
|
|
TOFU_DIR="$TOFU_ROOT/platforms/$PLATFORM/$ENV"
|
|
if [[ ! -d "$TOFU_DIR" ]]; then
|
|
echo "Error: tofu directory not found: $TOFU_DIR"
|
|
echo "Available environments for $PLATFORM:"
|
|
ls -1 "$TOFU_ROOT/platforms/$PLATFORM/" 2>/dev/null | grep -v modules || echo " (none)"
|
|
exit 1
|
|
fi
|
|
|
|
echo "========================================="
|
|
echo " Kubernetes Cluster Setup"
|
|
echo "========================================="
|
|
echo ""
|
|
echo " Cluster: $CLUSTER"
|
|
echo " Platform: $PLATFORM"
|
|
echo " Env: $ENV"
|
|
echo " Tofu dir: $TOFU_DIR"
|
|
echo ""
|
|
|
|
# ─── Prerequisites ────────────────────────────────────────────────────
|
|
echo "=== Checking Prerequisites ==="
|
|
command -v tofu >/dev/null 2>&1 || { echo "Error: tofu is not installed."; exit 1; }
|
|
command -v kubectl >/dev/null 2>&1 || { echo "Error: kubectl is not installed."; exit 1; }
|
|
command -v helm >/dev/null 2>&1 || { echo "Error: helm is not installed."; exit 1; }
|
|
echo " tofu, kubectl, helm: OK"
|
|
|
|
# ─── Load platform credentials ────────────────────────────────────────
|
|
ENV_FILE="$TOFU_ROOT/configs/$PLATFORM.env"
|
|
if [[ -f "$ENV_FILE" ]]; then
|
|
echo " Loading credentials from configs/$PLATFORM.env"
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
source "$ENV_FILE"
|
|
set +a
|
|
else
|
|
echo " Warning: $ENV_FILE not found — using existing environment/CLI auth"
|
|
echo " Copy configs/$PLATFORM.env.example → configs/$PLATFORM.env to configure"
|
|
fi
|
|
|
|
# ─── Load cluster config (if exists) ──────────────────────────────────
|
|
CLUSTER_CONFIG="$PROJECT_ROOT/clusters/$CLUSTER.yaml"
|
|
if [[ -f "$CLUSTER_CONFIG" ]]; then
|
|
echo " Loading cluster config from clusters/$CLUSTER.yaml"
|
|
if command -v yq >/dev/null 2>&1; then
|
|
eval "$(yq -r 'to_entries[] | "export CLUSTER_\(.key)=\"\(.value)\""' "$CLUSTER_CONFIG")"
|
|
echo " Cluster name: ${CLUSTER_clusterName:-$CLUSTER}"
|
|
else
|
|
echo " Warning: yq not installed — cluster config not loaded"
|
|
fi
|
|
else
|
|
echo " Warning: $CLUSTER_CONFIG not found — using defaults"
|
|
fi
|
|
echo ""
|
|
|
|
# ─── Run OpenTofu ─────────────────────────────────────────────────────
|
|
cd "$TOFU_DIR"
|
|
|
|
echo "=== Initializing OpenTofu ==="
|
|
tofu init
|
|
|
|
echo ""
|
|
if $DESTROY; then
|
|
echo "=== Planning Destruction ==="
|
|
tofu plan -destroy -out=tfplan
|
|
|
|
if ! $AUTO_APPROVE; then
|
|
echo ""
|
|
read -rp "DESTROY cluster $CLUSTER? This is irreversible. (yes/no) " REPLY
|
|
[[ "$REPLY" == "yes" ]] || { echo "Cancelled."; exit 1; }
|
|
fi
|
|
|
|
echo "Destroying infrastructure..."
|
|
tofu apply tfplan
|
|
echo ""
|
|
echo "=== Cluster $CLUSTER Destroyed ==="
|
|
|
|
elif $PLAN_ONLY; then
|
|
echo "=== Planning Infrastructure ==="
|
|
tofu plan
|
|
echo ""
|
|
echo "=== Plan complete (--plan mode, no changes applied) ==="
|
|
|
|
else
|
|
echo "=== Planning Infrastructure ==="
|
|
tofu plan -out=tfplan
|
|
|
|
if ! $AUTO_APPROVE; then
|
|
echo ""
|
|
read -rp "Apply this plan for $CLUSTER? (y/n) " -n 1 REPLY
|
|
echo
|
|
[[ "$REPLY" =~ ^[Yy]$ ]] || { echo "Cancelled."; exit 1; }
|
|
fi
|
|
|
|
echo "Applying infrastructure..."
|
|
tofu apply tfplan
|
|
|
|
# ─── Save kubeconfig ──────────────────────────────────────────────
|
|
KUBECONFIG_DIR="$PROJECT_ROOT/private/$CLUSTER"
|
|
mkdir -p "$KUBECONFIG_DIR"
|
|
KUBECONFIG_FILE="$KUBECONFIG_DIR/kubeconfig"
|
|
|
|
echo ""
|
|
echo "=== Saving Kubeconfig ==="
|
|
|
|
case "$PLATFORM" in
|
|
aks)
|
|
if tofu output -raw kubeconfig > "$KUBECONFIG_FILE" 2>/dev/null; then
|
|
echo " Saved from tofu output"
|
|
else
|
|
echo " Fetching from Azure CLI..."
|
|
RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}-rg")
|
|
NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")
|
|
az aks get-credentials --resource-group "$RG" --name "$NAME" --file "$KUBECONFIG_FILE" --overwrite-existing
|
|
fi
|
|
;;
|
|
eks)
|
|
NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")
|
|
REGION=$(tofu output -raw aws_region 2>/dev/null || echo "${AWS_REGION:-eu-west-1}")
|
|
aws eks update-kubeconfig --name "$NAME" --region "$REGION" --kubeconfig "$KUBECONFIG_FILE"
|
|
;;
|
|
gke)
|
|
NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")
|
|
REGION=$(tofu output -raw region 2>/dev/null || echo "${GCP_REGION:-europe-west4}")
|
|
PROJECT=$(tofu output -raw project_id 2>/dev/null || echo "${GCP_PROJECT_ID:-}")
|
|
gcloud container clusters get-credentials "$NAME" --region "$REGION" --project "$PROJECT" 2>/dev/null \
|
|
&& cp ~/.kube/config "$KUBECONFIG_FILE" \
|
|
|| echo " Warning: could not fetch kubeconfig via gcloud"
|
|
;;
|
|
upc)
|
|
if tofu output -raw kubeconfig > "$KUBECONFIG_FILE" 2>/dev/null; then
|
|
echo " Saved from tofu output"
|
|
else
|
|
CLUSTER_ID=$(tofu output -raw cluster_id 2>/dev/null || echo "${UPCLOUD_CLUSTER_ID:-}")
|
|
if [[ -n "$CLUSTER_ID" ]]; then
|
|
upctl kubernetes config "$CLUSTER_ID" > "$KUBECONFIG_FILE"
|
|
else
|
|
echo " Warning: could not determine cluster ID for kubeconfig"
|
|
fi
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
if [[ -f "$KUBECONFIG_FILE" ]]; then
|
|
chmod 600 "$KUBECONFIG_FILE"
|
|
echo " Kubeconfig: $KUBECONFIG_FILE"
|
|
fi
|
|
|
|
# ─── Wait for nodes ──────────────────────────────────────────────
|
|
echo ""
|
|
echo "=== Waiting for Cluster Nodes ==="
|
|
export KUBECONFIG="$KUBECONFIG_FILE"
|
|
if kubectl wait --for=condition=Ready nodes --all --timeout=300s 2>/dev/null; then
|
|
echo " All nodes ready"
|
|
else
|
|
echo " Warning: nodes not ready within timeout — check cluster status"
|
|
fi
|
|
|
|
# ─── Summary ─────────────────────────────────────────────────────
|
|
echo ""
|
|
echo "========================================="
|
|
echo " Cluster $CLUSTER Provisioned"
|
|
echo "========================================="
|
|
echo ""
|
|
echo " Kubeconfig: $KUBECONFIG_FILE"
|
|
echo ""
|
|
echo " Next steps:"
|
|
echo " export KUBECONFIG=$KUBECONFIG_FILE"
|
|
echo " ./bootstrap.sh $CLUSTER"
|
|
echo ""
|
|
fi
|