prole/mock_val/init_kerberos_test.sh
chrisfu 5618b662dd Remove prole-db-manager; simplify deployment via prole-authority; fix pg18 downgrade & cluster name
Summary:
Removed the prole-db-manager microservice and simplified deployment to use
prole-authority as the internal management and authorization point. Fixed two
blocking bugs that prevented silent install from completing on knoe-dev-cluster.

Removed: prole-db-manager
- Deleted db-manager-deployment.yaml and db-manager-service.yaml from opentofu manifests
- Deleted src/db-manager/ (Dockerfile, server.js, package.json, tests)
- Removed prole-db-manager port-forward mapping from installer/core/env.py
- Removed init_db_manager.sh from Initialization Scripts (milestones.py, actions.py)
- Removed init_certmgr.sh and init_db_manager.sh tabs from services screen (services.py)
- Removed live k8s Deployment/Service from knoe-dev-cluster

Fixed: PostgreSQL version downgrade error (pg17 -> pg18)
- Created conf/postgresql/.version with value 18
- Updated k8s/prole/prole-db.yaml and prole-db-recovery.yaml.tpl imageName to prole-db:18-089
- Fixed _init_database_options_state() to restore saved version_type from prole.cfg
  so db_version_type defaults to v18 (pg18) instead of silently reverting to pg17
- Added database_options.* keys to _collect_input_snapshot() in cfg.py so
  distribution, version_type, and all extension toggles persist to prole.cfg

Fixed: Cluster name inconsistency
- Removed stale prole-dev-cluster references; all scripts now use knoe-dev-cluster
- Added knoe-dev-cluster to mode-detection case in etc/prole_cfg.sh

Config: conf/prole.cfg
- Set kerberos_config.enabled = False, KERBEROS_AUTO_ENABLED = False
- Added database_options.distribution = percona, version_type = v18
- Added all 13 extension flags set to True (postgis, pgvector, pgcrypto, pgaudit,
  pg_repack, pg_stat_statements, pg_buffercache, pg_freespacemap, pgrowlocks,
  postgres_fdw, dblink, pg_stat_monitor, pgbadger)

Verification:
./install.py -s -l -v -c conf/prole.cfg completed successfully.
CNPG deployed prole-db:18-089 to knoe-dev-cluster; all milestones passed.

Co-authored-by: Junie <junie@jetbrains.com>
2026-03-01 20:40:44 -08:00

572 lines
18 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# init_kerberos_test.sh
# Purpose:
# - Run Kerberos authentication checks inside the in-cluster KDC pod
# Initialize SCRIPT_DIR
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
ORIG_ARGS=("$@")
# Load env
if [[ -n "${PROLE_HOME:-}" && -f "$PROLE_HOME/env.sh" ]]; then
set --
# shellcheck disable=SC1090
source "$PROLE_HOME/env.sh"
set -- "${ORIG_ARGS[@]}"
elif [[ -f "$HOME/.prole/env.sh" ]]; then
set --
# shellcheck disable=SC1090
source "$HOME/.prole/env.sh"
set -- "${ORIG_ARGS[@]}"
fi
# Load config values from prole.cfg before applying defaults/CLI overrides.
# shellcheck disable=SC1090
source "$SCRIPT_DIR/prole_cfg.sh"
if [[ "${1:-}" == "--mode" || "${1:-}" == "-m" ]]; then
prole_set_mode "${2:-}"
shift 2
elif [[ "${1:-}" == --mode=* || "${1:-}" == -m=* ]]; then
prole_set_mode "${1#*=}"
shift
fi
ACTION=${1:-test}
NAMESPACE=${NAMESPACE:-default}
SERVICE_NAMESPACE=${SERVICE_NAMESPACE:-${NAMESPACE}}
KRB5_REALM=${KRB5_REALM:-${REALM:-}}
KRB5_KDC=${KRB5_KDC:-}
KRB5_USER=${KRB5_USER:-${KRB5_USERNAME:-}}
KRB5_PASSWORD=${KRB5_PASSWORD:-}
PROLE_KDC_NAME=${PROLE_KDC_NAME:-auth}
PROLE_KDC_SERVICE=${PROLE_KDC_SERVICE:-auth}
SAMBA_ADMIN_USER=${SAMBA_ADMIN_USER:-}
SAMBA_ADMIN_PASSWORD=${SAMBA_ADMIN_PASSWORD:-}
SAMBA_DNS_SERVER=${SAMBA_DNS_SERVER:-}
KDC_POD_READY_TIMEOUT=${KDC_POD_READY_TIMEOUT:-60}
KDC_POD_READY_RETRIES=${KDC_POD_READY_RETRIES:-5}
PROLE_KDC_PRECHECK_TIMEOUT=${PROLE_KDC_PRECHECK_TIMEOUT:-5}
ensure_tools() {
for t in kubectl curl jq; do
command -v "$t" >/dev/null || { echo "Missing required tool: $t" >&2; exit 1; }
done
}
ensure_namespace() {
if ! kubectl get namespace "$NAMESPACE" >/dev/null 2>&1; then
echo "Creating namespace '$NAMESPACE' ..."
kubectl create namespace "$NAMESPACE" >/dev/null 2>&1 || true
fi
}
write_krb5_conf_to_pod() {
local kdc_ns="$1"
local pod_name="$2"
if [[ -z "$kdc_ns" || -z "$pod_name" ]]; then
return 0
fi
if [[ -z "$KRB5_REALM" || -z "$KRB5_KDC" ]]; then
return 0
fi
local admin_val domain_val tmp
admin_val="${KRB5_ADMIN:-$KRB5_KDC}"
domain_val=$(printf '%s' "$KRB5_REALM" | tr '[:upper:]' '[:lower:]')
tmp=$(mktemp)
cat >"$tmp" <<EOF
[libdefaults]
default_realm = $KRB5_REALM
dns_lookup_realm = false
dns_lookup_kdc = false
udp_preference_limit = 1
[realms]
$KRB5_REALM = {
kdc = $KRB5_KDC
admin_server = $admin_val
}
[domain_realm]
.$domain_val = $KRB5_REALM
$domain_val = $KRB5_REALM
EOF
echo "Updating /etc/krb5.conf in test pod ${pod_name} for realm ${KRB5_REALM} ..."
if ! kubectl -n "$kdc_ns" exec -i "$pod_name" -- sh -c 'cat > /etc/krb5.conf' <"$tmp"; then
echo "WARN: Unable to write /etc/krb5.conf in ${pod_name}." >&2
fi
rm -f "$tmp"
}
get_ready_kdc_pod() {
local kdc_ns="$1"
kubectl -n "$kdc_ns" wait --for=condition=Ready pod -l "app=${PROLE_KDC_NAME}" --timeout="${KDC_POD_READY_TIMEOUT}s" >/dev/null 2>&1 || true
kubectl -n "$kdc_ns" get pod -l "app=${PROLE_KDC_NAME}" --field-selector=status.phase=Running -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true
}
wait_for_kdc_pod() {
local kdc_ns="$1"
local attempt pod
attempt=1
while [[ $attempt -le $KDC_POD_READY_RETRIES ]]; do
pod=$(get_ready_kdc_pod "$kdc_ns")
if [[ -n "$pod" ]]; then
printf '%s' "$pod"
return 0
fi
echo "Waiting for KDC pod '${PROLE_KDC_NAME}' to be ready... (${attempt}/${KDC_POD_READY_RETRIES})" >&2
sleep 2
attempt=$((attempt + 1))
done
return 1
}
# Return 0 if pod is in CrashLoopBackOff (any container), else 1
is_pod_crashloop() {
local kdc_ns="$1"
local pod_name="$2"
if [[ -z "$pod_name" ]]; then
return 1
fi
local reason
reason=$(kubectl -n "$kdc_ns" get pod "$pod_name" -o jsonpath='{range .status.containerStatuses[*]}{.state.waiting.reason}{"\n"}{end}' 2>/dev/null | tr -d '\r' | tr -s '\n' ' ' || true)
if echo "${reason}" | grep -q "CrashLoopBackOff"; then
return 0
fi
return 1
}
debug_kdc_pod() {
local kdc_ns="$1"
local pod_name="$2"
if [[ -z "$pod_name" ]]; then
return 0
fi
echo "--- describe pod ${pod_name} ---" >&2
kubectl -n "$kdc_ns" describe pod "$pod_name" 1>&2 || true
echo "--- last 200 log lines from ${pod_name} ---" >&2
kubectl -n "$kdc_ns" logs "$pod_name" --tail=200 1>&2 || true
}
kdc_exec() {
local kdc_ns="$1"
local pod_name="$2"
shift 2
local output=""
if output=$(kubectl -n "$kdc_ns" exec "$pod_name" -- "$@" 2>&1); then
printf '%s' "$output"
return 0
fi
if echo "$output" | grep -qi "completed pod"; then
return 2
fi
if echo "$output" | grep -qi "not found"; then
return 2
fi
echo "$output" >&2
return 1
}
run_samba_join() {
local kdc_ns="$1"
local pod_name="$2"
local domain="$3"
local output=""
if output=$(kubectl -n "$kdc_ns" exec "$pod_name" -- \
env SAMBA_ADMIN_USER="$SAMBA_ADMIN_USER" SAMBA_ADMIN_PASSWORD="$SAMBA_ADMIN_PASSWORD" \
SAMBA_DNS_SERVER="$SAMBA_DNS_SERVER" SAMBA_REALM="${KRB5_REALM:-}" \
/bin/sh -c 'realm_flag=""; [ -n "${SAMBA_REALM}" ] && realm_flag="--realm=${SAMBA_REALM}"; samba-tool domain join "'"$domain"'" MEMBER -U"${SAMBA_ADMIN_USER}%${SAMBA_ADMIN_PASSWORD}" --server="${SAMBA_DNS_SERVER}" ${realm_flag}' 2>&1); then
printf '%s' "$output"
return 0
fi
if echo "$output" | grep -qi "completed pod"; then
return 2
fi
if echo "$output" | grep -qi "not found"; then
return 2
fi
if [[ -n "$output" ]]; then
echo "$output" >&2
else
echo "samba-tool produced no output." >&2
fi
return 1
}
run_kinit() {
local kdc_ns="$1"
local pod_name="$2"
local output=""
# Prefer /etc/krb5.conf if it exists, otherwise fallback to /opt/prole-kdc/krb5.conf
local krb5_config="/etc/krb5.conf"
if ! kubectl -n "$kdc_ns" exec "$pod_name" -- ls /etc/krb5.conf >/dev/null 2>&1; then
krb5_config="/opt/prole-kdc/krb5.conf"
fi
echo "Running kinit for ${KRB5_USER}@${KRB5_REALM} inside ${PROLE_KDC_NAME} (${pod_name}) using ${krb5_config} ..."
if output=$(printf '%s\n' "$KRB5_PASSWORD" | kubectl -n "$kdc_ns" exec -i "$pod_name" -- \
env KRB5_CONFIG="$krb5_config" kinit "${KRB5_USER}@${KRB5_REALM}" 2>&1); then
printf '%s' "$output"
return 0
fi
if echo "$output" | grep -qi "completed pod"; then
return 2
fi
if echo "$output" | grep -qi "not found"; then
return 2
fi
if [[ -n "$output" ]]; then
echo "$output" >&2
else
echo "kinit produced no output." >&2
fi
return 1
}
check_samba_connectivity() {
local kdc_ns="$1"
local pod_name="$2"
if [[ -z "$SAMBA_DNS_SERVER" ]]; then
return 0
fi
echo "Checking connectivity from ${PROLE_KDC_NAME} to ${SAMBA_DNS_SERVER} ..."
local ports="88 389 445 464"
local port
for port in $ports; do
local out=""
out=$(kubectl -n "$kdc_ns" exec "$pod_name" -- /bin/sh -c "timeout 3 bash -c '</dev/tcp/${SAMBA_DNS_SERVER}/${port}'" 2>&1) || true
if [[ -z "$out" ]]; then
echo "OK: ${SAMBA_DNS_SERVER}:${port}"
else
echo "WARN: ${SAMBA_DNS_SERVER}:${port} unreachable: ${out}"
fi
done
}
check_kdc_direct_connectivity() {
local kdc_ns="$1"
local pod_name="$2"
local kdc_ip="${AD_DC_IP:-${KDC_ANSIBLE_DETECTED:-${KDC_AUTO_DETECTED:-}}}"
if [[ -z "$kdc_ip" ]]; then
return 0
fi
echo "Checking connectivity from ${PROLE_KDC_NAME} to KDC IP ${kdc_ip} ..."
local ports="88 389 445 464"
local port
for port in $ports; do
local out=""
out=$(kubectl -n "$kdc_ns" exec "$pod_name" -- /bin/sh -c "timeout 3 bash -c '</dev/tcp/${kdc_ip}/${port}'" 2>&1) || true
if [[ -z "$out" ]]; then
echo "OK: ${kdc_ip}:${port}"
else
echo "WARN: ${kdc_ip}:${port} unreachable: ${out}"
fi
done
}
openbao_url() {
if [[ -n "${PROLE_OPENBAO_URL:-}" ]]; then
echo "$PROLE_OPENBAO_URL"
return 0
fi
if prole_is_in_cluster; then
echo "http://openbao.${SERVICE_NAMESPACE:-${NAMESPACE:-default}}.svc.cluster.local:8200"
return 0
fi
if curl -sS "http://127.0.0.1:8200/v1/sys/health" >/dev/null 2>&1; then
echo "http://127.0.0.1:8200"
return 0
elif curl -sS "http://127.0.0.1:8200/v1/sys/health" >/dev/null 2>&1; then
echo "http://127.0.0.1:8200"
return 0
else
echo ""
return 0
fi
}
openbao_token() {
if [[ -f "$PROLE_SERVICE/secrets/openbao-root-token" ]]; then
cat "$PROLE_SERVICE/secrets/openbao-root-token"
else
echo "${OPENBAO_ROOT_TOKEN:-}"
fi
}
fetch_openbao_secret() {
local path="$1"
local key="$2"
local token url
token=$(openbao_token)
url=$(openbao_url)
if [[ -z "$token" || -z "$url" ]]; then
echo ""
return 0
fi
curl -sS -H "X-Vault-Token: $token" "$url/v1/kv/data/$path" | jq -r ".data.data.\"$key\"" || echo ""
}
resolve_krb5_password() {
if [[ -z "${KRB5_PASSWORD}" || "${KRB5_PASSWORD}" == '${OPENBAO:'* || "${KRB5_PASSWORD}" == '${PROLE_SECRET:'* ]]; then
local path="prole/${NAMESPACE:-default}/kerberos"
local fetched
fetched=$(fetch_openbao_secret "$path" "password")
if [[ -n "$fetched" && "$fetched" != "null" ]]; then
KRB5_PASSWORD="$fetched"
fi
fi
}
resolve_samba_vars() {
if [[ -n "${SAMBA_ADMIN_USER}" && -n "${SAMBA_ADMIN_PASSWORD}" && -n "${SAMBA_DNS_SERVER}" ]]; then
return 0
fi
# 1. Fallback for DNS server from prole.cfg env (AD_DC_HOST)
if [[ -z "$SAMBA_DNS_SERVER" && -n "${AD_DC_HOST:-}" ]]; then
SAMBA_DNS_SERVER="$AD_DC_HOST"
echo "Using SAMBA_DNS_SERVER=${SAMBA_DNS_SERVER} from AD_DC_HOST"
fi
# 2. Try to resolve from Ansible inventory if possible
local root
if [[ -n "${PROLE_HOME:-}" && -d "${PROLE_HOME}" ]]; then
root="${PROLE_HOME}"
else
root="${SCRIPT_DIR}/.."
fi
local vars_file="${root}/infrastructure/inventory/group_vars/ad_dc/vars.yml"
if [[ -f "$vars_file" ]]; then
if [[ -z "$SAMBA_DNS_SERVER" ]]; then
SAMBA_DNS_SERVER=$(awk -F: '/^[[:space:]]*samba_dns_server[[:space:]]*:/ {sub(/^[^:]+:[[:space:]]*/, "", $0); gsub(/"/, "", $0); print $0; exit}' "$vars_file")
fi
if [[ -z "$SAMBA_ADMIN_USER" ]]; then
SAMBA_ADMIN_USER=$(awk -F: '/^[[:space:]]*samba_dns_admin_user[[:space:]]*:/ {sub(/^[^:]+:[[:space:]]*/, "", $0); gsub(/"/, "", $0); print $0; exit}' "$vars_file")
fi
fi
# 3. Fallback for Admin User
if [[ -z "$SAMBA_ADMIN_USER" ]]; then
if [[ -n "${AD_DC_USER:-}" ]]; then
SAMBA_ADMIN_USER="$AD_DC_USER"
echo "Using SAMBA_ADMIN_USER=${SAMBA_ADMIN_USER} from AD_DC_USER"
else
SAMBA_ADMIN_USER="administrator"
echo "Defaulting SAMBA_ADMIN_USER to administrator"
fi
fi
# 4. Try to resolve password from Ansible Vault
if [[ -z "$SAMBA_ADMIN_PASSWORD" ]]; then
local vault_file="${root}/infrastructure/inventory/group_vars/ad_dc/vault.yml"
local vault_pass_file=""
if [[ -n "${ANSIBLE_VAULT_PASSWORD_FILE:-}" && -f "${ANSIBLE_VAULT_PASSWORD_FILE}" ]]; then
vault_pass_file="${ANSIBLE_VAULT_PASSWORD_FILE}"
elif [[ -n "${PROLE_HOME:-}" && -f "${PROLE_HOME}/.vault_pass" ]]; then
vault_pass_file="${PROLE_HOME}/.vault_pass"
elif [[ -f "${root}/.vault_pass" ]]; then
vault_pass_file="${root}/.vault_pass"
fi
if [[ -f "$vault_file" && -n "$vault_pass_file" && -x "$(command -v ansible-vault)" ]]; then
local vault_out
vault_out=$(ansible-vault view "$vault_file" --vault-password-file "$vault_pass_file" 2>/dev/null || true)
if [[ -n "$vault_out" ]]; then
SAMBA_ADMIN_PASSWORD=$(printf '%s\n' "$vault_out" | awk -F: '/^[[:space:]]*vault_samba_dns_admin_pass[[:space:]]*:/ {sub(/^[^:]+:[[:space:]]*/, "", $0); gsub(/"/, "", $0); print $0; exit}')
fi
fi
fi
# 5. Fallback for Password from OpenBao
if [[ -z "$SAMBA_ADMIN_PASSWORD" ]]; then
local path="prole/${NAMESPACE:-default}/ad_dc"
local fetched
fetched=$(fetch_openbao_secret "$path" "password")
if [[ -n "$fetched" && "$fetched" != "null" ]]; then
SAMBA_ADMIN_PASSWORD="$fetched"
echo "Fetched SAMBA_ADMIN_PASSWORD from OpenBao (${path})"
else
# Try kerberos path as fallback
path="prole/${NAMESPACE:-default}/kerberos"
fetched=$(fetch_openbao_secret "$path" "samba_password")
if [[ -n "$fetched" && "$fetched" != "null" ]]; then
SAMBA_ADMIN_PASSWORD="$fetched"
echo "Fetched SAMBA_ADMIN_PASSWORD from OpenBao (${path}#samba_password)"
fi
fi
fi
}
join_samba_realm_if_needed() {
local kdc_ns="$1"
local pod_name="$2"
local domain=""
resolve_samba_vars
if [[ -z "$SAMBA_ADMIN_USER" || -z "$SAMBA_ADMIN_PASSWORD" || -z "$SAMBA_DNS_SERVER" ]]; then
echo "WARN: Missing Samba join info; skipping samba-tool realm join."
return 0
fi
check_samba_connectivity "$kdc_ns" "$pod_name"
if [[ -n "$KRB5_REALM" ]]; then
domain=$(printf '%s' "$KRB5_REALM" | tr '[:upper:]' '[:lower:]')
fi
if [[ -z "$domain" ]]; then
domain="$SAMBA_DNS_SERVER"
fi
if kubectl -n "$kdc_ns" exec "$pod_name" -- test -f /var/lib/samba/private/secrets.tdb >/dev/null 2>&1; then
echo "Samba already joined; skipping join."
return 0
fi
echo "Joining Samba realm '${domain}' (server ${SAMBA_DNS_SERVER}) ..."
local attempt=1
while true; do
if run_samba_join "$kdc_ns" "$pod_name" "$domain"; then
return 0
fi
if [[ $? -eq 2 ]]; then
if [[ $attempt -ge $KDC_POD_READY_RETRIES ]]; then
echo "WARN: KDC pod completed before join could run; skipping samba-tool join." >&2
return 0
fi
pod_name=$(wait_for_kdc_pod "$kdc_ns" || true)
if [[ -z "$pod_name" ]]; then
echo "WARN: KDC pod unavailable for samba-tool join." >&2
return 0
fi
attempt=$((attempt + 1))
continue
fi
echo "WARN: samba-tool domain join failed; continuing to Kerberos test." >&2
return 0
done
}
run_test() {
ensure_tools
ensure_namespace
resolve_krb5_password
# Support both names for the toggle from prole.cfg
local enabled="${KERBEROS_ENABLED:-${ENABLED:-false}}"
if [[ "$enabled" == "false" || "$enabled" == "0" || "$enabled" == "False" ]]; then
echo "Kerberos is disabled (KERBEROS_ENABLED=$enabled). Skipping test."
return 0
fi
if [[ -z "$KRB5_REALM" || -z "$KRB5_USER" || -z "$KRB5_PASSWORD" || -z "$KRB5_KDC" ]]; then
echo "ERROR: Missing Kerberos configuration. Ensure KRB5_REALM, KRB5_KDC, KRB5_USER, KRB5_PASSWORD are set." >&2
exit 1
fi
# Quick pre-check: if an existing 'auth' deployment is present but not Available, remove it
# to avoid starting a rollout that is likely to time out on a stale/broken replica set.
local kdc_ns
kdc_ns="${SERVICE_NAMESPACE:-${NAMESPACE:-default}}"
if kubectl -n "$kdc_ns" get deploy "$PROLE_KDC_NAME" >/dev/null 2>&1; then
# Try a fast availability wait; if it fails, treat as unhealthy and clean up before proceeding.
if ! kubectl -n "$kdc_ns" wait --for=condition=Available deploy/"$PROLE_KDC_NAME" --timeout="${PROLE_KDC_PRECHECK_TIMEOUT}s" >/dev/null 2>&1; then
echo "Detected unhealthy '$PROLE_KDC_NAME' deployment in namespace '$kdc_ns'; removing before Kerberos test rollout to avoid timeout..." >&2
if [[ -x "$SCRIPT_DIR/init_kdc.sh" ]]; then
SERVICE_NAMESPACE="$SERVICE_NAMESPACE" "$SCRIPT_DIR/init_kdc.sh" cleanup || true
else
kubectl -n "$kdc_ns" delete deploy "$PROLE_KDC_NAME" --ignore-not-found || true
kubectl -n "$kdc_ns" delete svc "$PROLE_KDC_SERVICE" --ignore-not-found || true
kubectl -n "$kdc_ns" delete configmap prole-kdc-config --ignore-not-found || true
fi
fi
fi
if [[ -x "$SCRIPT_DIR/init_kdc.sh" ]]; then
SERVICE_NAMESPACE="$SERVICE_NAMESPACE" KRB5_REALM="$KRB5_REALM" KRB5_KDC="$KRB5_KDC" \
KRB5_ADMIN="$KRB5_KDC" KRB5_USER="$KRB5_USER" KRB5_PASSWORD="$KRB5_PASSWORD" \
"$SCRIPT_DIR/init_kdc.sh" update || true
fi
local pod_name
pod_name=$(wait_for_kdc_pod "$kdc_ns" || true)
if [[ -z "$pod_name" ]]; then
echo "ERROR: KDC pod '${PROLE_KDC_NAME}' not found in namespace '$kdc_ns'. Run init_kdc.sh update first." >&2
exit 1
fi
# If the pod is crashlooping, dump logs and fail fast
if is_pod_crashloop "$kdc_ns" "$pod_name"; then
echo "ERROR: KDC pod '${pod_name}' is in CrashLoopBackOff. Dumping diagnostics..." >&2
debug_kdc_pod "$kdc_ns" "$pod_name"
exit 1
fi
write_krb5_conf_to_pod "$kdc_ns" "$pod_name"
check_kdc_direct_connectivity "$kdc_ns" "$pod_name"
join_samba_realm_if_needed "$kdc_ns" "$pod_name"
echo "Running kinit for ${KRB5_USER}@${KRB5_REALM} inside ${PROLE_KDC_NAME} (${pod_name}) ..."
local attempt=1
while true; do
if run_kinit "$kdc_ns" "$pod_name"; then
break
fi
if [[ $? -eq 2 ]] || kubectl -n "$kdc_ns" get pod "$pod_name" -o jsonpath='{.status.phase}' 2>/dev/null | grep -qi "Succeeded"; then
if [[ $attempt -ge $KDC_POD_READY_RETRIES ]]; then
echo "ERROR: KDC pod completed before kinit could run." >&2
exit 1
fi
pod_name=$(wait_for_kdc_pod "$kdc_ns" || true)
if [[ -z "$pod_name" ]]; then
echo "ERROR: KDC pod unavailable for kinit." >&2
exit 1
fi
attempt=$((attempt + 1))
continue
fi
# If the pod is crashlooping, show logs to aid troubleshooting
if is_pod_crashloop "$kdc_ns" "$pod_name"; then
echo "ERROR: KDC pod '${pod_name}' entered CrashLoopBackOff during kinit. Dumping diagnostics..." >&2
debug_kdc_pod "$kdc_ns" "$pod_name"
fi
echo "ERROR: kinit failed for ${KRB5_USER}@${KRB5_REALM}." >&2
exit 1
done
echo "Kerberos ticket cache:"
# Determine krb5 config path in the pod similar to run_kinit()
local krb5_config_in_pod="/etc/krb5.conf"
if ! kubectl -n "$kdc_ns" exec "$pod_name" -- ls /etc/krb5.conf >/dev/null 2>&1; then
krb5_config_in_pod="/opt/prole-kdc/krb5.conf"
fi
kubectl -n "$kdc_ns" exec "$pod_name" -- env KRB5_CONFIG="$krb5_config_in_pod" klist || true
}
case "$ACTION" in
test)
run_test
;;
cleanup)
echo "No test pods to cleanup (KDC-based test)."
;;
*)
echo "Usage: $0 {test|cleanup}" >&2
exit 2
;;
esac