mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 10:13:58 +00:00
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>
436 lines
12 KiB
Bash
Executable File
436 lines
12 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -uo pipefail
|
|
|
|
# repair_pipeline.sh
|
|
# Purpose:
|
|
# - Validate cluster readiness and common service health
|
|
# - Repair or re-deploy safe-to-recreate services when anomalies are detected
|
|
|
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
# shellcheck disable=SC1090
|
|
source "$SCRIPT_DIR/prole_cfg.sh"
|
|
|
|
ACTION="repair"
|
|
NAMESPACE_OVERRIDE=""
|
|
DB_NAMESPACE_OVERRIDE=""
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage: repair_pipeline.sh [-n|--namespace NS] [--db-namespace NS] [-m|--mode MODE] [repair]
|
|
|
|
Runs a best-effort repair pass across common services and cluster add-ons.
|
|
USAGE
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-m|--mode)
|
|
shift
|
|
prole_set_mode "${1:-}"
|
|
;;
|
|
-m=*|--mode=*)
|
|
prole_set_mode "${1#*=}"
|
|
;;
|
|
-n|--namespace)
|
|
shift
|
|
NAMESPACE_OVERRIDE="${1:-}"
|
|
;;
|
|
--db-namespace)
|
|
shift
|
|
DB_NAMESPACE_OVERRIDE="${1:-}"
|
|
;;
|
|
--db-namespace=*)
|
|
DB_NAMESPACE_OVERRIDE="${1#*=}"
|
|
;;
|
|
-n=*|--namespace=*)
|
|
NAMESPACE_OVERRIDE="${1#*=}"
|
|
;;
|
|
repair)
|
|
ACTION="repair"
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
usage
|
|
exit 2
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
BASE_NAMESPACE="${NAMESPACE:-}"
|
|
if [[ -n "$NAMESPACE_OVERRIDE" ]]; then
|
|
SERVICE_NAMESPACE="$NAMESPACE_OVERRIDE"
|
|
elif [[ -n "${SERVICE_NAMESPACE:-}" ]]; then
|
|
SERVICE_NAMESPACE="$SERVICE_NAMESPACE"
|
|
elif [[ -n "${NAMESPACE:-}" ]]; then
|
|
SERVICE_NAMESPACE="$NAMESPACE"
|
|
else
|
|
SERVICE_NAMESPACE="default"
|
|
fi
|
|
|
|
if [[ -n "$DB_NAMESPACE_OVERRIDE" ]]; then
|
|
DB_NAMESPACE="$DB_NAMESPACE_OVERRIDE"
|
|
elif [[ -n "${PROLE_DB_NAMESPACE:-}" ]]; then
|
|
DB_NAMESPACE="$PROLE_DB_NAMESPACE"
|
|
elif [[ -n "$BASE_NAMESPACE" ]]; then
|
|
DB_NAMESPACE="$BASE_NAMESPACE"
|
|
else
|
|
DB_NAMESPACE="$SERVICE_NAMESPACE"
|
|
fi
|
|
|
|
ARGOCD_NAMESPACE="${ARGOCD_NAMESPACE:-argocd}"
|
|
|
|
export SERVICE_NAMESPACE
|
|
export DB_NAMESPACE
|
|
export NAMESPACE="$SERVICE_NAMESPACE"
|
|
|
|
log() { printf '%s\n' "$*"; }
|
|
warn() { printf 'WARN: %s\n' "$*" >&2; }
|
|
err() { printf 'ERROR: %s\n' "$*" >&2; }
|
|
|
|
have() { command -v "$1" >/dev/null 2>&1; }
|
|
|
|
run_with_timeout() {
|
|
local timeout_s="$1"
|
|
shift
|
|
local cmd=( "$@" )
|
|
"${cmd[@]}" &
|
|
local pid=$!
|
|
local start=$SECONDS
|
|
while kill -0 "$pid" >/dev/null 2>&1; do
|
|
if (( SECONDS - start > timeout_s )); then
|
|
warn "Command timed out after ${timeout_s}s: ${cmd[*]}"
|
|
kill "$pid" >/dev/null 2>&1 || true
|
|
return 124
|
|
fi
|
|
sleep 2
|
|
done
|
|
wait "$pid"
|
|
return $?
|
|
}
|
|
|
|
ensure_kubectl() {
|
|
have kubectl || { err "kubectl not found"; exit 1; }
|
|
}
|
|
|
|
detect_mode() {
|
|
local mode
|
|
mode="${PROLE_MODE:-}"
|
|
if have prole_normalize_mode; then
|
|
mode="$(prole_normalize_mode "$mode")"
|
|
fi
|
|
printf '%s' "$mode"
|
|
}
|
|
|
|
ensure_kubeconfig_if_needed() {
|
|
local mode
|
|
mode="$(detect_mode)"
|
|
if [[ "$mode" == "k3s" || -n "${PROLE_K3S_SERVER:-}" || -n "${K3S_SERVER_URL:-}" ]]; then
|
|
prole_ensure_kubeconfig >/dev/null 2>&1 || true
|
|
fi
|
|
}
|
|
|
|
cluster_ready() {
|
|
ensure_kubectl
|
|
if ! kubectl cluster-info >/dev/null 2>&1; then
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
k3d_cluster_ready() {
|
|
local cluster="${K3D_CLUSTER:-knoe-dev-cluster}"
|
|
if have k3d; then
|
|
if k3d cluster list --no-headers 2>/dev/null | grep -q "^${cluster}[[:space:]]"; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
resource_exists() {
|
|
local kind="$1" name="$2" ns="$3"
|
|
kubectl -n "$ns" get "$kind" "$name" >/dev/null 2>&1
|
|
}
|
|
|
|
resource_ready() {
|
|
local kind="$1" name="$2" ns="$3"
|
|
local desired ready
|
|
if ! resource_exists "$kind" "$name" "$ns"; then
|
|
return 2
|
|
fi
|
|
desired=$(kubectl -n "$ns" get "$kind" "$name" -o jsonpath='{.spec.replicas}' 2>/dev/null || echo "")
|
|
ready=$(kubectl -n "$ns" get "$kind" "$name" -o jsonpath='{.status.readyReplicas}' 2>/dev/null || echo "")
|
|
desired=${desired:-1}
|
|
ready=${ready:-0}
|
|
if [[ "$ready" -ge "$desired" && "$desired" -gt 0 ]]; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
authority_context_exists() {
|
|
local base
|
|
if [[ -n "${PROLE_HOME:-}" ]]; then
|
|
if [[ -d "$PROLE_HOME/authority" || -d "$PROLE_HOME/prole/authority" ]]; then
|
|
return 0
|
|
fi
|
|
fi
|
|
base="$SCRIPT_DIR/.."
|
|
if [[ -d "$base/authority" || -d "$base/prole/authority" ]]; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
repair_dashboard() {
|
|
local ns="kubernetes-dashboard"
|
|
if ! kubectl get ns "$ns" >/dev/null 2>&1; then
|
|
warn "Dashboard namespace missing; installing via Helm"
|
|
if have helm; then
|
|
helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/ >/dev/null 2>&1 || true
|
|
if ! run_with_timeout 120 bash -c 'helm repo update >/dev/null 2>&1'; then
|
|
warn "Helm repo update timed out; continuing with cached index"
|
|
fi
|
|
if ! run_with_timeout 300 helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard \
|
|
--create-namespace --namespace "$ns" \
|
|
--set kong.image.tag=3.8 --set kong.image.repository=docker.io/library/kong; then
|
|
warn "Helm install timed out or failed"
|
|
fi
|
|
else
|
|
warn "helm not found; cannot install kubernetes-dashboard"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
local kong_pods
|
|
kong_pods=$(kubectl -n "$ns" get pods --no-headers 2>/dev/null | awk '{print $1}' | grep -E 'kong' || true)
|
|
if [[ -z "$kong_pods" ]]; then
|
|
warn "Dashboard Kong pod missing; re-applying Helm release"
|
|
if have helm; then
|
|
if ! run_with_timeout 300 helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard \
|
|
--create-namespace --namespace "$ns" \
|
|
--set kong.image.tag=3.8 --set kong.image.repository=docker.io/library/kong; then
|
|
warn "Helm install timed out or failed"
|
|
fi
|
|
else
|
|
warn "helm not found; cannot reinstall kubernetes-dashboard"
|
|
return 1
|
|
fi
|
|
else
|
|
local unhealthy
|
|
unhealthy=$(kubectl -n "$ns" get pods --no-headers 2>/dev/null | grep -E 'kong' | awk '$3 != "Running" {print $1}' || true)
|
|
if [[ -n "$unhealthy" ]]; then
|
|
warn "Dashboard Kong pod unhealthy; deleting pods for restart"
|
|
kubectl -n "$ns" delete pod $unhealthy --wait=false >/dev/null 2>&1 || true
|
|
fi
|
|
fi
|
|
}
|
|
|
|
repair_argocd() {
|
|
local ns="$1"
|
|
local need_fix=0
|
|
local items=(
|
|
"deploy argocd-server"
|
|
"deploy argocd-repo-server"
|
|
"deploy argocd-dex-server"
|
|
"deploy argocd-applicationset-controller"
|
|
"deploy argocd-notifications-controller"
|
|
"deploy argocd-redis"
|
|
"statefulset argocd-application-controller"
|
|
)
|
|
local item kind name status
|
|
for item in "${items[@]}"; do
|
|
kind="${item%% *}"
|
|
name="${item##* }"
|
|
resource_ready "$kind" "$name" "$ns"; status=$?
|
|
if [[ "$status" -ne 0 ]]; then
|
|
need_fix=1
|
|
break
|
|
fi
|
|
done
|
|
if [[ "$need_fix" -eq 1 ]]; then
|
|
warn "ArgoCD not ready; re-deploying"
|
|
REGISTRY_NAMESPACE="${REGISTRY_NAMESPACE:-default}" \
|
|
"$SCRIPT_DIR/init_registry.sh" -n "$ns" --registry-namespace "${REGISTRY_NAMESPACE:-default}" stop || true
|
|
REGISTRY_NAMESPACE="${REGISTRY_NAMESPACE:-default}" \
|
|
"$SCRIPT_DIR/init_registry.sh" -n "$ns" --registry-namespace "${REGISTRY_NAMESPACE:-default}" update || true
|
|
else
|
|
log "ArgoCD: OK"
|
|
fi
|
|
}
|
|
|
|
repair_openbao() {
|
|
local ns="$1"
|
|
local status
|
|
resource_ready deploy openbao "$ns"; status=$?
|
|
if [[ "$status" -eq 2 ]]; then
|
|
resource_ready statefulset openbao "$ns"; status=$?
|
|
fi
|
|
if [[ "$status" -ne 0 ]]; then
|
|
warn "OpenBao not ready; restarting pods and re-applying"
|
|
kubectl -n "$ns" delete pod -l app=openbao --wait=false >/dev/null 2>&1 || true
|
|
"$SCRIPT_DIR/init_openbao.sh" -n "$ns" update || true
|
|
else
|
|
log "OpenBao: OK"
|
|
fi
|
|
}
|
|
|
|
repair_opentofu() {
|
|
local ns="$1"
|
|
local status
|
|
resource_ready deploy opentofu "$ns"; status=$?
|
|
if [[ "$status" -ne 0 ]]; then
|
|
warn "OpenTofu not ready; re-deploying"
|
|
kubectl -n "$ns" delete deploy opentofu --ignore-not-found >/dev/null 2>&1 || true
|
|
"$SCRIPT_DIR/init_opentofu.sh" -n "$ns" update || true
|
|
else
|
|
log "OpenTofu: OK"
|
|
fi
|
|
}
|
|
|
|
repair_garage() {
|
|
local ns="$1"
|
|
local status
|
|
resource_ready statefulset garage "$ns"; status=$?
|
|
if [[ "$status" -ne 0 ]]; then
|
|
warn "Garage not ready; restarting pods (PVCs preserved)"
|
|
kubectl -n "$ns" delete pod -l app=garage --wait=false >/dev/null 2>&1 || true
|
|
"$SCRIPT_DIR/init_garage_store.sh" start || true
|
|
else
|
|
log "Garage: OK"
|
|
fi
|
|
}
|
|
|
|
repair_cnpg() {
|
|
local ns="$1"
|
|
local cluster="${CNPG_CLUSTER_NAME:-prole-db}"
|
|
if ! kubectl -n "$ns" get cluster "$cluster" >/dev/null 2>&1; then
|
|
warn "CNPG cluster '$cluster' not found in namespace '$ns'"
|
|
return 0
|
|
fi
|
|
|
|
local total ready bad
|
|
total=$(kubectl -n "$ns" get pods -l "cnpg.io/cluster=$cluster" --no-headers 2>/dev/null | wc -l | tr -d ' ')
|
|
if [[ "$total" -eq 0 ]]; then
|
|
warn "CNPG cluster '$cluster' has no pods; skipping rollout"
|
|
return 0
|
|
fi
|
|
ready=$(kubectl -n "$ns" get pods -l "cnpg.io/cluster=$cluster" --no-headers 2>/dev/null | awk '$2 ~ /^([0-9]+)\/\\1$/ {c++} END{print c+0}')
|
|
bad=$(kubectl -n "$ns" get pods -l "cnpg.io/cluster=$cluster" --no-headers 2>/dev/null | awk '$3 ~ /CrashLoopBackOff|Error|ImagePullBackOff|ErrImagePull/ {c++} END{print c+0}')
|
|
|
|
if [[ "$ready" -lt "$total" || "$bad" -gt 0 ]]; then
|
|
warn "CNPG pods unhealthy ($ready/$total ready, $bad bad); running rollout"
|
|
run_with_timeout 360 env NAMESPACE="$ns" "$SCRIPT_DIR/init_cloudnative_pg.sh" rollout || true
|
|
else
|
|
log "CNPG: OK"
|
|
fi
|
|
}
|
|
|
|
repair_barman_plugin() {
|
|
local ns="cnpg-system"
|
|
if ! kubectl -n "$ns" get deploy barman-cloud >/dev/null 2>&1; then
|
|
warn "Barman Cloud plugin missing; reinstalling"
|
|
run_with_timeout 300 env NAMESPACE="$DB_NAMESPACE" "$SCRIPT_DIR/init_cloudnative_pg.sh" install-barman-plugin || true
|
|
return 0
|
|
fi
|
|
|
|
local ready
|
|
ready=$(kubectl -n "$ns" get deploy barman-cloud -o jsonpath='{.status.readyReplicas}' 2>/dev/null || echo "0")
|
|
if [[ -z "$ready" || "$ready" == "0" ]]; then
|
|
warn "Barman Cloud plugin not ready; reinstalling and restarting"
|
|
run_with_timeout 300 env NAMESPACE="$DB_NAMESPACE" "$SCRIPT_DIR/init_cloudnative_pg.sh" install-barman-plugin || true
|
|
kubectl -n "$ns" rollout restart deploy/barman-cloud >/dev/null 2>&1 || true
|
|
else
|
|
log "Barman Cloud plugin: OK"
|
|
fi
|
|
}
|
|
|
|
repair_kdc() {
|
|
local ns="$1"
|
|
local status
|
|
if ! authority_context_exists; then
|
|
warn "Authority Docker context missing; skipping KDC rebuild"
|
|
return 0
|
|
fi
|
|
resource_ready deploy auth "$ns"; status=$?
|
|
if [[ "$status" -ne 0 ]]; then
|
|
warn "KDC (auth) not ready; re-deploying"
|
|
kubectl -n "$ns" delete deploy auth --ignore-not-found >/dev/null 2>&1 || true
|
|
kubectl -n "$ns" delete svc auth --ignore-not-found >/dev/null 2>&1 || true
|
|
"$SCRIPT_DIR/init_kdc.sh" update || true
|
|
else
|
|
log "KDC (auth): OK"
|
|
fi
|
|
}
|
|
|
|
case "${ACTION}" in
|
|
repair)
|
|
ensure_kubectl
|
|
ensure_kubeconfig_if_needed
|
|
|
|
log "== Repair Pipeline =="
|
|
log "Namespace: $NAMESPACE"
|
|
|
|
if ! cluster_ready; then
|
|
err "Cluster not reachable; aborting repair"
|
|
exit 2
|
|
fi
|
|
|
|
if [[ "$(detect_mode)" == "k3d" ]]; then
|
|
if ! k3d_cluster_ready; then
|
|
err "k3d cluster not running"
|
|
exit 2
|
|
fi
|
|
fi
|
|
|
|
log "-- Dashboard (Kong) --"
|
|
repair_dashboard || true
|
|
|
|
log "-- ArgoCD --"
|
|
repair_argocd "$ARGOCD_NAMESPACE"
|
|
|
|
log "-- OpenBao --"
|
|
repair_openbao "$SERVICE_NAMESPACE"
|
|
|
|
log "-- OpenTofu --"
|
|
repair_opentofu "$SERVICE_NAMESPACE"
|
|
|
|
log "-- Garage --"
|
|
repair_garage "$SERVICE_NAMESPACE"
|
|
|
|
if [[ "${KERBEROS_ENABLED:-}" == "0" || "${KERBEROS_ENABLED:-}" == "false" || "${KERBEROS_ENABLED:-}" == "False" ]]; then
|
|
log "KDC (auth): skipped (Kerberos disabled)"
|
|
elif [[ "${PROLE_KDC_ENABLED:-1}" != "0" ]]; then
|
|
log "-- KDC (auth) --"
|
|
repair_kdc "$SERVICE_NAMESPACE"
|
|
else
|
|
log "KDC (auth): skipped (disabled)"
|
|
fi
|
|
|
|
log "-- Barman Cloud Plugin --"
|
|
repair_barman_plugin
|
|
|
|
log "-- CNPG --"
|
|
repair_cnpg "$DB_NAMESPACE"
|
|
|
|
log "-- Common Services Status --"
|
|
if [[ "${KERBEROS_ENABLED:-}" == "1" || "${KERBEROS_ENABLED:-}" == "true" || "${KERBEROS_ENABLED:-}" == "True" ]]; then
|
|
"$SCRIPT_DIR/status_common_services.sh" -n "$SERVICE_NAMESPACE" -k || true
|
|
else
|
|
"$SCRIPT_DIR/status_common_services.sh" -n "$SERVICE_NAMESPACE" || true
|
|
fi
|
|
|
|
log "Repair pipeline complete."
|
|
;;
|
|
*)
|
|
usage
|
|
exit 2
|
|
;;
|
|
esac
|