#!/usr/bin/env bash # verify-t03.sh — verify NK-WP-0001-T03 done-criteria # # Checks: # 1. CloudNativePG operator is installed and running # 2. Cluster net-kingdom-pg is Ready # 3. privacyidea_db database exists # 4. privacyidea role exists # 5. K8s Secrets are present in the databases namespace # 6. (Optional) Scheduled backup CR is present when backup is configured # # Note: keycloak_db removed — Keycloak replaced by Authelia+LLDAP+KeyCape (T05). # # Usage: # chmod +x verify-t03.sh # ./verify-t03.sh set -euo pipefail PASS=0 FAIL=0 WARN=0 pass() { echo " [PASS] $1"; PASS=$((PASS + 1)); } fail() { echo " [FAIL] $1"; FAIL=$((FAIL + 1)); } warn() { echo " [WARN] $1"; WARN=$((WARN + 1)); } section() { echo ""; echo "── $1 ──────────────────────────────────────"; } # ── 1. CloudNativePG operator ───────────────────────────────────────────────── section "1. CloudNativePG operator" if kubectl get ns cnpg-system &>/dev/null; then pass "cnpg-system namespace exists" else fail "cnpg-system namespace not found — install operator first (see postgresql/README.md)" fi if kubectl get crd clusters.postgresql.cnpg.io &>/dev/null; then pass "clusters.postgresql.cnpg.io CRD registered" else fail "CloudNativePG CRD not found — operator not installed" fi CNPG_READY=$(kubectl get pods -n cnpg-system -l app.kubernetes.io/name=cloudnative-pg \ --field-selector=status.phase=Running --no-headers 2>/dev/null | wc -l || echo 0) if [[ "$CNPG_READY" -ge 1 ]]; then pass "CloudNativePG operator pod running ($CNPG_READY pod(s))" else fail "No running CloudNativePG operator pods in cnpg-system" fi # ── 2. Cluster readiness ────────────────────────────────────────────────────── section "2. Cluster net-kingdom-pg" CLUSTER_READY=$(kubectl get cluster net-kingdom-pg -n databases \ -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null || echo "") if [[ "$CLUSTER_READY" == "True" ]]; then pass "Cluster net-kingdom-pg status: Ready" else CLUSTER_PHASE=$(kubectl get cluster net-kingdom-pg -n databases \ -o jsonpath='{.status.phase}' 2>/dev/null || echo "not found") fail "Cluster net-kingdom-pg not Ready (phase: $CLUSTER_PHASE)" fi PRIMARY_POD=$(kubectl get pod -n databases \ -l "cnpg.io/cluster=net-kingdom-pg,role=primary" \ --field-selector=status.phase=Running \ -o name 2>/dev/null | head -1 || echo "") if [[ -n "$PRIMARY_POD" ]]; then pass "Primary pod running: $PRIMARY_POD" else fail "No running primary pod found for net-kingdom-pg" fi # ── 3. Databases ────────────────────────────────────────────────────────────── section "3. Databases" if [[ -n "$PRIMARY_POD" ]]; then DB_LIST=$(kubectl exec -n databases "$PRIMARY_POD" -- \ psql -U postgres -tAc "SELECT datname FROM pg_database WHERE datname = 'privacyidea_db';" \ 2>/dev/null || echo "") if echo "$DB_LIST" | grep -q "privacyidea_db"; then pass "privacyidea_db exists" else fail "privacyidea_db not found" fi else warn "Skipping database checks — no primary pod available" fi # ── 4. Roles ────────────────────────────────────────────────────────────────── section "4. Database roles" if [[ -n "$PRIMARY_POD" ]]; then ROLE_LIST=$(kubectl exec -n databases "$PRIMARY_POD" -- \ psql -U postgres -tAc "SELECT rolname FROM pg_roles WHERE rolname = 'privacyidea';" \ 2>/dev/null || echo "") if echo "$ROLE_LIST" | grep -q "privacyidea"; then pass "role privacyidea exists" else fail "role privacyidea not found" fi else warn "Skipping role checks — no primary pod available" fi # ── 5. K8s Secrets ──────────────────────────────────────────────────────────── section "5. K8s Secrets (databases namespace)" for secret in net-kingdom-pg-privacyidea-app; do if kubectl get secret "$secret" -n databases &>/dev/null; then pass "Secret $secret exists" else fail "Secret $secret not found — run create-secrets.sh" fi done # CNPG auto-creates these for secret in net-kingdom-pg-superuser; do if kubectl get secret "$secret" -n databases &>/dev/null; then pass "Secret $secret exists (CNPG-managed)" else warn "Secret $secret not found (CNPG creates this; may appear after cluster init)" fi done # ── 6. Backup configuration ─────────────────────────────────────────────────── section "6. Backup (optional until object storage is provisioned)" if kubectl get scheduledbackup net-kingdom-pg-daily -n databases &>/dev/null; then BACKUP_SUSPENDED=$(kubectl get scheduledbackup net-kingdom-pg-daily -n databases \ -o jsonpath='{.spec.suspend}' 2>/dev/null || echo "false") if [[ "$BACKUP_SUSPENDED" == "true" ]]; then warn "ScheduledBackup net-kingdom-pg-daily is suspended" else pass "ScheduledBackup net-kingdom-pg-daily present and active" fi LAST_BACKUP=$(kubectl get backup -n databases \ -l "cnpg.io/cluster=net-kingdom-pg" \ --sort-by='.metadata.creationTimestamp' \ -o name 2>/dev/null | tail -1 || echo "") if [[ -n "$LAST_BACKUP" ]]; then pass "At least one backup found: $LAST_BACKUP" else warn "No backups yet — trigger a manual backup or wait for schedule" fi else warn "ScheduledBackup not deployed — configure object storage, then apply scheduled-backup.yaml" fi # ── Summary ─────────────────────────────────────────────────────────────────── echo "" echo "════════════════════════════════════════════════" echo " T03 verification: PASS=$PASS WARN=$WARN FAIL=$FAIL" echo "════════════════════════════════════════════════" if [[ "$FAIL" -gt 0 ]]; then echo " Result: INCOMPLETE — resolve FAIL items before proceeding to T04" exit 1 elif [[ "$WARN" -gt 0 ]]; then echo " Result: PARTIAL — T03 core done; WARN items should be addressed before production" exit 0 else echo " Result: COMPLETE — T03 done-criteria met" exit 0 fi