#!/usr/bin/env bash set -euo pipefail NAMESPACE="stonks-oracle" REPO_DIR="$HOME/sources/celesrenata/stonks-oracle" CHART_DIR="$REPO_DIR/infra/helm/stonks-oracle" MIGRATIONS_DIR="$REPO_DIR/infra/migrations" KUBE_DIR="$HOME/sources/kube/stonks-oracle" # --- Secrets --- # All secrets are read from ~/sources/kube/stonks-oracle/ on gremlin-1. # This directory is NOT a git repo — secrets stay local to the deploy host. # # Required files: # ~/sources/kube/stonks-oracle/polygon.io.key # ~/sources/kube/stonks-oracle/alpaca.key # ~/sources/kube/stonks-oracle/alpaca.secret # ~/sources/kube/stonks-oracle/alpaca.url # /run/secrets/github_token _read_secret() { local file="$1" local default="${2:-}" if [ -f "$file" ]; then cat "$file" | tr -d '[:space:]' elif [ -n "$default" ]; then echo "$default" else echo "ERROR: Secret file not found: $file" >&2 exit 1 fi } GHCR_TOKEN=$(_read_secret /run/secrets/github_token) PG_PASSWORD='St0nks0racl3!' REDIS_PASSWORD='PSCh4ng3me!' MINIO_ACCESS_KEY="AKIA6V7J3N9B5P0D2YQH" MINIO_SECRET_KEY='8fG3!v2rJ7$wN@9mLpQ6zXbC4tKdPqW1' POLYGON_API_KEY=$(_read_secret "$KUBE_DIR/polygon.io.key") ALPACA_API_KEY=$(_read_secret "$KUBE_DIR/alpaca.key") ALPACA_API_SECRET=$(_read_secret "$KUBE_DIR/alpaca.secret") ALPACA_BASE_URL=$(_read_secret "$KUBE_DIR/alpaca.url" "https://paper-api.alpaca.markets") GMAIL_APP_PASSWORD=$(_read_secret "$KUBE_DIR/gmail.app" "") echo "=== Stonks Oracle Deployment ===" echo "Namespace: $NAMESPACE" echo "Chart: $CHART_DIR" echo "Secrets: $KUBE_DIR" # --- 0. Pull latest code --- echo "[0/5] Pulling latest code..." git -C "$REPO_DIR" pull --ff-only || echo "WARNING: git pull failed — using existing code" # --- 1. Ensure namespace exists with correct labels --- echo "[1/5] Ensuring namespace $NAMESPACE exists..." if ! kubectl get namespace "$NAMESPACE" >/dev/null 2>&1; then kubectl create namespace "$NAMESPACE" fi kubectl label namespace "$NAMESPACE" app.kubernetes.io/managed-by=Helm --overwrite kubectl annotate namespace "$NAMESPACE" meta.helm.sh/release-name=stonks-oracle meta.helm.sh/release-namespace=stonks-oracle --overwrite # --- 2. Create PostgreSQL user and database --- echo "[2/5] Setting up PostgreSQL database and user..." kubectl exec -i -n postgresql-service postgresql-1 -c postgres -- psql -U postgres < $(basename "$f")" kubectl exec -i -n postgresql-service postgresql-1 -c postgres -- psql -U postgres -d stonks < "$f" 2>&1 | grep -v "already exists" || true done # Grant permissions kubectl exec -i -n postgresql-service postgresql-1 -c postgres -- psql -U postgres -d stonks </dev/null 2>&1; then echo "WARNING: GHCR login failed — token may be expired or missing scopes." echo " Ensure /run/secrets/github_token has 'read:packages' scope." echo " Generate a new token at: https://github.com/settings/tokens" echo " Continuing anyway (Helm will create the secret, but pods may fail to pull)..." fi # Force-recreate the GHCR pull secret to ensure it's fresh kubectl delete secret ghcr-credentials -n "$NAMESPACE" --ignore-not-found kubectl create secret docker-registry ghcr-credentials \ --namespace "$NAMESPACE" \ --docker-server=ghcr.io \ --docker-username=celesrenata \ --docker-password="$GHCR_TOKEN" \ --dry-run=client -o yaml | kubectl apply -f - helm upgrade --install stonks-oracle "$CHART_DIR" \ --namespace "$NAMESPACE" \ --set "ghcrAuth.password=$GHCR_TOKEN" \ --set "secrets.core.POSTGRES_PASSWORD=$PG_PASSWORD" \ --set "secrets.core.MINIO_ACCESS_KEY=$MINIO_ACCESS_KEY" \ --set "secrets.core.MINIO_SECRET_KEY=$MINIO_SECRET_KEY" \ --set "secrets.core.REDIS_PASSWORD=$REDIS_PASSWORD" \ --set "secrets.market.MARKET_DATA_API_KEY=$POLYGON_API_KEY" \ --set "secrets.broker.BROKER_API_KEY=$ALPACA_API_KEY" \ --set "secrets.broker.BROKER_API_SECRET=$ALPACA_API_SECRET" \ --set "secrets.broker.BROKER_BASE_URL=$ALPACA_BASE_URL" \ --set "secrets.gmail.GMAIL_APP_PASSWORD=$GMAIL_APP_PASSWORD" # --- 5. Rolling restart to pick up new images --- echo "[5/5] Rolling restart..." for dep in $(kubectl get deployments -n "$NAMESPACE" -o name); do kubectl rollout restart -n "$NAMESPACE" "$dep" done echo "" echo "=== Deployment complete ===" echo "Waiting for pods..." sleep 10 kubectl get pods -n "$NAMESPACE" -o custom-columns='NAME:.metadata.name,READY:.status.containerStatuses[0].ready,STATUS:.status.phase,RESTARTS:.status.containerStatuses[0].restartCount' echo "" echo "Ingress endpoints:" kubectl get ingress -n "$NAMESPACE" -o custom-columns='HOST:.spec.rules[0].host,ADDRESS:.status.loadBalancer.ingress[0].ip'