Fix Node.js CI pipeline failures and stabilize GitHub Actions workflow #385
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Vertica CI | |
| on: | |
| # Triggers the workflow on push or pull request events but only for the main branch | |
| push: | |
| branches: [ master ] | |
| pull_request: | |
| branches: [ master ] | |
| # Allows you to run this workflow manually from the Actions tab | |
| workflow_dispatch: | |
| env: | |
| V_HOST: localhost | |
| V_PORT: 5433 | |
| V_USER: dbadmin | |
| V_DATABASE: vdb | |
| KC_REALM: test | |
| KC_USER: oauth_user | |
| KC_PASSWORD: password | |
| KC_CLIENT_ID: vertica | |
| KC_CLIENT_SECRET: P9f8350QQIUhFfK1GF5sMhq4Dm3P6Sbs | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| node: | |
| - '12' | |
| - '14' | |
| - '16' | |
| - '18' | |
| - '20' | |
| name: Node.js ${{ matrix.node }} | |
| steps: | |
| # --------------------------- | |
| # Checkout and setup | |
| # --------------------------- | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ matrix.node }} | |
| cache: yarn | |
| - name: build | |
| run: yarn | |
| - name: bootstrap | |
| run: yarn lerna bootstrap | |
| # --------------------------- | |
| # Kubernetes (KinD) + Helm setup | |
| # --------------------------- | |
| - name: Set up Kubernetes (KinD) | |
| uses: helm/kind-action@v1.8.0 | |
| with: | |
| cluster_name: vertica-ci | |
| node_image: kindest/node:v1.29.0 | |
| - name: Set up Helm | |
| uses: azure/setup-helm@v3 | |
| with: | |
| version: "3.11.3" | |
| - name: Add Helm repositories | |
| run: | | |
| helm repo add vertica-charts https://vertica.github.io/charts | |
| helm repo add bitnami https://charts.bitnami.com/bitnami || true | |
| helm repo update | |
| # --------------------------- | |
| # MinIO Setup | |
| # --------------------------- | |
| - name: Install MinIO | |
| run: | | |
| kubectl create ns minio | |
| cat <<'EOF' > minio.yaml | |
| apiVersion: apps/v1 | |
| kind: Deployment | |
| metadata: | |
| name: minio | |
| namespace: minio | |
| spec: | |
| replicas: 1 | |
| selector: | |
| matchLabels: | |
| app: minio | |
| template: | |
| metadata: | |
| labels: | |
| app: minio | |
| spec: | |
| containers: | |
| - name: minio | |
| image: minio/minio:latest | |
| args: ["server", "/data"] | |
| env: | |
| - name: MINIO_ROOT_USER | |
| value: "minioadmin" | |
| - name: MINIO_ROOT_PASSWORD | |
| value: "minioadmin" | |
| ports: | |
| - containerPort: 9000 | |
| volumeMounts: | |
| - name: data | |
| mountPath: /data | |
| volumes: | |
| - name: data | |
| emptyDir: {} | |
| --- | |
| apiVersion: v1 | |
| kind: Service | |
| metadata: | |
| name: minio | |
| namespace: minio | |
| spec: | |
| selector: | |
| app: minio | |
| ports: | |
| - port: 9000 | |
| targetPort: 9000 | |
| EOF | |
| kubectl apply -f minio.yaml | |
| kubectl -n minio rollout status deployment/minio --timeout=2m | |
| kubectl get pods -n minio -o wide || true | |
| kubectl get svc -n minio || true | |
| - name: Ensure MinIO bucket exists | |
| run: | | |
| kubectl run mc-client --rm -i --restart=Never \ | |
| --image=minio/mc:latest \ | |
| -n minio \ | |
| --command -- bash -c " | |
| mc alias set localminio http://minio.minio.svc.cluster.local:9000 minioadmin minioadmin && \ | |
| mc mb --ignore-existing localminio/vertica-fleeting && \ | |
| mc ls localminio | |
| " | |
| - name: Create MinIO Secret | |
| run: | | |
| kubectl create ns my-verticadb-operator | |
| kubectl delete secret communal-creds -n my-verticadb-operator --ignore-not-found | |
| kubectl create secret generic communal-creds \ | |
| -n my-verticadb-operator \ | |
| --from-literal=accesskey="minioadmin" \ | |
| --from-literal=secretkey="minioadmin" | |
| kubectl get secret communal-creds -n my-verticadb-operator -o yaml || true | |
| # --------------------------- | |
| # Vertica Operator + DB Deployment | |
| # --------------------------- | |
| - name: Install Vertica Operator | |
| run: | | |
| cat <<'EOF' > operator-values.yaml | |
| installCRDs: true | |
| controller: | |
| extraEnv: | |
| - name: AWS_REGION | |
| value: "us-east-1" | |
| - name: AWS_DEFAULT_REGION | |
| value: "us-east-1" | |
| EOF | |
| helm upgrade --install vdb-op vertica-charts/verticadb-operator \ | |
| -n my-verticadb-operator -f operator-values.yaml --wait --timeout 10m | |
| kubectl -n my-verticadb-operator get pods -o wide || true | |
| - name: Deploy VerticaDB | |
| run: | | |
| cat <<'EOF' | kubectl apply -f - | |
| apiVersion: vertica.com/v1 | |
| kind: VerticaDB | |
| metadata: | |
| name: verticadb-sample | |
| namespace: my-verticadb-operator | |
| annotations: | |
| vertica.com/k-safety: "0" | |
| spec: | |
| image: opentext/vertica-k8s:latest | |
| dbName: vdb | |
| initPolicy: Create | |
| communal: | |
| path: s3://vertica-fleeting/vertica-nodejs/ | |
| credentialSecret: communal-creds | |
| endpoint: http://minio.minio.svc.cluster.local:9000 | |
| region: us-east-1 | |
| local: | |
| dataPath: /data | |
| depotPath: /depot | |
| subclusters: | |
| - name: defaultsubcluster | |
| size: 1 | |
| EOF | |
| - name: Wait for Vertica readiness | |
| timeout-minutes: 10 | |
| run: | | |
| NS=my-verticadb-operator | |
| SS=verticadb-sample-defaultsubcluster | |
| POD=${SS}-0 | |
| for i in {1..30}; do | |
| kubectl get pod ${POD} -n ${NS} && break || sleep 10 | |
| done | |
| kubectl wait --for=condition=Ready pod/${POD} -n ${NS} --timeout=5m | |
| # --------------------------- | |
| # Keycloak + OAuth setup | |
| # --------------------------- | |
| - name: Deploy Keycloak | |
| run: | | |
| kubectl create ns keycloak | |
| cat <<'EOF' | kubectl apply -f - | |
| apiVersion: apps/v1 | |
| kind: Deployment | |
| metadata: | |
| name: keycloak | |
| namespace: keycloak | |
| spec: | |
| replicas: 1 | |
| selector: | |
| matchLabels: | |
| app: keycloak | |
| template: | |
| metadata: | |
| labels: | |
| app: keycloak | |
| spec: | |
| containers: | |
| - name: keycloak | |
| image: quay.io/keycloak/keycloak:23.0.4 | |
| args: ["start-dev"] | |
| env: | |
| - name: KEYCLOAK_ADMIN | |
| value: admin | |
| - name: KEYCLOAK_ADMIN_PASSWORD | |
| value: admin | |
| ports: | |
| - containerPort: 8080 | |
| readinessProbe: | |
| httpGet: | |
| path: / | |
| port: 8080 | |
| initialDelaySeconds: 20 | |
| periodSeconds: 5 | |
| failureThreshold: 6 | |
| --- | |
| apiVersion: v1 | |
| kind: Service | |
| metadata: | |
| name: keycloak | |
| namespace: keycloak | |
| spec: | |
| selector: | |
| app: keycloak | |
| ports: | |
| - port: 8080 | |
| targetPort: 8080 | |
| EOF | |
| - name: Wait for Keycloak readiness | |
| run: | | |
| kubectl -n keycloak rollout status deploy/keycloak --timeout=2m | |
| kubectl -n keycloak get pods -o wide | |
| - name: Configure Keycloak realm, client, and user | |
| run: | | |
| kubectl -n keycloak exec deploy/keycloak -- \ | |
| /opt/keycloak/bin/kcadm.sh config credentials \ | |
| --server http://localhost:8080 --realm master \ | |
| --user admin --password admin | |
| kubectl -n keycloak exec deploy/keycloak -- \ | |
| /opt/keycloak/bin/kcadm.sh create realms -s realm=${KC_REALM} -s enabled=true | |
| kubectl -n keycloak exec deploy/keycloak -- \ | |
| /opt/keycloak/bin/kcadm.sh update realms/${KC_REALM} -s accessTokenLifespan=3600 | |
| kubectl -n keycloak exec deploy/keycloak -- \ | |
| /opt/keycloak/bin/kcadm.sh create clients -r ${KC_REALM} \ | |
| -s clientId="${KC_CLIENT_ID}" -s enabled=true \ | |
| -s secret="${KC_CLIENT_SECRET}" \ | |
| -s 'redirectUris=["*"]' \ | |
| -s directAccessGrantsEnabled=true | |
| kubectl -n keycloak exec deploy/keycloak -- \ | |
| /opt/keycloak/bin/kcadm.sh create users -r ${KC_REALM} \ | |
| -s username=${KC_USER} -s enabled=true | |
| kubectl -n keycloak exec deploy/keycloak -- \ | |
| /opt/keycloak/bin/kcadm.sh set-password -r ${KC_REALM} \ | |
| --username ${KC_USER} --new-password ${KC_PASSWORD} | |
| - name: Configure Vertica Authentication | |
| run: | | |
| NS=my-verticadb-operator | |
| POD=verticadb-sample-defaultsubcluster-0 | |
| kubectl -n ${NS} exec ${POD} -c server -- bash -c " | |
| /opt/vertica/bin/vsql -U dbadmin -c \" | |
| CREATE AUTHENTICATION v_oauth METHOD 'oauth' HOST '0.0.0.0/0'; | |
| ALTER AUTHENTICATION v_oauth SET client_id = '${KC_CLIENT_ID}'; | |
| ALTER AUTHENTICATION v_oauth SET client_secret = '${KC_CLIENT_SECRET}'; | |
| ALTER AUTHENTICATION v_oauth SET discovery_url = 'http://keycloak.keycloak.svc.cluster.local:8080/realms/${KC_REALM}/.well-known/openid-configuration'; | |
| ALTER AUTHENTICATION v_oauth SET introspect_url = 'http://keycloak.keycloak.svc.cluster.local:8080/realms/${KC_REALM}/protocol/openid-connect/token/introspect'; | |
| CREATE USER ${KC_USER}; | |
| GRANT AUTHENTICATION v_oauth TO ${KC_USER}; | |
| GRANT ALL ON SCHEMA PUBLIC TO ${KC_USER}; | |
| CREATE AUTHENTICATION v_dbadmin_hash METHOD 'hash' HOST '0.0.0.0/0'; | |
| ALTER AUTHENTICATION v_dbadmin_hash PRIORITY 10000; | |
| GRANT AUTHENTICATION v_dbadmin_hash TO dbadmin; | |
| \" | |
| " | |
| # --------------------------- | |
| # Port forwarding for local tests | |
| # --------------------------- | |
| - name: Set up port forwarding | |
| run: | | |
| NS=my-verticadb-operator | |
| # Port-forward Vertica (5433) | |
| kubectl -n ${NS} port-forward svc/verticadb-sample-defaultsubcluster 5433:5433 & | |
| # Port-forward Keycloak (8080) | |
| kubectl -n keycloak port-forward svc/keycloak 8080:8080 & | |
| # Wait for port-forwards to be ready | |
| sleep 5 | |
| # Verify connectivity | |
| nc -zv localhost 5433 || echo "Warning: Vertica port-forward not ready" | |
| nc -zv localhost 8080 || echo "Warning: Keycloak port-forward not ready" | |
| # --------------------------- | |
| # Retrieve OAuth access token | |
| # --------------------------- | |
| - name: Retrieve OAuth access token | |
| run: | | |
| TOKEN="" | |
| for i in {1..10}; do | |
| echo "Attempt $i..." | |
| RAW=$(curl -s -X POST \ | |
| "http://localhost:8080/realms/${KC_REALM}/protocol/openid-connect/token" \ | |
| -d "client_id=${KC_CLIENT_ID}" \ | |
| -d "username=${KC_USER}" \ | |
| -d "password=${KC_PASSWORD}" \ | |
| -d "grant_type=password" \ | |
| -d "client_secret=${KC_CLIENT_SECRET}") || true | |
| if ! printf '%s' "$RAW" | python3 -c 'import sys,json; json.load(sys.stdin)' >/dev/null 2>&1; then | |
| echo "Token endpoint did not return valid JSON:" | |
| printf '%s\n' "$RAW" | |
| sleep 5 | |
| continue | |
| fi | |
| TOKEN=$(printf '%s' "$RAW" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("access_token", ""))') || true | |
| if [ -n "$TOKEN" ] && [ "$TOKEN" != "null" ] && [ "$TOKEN" != "" ]; then | |
| echo "Access token retrieved successfully (length: ${#TOKEN})" | |
| echo "$TOKEN" > access_token.txt | |
| break | |
| fi | |
| echo "Token fetch failed, Keycloak may not be ready yet." | |
| sleep 5 | |
| if [ "$i" -eq 10 ]; then | |
| echo "Failed to fetch access token after multiple retries." | |
| exit 1 | |
| fi | |
| done | |
| # --------------------------- | |
| # Test steps | |
| # --------------------------- | |
| - name: test-v-connection-string | |
| run: | | |
| cd packages/v-connection-string | |
| yarn test | |
| - name: test-v-pool | |
| run: | | |
| cd packages/v-pool | |
| yarn test | |
| - name: test-v-protocol | |
| run: | | |
| cd packages/v-protocol | |
| yarn test | |
| - name: test-vertica-nodejs | |
| run: | | |
| export VTEST_OAUTH_ACCESS_TOKEN=$(cat access_token.txt 2>/dev/null || echo "") | |
| cd packages/vertica-nodejs | |
| yarn test | |
| # --------------------------- | |
| # Cleanup | |
| # --------------------------- | |
| - name: Cleanup Kubernetes resources | |
| if: always() | |
| run: | | |
| echo "Starting cleanup..." | |
| echo "Deleting Keycloak..." | |
| kubectl delete deployment keycloak -n keycloak --ignore-not-found || true | |
| kubectl delete service keycloak -n keycloak --ignore-not-found || true | |
| kubectl delete ns keycloak --ignore-not-found || true | |
| echo "Deleting VerticaDB and Operator..." | |
| kubectl delete verticadb verticadb-sample -n my-verticadb-operator --ignore-not-found || true | |
| helm uninstall vdb-op -n my-verticadb-operator || true | |
| kubectl delete ns my-verticadb-operator --ignore-not-found || true | |
| echo "Deleting MinIO..." | |
| kubectl delete -f minio.yaml --ignore-not-found || true | |
| kubectl delete ns minio --ignore-not-found || true | |
| echo "Kubernetes resources cleanup done." | |
| - name: Delete KinD cluster | |
| if: always() | |
| run: | | |
| echo "Deleting KinD cluster..." | |
| kind delete cluster --name vertica-ci || true | |
| echo "KinD cluster removed successfully" |