Fixing hardoc issue #310
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: CI | |
| on: [push, pull_request] | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ['3.13'] | |
| env: | |
| REALM: test | |
| USER: oauth_user | |
| PASSWORD: password | |
| CLIENT_ID: vertica | |
| CLIENT_SECRET: P9f8350QQIUhFfK1GF5sMhq4Dm3P6Sbs | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - 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 repos | |
| run: | | |
| helm repo add vertica-charts https://vertica.github.io/charts || true | |
| helm repo add bitnami https://charts.bitnami.com/bitnami || true | |
| helm repo update | |
| - name: Install MinIO (namespace minio) | |
| run: | | |
| kubectl create ns minio || true | |
| 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:RELEASE.2025-09-07T16-13-09Z-cpuv1 | |
| 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 || true | |
| 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 || true | |
| 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 | |
| - 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 | |
| spec: | |
| image: opentext/vertica-k8s:latest | |
| dbName: vdb | |
| initPolicy: Create | |
| communal: | |
| path: s3://vertica-fleeting/mkottakota/ | |
| credentialSecret: communal-creds | |
| endpoint: http://minio.minio.svc.cluster.local:9000 | |
| region: us-east-1 | |
| local: | |
| dataPath: /data | |
| depotPath: /depot | |
| subclusters: | |
| - name: defaultsubcluster | |
| size: 3 | |
| EOF | |
| kubectl annotate verticadb verticadb-sample -n my-verticadb-operator \ | |
| vertica.com/ci-reconcile="$(date -u +%s)" --overwrite || true | |
| - name: Wait for Vertica readiness | |
| 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 || true | |
| - name: Deploy Keycloak | |
| run: | | |
| kubectl create ns keycloak || true | |
| 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=test -s enabled=true | |
| kubectl -n keycloak exec deploy/keycloak -- \ | |
| /opt/keycloak/bin/kcadm.sh create clients -r test \ | |
| -s clientId=vertica -s enabled=true \ | |
| -s secret=P9f8350QQIUhFfK1GF5sMhq4Dm3P6Sbs \ | |
| -s 'redirectUris=["*"]' \ | |
| -s directAccessGrantsEnabled=true | |
| kubectl -n keycloak exec deploy/keycloak -- \ | |
| /opt/keycloak/bin/kcadm.sh create users -r test \ | |
| -s username=oauth_user -s enabled=true | |
| kubectl -n keycloak exec deploy/keycloak -- \ | |
| /opt/keycloak/bin/kcadm.sh set-password -r test \ | |
| --username oauth_user --new-password 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 = 'vertica'; | |
| ALTER AUTHENTICATION v_oauth SET client_secret = 'P9f8350QQIUhFfK1GF5sMhq4Dm3P6Sbs'; | |
| ALTER AUTHENTICATION v_oauth SET discovery_url = 'http://keycloak.keycloak.svc.cluster.local:8080/realms/test/.well-known/openid-configuration'; | |
| ALTER AUTHENTICATION v_oauth SET introspect_url = 'http://keycloak.keycloak.svc.cluster.local:8080/realms/test/protocol/openid-connect/token/introspect'; | |
| CREATE USER oauth_user; | |
| GRANT AUTHENTICATION v_oauth TO oauth_user; | |
| GRANT ALL ON SCHEMA PUBLIC TO oauth_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; | |
| \" | |
| " | |
| - name: Fetch OAuth Access Token | |
| run: | | |
| set -euo pipefail | |
| NS=keycloak | |
| POD_NAME="curl-token-$$" | |
| IMAGE="curlimages/curl:latest" | |
| TOKEN_ENDPOINT="http://keycloak.keycloak.svc.cluster.local:8080/realms/${REALM}/protocol/openid-connect/token" | |
| WAIT_TIMEOUT=60 | |
| INTERVAL=2 | |
| kubectl -n ${NS} run ${POD_NAME} --restart=Never --image=${IMAGE} --command -- sleep 300 | |
| deadline=$((SECONDS + WAIT_TIMEOUT)) | |
| while [ $SECONDS -lt $deadline ]; do | |
| phase=$(kubectl -n ${NS} get pod ${POD_NAME} -o jsonpath='{.status.phase}' 2>/dev/null || echo "") | |
| if [ "$phase" = "Running" ]; then | |
| break | |
| fi | |
| if [ "$phase" = "Failed" ] || [ "$phase" = "Unknown" ]; then | |
| kubectl -n ${NS} describe pod ${POD_NAME} || true | |
| kubectl -n ${NS} logs ${POD_NAME} || true | |
| kubectl -n ${NS} delete pod ${POD_NAME} --ignore-not-found || true | |
| echo "Pod ${POD_NAME} entered non-running phase: $phase" | |
| exit 1 | |
| fi | |
| sleep ${INTERVAL} | |
| done | |
| if [ "$(kubectl -n ${NS} get pod ${POD_NAME} -o jsonpath='{.status.phase}')" != "Running" ]; then | |
| echo "Timed out waiting for curl pod to become Running" | |
| kubectl -n ${NS} describe pod ${POD_NAME} || true | |
| kubectl -n ${NS} logs ${POD_NAME} || true | |
| kubectl -n ${NS} delete pod ${POD_NAME} --ignore-not-found || true | |
| exit 1 | |
| fi | |
| kubectl -n ${NS} exec ${POD_NAME} -- sh -c " | |
| curl -s -w '\n%{http_code}' -X POST '${TOKEN_ENDPOINT}' \ | |
| -d 'client_id=${CLIENT_ID}' \ | |
| -d 'username=${USER}' \ | |
| -d 'password=${PASSWORD}' \ | |
| -d 'grant_type=password' \ | |
| -d 'client_secret=${CLIENT_SECRET}' > /tmp/token_resp.txt | |
| " | |
| RAW_JSON=$(kubectl -n ${NS} exec ${POD_NAME} -- cat /tmp/token_resp.txt || true) | |
| kubectl -n ${NS} delete pod ${POD_NAME} --ignore-not-found | |
| HTTP_CODE=$(printf "%s" "$RAW_JSON" | tail -n1) | |
| BODY=$(printf "%s" "$RAW_JSON" | sed '$d') | |
| echo "Token endpoint HTTP status: $HTTP_CODE" | |
| if [ -z "$HTTP_CODE" ] || [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then | |
| echo "Failed to get token; response (truncated):" | |
| printf "%.1024s\n" "$BODY" | |
| exit 1 | |
| fi | |
| TOKEN=$(printf "%s" "$BODY" | python3 -c 'import json,sys;obj=json.load(sys.stdin);print(obj.get("access_token",""))' || true) | |
| if [ -z "$TOKEN" ]; then | |
| echo "No access_token found in response; full body:" | |
| echo "$BODY" | |
| exit 1 | |
| fi | |
| printf "%s" "$TOKEN" > access_token.txt | |
| echo "Access token saved to access_token.txt" | |
| - name: Create and populate python test pod (robust) | |
| run: | | |
| set -euo pipefail | |
| NS=my-verticadb-operator | |
| POD=py-test-runner | |
| IMAGE=python:3.11-slim | |
| WAIT_TIMEOUT=180 | |
| INTERVAL=3 | |
| kubectl create ns ${NS} --dry-run=client -o yaml | kubectl apply -f - 2>/dev/null || true | |
| kubectl -n ${NS} delete pod ${POD} --ignore-not-found || true | |
| kubectl -n ${NS} run ${POD} --image=${IMAGE} --restart=Never --command -- sleep infinity | |
| deadline=$((SECONDS + WAIT_TIMEOUT)) | |
| while [ $SECONDS -lt $deadline ]; do | |
| pod_phase=$(kubectl -n ${NS} get pod ${POD} -o jsonpath='{.status.phase}' 2>/dev/null || echo "") | |
| if [ "$pod_phase" = "Running" ]; then | |
| echo "Pod ${POD} is Running" | |
| break | |
| fi | |
| if [ -n "$pod_phase" ] && { [ "$pod_phase" = "Failed" ] || [ "$pod_phase" = "Unknown" ]; }; then | |
| echo "Pod entered non-running phase: $pod_phase" | |
| kubectl -n ${NS} describe pod ${POD} || true | |
| kubectl -n ${NS} get events --sort-by=.metadata.creationTimestamp -n ${NS} || true | |
| kubectl -n ${NS} logs ${POD} || true | |
| kubectl -n ${NS} delete pod ${POD} --ignore-not-found || true | |
| exit 1 | |
| fi | |
| sleep ${INTERVAL} | |
| done | |
| if [ "$(kubectl -n ${NS} get pod ${POD} -o jsonpath='{.status.phase}' 2>/dev/null || echo "")" != "Running" ]; then | |
| echo "Timed out waiting for pod ${POD} to become Running" | |
| kubectl -n ${NS} describe pod ${POD} || true | |
| kubectl -n ${NS} get events --sort-by=.metadata.creationTimestamp -n ${NS} || true | |
| kubectl -n ${NS} logs ${POD} || true | |
| kubectl -n ${NS} delete pod ${POD} --ignore-not-found || true | |
| exit 1 | |
| fi | |
| kubectl -n ${NS} exec -i pod/${POD} -- mkdir -p /workspace | |
| tar cf - . | kubectl -n ${NS} exec -i pod/${POD} -- tar xf - -C /workspace | |
| if kubectl -n ${NS} cp access_token.txt pod/${POD}:/workspace/access_token.txt 2>/dev/null; then | |
| echo "Token copied into pod via kubectl cp" | |
| else | |
| echo "kubectl cp failed; falling back to pipe into pod" | |
| TOKEN_CONTENT=$(cat access_token.txt) | |
| printf '%s' "$TOKEN_CONTENT" | kubectl -n ${NS} exec -i pod/${POD} -- tee /workspace/access_token.txt >/dev/null | |
| echo "Token written into pod via fallback" | |
| fi | |
| - name: Run tests inside python pod | |
| run: | | |
| NS=my-verticadb-operator | |
| POD=py-test-runner | |
| kubectl -n ${NS} exec -i pod/${POD} -- bash -lc " | |
| set -euo pipefail | |
| cd /workspace | |
| python -m pip install --upgrade pip >/dev/null 2>&1 || true | |
| pip install tox pytest >/dev/null 2>&1 || true | |
| export VP_TEST_OAUTH_ACCESS_TOKEN=\$(cat access_token.txt) | |
| tox -e py | |
| " | |
| - name: Cleanup python test pod | |
| if: always() | |
| run: | | |
| kubectl -n my-verticadb-operator delete pod py-test-runner --ignore-not-found || true | |
| - name: Uninstall MinIO | |
| if: always() | |
| run: | | |
| kubectl delete pod minio -n minio --ignore-not-found || true | |
| kubectl delete svc minio -n minio --ignore-not-found || true | |
| kubectl delete ns minio || true | |
| echo "MinIO cleanup complete" |