#!/bin/bash set -euo pipefail # runmefirst.sh — Full CI/CD pipeline infrastructure install # Installs: Gitea config → Woodpecker CI → ArgoCD → Kargo # Tears down ARC first (if present) # Persists state on NFS volumes at nfs://192.168.42.8:/volume1/Kubernetes/pipelines SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" # ------------------------------------------------------- # 1. Create namespaces # ------------------------------------------------------- echo "--- Step 1: Creating namespaces ---" for ns in woodpecker argocd kargo stonks-beta stonks-paper; do kubectl create namespace "$ns" --dry-run=client -o yaml | kubectl apply -f - echo " ✓ namespace/$ns" done echo "" # ------------------------------------------------------- # 1b. Ensure proxy-ca-cert ConfigMap exists in pipeline namespaces # ------------------------------------------------------- echo "--- Step 1b: Ensuring proxy CA cert ConfigMap ---" CA_CERT_PATH="/home/celes/nixos-goblin-1-2-3/home.crt" for ns in woodpecker argocd kargo; do if ! kubectl get configmap proxy-ca-cert -n "$ns" > /dev/null 2>&1; then kubectl create configmap proxy-ca-cert --from-file=ca.crt="$CA_CERT_PATH" -n "$ns" echo " ✓ proxy-ca-cert created in $ns" else echo " ✓ proxy-ca-cert already exists in $ns" fi done echo "" # ------------------------------------------------------- # 2. Apply NFS PersistentVolumes # ------------------------------------------------------- echo "--- Step 2: Applying NFS PersistentVolumes ---" kubectl apply -f pvs/argocd-pv.yaml kubectl apply -f pvs/kargo-pv.yaml kubectl apply -f pvs/woodpecker-pv.yaml echo " ✓ PVs applied" echo "" # ------------------------------------------------------- # 3. Configure Gitea (admin user, repo, webhook config) # ------------------------------------------------------- echo "--- Step 3: Configuring Gitea ---" bash gitea/setup.sh echo " ✓ Gitea configured" # Ensure Gitea allows webhook delivery to local/cluster addresses GITEA_POD=$(kubectl get pods -n git-server -l app=gitea -o jsonpath='{.items[0].metadata.name}') if ! kubectl exec -n git-server "$GITEA_POD" -- grep -q '\[webhook\]' /data/gitea/conf/app.ini 2>/dev/null; then kubectl exec -n git-server "$GITEA_POD" -- sh -c 'printf "\n[webhook]\nALLOWED_HOST_LIST = *\nSKIP_TLS_VERIFY = true\n" >> /data/gitea/conf/app.ini' kubectl rollout restart deployment/gitea -n git-server kubectl rollout status deployment/gitea -n git-server --timeout=60s echo " ✓ Gitea webhook config added (ALLOWED_HOST_LIST=*)" else echo " ✓ Gitea webhook config already present" fi echo "" # ------------------------------------------------------- # 4. Install Woodpecker CI via Helm # ------------------------------------------------------- echo "--- Step 4: Installing Woodpecker CI ---" # Check if Woodpecker is already installed (upgrade vs fresh install) WOODPECKER_EXISTS=$(helm list -n woodpecker -q 2>/dev/null | grep -c woodpecker || true) if [ "${WOODPECKER_EXISTS:-0}" -gt 0 ]; then # Upgrade — don't touch OAuth2 credentials, Woodpecker DB already has them echo " Woodpecker already installed — upgrading (preserving OAuth2 grants)..." helm upgrade woodpecker oci://ghcr.io/woodpecker-ci/helm/woodpecker \ --namespace woodpecker \ --values woodpecker/values.yaml \ --wait --timeout 5m else # Fresh install — need fresh OAuth2 credentials from Gitea echo " Fresh Woodpecker install — creating fresh OAuth2 app..." # Delete any existing OAuth2 app in Gitea (stale from previous install) GITEA_AUTH="Authorization: Basic $(echo -n 'admin:St0nks0racl3!' | base64)" GITEA_API="http://10.1.1.12:30300/api/v1" EXISTING_APP_ID=$(curl -s -H "$GITEA_AUTH" "$GITEA_API/user/applications/oauth2" | python3 -c ' import sys, json for app in json.loads(sys.stdin.read()): if app.get("name") == "woodpecker-ci": print(app["id"]) break ' 2>/dev/null || echo "") if [ -n "$EXISTING_APP_ID" ]; then curl -s -X DELETE -H "$GITEA_AUTH" "$GITEA_API/user/applications/oauth2/$EXISTING_APP_ID" > /dev/null echo " Deleted stale OAuth2 app (id=$EXISTING_APP_ID)" fi # Create fresh OAuth2 app OAUTH2_RESP=$(curl -s -X POST "$GITEA_API/user/applications/oauth2" \ -H "$GITEA_AUTH" -H "Content-Type: application/json" \ -d '{"name":"woodpecker-ci","redirect_uris":["https://stonks-ci.celestium.life/authorize"],"confidential_client":true}') GITEA_CLIENT_ID=$(echo "$OAUTH2_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['client_id'])") GITEA_CLIENT_SECRET=$(echo "$OAUTH2_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['client_secret'])") echo " ✓ OAuth2 app created (client_id: $GITEA_CLIENT_ID)" helm install woodpecker oci://ghcr.io/woodpecker-ci/helm/woodpecker \ --namespace woodpecker \ --values woodpecker/values.yaml \ --set server.env.WOODPECKER_GITEA_CLIENT="${GITEA_CLIENT_ID}" \ --set server.env.WOODPECKER_GITEA_SECRET="${GITEA_CLIENT_SECRET}" \ --wait --timeout 5m fi echo " ✓ Woodpecker CI installed" echo "" # ------------------------------------------------------- # 5. Apply Woodpecker agent RBAC # ------------------------------------------------------- echo "--- Step 5: Applying Woodpecker agent RBAC ---" kubectl apply -f woodpecker/agent-rbac.yaml echo " ✓ Agent RBAC applied" echo "" # ------------------------------------------------------- # 6. Install ArgoCD via Helm # ------------------------------------------------------- echo "--- Step 6: Installing ArgoCD ---" ARGOCD_EXISTS=$(helm list -n argocd -q 2>/dev/null | grep -c argocd || true) if [ "${ARGOCD_EXISTS:-0}" -eq 0 ]; then # Fresh install — clean up leftover CRDs and SAs kubectl delete crd applications.argoproj.io applicationsets.argoproj.io appprojects.argoproj.io \ --ignore-not-found --timeout=30s > /dev/null 2>&1 || true kubectl delete sa --all -n argocd --ignore-not-found --timeout=10s > /dev/null 2>&1 || true kubectl delete role --all -n argocd --ignore-not-found --timeout=10s > /dev/null 2>&1 || true kubectl delete rolebinding --all -n argocd --ignore-not-found --timeout=10s > /dev/null 2>&1 || true fi helm repo add argo https://argoproj.github.io/argo-helm || true helm repo update helm upgrade --install argocd argo/argo-cd \ --namespace argocd \ --values argocd/values.yaml \ --wait --timeout 5m echo " ✓ ArgoCD installed" # Apply repo secret and Applications kubectl apply -f argocd/repo-secret.yaml kubectl apply -f argocd/apps/stonks-beta.yaml kubectl apply -f argocd/apps/stonks-paper.yaml kubectl apply -f argocd/apps/stonks-live.yaml echo " ✓ ArgoCD repo secret and Applications applied" echo "" # ------------------------------------------------------- # 7. Install Kargo via Helm # ------------------------------------------------------- echo "--- Step 7: Installing Kargo ---" KARGO_EXISTS=$(helm list -n kargo -q 2>/dev/null | grep -c kargo || true) if [ "${KARGO_EXISTS:-0}" -eq 0 ]; then # Fresh install — clean up leftover CRDs and SAs from previous installs kubectl delete crd freights.kargo.akuity.io projects.kargo.akuity.io stages.kargo.akuity.io \ warehouses.kargo.akuity.io promotions.kargo.akuity.io promotiontasks.kargo.akuity.io \ clusterpromotiontasks.kargo.akuity.io projectconfigs.kargo.akuity.io \ clusterconfigs.kargo.akuity.io --ignore-not-found --timeout=30s > /dev/null 2>&1 || true kubectl delete sa --all -n kargo --ignore-not-found --timeout=10s > /dev/null 2>&1 || true kubectl delete role --all -n kargo --ignore-not-found --timeout=10s > /dev/null 2>&1 || true kubectl delete rolebinding --all -n kargo --ignore-not-found --timeout=10s > /dev/null 2>&1 || true fi helm upgrade --install kargo oci://ghcr.io/akuity/kargo-charts/kargo \ --namespace kargo \ --values kargo/values.yaml \ --timeout 5m || true # Kargo chart bug: controller deployment references SA 'kargo-controller' but chart doesn't create it kubectl create serviceaccount kargo-controller -n kargo 2>/dev/null || true # Wait for controller to stabilize echo " Waiting for kargo-controller..." for i in $(seq 1 24); do if kubectl get pods -n kargo -l app.kubernetes.io/component=controller -o jsonpath='{.items[0].status.containerStatuses[0].ready}' 2>/dev/null | grep -q true; then break fi kubectl delete pod -n kargo -l app.kubernetes.io/component=controller --field-selector=status.phase=Failed --ignore-not-found > /dev/null 2>&1 || true sleep 5 done echo " ✓ Kargo installed" # Apply Kargo resources kubectl apply -f kargo/project.yaml kubectl apply -f kargo/project-config.yaml kubectl apply -f kargo/warehouse.yaml kubectl apply -f kargo/market-hours-check.yaml kubectl apply -f kargo/stages/beta.yaml kubectl apply -f kargo/stages/paper.yaml kubectl apply -f kargo/stages/live.yaml echo " ✓ Kargo project, warehouse, and stages applied" echo "" echo "=== Pipeline Infrastructure Install Complete ===" echo "" echo "Endpoints:" echo " Woodpecker CI: https://stonks-ci.celestium.life" echo " ArgoCD: https://stonks-argocd.celestium.life" echo " Kargo: https://stonks-kargo.celestium.life"