diff --git a/runmefirst.sh b/runmefirst.sh new file mode 100755 index 0000000..7179914 --- /dev/null +++ b/runmefirst.sh @@ -0,0 +1,143 @@ +#!/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'