mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 19:14:33 +00:00
Itemized changes:
1. knoe-auth: New cluster-internal KDC and SSO gateway service
- Created etc/init_knoe_auth.sh based on init_kdc.sh with knoe-auth naming
- Namespace defaults to SERVICE_NAMESPACE (knoe-system)
- ConfigMap: knoe-auth-kdc-config, Secret: knoe-auth-secrets
- Legacy cleanup removes old auth/dog/authority deployments
2. Orchestration: knoe-auth initializes before CloudNativePG
- Updated prole.sh to insert init_knoe_auth.sh as step 2 (before CNPG)
- Renumbered all subsequent initialization steps
3. Kong routing: Updated init_kong.sh to route to knoe-auth in SERVICE_NAMESPACE
4. Comment/reference updates for knoe-auth
- Updated init_common_services.sh, init_service_layer.sh, init_kerberos.sh
5. prole-db renamed to knoe-db across the entire codebase
- Renamed prole-db/ directory to knoe-db/
- Renamed all prole-db Kubernetes manifests (deploy/opentofu, k8s/)
- Renamed scripts: docker-root-knoe-db.sh, docker-run-knoe-db.sh, test-cnpg-knoe-db.sh
- Renamed etc/init_prole-db-reset.sh to etc/init_knoe-db-reset.sh
- Renamed etc/prole-db-passwwd.sh to etc/knoe-db-passwwd.sh
- Renamed mock_val counterparts accordingly
- Renamed tests/etc/test_init_prole-db-reset.sh to test_init_knoe-db-reset.sh
- Renamed docs/prole-db-documentation-mcp-architecture.md to knoe-db variant
- Renamed modes/k3d/prole-db/ to modes/k3d/knoe-db/
- Renamed prole-db.iml to knoe-db.iml
6. Configuration updates
- Updated conf/dev, conf/prod, conf/test, conf/service prole.cfg files
- Updated conf/port-mapping.cfg
- Updated etc/prole_cfg.sh and mock_val/prole_cfg.sh
- Updated service/prole.cfg
7. Kubernetes manifests and deploy configuration
- Updated deploy/opentofu/k3s ArgoCD application YAMLs
- Updated kong-configmap.yaml and kustomization.yaml
- Updated k3s/kong-config.yml and prole-resources.yaml
- Updated prole-mssql-db deployment YAMLs
- Updated supabase helm render and deploy scripts
8. Infrastructure and GCP Terraform
- Updated deploy/gcp/terraform: folders, groups, IAM, service-projects
9. Python/installer code updates
- Updated knoe/core: actions, build_context, controller, env, milestones
- Updated knoe/milestone.py
- Updated knoe/ui/screens: cfg, database, database_options, deploy, docker,
navigation, security, services, validate
- Updated knoe.spec, status.py
10. Shell script updates
- Updated etc/: build_db, init_cloudnative_pg, init_cnpg_backup,
init_db_manager, init_forgejo, init_gitlab, init_monitoring, init_openbao,
init_port_forwards, init_postgrest, init_supabase_ports, status
- Updated mock_val/ counterparts for all above scripts
- Updated prole-net/init-prole-dns.sh
- Updated bin/prole-kpf.sh, gitea/deploy.sh, supabase/deploy.sh
11. Test updates
- Updated tests/etc/: test_init_cloudnative_pg*, test_init_cnpg_backup*,
test_init_kdc*, test_init_kerberos*, test_init_kong*, test_prole_cfg*
- Updated tests/installer/: test_actions_helpers, test_cfg_save_kubecontext,
test_controller, test_core_classes, test_milestones, test_milestones_extended,
test_namespace_propagation
- Updated tests/: test_database_options, test_navigation,
test_render_supabase_hostname, test_docker_build_fix,
test_all_prole_home_fixes, silent_install_test, final_test
12. Documentation updates
- Updated docs/: DOCKER-BUILD-FIX, PROLE-CFG-SECRETS, PROLE-HOME-DIRECTORY,
build-system, patent
- Updated scan/network_description.txt
- Updated pom.xml
13. Miscellaneous script updates
- Updated root-level: _adopt_replica_pvcs, _fix_replica_merlin, _import_pi,
_patch_cluster, _prebind_pvcs, _rebind_d002, _rebind_d002b, test_resolve
- Updated scripts/generate_spec.py
Co-authored-by: Junie <junie@jetbrains.com>
391 lines
11 KiB
Bash
Executable File
391 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
# init_knoe-db-reset.sh
|
|
# Purpose:
|
|
# - Orderly shutdown of knoe-db with mandatory backup/export
|
|
# - Reset namespace resources
|
|
# - Recreate knoe-db from backup if available, else fresh init
|
|
#
|
|
# Usage:
|
|
# ./init_knoe-db-reset.sh reset # shutdown + reset + recreate
|
|
# ./init_knoe-db-reset.sh shutdown # orderly shutdown only
|
|
# ./init_knoe-db-reset.sh recreate # recreate from backup if available
|
|
|
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
|
|
# Load environment and config via prole_cfg.sh
|
|
# 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:-reset}
|
|
|
|
NAMESPACE="${PROLE_NAMESPACE}"
|
|
CNPG_CLUSTER_NAME=${CNPG_CLUSTER_NAME:-knoe-db}
|
|
PROLE_HOME=${PROLE_HOME:-$(cd "$SCRIPT_DIR/.." && pwd)}
|
|
|
|
ADMIN_USER=${KNOE_DB_ADMIN_USER:-postgres}
|
|
ADMIN_DB=${KNOE_DB_ADMIN_DB:-postgres}
|
|
|
|
GARAGE_NAME=${GARAGE_NAME:-garage}
|
|
SERVICE_NAMESPACE=${SERVICE_NAMESPACE:-}
|
|
if [[ -z "${GARAGE_NAMESPACE:-}" ]]; then
|
|
if [[ -n "$SERVICE_NAMESPACE" ]]; then
|
|
GARAGE_NAMESPACE="$SERVICE_NAMESPACE"
|
|
else
|
|
GARAGE_NAMESPACE="$NAMESPACE"
|
|
fi
|
|
fi
|
|
GARAGE_BACKUP_BUCKET=${GARAGE_BACKUP_BUCKET:-knoe-db-backups}
|
|
GARAGE_BACKUP_SECRET_NAME=${GARAGE_BACKUP_SECRET_NAME:-knoe-db-barman-s3}
|
|
GARAGE_S3_ENDPOINT=${GARAGE_S3_ENDPOINT:-http://$GARAGE_NAME.$GARAGE_NAMESPACE.svc.cluster.local:3900}
|
|
|
|
BACKUP_DIR=${BACKUP_DIR:-$PROLE_HOME/prole/backup}
|
|
BACKUP_WAIT_TIMEOUT=${BACKUP_WAIT_TIMEOUT:-1800}
|
|
EXPORT_WAIT_TIMEOUT=${EXPORT_WAIT_TIMEOUT:-1800}
|
|
ALLOW_NO_BACKUP=${ALLOW_NO_BACKUP:-0}
|
|
|
|
RECOVERY_TEMPLATE="$SCRIPT_DIR/../k8s/prole/knoe-db-recovery.yaml.tpl"
|
|
|
|
log() { printf '%s\n' "$*"; }
|
|
err() { printf '%s\n' "$*" >&2; }
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: $0 {reset|shutdown|recreate}
|
|
|
|
Actions:
|
|
reset Orderly shutdown + reset namespace + recreate (default)
|
|
shutdown Orderly shutdown only (backup + export + reset namespace)
|
|
recreate Recreate from backup if available, else fresh init
|
|
|
|
Env overrides:
|
|
BACKUP_DIR, BACKUP_WAIT_TIMEOUT, EXPORT_WAIT_TIMEOUT, ALLOW_NO_BACKUP
|
|
KNOE_DB_ADMIN_USER, KNOE_DB_ADMIN_DB
|
|
GARAGE_BACKUP_BUCKET, GARAGE_BACKUP_SECRET_NAME, GARAGE_S3_ENDPOINT
|
|
EOF
|
|
}
|
|
|
|
ensure_tools() {
|
|
for t in kubectl sed awk; do
|
|
command -v "$t" >/dev/null || { err "Missing required tool: $t"; exit 1; }
|
|
done
|
|
}
|
|
|
|
cluster_exists() {
|
|
kubectl -n "$NAMESPACE" get cluster "$CNPG_CLUSTER_NAME" >/dev/null 2>&1
|
|
}
|
|
|
|
get_primary_pod() {
|
|
local primary
|
|
primary=$(kubectl -n "$NAMESPACE" get cluster "$CNPG_CLUSTER_NAME" -o jsonpath='{.status.currentPrimary}' 2>/dev/null || true)
|
|
if [[ -z "$primary" ]]; then
|
|
primary=$(kubectl -n "$NAMESPACE" get pods -l "cnpg.io/cluster=$CNPG_CLUSTER_NAME" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)
|
|
fi
|
|
printf '%s' "$primary"
|
|
}
|
|
|
|
|
|
terminate_non_admin_connections() {
|
|
local pod
|
|
pod=$(get_primary_pod)
|
|
if [[ -z "$pod" ]]; then
|
|
log "No primary CNPG pod detected; skipping connection cleanup."
|
|
return 0
|
|
fi
|
|
|
|
log "Terminating non-admin database connections (admin=$ADMIN_USER) ..."
|
|
kubectl -n "$NAMESPACE" exec "$pod" -c postgres -- \
|
|
psql -U "$ADMIN_USER" -d "$ADMIN_DB" -v ON_ERROR_STOP=1 -c \
|
|
"SELECT pg_terminate_backend(pid)
|
|
FROM pg_stat_activity
|
|
WHERE usename <> '${ADMIN_USER}'
|
|
AND pid <> pg_backend_pid();" || true
|
|
}
|
|
|
|
latest_backup_name() {
|
|
kubectl -n "$NAMESPACE" get backup \
|
|
--sort-by=.metadata.creationTimestamp \
|
|
-o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null | tail -n 1
|
|
}
|
|
|
|
latest_completed_backup_name() {
|
|
kubectl -n "$NAMESPACE" get backup \
|
|
--sort-by=.metadata.creationTimestamp \
|
|
-o jsonpath='{range .items[*]}{.metadata.name}{"|"}{.status.phase}{"\n"}{end}' 2>/dev/null | \
|
|
awk -F'|' '{p=tolower($2); if (p=="completed" || p=="succeeded") {name=$1}} END {print name}'
|
|
}
|
|
|
|
wait_for_backup() {
|
|
local backup_name="$1"
|
|
local start_time now phase phase_lc
|
|
start_time=$(date +%s)
|
|
|
|
while true; do
|
|
phase=$(kubectl -n "$NAMESPACE" get backup "$backup_name" -o jsonpath='{.status.phase}' 2>/dev/null || true)
|
|
phase_lc=$(printf '%s' "$phase" | tr '[:upper:]' '[:lower:]')
|
|
|
|
case "$phase_lc" in
|
|
completed|succeeded)
|
|
log "Backup $backup_name completed."
|
|
return 0
|
|
;;
|
|
failed|error)
|
|
err "Backup $backup_name failed (phase=$phase)."
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
now=$(date +%s)
|
|
if (( now - start_time > BACKUP_WAIT_TIMEOUT )); then
|
|
err "Timed out waiting for backup $backup_name."
|
|
return 1
|
|
fi
|
|
|
|
log "Waiting for backup $backup_name to complete (phase=${phase:-unknown}) ..."
|
|
sleep 10
|
|
done
|
|
}
|
|
|
|
run_barman_backup() {
|
|
if ! cluster_exists; then
|
|
err "Cluster '$CNPG_CLUSTER_NAME' not found; cannot run backup."
|
|
return 1
|
|
fi
|
|
|
|
if [[ -x "$SCRIPT_DIR/init_cnpg_backup.sh" ]]; then
|
|
log "Running barman backup (Garage bucket: $GARAGE_BACKUP_BUCKET) ..."
|
|
NAMESPACE="$NAMESPACE" \
|
|
GARAGE_BACKUP_BUCKET="$GARAGE_BACKUP_BUCKET" \
|
|
GARAGE_BACKUP_SECRET_NAME="$GARAGE_BACKUP_SECRET_NAME" \
|
|
GARAGE_S3_ENDPOINT="$GARAGE_S3_ENDPOINT" \
|
|
RUN_FIRST_BACKUP=1 "$SCRIPT_DIR/init_cnpg_backup.sh" start
|
|
else
|
|
err "init_cnpg_backup.sh not found; cannot run backup."
|
|
return 1
|
|
fi
|
|
|
|
sleep 2
|
|
local backup_name
|
|
backup_name=$(latest_backup_name)
|
|
if [[ -z "$backup_name" ]]; then
|
|
err "No backup resource detected after triggering backup."
|
|
return 1
|
|
fi
|
|
|
|
wait_for_backup "$backup_name"
|
|
}
|
|
|
|
export_backup_bucket() {
|
|
if [[ -z "$GARAGE_BACKUP_BUCKET" ]]; then
|
|
err "GARAGE_BACKUP_BUCKET is not set; cannot export backup."
|
|
return 1
|
|
fi
|
|
if ! kubectl -n "$NAMESPACE" get secret "$GARAGE_BACKUP_SECRET_NAME" >/dev/null 2>&1; then
|
|
err "Garage backup secret '$GARAGE_BACKUP_SECRET_NAME' not found; cannot export backup."
|
|
return 1
|
|
fi
|
|
|
|
local image pod_name export_subdir
|
|
image=$(kubectl -n "$NAMESPACE" get cluster "$CNPG_CLUSTER_NAME" -o jsonpath='{.spec.imageName}' 2>/dev/null || true)
|
|
image=${image:-${KNOE_DB_IMAGE:-knoe-db:latest}}
|
|
|
|
pod_name="prole-barman-export-$(date +%s)"
|
|
export_subdir="${BACKUP_DIR}/garage-export-$(date +%Y%m%d%H%M%S)"
|
|
|
|
log "Creating export pod $pod_name using image $image ..."
|
|
cat <<EOF | kubectl apply -n "$NAMESPACE" -f -
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: ${pod_name}
|
|
namespace: ${NAMESPACE}
|
|
spec:
|
|
restartPolicy: Never
|
|
containers:
|
|
- name: exporter
|
|
image: ${image}
|
|
command: ["sleep","3600"]
|
|
env:
|
|
- name: AWS_ACCESS_KEY_ID
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: ${GARAGE_BACKUP_SECRET_NAME}
|
|
key: ACCESS_KEY_ID
|
|
- name: AWS_SECRET_ACCESS_KEY
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: ${GARAGE_BACKUP_SECRET_NAME}
|
|
key: SECRET_ACCESS_KEY
|
|
- name: AWS_DEFAULT_REGION
|
|
value: us-east-1
|
|
- name: GARAGE_S3_ENDPOINT
|
|
value: ${GARAGE_S3_ENDPOINT}
|
|
- name: GARAGE_BACKUP_BUCKET
|
|
value: ${GARAGE_BACKUP_BUCKET}
|
|
- name: EXPORT_DIR
|
|
value: /backup
|
|
volumeMounts:
|
|
- name: backup
|
|
mountPath: /backup
|
|
volumes:
|
|
- name: backup
|
|
emptyDir: {}
|
|
EOF
|
|
trap 'kubectl -n "$NAMESPACE" delete pod "$pod_name" --ignore-not-found >/dev/null 2>&1 || true' RETURN
|
|
|
|
log "Waiting for export pod to become ready..."
|
|
if ! kubectl -n "$NAMESPACE" wait --for=condition=Ready pod/"$pod_name" --timeout="${EXPORT_WAIT_TIMEOUT}s" >/dev/null 2>&1; then
|
|
err "Export pod did not become ready."
|
|
kubectl -n "$NAMESPACE" describe pod "$pod_name" || true
|
|
return 1
|
|
fi
|
|
|
|
log "Exporting Garage bucket to pod filesystem..."
|
|
kubectl -n "$NAMESPACE" exec "$pod_name" -- sh -c 'python3 - <<PY
|
|
import os
|
|
import sys
|
|
try:
|
|
import boto3
|
|
from botocore.config import Config
|
|
except Exception as exc:
|
|
print(f"boto3 is required in the export image: {exc}", file=sys.stderr)
|
|
sys.exit(3)
|
|
|
|
endpoint = os.environ.get("GARAGE_S3_ENDPOINT")
|
|
bucket_name = os.environ.get("GARAGE_BACKUP_BUCKET")
|
|
export_dir = os.environ.get("EXPORT_DIR", "/backup")
|
|
|
|
if not endpoint or not bucket_name:
|
|
print("Missing GARAGE_S3_ENDPOINT or GARAGE_BACKUP_BUCKET", file=sys.stderr)
|
|
sys.exit(2)
|
|
|
|
os.makedirs(export_dir, exist_ok=True)
|
|
|
|
config = Config(s3={"addressing_style": "path"})
|
|
s3 = boto3.resource("s3", endpoint_url=endpoint, config=config)
|
|
bucket = s3.Bucket(bucket_name)
|
|
|
|
count = 0
|
|
for obj in bucket.objects.all():
|
|
key = obj.key
|
|
if key.endswith("/"):
|
|
continue
|
|
dest = os.path.join(export_dir, key)
|
|
os.makedirs(os.path.dirname(dest), exist_ok=True)
|
|
bucket.download_file(key, dest)
|
|
count += 1
|
|
|
|
print(f"Downloaded {count} objects from {bucket_name} to {export_dir}")
|
|
PY'
|
|
|
|
log "Copying exported backup to $export_subdir ..."
|
|
mkdir -p "$export_subdir"
|
|
kubectl -n "$NAMESPACE" cp "$pod_name":/backup "$export_subdir"
|
|
|
|
log "Cleaning up export pod $pod_name ..."
|
|
kubectl -n "$NAMESPACE" delete pod "$pod_name" --ignore-not-found
|
|
trap - RETURN
|
|
}
|
|
|
|
shutdown_database() {
|
|
if [[ -x "$SCRIPT_DIR/init_cloudnative_pg.sh" ]]; then
|
|
log "Stopping knoe-db cluster ..."
|
|
"$SCRIPT_DIR/init_cloudnative_pg.sh" stop || true
|
|
else
|
|
log "init_cloudnative_pg.sh not found; deleting cluster resource directly."
|
|
kubectl -n "$NAMESPACE" delete cluster "$CNPG_CLUSTER_NAME" --ignore-not-found
|
|
fi
|
|
}
|
|
|
|
reset_namespace() {
|
|
if [[ -x "$SCRIPT_DIR/../scripts/reset-ns.sh" ]]; then
|
|
log "Resetting namespace $NAMESPACE ..."
|
|
"$SCRIPT_DIR/../scripts/reset-ns.sh" -n "$NAMESPACE"
|
|
else
|
|
err "scripts/reset-ns.sh not found."
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
recreate_from_backup() {
|
|
local backup_name manifest_tmp
|
|
backup_name=$(latest_completed_backup_name)
|
|
if [[ -z "$backup_name" ]]; then
|
|
return 1
|
|
fi
|
|
|
|
if [[ ! -f "$RECOVERY_TEMPLATE" ]]; then
|
|
err "Recovery template not found: $RECOVERY_TEMPLATE"
|
|
return 1
|
|
fi
|
|
|
|
manifest_tmp="/tmp/knoe-db-recovery-$$.yaml"
|
|
sed "s/{{BACKUP_NAME}}/${backup_name}/g" "$RECOVERY_TEMPLATE" > "$manifest_tmp"
|
|
|
|
log "Recreating knoe-db from backup $backup_name ..."
|
|
CNPG_MANIFEST_OVERRIDE="$manifest_tmp" "$SCRIPT_DIR/init_cloudnative_pg.sh" initialize
|
|
|
|
rm -f "$manifest_tmp"
|
|
}
|
|
|
|
recreate_fresh() {
|
|
log "Recreating knoe-db from scratch ..."
|
|
"$SCRIPT_DIR/init_cloudnative_pg.sh" initialize
|
|
}
|
|
|
|
shutdown() {
|
|
ensure_tools
|
|
terminate_non_admin_connections
|
|
|
|
if run_barman_backup; then
|
|
export_backup_bucket
|
|
else
|
|
if [[ "$ALLOW_NO_BACKUP" == "1" ]]; then
|
|
err "Backup failed, but ALLOW_NO_BACKUP=1 set; proceeding without export."
|
|
else
|
|
err "Backup failed and ALLOW_NO_BACKUP is not set; aborting shutdown."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
shutdown_database
|
|
reset_namespace
|
|
}
|
|
|
|
recreate() {
|
|
ensure_tools
|
|
if recreate_from_backup; then
|
|
log "Recovery initiated from existing backup."
|
|
else
|
|
log "No completed backups found; starting fresh."
|
|
recreate_fresh
|
|
fi
|
|
}
|
|
|
|
case "$ACTION" in
|
|
shutdown)
|
|
shutdown
|
|
;;
|
|
recreate)
|
|
recreate
|
|
;;
|
|
reset)
|
|
shutdown
|
|
recreate
|
|
;;
|
|
*)
|
|
usage
|
|
exit 2
|
|
;;
|
|
esac
|