Files
sbbb/scripts/local-up.sh

204 lines
9.3 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# Start the Sunbeam local dev stack.
# Idempotent: safe to run multiple times.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
CTX="--context=sunbeam"
# ---------------------------------------------------------------------------
# 1. Check prerequisites
# ---------------------------------------------------------------------------
echo "==> Checking prerequisites..."
for tool in limactl mkcert kubectl kustomize linkerd jq yq; do
if ! command -v "$tool" &>/dev/null; then
echo "ERROR: '$tool' not found. Install with: brew install $tool" >&2
exit 1
fi
done
echo " OK"
# ---------------------------------------------------------------------------
# 2. Start Lima VM (skip if already running)
# ---------------------------------------------------------------------------
# Separate existence check from status — avoids falling through to "create"
# when VM exists but has an unexpected status (Broken, Starting, etc.)
LIMA_STATUS=$(limactl list --json 2>/dev/null | \
python3 -c "import sys,json; vms=[v for v in json.load(sys.stdin) if v['name']=='sunbeam']; print(vms[0]['status'] if vms else 'none')" 2>/dev/null || echo "none")
if [[ "$LIMA_STATUS" == "none" ]]; then
echo "==> Creating Lima VM 'sunbeam' (k3s, 6 CPU / 12 GB / 60 GB)..."
limactl start \
--name=sunbeam \
template:k3s \
--memory=12 \
--cpus=6 \
--disk=60 \
--vm-type=vz \
--mount-type=virtiofs
elif [[ "$LIMA_STATUS" == "Running" ]]; then
echo "==> Lima VM 'sunbeam' already running."
else
# Covers Stopped, Broken, Starting, or any other state
echo "==> Starting Lima VM 'sunbeam' (status: $LIMA_STATUS)..."
limactl start sunbeam
fi
# ---------------------------------------------------------------------------
# 3. Merge kubeconfig into ~/.kube/config as context "sunbeam"
# ---------------------------------------------------------------------------
echo "==> Merging kubeconfig..."
LIMA_KUBECONFIG="/Users/$USER/.lima/sunbeam/copied-from-guest/kubeconfig.yaml"
if [[ ! -f "$LIMA_KUBECONFIG" ]]; then
echo "ERROR: Lima kubeconfig not found at $LIMA_KUBECONFIG" >&2
exit 1
fi
# Extract cert data and set context
mkdir -p ~/.kube /tmp/sunbeam-kube
yq '.clusters[0].cluster.certificate-authority-data' "$LIMA_KUBECONFIG" | base64 -d > /tmp/sunbeam-kube/ca.crt
yq '.users[0].user.client-certificate-data' "$LIMA_KUBECONFIG" | base64 -d > /tmp/sunbeam-kube/client.crt
yq '.users[0].user.client-key-data' "$LIMA_KUBECONFIG" | base64 -d > /tmp/sunbeam-kube/client.key
kubectl config set-cluster sunbeam --server=https://127.0.0.1:6443 --certificate-authority=/tmp/sunbeam-kube/ca.crt --embed-certs=true
kubectl config set-credentials sunbeam-admin --client-certificate=/tmp/sunbeam-kube/client.crt --client-key=/tmp/sunbeam-kube/client.key --embed-certs=true
kubectl config set-context sunbeam --cluster=sunbeam --user=sunbeam-admin
rm -rf /tmp/sunbeam-kube
echo " Context 'sunbeam' ready."
# ---------------------------------------------------------------------------
# 4. Disable Traefik (k3s default) if still present
# ---------------------------------------------------------------------------
if kubectl $CTX get helmchart traefik -n kube-system &>/dev/null; then
echo "==> Removing Traefik (replaced by Pingora)..."
kubectl $CTX delete helmchart traefik traefik-crd -n kube-system 2>/dev/null || true
fi
# Remove startup manifest so k3s doesn't re-create it
limactl shell sunbeam sudo rm -f /var/lib/rancher/k3s/server/manifests/traefik.yaml 2>/dev/null || true
# ---------------------------------------------------------------------------
# 5. Install cert-manager
# ---------------------------------------------------------------------------
if ! kubectl $CTX get ns cert-manager &>/dev/null; then
echo "==> Installing cert-manager..."
kubectl $CTX apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.0/cert-manager.yaml
echo " Waiting for cert-manager webhooks..."
kubectl $CTX -n cert-manager rollout status deployment/cert-manager --timeout=120s
kubectl $CTX -n cert-manager rollout status deployment/cert-manager-webhook --timeout=120s
kubectl $CTX -n cert-manager rollout status deployment/cert-manager-cainjector --timeout=120s
echo " cert-manager installed."
else
echo "==> cert-manager already installed."
fi
# ---------------------------------------------------------------------------
# 6. Install Gateway API CRDs + Linkerd via CLI# ---------------------------------------------------------------------------
if ! kubectl $CTX get ns linkerd &>/dev/null; then
echo "==> Installing Gateway API CRDs..."
kubectl $CTX apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml
echo "==> Installing Linkerd CRDs..."
linkerd install --crds | kubectl $CTX apply --server-side -f -
echo "==> Installing Linkerd control plane..."
linkerd install | kubectl $CTX apply --server-side -f -
kubectl $CTX -n linkerd rollout status deployment/linkerd-identity --timeout=120s
kubectl $CTX -n linkerd rollout status deployment/linkerd-destination --timeout=120s
kubectl $CTX -n linkerd rollout status deployment/linkerd-proxy-injector --timeout=120s
echo " Linkerd installed."
else
echo "==> Linkerd already installed."
fi
# ---------------------------------------------------------------------------
# 7. Generate mkcert wildcard cert# ---------------------------------------------------------------------------
# Use eth1 (socket_vmnet shared network) — the address reachable from the Mac host.
LIMA_IP=$(limactl shell sunbeam ip -4 addr show eth1 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1)
if [[ -z "$LIMA_IP" ]]; then
# Fallback: first non-loopback IP (works on first-boot before eth1 is up)
LIMA_IP=$(limactl shell sunbeam hostname -I | awk '{print $1}')
fi
DOMAIN="${LIMA_IP}.sslip.io"
SECRETS_DIR="$REPO_ROOT/secrets/local"
if [[ ! -f "$SECRETS_DIR/tls.crt" ]]; then
echo "==> Generating TLS cert for *.$DOMAIN..."
mkdir -p "$SECRETS_DIR"
cd "$SECRETS_DIR"
mkcert "*.$DOMAIN"
mv "_wildcard.${DOMAIN}.pem" tls.crt
mv "_wildcard.${DOMAIN}-key.pem" tls.key
cd "$REPO_ROOT"
else
echo "==> TLS cert already exists."
fi
# ---------------------------------------------------------------------------
# 8. Create TLS Secret in ingress namespace# ---------------------------------------------------------------------------
echo "==> Applying TLS Secret to ingress namespace..."
kubectl $CTX create namespace ingress --dry-run=client -o yaml | kubectl $CTX apply -f -
kubectl $CTX create secret tls pingora-tls \
--cert="$SECRETS_DIR/tls.crt" \
--key="$SECRETS_DIR/tls.key" \
-n ingress \
--dry-run=client -o yaml | kubectl $CTX apply -f -
# ---------------------------------------------------------------------------
# 9. Apply manifests (server-side apply handles large CRDs)# ---------------------------------------------------------------------------
echo "==> Applying manifests (domain: $DOMAIN)..."
cd "$REPO_ROOT"
kustomize build overlays/local --enable-helm | \
sed "s/DOMAIN_SUFFIX/${DOMAIN}/g" | \
kubectl $CTX apply --server-side --force-conflicts -f -
# ---------------------------------------------------------------------------
# 10. Seed secrets (waits for postgres, creates K8s secrets, inits OpenBao)# ---------------------------------------------------------------------------
echo "==> Seeding secrets..."
bash "$SCRIPT_DIR/local-seed-secrets.sh"
# ---------------------------------------------------------------------------
# 11. Restart deployments that were waiting for secrets# ---------------------------------------------------------------------------
echo "==> Restarting services that were waiting for secrets..."
for ns_deploy in \
"ory/hydra" \
"ory/kratos" \
"ory/login-ui" \
"devtools/gitea" \
"storage/seaweedfs-filer" \
"lasuite/hive" \
"media/livekit-server"; do
ns="${ns_deploy%%/*}"
dep="${ns_deploy##*/}"
kubectl $CTX -n "$ns" rollout restart deployment/"$dep" 2>/dev/null || true
done
# ---------------------------------------------------------------------------
# 12. Wait for core components# ---------------------------------------------------------------------------
echo "==> Waiting for Valkey..."
kubectl $CTX rollout status deployment/valkey -n data --timeout=120s || true
echo "==> Waiting for Kratos..."
kubectl $CTX rollout status deployment/kratos -n ory --timeout=120s || true
echo "==> Waiting for Hydra..."
kubectl $CTX rollout status deployment/hydra -n ory --timeout=120s || true
# ---------------------------------------------------------------------------
# 13. Print URLs# ---------------------------------------------------------------------------
echo ""
echo "==> Stack is up. Domain: $DOMAIN"
echo ""
echo "Services:"
echo " Auth: https://auth.${DOMAIN}/"
echo " Docs: https://docs.${DOMAIN}/"
echo " Meet: https://meet.${DOMAIN}/"
echo " Drive: https://drive.${DOMAIN}/"
echo " Messages: https://messages.${DOMAIN}/"
echo " Mail: https://mail.${DOMAIN}/"
echo " People: https://people.${DOMAIN}/"
echo " Gitea: https://src.${DOMAIN}/"
echo ""
echo "OpenBao UI: kubectl $CTX -n data port-forward svc/openbao 8200:8200"
echo " http://localhost:8200 (token from: kubectl $CTX -n data get secret openbao-keys -o jsonpath='{.data.root-token}' | base64 -d)"