mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 10:13:58 +00:00
Refactor project structure and update initialization scripts
- Moved files from 'prole/' subdirectory to root level or appropriate subdirectories (tests, authority, infrastructure) to flatten the project structure. - Updated 'install.py' and initialization scripts in 'etc/' to reflect the new directory layout. - Added 'etc/repair_pipeline.sh' for automated pipeline repairs. - Updated configuration files including 'conf/prole.cfg' and 'env.sh'. - Integrated ArgoCD manifests in 'k8s/argocd/'. - Updated 'prole-app' environment and properties. - Moved and updated test scripts for better organization and reliability. - Added 'tests/silent_install_test.sh' for automated installation testing.
This commit is contained in:
parent
f2c9012cce
commit
d2efb835b0
1
.gitignore
vendored
1
.gitignore
vendored
@ -43,7 +43,6 @@
|
||||
# Secrets and local config
|
||||
*.kubeconfig
|
||||
etc/secrets/
|
||||
prole/conf/
|
||||
*-password.txt
|
||||
*secret.yaml
|
||||
.vault_pass
|
||||
|
||||
13
conf/port-mapping.cfg
Normal file
13
conf/port-mapping.cfg
Normal file
@ -0,0 +1,13 @@
|
||||
# Port mappings for Prole Tools (read by scripts).
|
||||
# Format examples:
|
||||
# grafana: local=3000 remote=80 ns=default svc=prometheus-community-grafana address=0.0.0.0
|
||||
# db: local=5432 remote=5432 ns=default svc=prole-db-rw address=0.0.0.0
|
||||
|
||||
# Add your mappings below. One mapping per line as key=value tokens.
|
||||
argocd: local=8081 remote=80 ns=default svc=argocd-server address=0.0.0.0
|
||||
prometheus: local=9090 remote=9090 ns=default svc=prometheus-community-kube-prometheus address=0.0.0.0
|
||||
dashboard: local=8443 remote=443 ns=kubernetes-dashboard svc=kubernetes-dashboard-kong-proxy address=0.0.0.0
|
||||
openbao: local=8200 remote=8200 ns=default svc=openbao address=0.0.0.0
|
||||
opentofu: local=8080 remote=8080 ns=default svc=opentofu address=0.0.0.0
|
||||
db: local=5432 remote=5432 ns=prole-db-a0e0d0d0 svc=prole-db-rw address=0.0.0.0
|
||||
grafana: local=3000 remote=80 ns=default svc=prometheus-community-grafana address=0.0.0.0
|
||||
@ -1,13 +0,0 @@
|
||||
# Port mappings for Prole Tools (read by scripts).
|
||||
# Format examples:
|
||||
# grafana: local=3000 remote=80 ns=default svc=prometheus-community-grafana address=0.0.0.0
|
||||
# db: local=5432 remote=5432 ns=default svc=prole-db-rw address=0.0.0.0
|
||||
|
||||
# Add your mappings below. One mapping per line as key=value tokens.
|
||||
registry: local=5000 remote=80 ns=default svc=registry address=0.0.0.0
|
||||
dashboard: local=8000 remote=80 ns=kubernetes-dashboard svc=kubernetes-dashboard-web address=0.0.0.0
|
||||
openbao: local=8200 remote=80 ns=default svc=openbao address=0.0.0.0
|
||||
garage: local=8200 remote=80 ns=default svc=garage address=0.0.0.0
|
||||
opentofu: local=8080 remote=80 ns=default svc=opentofu address=0.0.0.0
|
||||
db: local=5432 remote=5432 ns=prole-db-a0e0d0d0 svc=prole-db-rw address=0.0.0.0
|
||||
grafana: local=3000 remote=80 ns=prole-db-a0e0d0d0 svc=prometheus-community-grafana address=0.0.0.0
|
||||
@ -1,10 +1,10 @@
|
||||
; Prole Master Configuration File
|
||||
; Generated by install.py on 2026-02-13 20:39:34
|
||||
; Generated by install.py on 2026-02-14 11:50:44
|
||||
; This file is used as input for Ansible deployment and k8s cluster creation.
|
||||
|
||||
[User]
|
||||
; User-editable values; derived values below reference these by default.
|
||||
NAMESPACE = prole-db-a0e0d0d0
|
||||
NAMESPACE = prole-db-101
|
||||
PROLE_CONF = ${PROLE_HOME}/conf
|
||||
PROLE_DATA = /opt/prole/data/chrisfu
|
||||
PROLE_HOME = /Users/chrisfu/dev/prole
|
||||
@ -36,26 +36,26 @@ init_cluster.at_rest_encryption_enabled = true
|
||||
init_cluster.cluster_env = k3d-prole-dev-cluster
|
||||
init_cluster.deployment_target = prole-dev-cluster
|
||||
init_cluster.k3s_server_url = https://myrddin.prole.org:6443
|
||||
init_cluster.k3s_token = ${OPENBAO:REDACTED}
|
||||
init_cluster.k3s_token =
|
||||
init_cluster.kerberos_enabled = true
|
||||
init_cluster.mode = k3d
|
||||
init_cluster.start_cluster = true
|
||||
init_cluster.supabase_enabled = true
|
||||
init_cluster.supabase_enabled = false
|
||||
init_cnpg_deploy.force_rollout = false
|
||||
init_cnpg_deploy.run_deploy = true
|
||||
init_db_build.run_build = true
|
||||
init_password.db_host_port = 5432
|
||||
init_password.db_password = ${OPENBAO:kv/prole/prole-db-a0e0d0d0/db#password}
|
||||
init_password.db_password_confirm = ${OPENBAO:kv/prole/prole-db-a0e0d0d0/db#password}
|
||||
init_password.db_username = chrisfu
|
||||
init_password.db_password = ${OPENBAO:kv/prole/prole-db-101/db#password}
|
||||
init_password.db_password_confirm = ${OPENBAO:kv/prole/prole-db-101/db#password}
|
||||
init_password.db_username = root
|
||||
init_password.generate_ssh_key = true
|
||||
init_scripts.run_scripts = true
|
||||
kerberos_config.enabled = true
|
||||
kerberos_config.kdc = 10.0.0.3
|
||||
kerberos_config.password = ${OPENBAO:kv/prole/prole-db-a0e0d0d0/kerberos#password}
|
||||
kerberos_config.password = ${OPENBAO:kv/prole/prole-db-101/kerberos#password}
|
||||
kerberos_config.realm = PROLE.ORG
|
||||
kerberos_config.test_connection = true
|
||||
kerberos_config.user = chrisfu
|
||||
kerberos_config.test_connection = false
|
||||
kerberos_config.user =
|
||||
network_scan.run = true
|
||||
ollama_config.model =
|
||||
ollama_config.server_host =
|
||||
@ -65,12 +65,12 @@ ollama_config.server_port = 11434
|
||||
; Variables used by name in more than one place or assumed global scope
|
||||
CLUSTER_ENV = k3d-prole-dev-cluster
|
||||
DB_HOST_PORT = 5432
|
||||
DB_PASSWORD = ${OPENBAO:kv/prole/prole-db-a0e0d0d0/db#password}
|
||||
DB_PASSWORD = ${OPENBAO:kv/prole/prole-db-101/db#password}
|
||||
DEPLOYMENT_MODE = k3d
|
||||
DEPLOYMENT_TARGET = prole-dev-cluster
|
||||
DOCKER_IMPORT_DIR =
|
||||
NAMESPACE = ${NAMESPACE}
|
||||
PROLE_DB_USER = chrisfu
|
||||
PROLE_DB_USER = root
|
||||
PROLE_HOME = ${PROLE_HOME}
|
||||
PROLE_K3S_SERVER = https://myrddin.prole.org:6443
|
||||
PROLE_K3S_TOKEN = ${OPENBAO:REDACTED}
|
||||
@ -81,7 +81,7 @@ SERVICE_NAMESPACE = ${SERVICE_NAMESPACE}
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Dependencies]
|
||||
; No configuration values captured yet for this section.
|
||||
STATUS = All installed
|
||||
|
||||
[Network]
|
||||
AD_DC_HOST = myrddin.prole.org
|
||||
@ -96,17 +96,25 @@ KDC_AUTO_DETECTED = 10.0.0.3
|
||||
KERBEROS_AUTO_ENABLED = True
|
||||
|
||||
[Port Forwards]
|
||||
; No configuration values captured yet for this section.
|
||||
PORT_FORWARD_K3D_MAPPING_1 = id=registry;namespace=default;target=svc/registry;address=0.0.0.0;hostPort=5000;servicePort=5000;protocol=TCP;description=Docker registry
|
||||
PORT_FORWARD_K3D_MAPPING_2 = id=garage;namespace=default;target=svc/garage;address=0.0.0.0;hostPort=3900;servicePort=3900;protocol=TCP;description=Garage S3
|
||||
PORT_FORWARD_K3D_MAPPING_3 = id=openbao;namespace=default;target=svc/openbao;address=127.0.0.1;hostPort=8200;servicePort=8200;protocol=TCP;description=OpenBao
|
||||
PORT_FORWARD_K3D_MAPPING_4 = id=opentofu;namespace=default;target=svc/opentofu;address=0.0.0.0;hostPort=8080;servicePort=8080;protocol=TCP;description=OpenTofu
|
||||
PORT_FORWARD_K3D_MAPPING_5 = id=dashboard;namespace=kubernetes-dashboard;target=svc/kubernetes-dashboard-kong-proxy;address=127.0.0.1;hostPort=8443;servicePort=443;protocol=TCP;description=Kubernetes Dashboard
|
||||
PORT_FORWARD_K3D_MAPPING_6 = id=postgres;namespace=${NAMESPACE};target=svc/prole-db-rw;address=0.0.0.0;hostPort=5432;servicePort=5432;protocol=TCP;description=PostgreSQL (primary)
|
||||
PORT_FORWARD_K3D_MAPPING_7 = id=grafana;namespace=${NAMESPACE};target=svc/grafana;address=0.0.0.0;hostPort=3000;servicePort=3000;protocol=TCP;description=Grafana UI
|
||||
PORT_FORWARD_K3D_MAPPING_8 = id=argocd;namespace=default;target=svc/argocd-server;address=0.0.0.0;hostPort=8081;servicePort=80;protocol=TCP;description=ArgoCD
|
||||
|
||||
[System Environment]
|
||||
PROLE_CONF = ${PROLE_CONF}
|
||||
PROLE_DATA = ${PROLE_DATA}
|
||||
PROLE_HOME = ${PROLE_HOME}
|
||||
PROLE_LOGS = ${PROLE_LOGS}
|
||||
PROLE_OPENTOFU_URL = http://127.0.0.1:8080
|
||||
PROLE_SERVICE = ${PROLE_SERVICE}
|
||||
|
||||
[Monitoring]
|
||||
GRAFANA_ADMIN_PASSWORD = ${OPENBAO:kv/prole/prole-db-a0e0d0d0/monitoring#grafana_admin_password}
|
||||
GRAFANA_ADMIN_PASSWORD = ${OPENBAO:kv/prole/prole-db-101/monitoring#grafana_admin_password}
|
||||
|
||||
[Kerberos Authentication]
|
||||
AD_PORT_FORWARD = 1
|
||||
@ -115,27 +123,27 @@ AD_PROXY_IMAGE = alpine/socat
|
||||
AD_PROXY_SERVICE = prole-kerberos-ad-dc
|
||||
AD_TCP_PORTS = 88 389 445 464 636
|
||||
AD_UDP_PORTS = 88 464
|
||||
ENABLED = True
|
||||
ENABLED = true
|
||||
KDC = 10.0.0.3
|
||||
PASSWORD = ${OPENBAO:kv/prole/prole-db-a0e0d0d0/kerberos#password}
|
||||
PASSWORD = ${OPENBAO:kv/prole/prole-db-101/kerberos#password}
|
||||
REALM = PROLE.ORG
|
||||
SERVER = 10.0.0.3
|
||||
USER = chrisfu
|
||||
USER =
|
||||
|
||||
[Ollama]
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Optional Features]
|
||||
AT_REST_ENCRYPTION_ENABLED = True
|
||||
KERBEROS_ENABLED = True
|
||||
SUPABASE_ENABLED = False
|
||||
AT_REST_ENCRYPTION_ENABLED = true
|
||||
KERBEROS_ENABLED = true
|
||||
SUPABASE_ENABLED = false
|
||||
|
||||
[Database Creation]
|
||||
|
||||
[Initialize Cluster]
|
||||
ENVIRONMENT = k3d-prole-dev-cluster
|
||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||
K3S_TOKEN = ${OPENBAO:REDACTED}
|
||||
K3S_TOKEN =
|
||||
|
||||
[Dev Cluster (k3d)]
|
||||
CLUSTER_ENV = k3d-prole-dev-cluster
|
||||
@ -147,12 +155,12 @@ MODE = k3d
|
||||
CLUSTER_ENV = prole-service-cluster
|
||||
DISPLAY_NAME = prole-service-cluster
|
||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||
K3S_TOKEN = ${OPENBAO:REDACTED}
|
||||
K3S_TOKEN = ${OPENBAO:kv/prole/prole-db-101/k3s#token}
|
||||
MODE = k3s
|
||||
PIPELINE_URL = http://127.0.0.1:8080
|
||||
|
||||
[Prod Cluster (k8s)]
|
||||
ARTIFACTS_DIR = /Users/chrisfu/dev/prole/data/staging
|
||||
ARTIFACTS_DIR = ${PROLE_DATA}/staging
|
||||
CLUSTER_ENV = prole-prod-cluster
|
||||
DISPLAY_NAME = prole-prod-cluster
|
||||
MODE = k8s
|
||||
@ -161,9 +169,10 @@ PIPELINE_URL = http://127.0.0.1:8080
|
||||
[Docker Build]
|
||||
LOCAL_REGISTRY = localhost:5000
|
||||
LOCAL_REGISTRY_INTERNAL = k3d-prole-registry.localhost:5000
|
||||
STATUS = Built
|
||||
|
||||
[Initialization Scripts]
|
||||
STATUS = Attempted
|
||||
; No configuration values captured yet for this section.
|
||||
|
||||
[Deployment]
|
||||
MODE = k3d
|
||||
|
||||
2
env.sh
2
env.sh
@ -8,7 +8,7 @@ export PROLE_CONF="/Users/chrisfu/dev/prole/conf"
|
||||
export PROLE_DATA="/opt/prole/data/chrisfu"
|
||||
export PROLE_LOGS="/opt/prole/logs/chrisfu"
|
||||
export PROLE_SERVICE="/Users/chrisfu/dev/prole/etc"
|
||||
export NAMESPACE="prole-db-a0e0d0d0"
|
||||
export NAMESPACE="prole-db-101"
|
||||
|
||||
# Ensure PATH works for GUI-launched shells (Docker, etc.)
|
||||
_prole_add_path() { case ":${PATH}:" in *":$1:"*) ;; *) PATH="$1:${PATH:-}" ;; esac; }
|
||||
|
||||
@ -1,25 +1,79 @@
|
||||
#!/bin/bash
|
||||
|
||||
# usage: etc/final_deployment.sh [-e|--docker-export]
|
||||
# usage: etc/final_deployment.sh [-e|--docker-export] [-c|--helm-chart] [-k|--kustomize] [-o|--output-dir DIR]
|
||||
#
|
||||
# This script handles post-installation deployment tasks for Prole.
|
||||
# 1st use case: -e|--docker-export
|
||||
# Runs docker image export for each image required to deploy Prole.
|
||||
# Artifacts are written to DOCKER_IMPORT_DIR.
|
||||
# 2nd use case: -c|--helm-chart
|
||||
# Creates a Helm chart from the current k8s manifests.
|
||||
# Artifacts are written to HELM_CHART_DIR.
|
||||
# 3rd use case: -k|--kustomize
|
||||
# Creates kustomize deployments (one per component).
|
||||
# Artifacts are written to KUSTOMIZE_DIR.
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [options]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -e, --docker-export Export required docker images to DOCKER_IMPORT_DIR"
|
||||
echo " -c, --helm-chart Create Helm chart from k8s manifests"
|
||||
echo " -k, --kustomize Create kustomize deployments from k8s manifests"
|
||||
echo " -o, --output-dir DIR Base directory for docker-import/, helm-chart/, and kustomize/"
|
||||
echo ""
|
||||
}
|
||||
|
||||
do_docker_export=0
|
||||
do_helm_chart=0
|
||||
do_kustomize=0
|
||||
export_dir=""
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-e|--docker-export)
|
||||
do_docker_export=1
|
||||
shift
|
||||
;;
|
||||
-c|--helm-chart)
|
||||
do_helm_chart=1
|
||||
shift
|
||||
;;
|
||||
-k|--kustomize)
|
||||
do_kustomize=1
|
||||
shift
|
||||
;;
|
||||
-o|--output-dir)
|
||||
if [[ -z "${2:-}" ]]; then
|
||||
echo "Missing value for $1"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
export_dir="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ $do_docker_export -eq 0 && $do_helm_chart -eq 0 && $do_kustomize -eq 0 ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
export PROJECT_ROOT
|
||||
|
||||
@ -31,7 +85,17 @@ fi
|
||||
default_owner="$(id -un 2>/dev/null || echo prole)"
|
||||
prole_data="${PROLE_DATA:-/opt/prole/data/${default_owner}}"
|
||||
prole_data="${prole_data%/}"
|
||||
|
||||
if [[ -n "$export_dir" ]]; then
|
||||
export_dir="${export_dir%/}"
|
||||
DOCKER_IMPORT_DIR="${export_dir}/docker-import"
|
||||
HELM_CHART_DIR="${export_dir}/helm-chart"
|
||||
KUSTOMIZE_DIR="${export_dir}/kustomize"
|
||||
fi
|
||||
|
||||
DOCKER_IMPORT_DIR="${DOCKER_IMPORT_DIR:-${prole_data}/docker-import}"
|
||||
HELM_CHART_DIR="${HELM_CHART_DIR:-${prole_data}/helm-chart}"
|
||||
KUSTOMIZE_DIR="${KUSTOMIZE_DIR:-${prole_data}/kustomize}"
|
||||
|
||||
export_docker_images() {
|
||||
echo "Exporting Docker images to: ${DOCKER_IMPORT_DIR}"
|
||||
@ -87,12 +151,117 @@ export_docker_images() {
|
||||
echo "Docker export complete."
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
-e|--docker-export)
|
||||
export_docker_images
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
create_helm_chart() {
|
||||
local chart_dir="${HELM_CHART_DIR}"
|
||||
local chart_name="prole"
|
||||
local chart_version="0.1.0"
|
||||
local app_version
|
||||
app_version="$(date -u +%Y.%m.%d)"
|
||||
|
||||
echo "Creating Helm chart in: ${chart_dir}"
|
||||
mkdir -p "${chart_dir}/templates"
|
||||
|
||||
# Clean managed template subdirs to avoid stale manifests.
|
||||
rm -rf "${chart_dir}/templates/prole" "${chart_dir}/templates/openbao" "${chart_dir}/templates/opentofu"
|
||||
|
||||
cat > "${chart_dir}/Chart.yaml" <<EOF
|
||||
apiVersion: v2
|
||||
name: ${chart_name}
|
||||
description: Prole deployment manifests
|
||||
type: application
|
||||
version: ${chart_version}
|
||||
appVersion: "${app_version}"
|
||||
EOF
|
||||
|
||||
cat > "${chart_dir}/values.yaml" <<'EOF'
|
||||
# Values are unused by default. Manifests are installed as-is.
|
||||
EOF
|
||||
|
||||
copy_manifests() {
|
||||
local src_dir="$1"
|
||||
local dest_subdir="$2"
|
||||
if [[ ! -d "$src_dir" ]]; then
|
||||
echo "Skipping missing manifest dir: $src_dir"
|
||||
return
|
||||
fi
|
||||
local dest_dir="${chart_dir}/templates/${dest_subdir}"
|
||||
mkdir -p "${dest_dir}"
|
||||
local found=0
|
||||
while IFS= read -r -d '' file; do
|
||||
if [[ "$(basename "$file")" == "kustomization.yaml" ]]; then
|
||||
continue
|
||||
fi
|
||||
cp "$file" "${dest_dir}/"
|
||||
found=1
|
||||
done < <(find "$src_dir" -maxdepth 1 -type f -name "*.yaml" -print0)
|
||||
if [[ $found -eq 0 ]]; then
|
||||
echo "No manifests found in $src_dir"
|
||||
fi
|
||||
}
|
||||
|
||||
copy_manifests "${PROJECT_ROOT}/k8s/prole" "prole"
|
||||
copy_manifests "${PROJECT_ROOT}/k8s/openbao" "openbao"
|
||||
copy_manifests "${PROJECT_ROOT}/k8s/opentofu" "opentofu"
|
||||
|
||||
echo "Helm chart creation complete."
|
||||
}
|
||||
|
||||
create_kustomize_deployments() {
|
||||
local base_dir="${KUSTOMIZE_DIR}"
|
||||
echo "Creating kustomize deployments in: ${base_dir}"
|
||||
mkdir -p "${base_dir}"
|
||||
|
||||
create_kustomize_package() {
|
||||
local name="$1"
|
||||
local src_dir="$2"
|
||||
if [[ ! -d "$src_dir" ]]; then
|
||||
echo "Skipping missing manifest dir: $src_dir"
|
||||
return
|
||||
fi
|
||||
|
||||
local dest_dir="${base_dir}/${name}"
|
||||
mkdir -p "${dest_dir}"
|
||||
|
||||
# Copy manifests except kustomization.yaml
|
||||
local files=()
|
||||
while IFS= read -r -d '' file; do
|
||||
if [[ "$(basename "$file")" == "kustomization.yaml" ]]; then
|
||||
continue
|
||||
fi
|
||||
cp "$file" "${dest_dir}/"
|
||||
files+=("$(basename "$file")")
|
||||
done < <(find "$src_dir" -maxdepth 1 -type f -name "*.yaml" -print0)
|
||||
|
||||
if [[ ${#files[@]} -eq 0 ]]; then
|
||||
echo "No manifests found in $src_dir"
|
||||
return
|
||||
fi
|
||||
|
||||
{
|
||||
echo "apiVersion: kustomize.config.k8s.io/v1beta1"
|
||||
echo "kind: Kustomization"
|
||||
echo "resources:"
|
||||
for f in "${files[@]}"; do
|
||||
echo " - ${f}"
|
||||
done
|
||||
} > "${dest_dir}/kustomization.yaml"
|
||||
}
|
||||
|
||||
create_kustomize_package "prole" "${PROJECT_ROOT}/k8s/prole"
|
||||
create_kustomize_package "openbao" "${PROJECT_ROOT}/k8s/openbao"
|
||||
create_kustomize_package "opentofu" "${PROJECT_ROOT}/k8s/opentofu"
|
||||
|
||||
echo "Kustomize deployments creation complete."
|
||||
}
|
||||
|
||||
if [[ $do_docker_export -eq 1 ]]; then
|
||||
export_docker_images
|
||||
fi
|
||||
|
||||
if [[ $do_helm_chart -eq 1 ]]; then
|
||||
create_helm_chart
|
||||
fi
|
||||
|
||||
if [[ $do_kustomize -eq 1 ]]; then
|
||||
create_kustomize_deployments
|
||||
fi
|
||||
|
||||
@ -9,7 +9,7 @@ usage() {
|
||||
cat <<EOF
|
||||
Usage: init_common_services.sh [-n|--namespace NS] [-k|--kerberos] <update|start|status>
|
||||
|
||||
Deploys common infrastructure services (OpenBao, OpenTofu, registry if available)
|
||||
Deploys common infrastructure services (ArgoCD, OpenBao, OpenTofu, Garage)
|
||||
into the given Kubernetes namespace. Use -k to include the Kerberos/KDC service.
|
||||
EOF
|
||||
}
|
||||
@ -82,7 +82,7 @@ fi
|
||||
|
||||
OPENBAO_NAME=${OPENBAO_NAME:-openbao}
|
||||
OPENTOFU_NAME=${OPENTOFU_NAME:-opentofu}
|
||||
REGISTRY_NAME=${REGISTRY_NAME:-registry}
|
||||
ARGOCD_SERVER_NAME=${ARGOCD_SERVER_NAME:-argocd-server}
|
||||
GARAGE_NAME=${GARAGE_NAME:-garage}
|
||||
OPENTOFU_CONFIGMAP=${OPENTOFU_CONFIGMAP:-opentofu-nginx}
|
||||
OPENTOFU_SECRET=${OPENTOFU_SECRET:-opentofu-admin}
|
||||
@ -132,13 +132,13 @@ migrate_common_services() {
|
||||
kubectl delete -n "$old_ns" secret "$OPENTOFU_SECRET" --ignore-not-found >/dev/null 2>&1 || true
|
||||
done
|
||||
|
||||
for old_ns in $(collect_other_namespaces "$REGISTRY_NAME" deployment service); do
|
||||
echo "Found registry in namespace '$old_ns'; removing before deploy to '$NS' ..."
|
||||
for old_ns in $(collect_other_namespaces "$ARGOCD_SERVER_NAME" deployment service); do
|
||||
echo "Found ArgoCD in namespace '$old_ns'; removing before deploy to '$NS' ..."
|
||||
if [ -x "$SCRIPT_DIR/init_registry.sh" ]; then
|
||||
"$SCRIPT_DIR/init_registry.sh" -n "$old_ns" stop || true
|
||||
else
|
||||
kubectl delete -n "$old_ns" deploy "$REGISTRY_NAME" --ignore-not-found >/dev/null 2>&1 || true
|
||||
kubectl delete -n "$old_ns" svc "$REGISTRY_NAME" --ignore-not-found >/dev/null 2>&1 || true
|
||||
kubectl delete -n "$old_ns" deploy "$ARGOCD_SERVER_NAME" --ignore-not-found >/dev/null 2>&1 || true
|
||||
kubectl delete -n "$old_ns" svc "$ARGOCD_SERVER_NAME" --ignore-not-found >/dev/null 2>&1 || true
|
||||
fi
|
||||
done
|
||||
|
||||
@ -176,7 +176,7 @@ fi
|
||||
if [ -x "$SCRIPT_DIR/init_registry.sh" ]; then
|
||||
"$SCRIPT_DIR/init_registry.sh" -n "$NS" "$ACTION" || rc=$?
|
||||
else
|
||||
echo "WARN: init_registry.sh not found; registry deploy skipped."
|
||||
echo "WARN: init_registry.sh not found; ArgoCD deploy skipped."
|
||||
fi
|
||||
|
||||
if [ -x "$SCRIPT_DIR/init_garage_store.sh" ]; then
|
||||
|
||||
@ -281,10 +281,18 @@ resolve_kdc_docker_dir() {
|
||||
echo "$PROLE_HOME/prole/authority"
|
||||
return 0
|
||||
fi
|
||||
if [[ -n "${PROLE_HOME:-}" && -d "$PROLE_HOME/authority" ]]; then
|
||||
echo "$PROLE_HOME/authority"
|
||||
return 0
|
||||
fi
|
||||
if [[ -d "$SCRIPT_DIR/../prole/authority" ]]; then
|
||||
echo "$SCRIPT_DIR/../prole/authority"
|
||||
return 0
|
||||
fi
|
||||
if [[ -d "$SCRIPT_DIR/../authority" ]]; then
|
||||
echo "$SCRIPT_DIR/../authority"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
@ -205,16 +205,18 @@ scan_pairs() {
|
||||
if ! json=$(curl -fsS --connect-timeout "$timeout" --max-time "$timeout" "$url" 2>/dev/null); then
|
||||
continue
|
||||
fi
|
||||
models=$(printf '%s' "$json" | python3 - <<'PY'
|
||||
if ! models=$(printf '%s' "$json" | python3 - <<'PY'
|
||||
import json
|
||||
import sys
|
||||
data = sys.stdin.read().strip()
|
||||
if not data:
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
try:
|
||||
payload = json.loads(data)
|
||||
except Exception:
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
if not isinstance(payload, dict) or "models" not in payload:
|
||||
sys.exit(1)
|
||||
models = []
|
||||
for entry in payload.get("models", []):
|
||||
name = entry.get("name") or entry.get("model") or ""
|
||||
@ -222,7 +224,9 @@ for entry in payload.get("models", []):
|
||||
models.append(name)
|
||||
print(",".join(models))
|
||||
PY
|
||||
)
|
||||
); then
|
||||
continue
|
||||
fi
|
||||
printf '%s\t%s\t%s\n' "$host" "$port_val" "$models"
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
@ -42,6 +42,8 @@ Examples:
|
||||
Config (prole.cfg or port-mapping.cfg):
|
||||
PORT_FORWARD_K3D_MAPPING_1 = id=dashboard;namespace=kubernetes-dashboard;target=svc/kubernetes-dashboard-kong-proxy;address=127.0.0.1;hostPort=8443;servicePort=443;protocol=TCP;description=Kubernetes Dashboard
|
||||
PORT_FORWARD_K3S_MAPPING_1 = id=opentofu;namespace=\${NAMESPACE};target=svc/opentofu;address=0.0.0.0;hostPort=8080;servicePort=8080;protocol=TCP;description=OpenTofu
|
||||
Legacy port-mapping.cfg:
|
||||
dashboard: local=8000 remote=80 ns=kubernetes-dashboard svc=kubernetes-dashboard-web address=0.0.0.0
|
||||
EOF
|
||||
}
|
||||
|
||||
@ -190,11 +192,33 @@ collect_cfg_mappings() {
|
||||
if (key ~ ("^" p "[0-9]+$")) {
|
||||
num=substr(key, length(p)+1)+0
|
||||
print num "\t" val
|
||||
count++
|
||||
}
|
||||
}
|
||||
END { if (count == 0) exit 1 }
|
||||
' "$file" | sort -n
|
||||
}
|
||||
|
||||
collect_cfg_mappings_for_mode() {
|
||||
local file="$1"
|
||||
local prefix
|
||||
prefix="$(mapping_prefix_for_mode)"
|
||||
if collect_cfg_mappings "$prefix" "$file"; then
|
||||
return 0
|
||||
fi
|
||||
# Fallback to generic mappings if mode-specific ones are absent
|
||||
if collect_cfg_mappings "PORT_FORWARD_MAPPING_" "$file"; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
has_ini_mappings() {
|
||||
local file="$1"
|
||||
[ -f "$file" ] || return 1
|
||||
grep -Eq '^[[:space:]]*PORT_FORWARD_.*_MAPPING_[0-9]+' "$file"
|
||||
}
|
||||
|
||||
parse_cfg_mapping() {
|
||||
local line="$1"
|
||||
local id="" ns="" target="" address="" hostPort="" servicePort="" protocol="" description=""
|
||||
@ -496,6 +520,28 @@ docker_is_running() {
|
||||
docker info >/dev/null 2>&1
|
||||
}
|
||||
|
||||
docker_port_owner() {
|
||||
local port="$1"
|
||||
have docker || return 1
|
||||
docker ps --format '{{.ID}}\t{{.Names}}\t{{.Ports}}' 2>/dev/null | \
|
||||
awk -v p=":"$port"->" 'index($0, p) {print $1 "\t" $2; exit 0}'
|
||||
}
|
||||
|
||||
should_skip_mapping() {
|
||||
local id="$1" hostPort="$2"
|
||||
case "$id" in
|
||||
registry|openbao)
|
||||
local owner
|
||||
owner="$(docker_port_owner "$hostPort")"
|
||||
if [ -n "$owner" ]; then
|
||||
log "Skipping $id port-forward; docker is already publishing port $hostPort ($owner)."
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
# Hard-fail with clean guidance when Docker is not up (used for start/restart).
|
||||
ensure_docker_running() {
|
||||
if docker_is_running; then
|
||||
@ -579,6 +625,19 @@ is_pid_running() {
|
||||
[ -n "$pid" ] && kill -0 "$pid" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
is_matching_port_forward() {
|
||||
local pid="$1" target="$2" hostPort="$3" servicePort="$4"
|
||||
local cmd
|
||||
cmd="$(ps -p "$pid" -o command= 2>/dev/null || true)"
|
||||
if [ -z "$cmd" ]; then
|
||||
return 1
|
||||
fi
|
||||
case "$cmd" in
|
||||
*port-forward*"$target"*"$hostPort:$servicePort"*) return 0 ;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
read_pid() {
|
||||
local pf="$1"
|
||||
[ -f "$pf" ] || return 1
|
||||
@ -597,48 +656,111 @@ remove_pidfile() {
|
||||
rm -f "$pf" >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
handle_mapping_parsed() {
|
||||
local callback="$1"
|
||||
local parsed="$2"
|
||||
local id ns target address hostPort servicePort protocol description
|
||||
IFS=$'\t' read -r id ns target address hostPort servicePort protocol description <<<"$parsed"
|
||||
|
||||
if [ -z "$id" ] || [ -z "$ns" ] || [ -z "$target" ] || [ -z "$hostPort" ] || [ -z "$servicePort" ]; then
|
||||
err "Invalid mapping (missing required fields): $parsed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$TARGET_ID" ] && [ "$id" != "$TARGET_ID" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
vlog "mapping: id=$id ns=$ns target=$target address=$address hostPort=$hostPort servicePort=$servicePort protocol=$protocol"
|
||||
"$callback" "$id" "$ns" "$target" "$address" "$hostPort" "$servicePort" "$protocol" "$description"
|
||||
return 0
|
||||
}
|
||||
|
||||
foreach_mapping_cfg() {
|
||||
local callback="$1"
|
||||
local file="${2:-$PORT_MAPPING_FILE_PATH}"
|
||||
local prefix mappings line parsed
|
||||
local mappings line parsed count=0
|
||||
[ -n "$file" ] || return 1
|
||||
prefix="$(mapping_prefix_for_mode)"
|
||||
if ! mappings="$(collect_cfg_mappings "$prefix" "$file")"; then
|
||||
if ! mappings="$(collect_cfg_mappings_for_mode "$file")"; then
|
||||
return 1
|
||||
fi
|
||||
while IFS= read -r line; do
|
||||
[ -z "$line" ] && continue
|
||||
parsed="$(parse_cfg_mapping "${line#*$'\t'}")"
|
||||
local id ns target address hostPort servicePort protocol description
|
||||
IFS=$'\t' read -r id ns target address hostPort servicePort protocol description <<<"$parsed"
|
||||
|
||||
if [ -z "$id" ] || [ -z "$ns" ] || [ -z "$target" ] || [ -z "$hostPort" ] || [ -z "$servicePort" ]; then
|
||||
err "Invalid mapping (missing required fields): ${line#*$'\t'}"
|
||||
exit 1
|
||||
if handle_mapping_parsed "$callback" "$parsed"; then
|
||||
count=$((count + 1))
|
||||
fi
|
||||
done <<<"$mappings"
|
||||
[ "$count" -gt 0 ] || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
if [ -n "$TARGET_ID" ] && [ "$id" != "$TARGET_ID" ]; then
|
||||
foreach_mapping_legacy() {
|
||||
local callback="$1"
|
||||
local file="${2:-$PORT_MAPPING_FILE_PATH}"
|
||||
local line id rest token key value
|
||||
local hostPort servicePort ns target address protocol description
|
||||
local count=0
|
||||
[ -f "$file" ] || return 1
|
||||
while IFS= read -r line; do
|
||||
line="$(trim "$line")"
|
||||
[ -z "$line" ] && continue
|
||||
case "$line" in \#*|\;*) continue ;; esac
|
||||
id="${line%%:*}"
|
||||
rest="${line#*:}"
|
||||
if [ "$id" = "$line" ]; then
|
||||
continue
|
||||
fi
|
||||
id="$(trim "$id")"
|
||||
rest="$(trim "$rest")"
|
||||
hostPort="" servicePort="" ns="" target="" address="" protocol="" description=""
|
||||
for token in $rest; do
|
||||
key="$(trim "${token%%=*}")"
|
||||
value="$(trim "${token#*=}")"
|
||||
case "$key" in
|
||||
local|host|hostPort|host_port) hostPort="$value" ;;
|
||||
remote|servicePort|service_port) servicePort="$value" ;;
|
||||
ns|namespace) ns="$value" ;;
|
||||
svc|service) target="svc/$value" ;;
|
||||
target) target="$value" ;;
|
||||
address|addr) address="$value" ;;
|
||||
protocol|proto) protocol="$value" ;;
|
||||
desc|description) description="$value" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
vlog "mapping: id=$id ns=$ns target=$target address=$address hostPort=$hostPort servicePort=$servicePort protocol=$protocol"
|
||||
"$callback" "$id" "$ns" "$target" "$address" "$hostPort" "$servicePort" "$protocol" "$description"
|
||||
done <<<"$mappings"
|
||||
if [ -z "$address" ]; then address="127.0.0.1"; fi
|
||||
if [ -z "$protocol" ]; then protocol="TCP"; fi
|
||||
|
||||
line="id=$id;namespace=$ns;target=$target;address=$address;hostPort=$hostPort;servicePort=$servicePort;protocol=$protocol;description=$description"
|
||||
parsed="$(parse_cfg_mapping "$line")"
|
||||
if handle_mapping_parsed "$callback" "$parsed"; then
|
||||
count=$((count + 1))
|
||||
fi
|
||||
done <"$file"
|
||||
[ "$count" -gt 0 ] || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
foreach_mapping() {
|
||||
local callback="$1"
|
||||
if foreach_mapping_cfg "$callback" "$CFG_FILE"; then
|
||||
return 0
|
||||
fi
|
||||
if [ -n "${PORT_MAPPING_FILE_PATH:-}" ] && [ -f "$PORT_MAPPING_FILE_PATH" ]; then
|
||||
if foreach_mapping_cfg "$callback" "$PORT_MAPPING_FILE_PATH"; then
|
||||
if [ -n "${CFG_FILE:-}" ] && [ -f "$CFG_FILE" ]; then
|
||||
if foreach_mapping_cfg "$callback" "$CFG_FILE"; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
err "No port-forward mappings found in ${CFG_FILE:-prole.cfg}."
|
||||
exit 1
|
||||
if [ -n "${PORT_MAPPING_FILE_PATH:-}" ] && [ -f "$PORT_MAPPING_FILE_PATH" ]; then
|
||||
if has_ini_mappings "$PORT_MAPPING_FILE_PATH"; then
|
||||
if foreach_mapping_cfg "$callback" "$PORT_MAPPING_FILE_PATH"; then
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
if foreach_mapping_legacy "$callback" "$PORT_MAPPING_FILE_PATH"; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
build_port_forward_cmd() {
|
||||
@ -653,6 +775,11 @@ start_port_forward() {
|
||||
local id="$1" ns="$2" target="$3" address="$4" hostPort="$5" servicePort="$6" protocol="$7" description="$8"
|
||||
local pidfile logfile cmd pid
|
||||
|
||||
if should_skip_mapping "$id" "$hostPort"; then
|
||||
stop_port_forward "$id" "$ns" "$target" "$address" "$hostPort" "$servicePort" "$protocol" "$description"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Aggressively stop existing processes before starting to avoid port conflicts
|
||||
stop_port_forward "$id" "$ns" "$target" "$address" "$hostPort" "$servicePort" "$protocol" "$description"
|
||||
|
||||
@ -749,6 +876,10 @@ status_one() {
|
||||
scan_for_collisions() {
|
||||
local id="$1" ns="$2" target="$3" address="$4" hostPort="$5" servicePort="$6" protocol="$7" description="$8"
|
||||
|
||||
if should_skip_mapping "$id" "$hostPort"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if port_in_use "$hostPort"; then
|
||||
# find which process is using it
|
||||
local pid_info=""
|
||||
@ -757,6 +888,10 @@ scan_for_collisions() {
|
||||
fi
|
||||
|
||||
if [ -n "$pid_info" ]; then
|
||||
if is_matching_port_forward "$pid_info" "$target" "$hostPort" "$servicePort"; then
|
||||
vlog "Port $hostPort already forwarded by kubectl for $id (pid=$pid_info)."
|
||||
return 0
|
||||
fi
|
||||
# Check if this PID is already managed by us
|
||||
local pidfile pid_managed
|
||||
pidfile="$(pid_file_for "$id")"
|
||||
@ -810,15 +945,23 @@ do_start() {
|
||||
ensure_supabase_ports
|
||||
|
||||
vlog "Scanning for port collisions..."
|
||||
foreach_mapping scan_for_collisions
|
||||
if ! foreach_mapping scan_for_collisions; then
|
||||
err "No port-forward mappings found. Check ${CFG_FILE:-prole.cfg} or ${PORT_MAPPING_FILE_PATH:-port-mapping.cfg}."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
foreach_mapping start_port_forward
|
||||
if ! foreach_mapping start_port_forward; then
|
||||
err "No port-forward mappings started. Check ${CFG_FILE:-prole.cfg} or ${PORT_MAPPING_FILE_PATH:-port-mapping.cfg}."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
do_stop() {
|
||||
# stop doesn't require cluster access, but it does need state dirs
|
||||
ensure_dirs
|
||||
foreach_mapping stop_port_forward
|
||||
if ! foreach_mapping stop_port_forward; then
|
||||
log "No port-forward mappings found to stop."
|
||||
fi
|
||||
}
|
||||
|
||||
do_restart() {
|
||||
@ -840,9 +983,18 @@ do_restart() {
|
||||
|
||||
vlog "Scanning for port collisions (excluding our own)..."
|
||||
# During restart, we'll stop them first anyway, but let's be safe.
|
||||
foreach_mapping stop_port_forward
|
||||
foreach_mapping scan_for_collisions
|
||||
foreach_mapping start_port_forward
|
||||
if ! foreach_mapping stop_port_forward; then
|
||||
err "No port-forward mappings found. Check ${CFG_FILE:-prole.cfg} or ${PORT_MAPPING_FILE_PATH:-port-mapping.cfg}."
|
||||
exit 1
|
||||
fi
|
||||
if ! foreach_mapping scan_for_collisions; then
|
||||
err "No port-forward mappings found. Check ${CFG_FILE:-prole.cfg} or ${PORT_MAPPING_FILE_PATH:-port-mapping.cfg}."
|
||||
exit 1
|
||||
fi
|
||||
if ! foreach_mapping start_port_forward; then
|
||||
err "No port-forward mappings started. Check ${CFG_FILE:-prole.cfg} or ${PORT_MAPPING_FILE_PATH:-port-mapping.cfg}."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
do_status() {
|
||||
@ -881,7 +1033,9 @@ do_status() {
|
||||
log ""
|
||||
|
||||
log "== Port-forward processes =="
|
||||
foreach_mapping status_one
|
||||
if ! foreach_mapping status_one; then
|
||||
log " (no port-forward mappings found)"
|
||||
fi
|
||||
log ""
|
||||
|
||||
log "== Quick k3d awareness checks (best-effort) =="
|
||||
|
||||
@ -4,7 +4,7 @@ set -euo pipefail
|
||||
|
||||
# init_registry.sh
|
||||
# Purpose:
|
||||
# - Deploy a Docker registry into Kubernetes
|
||||
# - Deploy ArgoCD into Kubernetes (replaces in-cluster Docker registry)
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
|
||||
@ -20,19 +20,22 @@ fi
|
||||
ACTION=""
|
||||
NAMESPACE_OVERRIDE=""
|
||||
|
||||
REGISTRY_NAME=${REGISTRY_NAME:-registry}
|
||||
|
||||
if [[ -d "$SCRIPT_DIR/../k8s/registry" ]]; then
|
||||
REGISTRY_MANIFEST_DIR="$SCRIPT_DIR/../k8s/registry"
|
||||
elif [[ -n "${PROLE_HOME:-}" && -d "$PROLE_HOME/k8s/registry" ]]; then
|
||||
REGISTRY_MANIFEST_DIR="$PROLE_HOME/k8s/registry"
|
||||
if [[ -d "$SCRIPT_DIR/../k8s/argocd" ]]; then
|
||||
ARGOCD_MANIFEST_DIR="$SCRIPT_DIR/../k8s/argocd"
|
||||
elif [[ -n "${PROLE_HOME:-}" && -d "$PROLE_HOME/k8s/argocd" ]]; then
|
||||
ARGOCD_MANIFEST_DIR="$PROLE_HOME/k8s/argocd"
|
||||
else
|
||||
REGISTRY_MANIFEST_DIR="$SCRIPT_DIR/../k8s/registry"
|
||||
ARGOCD_MANIFEST_DIR="$SCRIPT_DIR/../k8s/argocd"
|
||||
fi
|
||||
|
||||
ARGOCD_MANIFEST_FILE=${ARGOCD_MANIFEST_FILE:-"$ARGOCD_MANIFEST_DIR/install.yaml"}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: init_registry.sh [-n|--namespace NS] <start|stop|status|restart|initialize|update|reload>
|
||||
|
||||
Deploys ArgoCD into the target namespace (common services layer).
|
||||
Note: The local Docker registry (port 5000) is managed separately.
|
||||
EOF
|
||||
}
|
||||
|
||||
@ -77,44 +80,64 @@ while [[ $# -gt 0 ]]; do
|
||||
done
|
||||
|
||||
if [[ -n "$NAMESPACE_OVERRIDE" ]]; then
|
||||
NAMESPACE="$NAMESPACE_OVERRIDE"
|
||||
export NAMESPACE
|
||||
elif [[ -n "${REGISTRY_NAMESPACE:-}" ]]; then
|
||||
NAMESPACE="$REGISTRY_NAMESPACE"
|
||||
export NAMESPACE
|
||||
ARGOCD_NAMESPACE="$NAMESPACE_OVERRIDE"
|
||||
elif [[ -n "${ARGOCD_NAMESPACE:-}" ]]; then
|
||||
ARGOCD_NAMESPACE="$ARGOCD_NAMESPACE"
|
||||
elif [[ -n "${SERVICE_NAMESPACE:-}" ]]; then
|
||||
NAMESPACE="$SERVICE_NAMESPACE"
|
||||
export NAMESPACE
|
||||
elif [[ -z "${NAMESPACE:-}" ]]; then
|
||||
NAMESPACE="default"
|
||||
export NAMESPACE
|
||||
ARGOCD_NAMESPACE="$SERVICE_NAMESPACE"
|
||||
elif [[ -n "${NAMESPACE:-}" ]]; then
|
||||
ARGOCD_NAMESPACE="$NAMESPACE"
|
||||
else
|
||||
ARGOCD_NAMESPACE="default"
|
||||
fi
|
||||
|
||||
export ARGOCD_NAMESPACE
|
||||
export NAMESPACE="$ARGOCD_NAMESPACE"
|
||||
|
||||
ARGOCD_LABEL_SELECTOR=${ARGOCD_LABEL_SELECTOR:-"app.kubernetes.io/part-of=argocd"}
|
||||
ARGOCD_SERVER_SERVICE=${ARGOCD_SERVER_SERVICE:-argocd-server}
|
||||
ARGOCD_PORT_FORWARD_LOCAL=${ARGOCD_PORT_FORWARD_LOCAL:-8081}
|
||||
ARGOCD_PORT_FORWARD_REMOTE=${ARGOCD_PORT_FORWARD_REMOTE:-80}
|
||||
|
||||
ensure_tools() {
|
||||
command -v kubectl >/dev/null || { echo "Missing required tool: kubectl" >&2; exit 1; }
|
||||
}
|
||||
|
||||
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
|
||||
if ! kubectl get namespace "$ARGOCD_NAMESPACE" >/dev/null 2>&1; then
|
||||
echo "Creating namespace '$ARGOCD_NAMESPACE' ..."
|
||||
kubectl create namespace "$ARGOCD_NAMESPACE" >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
render_manifest() {
|
||||
if [[ ! -f "$ARGOCD_MANIFEST_FILE" ]]; then
|
||||
echo "ERROR: ArgoCD manifest not found: $ARGOCD_MANIFEST_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
sed "s|\\${ARGOCD_NAMESPACE}|$ARGOCD_NAMESPACE|g" "$ARGOCD_MANIFEST_FILE"
|
||||
}
|
||||
|
||||
apply_k8s() {
|
||||
echo "Applying registry manifest to namespace '$NAMESPACE' ..."
|
||||
prole_render_manifest "$REGISTRY_MANIFEST_DIR/deployment.yaml" | kubectl apply --validate=false -n "$NAMESPACE" -f -
|
||||
kubectl rollout status deploy/"$REGISTRY_NAME" -n "$NAMESPACE" --timeout=120s || true
|
||||
echo "Applying ArgoCD manifest to namespace '$ARGOCD_NAMESPACE' ..."
|
||||
render_manifest | kubectl apply --server-side --force-conflicts --field-manager=prole-installer --validate=false -n "$ARGOCD_NAMESPACE" -f -
|
||||
kubectl rollout status deploy/argocd-server -n "$ARGOCD_NAMESPACE" --timeout=180s || true
|
||||
kubectl rollout status deploy/argocd-repo-server -n "$ARGOCD_NAMESPACE" --timeout=180s || true
|
||||
kubectl rollout status deploy/argocd-dex-server -n "$ARGOCD_NAMESPACE" --timeout=180s || true
|
||||
kubectl rollout status deploy/argocd-applicationset-controller -n "$ARGOCD_NAMESPACE" --timeout=180s || true
|
||||
kubectl rollout status deploy/argocd-notifications-controller -n "$ARGOCD_NAMESPACE" --timeout=180s || true
|
||||
kubectl rollout status deploy/argocd-redis -n "$ARGOCD_NAMESPACE" --timeout=180s || true
|
||||
kubectl rollout status statefulset/argocd-application-controller -n "$ARGOCD_NAMESPACE" --timeout=180s || true
|
||||
}
|
||||
|
||||
delete_k8s() {
|
||||
echo "Removing registry resources from namespace '$NAMESPACE' ..."
|
||||
kubectl delete -n "$NAMESPACE" -f "$REGISTRY_MANIFEST_DIR/deployment.yaml" --ignore-not-found
|
||||
echo "Removing ArgoCD resources from namespace '$ARGOCD_NAMESPACE' ..."
|
||||
render_manifest | kubectl delete -n "$ARGOCD_NAMESPACE" -f - --ignore-not-found
|
||||
}
|
||||
|
||||
status_k8s() {
|
||||
kubectl -n "$NAMESPACE" get deploy "$REGISTRY_NAME" 2>/dev/null || true
|
||||
kubectl -n "$NAMESPACE" get svc "$REGISTRY_NAME" 2>/dev/null || true
|
||||
kubectl -n "$ARGOCD_NAMESPACE" get deploy,statefulset,svc -l "$ARGOCD_LABEL_SELECTOR" 2>/dev/null || true
|
||||
kubectl -n "$ARGOCD_NAMESPACE" get pods -l "$ARGOCD_LABEL_SELECTOR" 2>/dev/null || true
|
||||
}
|
||||
|
||||
case "${ACTION:-}" in
|
||||
@ -122,6 +145,8 @@ case "${ACTION:-}" in
|
||||
ensure_tools
|
||||
ensure_namespace
|
||||
apply_k8s
|
||||
prole_register_port_forward "argocd" "$ARGOCD_NAMESPACE" "svc/${ARGOCD_SERVER_SERVICE}" \
|
||||
"$ARGOCD_PORT_FORWARD_LOCAL" "$ARGOCD_PORT_FORWARD_REMOTE" "0.0.0.0" "TCP" "ArgoCD"
|
||||
;;
|
||||
stop)
|
||||
ensure_tools
|
||||
|
||||
@ -4,9 +4,9 @@ set -euo pipefail
|
||||
|
||||
# init_service_layer.sh
|
||||
# Purpose:
|
||||
# - Deploy the Prole service layer (registry, OpenBao, OpenTofu, Garage; Kerberos optional)
|
||||
# - Deploy the Prole service layer (ArgoCD, OpenBao, OpenTofu, Garage; Kerberos optional)
|
||||
# - Keep service-layer resources grouped in SERVICE_NAMESPACE
|
||||
# - Migrate service layer to a new namespace with best-effort registry data copy
|
||||
# - Migrate service layer to a new namespace
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
# shellcheck disable=SC1090
|
||||
@ -140,35 +140,6 @@ cleanup_openbao() {
|
||||
kubectl -n "$ns" delete configmap prole-krb5-conf --ignore-not-found >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
copy_registry_data() {
|
||||
local from_ns="$1"
|
||||
local to_ns="$2"
|
||||
local src_pod dst_pod
|
||||
|
||||
src_pod=$(kubectl -n "$from_ns" get pods -l app=registry -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)
|
||||
dst_pod=$(kubectl -n "$to_ns" get pods -l app=registry -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)
|
||||
if [[ -z "$src_pod" || -z "$dst_pod" ]]; then
|
||||
log "Registry pods not found for copy ($from_ns -> $to_ns); skipping."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! kubectl -n "$from_ns" exec "$src_pod" -- sh -c 'command -v tar >/dev/null 2>&1'; then
|
||||
log "Registry source pod lacks tar; skipping data copy."
|
||||
return 0
|
||||
fi
|
||||
if ! kubectl -n "$to_ns" exec "$dst_pod" -- sh -c 'command -v tar >/dev/null 2>&1'; then
|
||||
log "Registry destination pod lacks tar; skipping data copy."
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "Copying registry data from '$from_ns' to '$to_ns' (best-effort)..."
|
||||
if kubectl -n "$from_ns" exec "$src_pod" -- tar -C /var/lib/registry -cf - . \
|
||||
| kubectl -n "$to_ns" exec -i "$dst_pod" -- tar -C /var/lib/registry -xf -; then
|
||||
log "Registry data copy complete."
|
||||
else
|
||||
log "Registry data copy failed; continuing."
|
||||
fi
|
||||
}
|
||||
|
||||
deploy_service_layer() {
|
||||
local action="$1"
|
||||
@ -178,13 +149,13 @@ deploy_service_layer() {
|
||||
ensure_namespace "$ns"
|
||||
label_namespace "$ns"
|
||||
|
||||
local registry_action openbao_action opentofu_action garage_action kdc_action
|
||||
local argocd_action openbao_action opentofu_action garage_action kdc_action
|
||||
case "$action" in
|
||||
start|initialize|update|reload) registry_action="update" ;;
|
||||
restart) registry_action="restart" ;;
|
||||
stop) registry_action="stop" ;;
|
||||
status) registry_action="status" ;;
|
||||
*) registry_action="update" ;;
|
||||
start|initialize|update|reload) argocd_action="update" ;;
|
||||
restart) argocd_action="restart" ;;
|
||||
stop) argocd_action="stop" ;;
|
||||
status) argocd_action="status" ;;
|
||||
*) argocd_action="update" ;;
|
||||
esac
|
||||
|
||||
case "$action" in
|
||||
@ -214,8 +185,8 @@ deploy_service_layer() {
|
||||
*) kdc_action="update" ;;
|
||||
esac
|
||||
|
||||
REGISTRY_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \
|
||||
"$SCRIPT_DIR/init_registry.sh" -n "$ns" "$registry_action" || rc=$?
|
||||
ARGOCD_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \
|
||||
"$SCRIPT_DIR/init_registry.sh" -n "$ns" "$argocd_action" || rc=$?
|
||||
|
||||
if [[ "$action" == "stop" ]]; then
|
||||
cleanup_openbao "$ns" || true
|
||||
@ -241,7 +212,7 @@ deploy_service_layer() {
|
||||
cleanup_old_namespace() {
|
||||
local ns="$1"
|
||||
log "Cleaning up service layer in old namespace '$ns' ..."
|
||||
REGISTRY_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \
|
||||
ARGOCD_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \
|
||||
"$SCRIPT_DIR/init_registry.sh" -n "$ns" stop || true
|
||||
OPENTOFU_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \
|
||||
"$SCRIPT_DIR/init_opentofu.sh" -n "$ns" stop || true
|
||||
@ -275,7 +246,6 @@ migrate_service_layer() {
|
||||
|
||||
log "Migrating service layer from '$from_ns' to '$to_ns' ..."
|
||||
deploy_service_layer update "$to_ns"
|
||||
copy_registry_data "$from_ns" "$to_ns" || true
|
||||
cleanup_old_namespace "$from_ns"
|
||||
write_last_namespace "$to_ns"
|
||||
}
|
||||
|
||||
423
etc/repair_pipeline.sh
Executable file
423
etc/repair_pipeline.sh
Executable file
@ -0,0 +1,423 @@
|
||||
#!/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
|
||||
|
||||
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:-prole-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
|
||||
helm repo update >/dev/null 2>&1 || true
|
||||
helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard \
|
||||
--create-namespace --namespace "$ns"
|
||||
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
|
||||
helm upgrade --install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard \
|
||||
--create-namespace --namespace "$ns"
|
||||
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"
|
||||
"$SCRIPT_DIR/init_registry.sh" -n "$ns" stop || true
|
||||
"$SCRIPT_DIR/init_registry.sh" -n "$ns" 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 "$SERVICE_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
|
||||
@ -9,7 +9,7 @@ usage() {
|
||||
cat <<EOF
|
||||
Usage: status_common_services.sh [-n|--namespace NS] [-k|--kerberos]
|
||||
|
||||
Checks common infrastructure services (Docker registry, OpenBao, OpenTofu, Garage).
|
||||
Checks common infrastructure services (ArgoCD, OpenBao, OpenTofu, Garage).
|
||||
Use -k to include the Prole KDC (auth) checks.
|
||||
EOF
|
||||
}
|
||||
@ -76,24 +76,24 @@ run_cmd() {
|
||||
|
||||
echo "== Services =="
|
||||
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
||||
run_cmd kubectl -n "$NS" get svc registry openbao opentofu garage auth
|
||||
run_cmd kubectl -n "$NS" get svc argocd-server openbao opentofu garage auth
|
||||
else
|
||||
run_cmd kubectl -n "$NS" get svc registry openbao opentofu garage
|
||||
run_cmd kubectl -n "$NS" get svc argocd-server openbao opentofu garage
|
||||
fi
|
||||
|
||||
echo "== Workloads =="
|
||||
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
||||
run_cmd kubectl -n "$NS" get deploy registry opentofu auth
|
||||
run_cmd kubectl -n "$NS" get deploy argocd-server argocd-repo-server argocd-dex-server argocd-applicationset-controller argocd-notifications-controller argocd-redis opentofu auth
|
||||
else
|
||||
run_cmd kubectl -n "$NS" get deploy registry opentofu
|
||||
run_cmd kubectl -n "$NS" get deploy argocd-server argocd-repo-server argocd-dex-server argocd-applicationset-controller argocd-notifications-controller argocd-redis opentofu
|
||||
fi
|
||||
run_cmd kubectl -n "$NS" get statefulset openbao garage
|
||||
run_cmd kubectl -n "$NS" get statefulset argocd-application-controller openbao garage
|
||||
|
||||
echo "== Pods =="
|
||||
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
||||
run_cmd kubectl -n "$NS" get pods | grep -Ei "registry|openbao|opentofu|garage|auth" || true
|
||||
run_cmd kubectl -n "$NS" get pods | grep -Ei "argocd|openbao|opentofu|garage|auth" || true
|
||||
else
|
||||
run_cmd kubectl -n "$NS" get pods | grep -Ei "registry|openbao|opentofu|garage" || true
|
||||
run_cmd kubectl -n "$NS" get pods | grep -Ei "argocd|openbao|opentofu|garage" || true
|
||||
fi
|
||||
|
||||
echo "== Health Check =="
|
||||
@ -161,7 +161,7 @@ check_resource() {
|
||||
fi
|
||||
}
|
||||
|
||||
check_resource svc registry
|
||||
check_resource svc argocd-server
|
||||
check_resource svc openbao
|
||||
check_resource svc opentofu
|
||||
check_resource svc garage
|
||||
@ -169,17 +169,23 @@ if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
||||
check_resource svc auth
|
||||
fi
|
||||
|
||||
check_resource deploy registry
|
||||
check_resource deploy argocd-server
|
||||
check_resource deploy argocd-repo-server
|
||||
check_resource deploy argocd-dex-server
|
||||
check_resource deploy argocd-applicationset-controller
|
||||
check_resource deploy argocd-notifications-controller
|
||||
check_resource deploy argocd-redis
|
||||
check_resource deploy opentofu
|
||||
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
||||
check_resource deploy auth
|
||||
fi
|
||||
check_resource statefulset argocd-application-controller
|
||||
check_resource statefulset openbao
|
||||
check_resource statefulset garage
|
||||
|
||||
pod_filter="registry|openbao|opentofu|garage"
|
||||
pod_filter="argocd|openbao|opentofu|garage"
|
||||
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
||||
pod_filter="registry|openbao|opentofu|garage|auth"
|
||||
pod_filter="argocd|openbao|opentofu|garage|auth"
|
||||
fi
|
||||
|
||||
analyze_pods
|
||||
@ -200,7 +206,7 @@ fi
|
||||
if [ $blocked -gt 0 ]; then
|
||||
repairable=()
|
||||
fail_all=()
|
||||
for comp in registry openbao opentofu garage auth; do
|
||||
for comp in argocd openbao opentofu garage auth; do
|
||||
if [[ "$comp" == "auth" && "$ENABLE_KERBEROS" != "1" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
442
install.py
442
install.py
@ -1632,6 +1632,9 @@ class ProleInstaller:
|
||||
self._managed_kubeconfig = None
|
||||
self._kong_last_repair_at = 0.0
|
||||
self._kong_repair_cooldown_s = 120
|
||||
self._repair_last_run_at = 0.0
|
||||
self._repair_cooldown_s = 600
|
||||
self._repair_inflight = False
|
||||
_ensure_ansible_vault_credentials(prompt_ui=True, root=root)
|
||||
self._action_flags = {}
|
||||
self.root.title("Prole Database Installer")
|
||||
@ -3953,8 +3956,8 @@ class ProleInstaller:
|
||||
# messagebox.showerror("Invalid Port", "Please enter a valid numeric port.")
|
||||
# return
|
||||
|
||||
# Determine path: prole/conf/prole.cfg
|
||||
# If PROLE_CONF is set, use it. Otherwise fallback to PROJECT_ROOT/prole/conf
|
||||
# Determine path: conf/prole.cfg
|
||||
# If PROLE_CONF is set, use it. Otherwise fallback to PROJECT_ROOT/conf
|
||||
if self._cfg_path_override is not None:
|
||||
cfg_path = self._cfg_path_override
|
||||
if cfg_path.is_dir():
|
||||
@ -3967,7 +3970,8 @@ class ProleInstaller:
|
||||
if prole_conf:
|
||||
conf_dir = Path(prole_conf).expanduser()
|
||||
else:
|
||||
conf_dir = PROJECT_ROOT / 'prole' / 'conf'
|
||||
conf_dir = PROJECT_ROOT / 'conf'
|
||||
os.environ.setdefault('PROLE_CONF', str(conf_dir))
|
||||
cfg_path = conf_dir / 'prole.cfg'
|
||||
|
||||
conf_dir.mkdir(parents=True, exist_ok=True)
|
||||
@ -4487,6 +4491,8 @@ class ProleInstaller:
|
||||
combo = getattr(self, '_ollama_model_combo', None)
|
||||
if not combo:
|
||||
return
|
||||
if getattr(self, '_refreshing_ollama_table', False):
|
||||
return
|
||||
values = models or []
|
||||
try:
|
||||
combo.configure(values=values)
|
||||
@ -4544,6 +4550,13 @@ class ProleInstaller:
|
||||
if getattr(self, '_refreshing_ollama_table', False):
|
||||
return
|
||||
self._refreshing_ollama_table = True
|
||||
self._ollama_model_options = {}
|
||||
combo = getattr(self, '_ollama_model_combo', None)
|
||||
if combo:
|
||||
try:
|
||||
combo.configure(values=[], state='disabled')
|
||||
except Exception:
|
||||
pass
|
||||
if getattr(self, '_ollama_status_var', None):
|
||||
self._ollama_status_var.set("Scanning...")
|
||||
|
||||
@ -4587,8 +4600,16 @@ class ProleInstaller:
|
||||
notice = f"Scan error: {e}"
|
||||
self.safe_after(lambda: self._ollama_status_var.set("Scan failed") if getattr(self, '_ollama_status_var', None) else None)
|
||||
finally:
|
||||
self.safe_after(lambda: self._update_ollama_table(rows, notice))
|
||||
self._refreshing_ollama_table = False
|
||||
def finish():
|
||||
self._refreshing_ollama_table = False
|
||||
self._update_ollama_table(rows, notice)
|
||||
combo = getattr(self, '_ollama_model_combo', None)
|
||||
if combo:
|
||||
try:
|
||||
combo.configure(state='normal')
|
||||
except Exception:
|
||||
pass
|
||||
self.safe_after(finish)
|
||||
|
||||
threading.Thread(target=worker, daemon=True).start()
|
||||
|
||||
@ -4696,6 +4717,8 @@ class ProleInstaller:
|
||||
self.bg_canvas.itemconfig(preview_item, text=text)
|
||||
except Exception:
|
||||
pass
|
||||
if getattr(self, '_refreshing_ollama_table', False):
|
||||
return
|
||||
current_key = self._ollama_current_key()
|
||||
models = self._ollama_model_options.get(current_key, [])
|
||||
if models:
|
||||
@ -5596,7 +5619,7 @@ class ProleInstaller:
|
||||
font=('SF Pro Text', 18), anchor='ne')
|
||||
|
||||
self._render_title('Cluster Environment', y=150)
|
||||
self._render_paragraph('Select a cluster environment and ensure the cluster (k3d/k3s/prod), OpenBao, and required services are running.', y=200)
|
||||
self._render_paragraph('Select a cluster environment and ensure the cluster is running and common services can be deployed.', y=200)
|
||||
|
||||
# Cluster Selection (Radio Buttons)
|
||||
x_label = 48
|
||||
@ -5775,23 +5798,15 @@ class ProleInstaller:
|
||||
ui.canvas_text(self, x_label + 20, y, '(Used by etc/deploy_pipeline.sh --mode gcp)', fill='#6e6e73', font=('SF Pro Text', 10))
|
||||
y += 30
|
||||
|
||||
# Docker/K3D Status (only if dev)
|
||||
# Cluster Status (only if dev)
|
||||
if selected_env_key == 'dev':
|
||||
y += 10
|
||||
self.docker_status_label = ui.canvas_text(self, x_label, y, 'Docker: Checking...', fill='#6e6e73', font=('SF Pro Text', 12))
|
||||
self._canvas_items.append(self.docker_status_label)
|
||||
|
||||
y += 30
|
||||
self.k3d_status_label = ui.canvas_text(self, x_label, y, 'Cluster: Checking...', fill='#6e6e73', font=('SF Pro Text', 12))
|
||||
self._canvas_items.append(self.k3d_status_label)
|
||||
|
||||
y += 30
|
||||
self.registry_status_label = ui.canvas_text(self, x_label, y, 'Local Registry: Checking...', fill='#6e6e73', font=('SF Pro Text', 12))
|
||||
self._canvas_items.append(self.registry_status_label)
|
||||
|
||||
y += 30
|
||||
self.openbao_status_label = ui.canvas_text(self, x_label, y, 'OpenBao: Checking...', fill='#6e6e73', font=('SF Pro Text', 12))
|
||||
self._canvas_items.append(self.openbao_status_label)
|
||||
self.common_services_status_label = ui.canvas_text(self, x_label, y, 'Common Services: Checking...', fill='#6e6e73', font=('SF Pro Text', 12))
|
||||
self._canvas_items.append(self.common_services_status_label)
|
||||
|
||||
y += 30
|
||||
self._cluster_env_message_label = ui.canvas_text(self, x_label, y, '', fill='#34c759', font=('SF Pro Text', 11))
|
||||
@ -5883,9 +5898,9 @@ class ProleInstaller:
|
||||
rc_ns, out_ns = self._run_cmd_capture(base_cmd + ['get', 'ns', ns, '-o', 'name'], timeout=6)
|
||||
if rc_ns != 0 or ns not in (out_ns or ''):
|
||||
return {
|
||||
'ok': True,
|
||||
'msg': 'Dashboard (Kong): Not installed',
|
||||
'fill': '#6e6e73',
|
||||
'ok': False,
|
||||
'msg': 'Dashboard (Kong): Missing',
|
||||
'fill': '#ff9f0a',
|
||||
'reset_pods': [],
|
||||
}
|
||||
|
||||
@ -5916,9 +5931,9 @@ class ProleInstaller:
|
||||
|
||||
if not kong_pods:
|
||||
return {
|
||||
'ok': True,
|
||||
'msg': 'Dashboard (Kong): Not installed',
|
||||
'fill': '#6e6e73',
|
||||
'ok': False,
|
||||
'msg': 'Dashboard (Kong): Missing',
|
||||
'fill': '#ff9f0a',
|
||||
'reset_pods': [],
|
||||
}
|
||||
|
||||
@ -5969,6 +5984,79 @@ class ProleInstaller:
|
||||
pass
|
||||
self.safe_after(_clear, delay=clear_after_ms)
|
||||
|
||||
def _authority_context_missing(self) -> bool:
|
||||
"""Detect missing authority Docker context when Kerberos is enabled."""
|
||||
try:
|
||||
if not self.kerberos_enabled.get():
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
candidates = []
|
||||
env_home = (os.environ.get('PROLE_HOME') or '').strip()
|
||||
if env_home:
|
||||
candidates.append(Path(env_home))
|
||||
candidates.append(PROJECT_ROOT)
|
||||
|
||||
for base in candidates:
|
||||
try:
|
||||
if (base / 'authority').is_dir():
|
||||
return False
|
||||
if (base / 'prole' / 'authority').is_dir():
|
||||
return False
|
||||
except Exception:
|
||||
continue
|
||||
return True
|
||||
|
||||
def _maybe_run_repair_pipeline(self, status: dict, kong_status: dict | None):
|
||||
"""Run repair pipeline when cluster is ready and anomalies are detected."""
|
||||
if not status.get('cluster_ok'):
|
||||
return
|
||||
|
||||
anomalies = []
|
||||
if kong_status and not kong_status.get('ok', True):
|
||||
anomalies.append('dashboard')
|
||||
if self._authority_context_missing():
|
||||
anomalies.append('authority')
|
||||
|
||||
if not anomalies:
|
||||
return
|
||||
|
||||
now = time.time()
|
||||
if self._repair_inflight:
|
||||
return
|
||||
if now - self._repair_last_run_at < self._repair_cooldown_s:
|
||||
return
|
||||
|
||||
self._repair_last_run_at = now
|
||||
self._repair_inflight = True
|
||||
|
||||
def worker():
|
||||
try:
|
||||
env_key = status.get('env') or self._cluster_env_key()
|
||||
if env_key == 'service':
|
||||
ns = self._get_service_namespace()
|
||||
else:
|
||||
ns = (self.db_namespace.get() or '').strip() or 'default'
|
||||
env = self._script_env_for_namespace(ns)
|
||||
if env_key == 'service':
|
||||
env["PROLE_MODE"] = "k3s"
|
||||
elif env_key == 'dev':
|
||||
env["PROLE_MODE"] = "k3d"
|
||||
self._set_cluster_env_message("Repair pipeline started", '#34c759', clear_after_ms=3000)
|
||||
self.controller.run_script(
|
||||
"repair_pipeline.sh",
|
||||
args=["-n", ns],
|
||||
env=env,
|
||||
)
|
||||
self._set_cluster_env_message("Repair pipeline complete", '#34c759', clear_after_ms=3000)
|
||||
except Exception as e:
|
||||
self._set_cluster_env_message(f"Repair pipeline failed: {e}", '#ff3b30', clear_after_ms=6000)
|
||||
finally:
|
||||
self._repair_inflight = False
|
||||
|
||||
threading.Thread(target=worker, daemon=True).start()
|
||||
|
||||
def _check_opentofu_health(self) -> bool:
|
||||
"""Check OpenTofu readiness in the selected namespace."""
|
||||
try:
|
||||
@ -6115,7 +6203,7 @@ class ProleInstaller:
|
||||
threading.Thread(target=worker, daemon=True).start()
|
||||
|
||||
def _deploy_k3s_services(self):
|
||||
"""Deploy common services (registry/OpenBao/OpenTofu) to remote k3s cluster."""
|
||||
"""Deploy common services (ArgoCD/OpenBao/OpenTofu/Garage) to remote k3s cluster."""
|
||||
def _deploy():
|
||||
console = self._k3s_service_deploy_console
|
||||
if console:
|
||||
@ -6228,39 +6316,6 @@ class ProleInstaller:
|
||||
def _cluster_status_snapshot(self) -> dict:
|
||||
env = self._cluster_env_key()
|
||||
|
||||
docker_ok = self.controller.check_docker_running()
|
||||
docker_msg = 'Docker: Running' if docker_ok else 'Docker: Not running'
|
||||
docker_fill = '#34c759' if docker_ok else '#ff3b30'
|
||||
|
||||
openbao_ok = self._check_openbao_health()
|
||||
openbao_msg = 'OpenBao: Running' if openbao_ok else 'OpenBao: Not reachable'
|
||||
openbao_fill = '#34c759' if openbao_ok else '#ff9f0a'
|
||||
|
||||
registry_ok = False
|
||||
registry_msg = ''
|
||||
registry_fill = '#6e6e73'
|
||||
if env == 'dev':
|
||||
if docker_ok:
|
||||
try:
|
||||
ps = subprocess.run(['docker', 'ps', '--format', '{{.Names}} {{.Image}}'], capture_output=True, text=True)
|
||||
for line in (ps.stdout or '').splitlines():
|
||||
parts = line.split()
|
||||
if not parts:
|
||||
continue
|
||||
name = parts[0]
|
||||
image = parts[1] if len(parts) > 1 else ''
|
||||
if name == 'k3d-prole-registry' or image.startswith('registry:2'):
|
||||
registry_ok = True
|
||||
break
|
||||
except Exception:
|
||||
registry_ok = False
|
||||
registry_msg = 'Local Registry: Running' if registry_ok else 'Local Registry: Not running'
|
||||
registry_fill = '#34c759' if registry_ok else '#ff9f0a'
|
||||
else:
|
||||
registry_ok = True
|
||||
registry_msg = 'Local Registry: Not required'
|
||||
registry_fill = '#6e6e73'
|
||||
|
||||
cluster_ok = False
|
||||
if env == 'dev':
|
||||
cluster_name = "prole-dev-cluster"
|
||||
@ -6274,33 +6329,24 @@ class ProleInstaller:
|
||||
cluster_ok, cluster_msg = self._check_k8s_cluster(env)
|
||||
cluster_fill = '#34c759' if cluster_ok else '#ff9f0a'
|
||||
|
||||
common_ok = cluster_ok
|
||||
common_msg = 'Common Services: Ready to deploy' if common_ok else 'Common Services: Not ready'
|
||||
common_fill = '#34c759' if common_ok else '#ff9f0a'
|
||||
|
||||
return {
|
||||
'env': env,
|
||||
'docker_ok': docker_ok,
|
||||
'docker_msg': docker_msg,
|
||||
'docker_fill': docker_fill,
|
||||
'cluster_ok': cluster_ok,
|
||||
'cluster_msg': cluster_msg,
|
||||
'cluster_fill': cluster_fill,
|
||||
'registry_ok': registry_ok,
|
||||
'registry_msg': registry_msg,
|
||||
'registry_fill': registry_fill,
|
||||
'openbao_ok': openbao_ok,
|
||||
'openbao_msg': openbao_msg,
|
||||
'openbao_fill': openbao_fill,
|
||||
'common_ok': common_ok,
|
||||
'common_msg': common_msg,
|
||||
'common_fill': common_fill,
|
||||
}
|
||||
|
||||
def _cluster_ready_for_navigation(self) -> bool:
|
||||
status = self._cluster_status_snapshot()
|
||||
env = status['env']
|
||||
|
||||
if env == 'dev' and not status['docker_ok']:
|
||||
try:
|
||||
messagebox.showerror('Docker', 'Docker is not running. Please start Docker and try again.')
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
if not status['cluster_ok']:
|
||||
try:
|
||||
messagebox.showerror('Cluster', 'Cluster is not reachable. Please verify your cluster and try again.')
|
||||
@ -6308,48 +6354,6 @@ class ProleInstaller:
|
||||
pass
|
||||
return False
|
||||
|
||||
if env == 'dev' and not status['registry_ok']:
|
||||
try:
|
||||
messagebox.showerror('Registry', 'Local registry is not running. Start the registry and try again.')
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
if not status['openbao_ok']:
|
||||
if env == 'dev':
|
||||
# Attempt to start OpenBao locally
|
||||
if status['docker_ok']:
|
||||
env_vars = self._script_env_for_namespace((self.db_namespace.get() or '').strip())
|
||||
env_vars["PROLE_DB_USER"] = self.db_username.get().strip()
|
||||
env_vars["AT_REST_ENCRYPTION_ENABLED"] = _bool_str(self.at_rest_encryption_enabled.get())
|
||||
rc_openbao = self.controller.run_script("init_openbao.sh", args=["start"], env=env_vars)
|
||||
if rc_openbao != 0:
|
||||
try:
|
||||
messagebox.showerror('OpenBao', f'Failed to start OpenBao (code {rc_openbao}).')
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
# Re-check after start
|
||||
status = self._cluster_status_snapshot()
|
||||
if not status['openbao_ok']:
|
||||
try:
|
||||
messagebox.showerror('OpenBao', 'OpenBao is not reachable after startup.')
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
messagebox.showerror('OpenBao', 'OpenBao is not reachable and Docker is not running.')
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
messagebox.showerror('OpenBao', 'OpenBao is not reachable for the selected cluster.')
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
# Refresh status display for any changes
|
||||
self.check_cluster_status_async()
|
||||
return True
|
||||
@ -6387,15 +6391,17 @@ class ProleInstaller:
|
||||
else:
|
||||
self._set_cluster_env_message("Execute Actions (REPAIR): none needed", '#34c759', clear_after_ms=1500)
|
||||
|
||||
# Run the repair pipeline if anomalies are detected on a ready cluster
|
||||
try:
|
||||
self._maybe_run_repair_pipeline(status, kong_status)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def update_ui():
|
||||
if hasattr(self, 'docker_status_label'):
|
||||
self.bg_canvas.itemconfig(self.docker_status_label, text=status['docker_msg'], fill=status['docker_fill'])
|
||||
if hasattr(self, 'k3d_status_label'):
|
||||
self.bg_canvas.itemconfig(self.k3d_status_label, text=status['cluster_msg'], fill=status['cluster_fill'])
|
||||
if hasattr(self, 'registry_status_label'):
|
||||
self.bg_canvas.itemconfig(self.registry_status_label, text=status['registry_msg'], fill=status['registry_fill'])
|
||||
if hasattr(self, 'openbao_status_label'):
|
||||
self.bg_canvas.itemconfig(self.openbao_status_label, text=status['openbao_msg'], fill=status['openbao_fill'])
|
||||
if hasattr(self, 'common_services_status_label'):
|
||||
self.bg_canvas.itemconfig(self.common_services_status_label, text=status['common_msg'], fill=status['common_fill'])
|
||||
if hasattr(self, '_init_cluster_button'):
|
||||
try:
|
||||
self._init_cluster_button.configure(text='Save')
|
||||
@ -6461,25 +6467,7 @@ class ProleInstaller:
|
||||
self.root.after(0, lambda: messagebox.showerror('Docker', 'Could not start Docker. Please start it manually.'))
|
||||
return
|
||||
|
||||
# 2. Ensure OpenBao container is running (local-only)
|
||||
env = self._script_env_for_namespace((self.db_namespace.get() or '').strip())
|
||||
env["PROLE_DB_USER"] = self.db_username.get().strip()
|
||||
env["AT_REST_ENCRYPTION_ENABLED"] = _bool_str(self.at_rest_encryption_enabled.get())
|
||||
rc_openbao = self.controller.run_script("init_openbao.sh", args=["start"], env=env)
|
||||
if rc_openbao != 0:
|
||||
self.root.after(0, lambda: messagebox.showerror('OpenBao', f'Failed to start OpenBao (code {rc_openbao}).'))
|
||||
return
|
||||
|
||||
# 3. Ensure local registry is available before cluster creation (dev only)
|
||||
try:
|
||||
reg_info = self.ensure_local_registry_available()
|
||||
except Exception:
|
||||
reg_info = None
|
||||
if not reg_info:
|
||||
self.root.after(0, lambda: messagebox.showerror('Registry', 'Local registry is not running. Please start the registry and try again.'))
|
||||
return
|
||||
|
||||
# 4. Manage or verify cluster
|
||||
# 2. Manage or verify cluster
|
||||
cluster_name = 'prole-dev-cluster'
|
||||
res = subprocess.run(['k3d', 'cluster', 'list', '--no-headers'], capture_output=True, text=True)
|
||||
if cluster_name not in (res.stdout or ''):
|
||||
@ -6716,7 +6704,7 @@ class ProleInstaller:
|
||||
self._overlay_widgets.append(owner_entry)
|
||||
|
||||
y += 42
|
||||
self._canvas_items.append(ui.canvas_text(self, x_label, y, 'Root Password:', fill='black', font=('SF Pro Text', 12, 'bold')))
|
||||
self._canvas_items.append(ui.canvas_text(self, x_label, y, 'Master Password:', fill='black', font=('SF Pro Text', 12, 'bold')))
|
||||
# Use tk.Entry on canvas
|
||||
p1 = tk.Entry(self.bg_canvas, textvariable=self.db_password, show='*', bg='white', fg='black',
|
||||
insertbackground='black', highlightbackground='#CCCCCC', highlightthickness=1,
|
||||
@ -6895,20 +6883,26 @@ class ProleInstaller:
|
||||
# Output Console
|
||||
self._cnpg_deploy_console = self._create_console_output(y=260, title="Deployment Output", width=900, height=520)
|
||||
|
||||
# Deployment mode selector
|
||||
mode_label = ui.canvas_text(self, 48, 782, "Mode", fill='#6e6e73', font=('SF Pro Text', 10, 'bold'))
|
||||
self._canvas_items.append(mode_label)
|
||||
mode_values = ['prole-dev-cluster', 'prole-service-cluster', 'prole-prod-cluster']
|
||||
mode_combo = ttk.Combobox(self.bg_canvas, textvariable=self.deploy_target, values=mode_values, state='readonly', width=24)
|
||||
mode_combo_window = self.bg_canvas.create_window(48, 800, window=mode_combo, anchor='nw', width=180)
|
||||
self._canvas_items.append(mode_combo_window)
|
||||
self._overlay_widgets.append(mode_combo)
|
||||
|
||||
# Use tk.Button
|
||||
self._cnpg_deploy_button = tk.Button(self.bg_canvas, text='Run Deployment', command=self.run_cnpg_deploy,
|
||||
bg='#F5F5DC', fg='black', activebackground='#E5E5D5',
|
||||
highlightbackground='#F5F5DC', highlightthickness=0,
|
||||
relief='flat', font=('SF Pro Text', 11), padx=16, pady=8)
|
||||
self._cnpg_deploy_button.update_idletasks()
|
||||
deploy_btn_height = self._cnpg_deploy_button.winfo_reqheight() or 32
|
||||
|
||||
# Deployment mode selector
|
||||
mode_label = ui.canvas_text(self, 48, 782, "Mode", fill='#6e6e73', font=('SF Pro Text', 10, 'bold'))
|
||||
self._canvas_items.append(mode_label)
|
||||
mode_values = ['prole-dev-cluster', 'prole-service-cluster', 'prole-prod-cluster']
|
||||
mode_frame = tk.Frame(self.bg_canvas, bg='#F5F5DC', width=180, height=deploy_btn_height)
|
||||
mode_frame.pack_propagate(False)
|
||||
mode_combo = ttk.Combobox(mode_frame, textvariable=self.deploy_target, values=mode_values, state='readonly', width=24)
|
||||
mode_combo.pack(fill='both', expand=True)
|
||||
mode_combo_window = self.bg_canvas.create_window(48, 800, window=mode_frame, anchor='nw', width=180, height=deploy_btn_height)
|
||||
self._canvas_items.append(mode_combo_window)
|
||||
self._overlay_widgets.append(mode_frame)
|
||||
|
||||
btn_window = self.bg_canvas.create_window(240, 800, window=self._cnpg_deploy_button, anchor='nw', width=180)
|
||||
self._canvas_items.append(btn_window)
|
||||
self._overlay_widgets.append(self._cnpg_deploy_button)
|
||||
@ -6922,9 +6916,20 @@ class ProleInstaller:
|
||||
self._canvas_items.append(rollout_btn_window)
|
||||
self._overlay_widgets.append(self._cnpg_rollout_button)
|
||||
|
||||
# Status Label
|
||||
self._cnpg_deploy_status_label = ui.canvas_text(self, 600, 812, "", fill='black', font=('SF Pro Text', 12))
|
||||
# Save Deployment Button (moved from Post Install)
|
||||
self._save_deployment_button = tk.Button(self.bg_canvas, text='Save Deployment', command=self.run_final_deployment,
|
||||
bg='#F5F5DC', fg='black', activebackground='#E5E5D5',
|
||||
highlightbackground='#F5F5DC', highlightthickness=0,
|
||||
relief='flat', font=('SF Pro Text', 11), padx=16, pady=8)
|
||||
save_btn_window = self.bg_canvas.create_window(600, 800, window=self._save_deployment_button, anchor='nw', width=180)
|
||||
self._canvas_items.append(save_btn_window)
|
||||
self._overlay_widgets.append(self._save_deployment_button)
|
||||
|
||||
# Status Labels (below the buttons row to avoid overlap)
|
||||
self._cnpg_deploy_status_label = ui.canvas_text(self, 48, 840, "", fill='black', font=('SF Pro Text', 12))
|
||||
self._canvas_items.append(self._cnpg_deploy_status_label)
|
||||
self._save_deployment_status_label = ui.canvas_text(self, 600, 840, "", fill='black', font=('SF Pro Text', 12))
|
||||
self._canvas_items.append(self._save_deployment_status_label)
|
||||
|
||||
def run_cnpg_deploy(self):
|
||||
self._action_flags['init_cnpg_deploy.run_deploy'] = True
|
||||
@ -9177,6 +9182,30 @@ echo "-------------------------------------------------------------------";
|
||||
|
||||
# ---------------- Build Summary page ----------------
|
||||
def run_final_deployment(self):
|
||||
initial_dir = str(self._resolve_env_dir('PROLE_DATA', 'data'))
|
||||
try:
|
||||
if not Path(initial_dir).exists():
|
||||
initial_dir = str(Path.home())
|
||||
except Exception:
|
||||
initial_dir = str(Path.home())
|
||||
|
||||
export_base = filedialog.askdirectory(
|
||||
initialdir=initial_dir,
|
||||
title="Select deployment export directory"
|
||||
)
|
||||
if not export_base:
|
||||
self.safe_after(lambda: self.bg_canvas.itemconfig(
|
||||
self._save_deployment_status_label,
|
||||
text="Save canceled.",
|
||||
fill='#6e6e73'
|
||||
) if hasattr(self, '_save_deployment_status_label') and self.bg_canvas.winfo_exists() else None)
|
||||
return
|
||||
|
||||
export_base = str(Path(export_base).expanduser())
|
||||
docker_export_dir = str(Path(export_base) / "docker-import")
|
||||
helm_export_dir = str(Path(export_base) / "helm-chart")
|
||||
kustomize_export_dir = str(Path(export_base) / "kustomize")
|
||||
|
||||
def worker():
|
||||
self.safe_after(lambda: self._save_deployment_button.configure(state='disabled') if hasattr(self, '_save_deployment_button') and self._save_deployment_button.winfo_exists() else None)
|
||||
self.safe_after(lambda: self.bg_canvas.itemconfig(self._save_deployment_status_label, text="Saving deployment...", fill='blue') if hasattr(self, '_save_deployment_status_label') and self.bg_canvas.winfo_exists() else None)
|
||||
@ -9187,14 +9216,18 @@ echo "-------------------------------------------------------------------";
|
||||
|
||||
env = os.environ.copy()
|
||||
env["PROLE_HOME"] = str(PROJECT_ROOT)
|
||||
import_dir = self.docker_import_dir.get().strip()
|
||||
if import_dir:
|
||||
env["DOCKER_IMPORT_DIR"] = import_dir
|
||||
env["DOCKER_IMPORT_DIR"] = docker_export_dir
|
||||
env["HELM_CHART_DIR"] = helm_export_dir
|
||||
env["KUSTOMIZE_DIR"] = kustomize_export_dir
|
||||
|
||||
console = getattr(self, 'install_consoles', {}).get(script_name)
|
||||
if console:
|
||||
console.clear()
|
||||
console.write(f"Running {script_name} --docker-export...\n")
|
||||
console.write("Saving deployment artifacts...\n")
|
||||
console.write(f"Export base: {export_base}\n")
|
||||
console.write(f"Docker images: {docker_export_dir}\n")
|
||||
console.write(f"Helm chart: {helm_export_dir}\n")
|
||||
console.write(f"Kustomize: {kustomize_export_dir}\n\n")
|
||||
|
||||
def _on_line(line):
|
||||
if console:
|
||||
@ -9202,7 +9235,7 @@ echo "-------------------------------------------------------------------";
|
||||
|
||||
rc = self.controller.run_script(
|
||||
script_name,
|
||||
args=['--docker-export'],
|
||||
args=['--docker-export', '--helm-chart', '--kustomize', '--output-dir', export_base],
|
||||
env=env,
|
||||
on_line=_on_line
|
||||
)
|
||||
@ -9385,20 +9418,9 @@ echo "-------------------------------------------------------------------";
|
||||
self._canvas_items.append(bao_btn_window)
|
||||
self._overlay_widgets.append(self._build_a_bao_button)
|
||||
|
||||
# Save Deployment Button
|
||||
self._save_deployment_button = tk.Button(self.bg_canvas, text='Save Deployment', command=self.run_final_deployment,
|
||||
bg='#F5F5DC', fg='black', activebackground='#E5E5D5',
|
||||
highlightbackground='#F5F5DC', highlightthickness=0,
|
||||
relief='flat', font=('SF Pro Text', 11), padx=16, pady=8)
|
||||
btn_window = self.bg_canvas.create_window(240, 760, window=self._save_deployment_button, anchor='nw', width=180)
|
||||
self._canvas_items.append(btn_window)
|
||||
self._overlay_widgets.append(self._save_deployment_button)
|
||||
|
||||
# Status Labels
|
||||
# Status Label
|
||||
self._build_a_bao_status_label = ui.canvas_text(self, 48, 802, "", fill='black', font=('SF Pro Text', 12))
|
||||
self._canvas_items.append(self._build_a_bao_status_label)
|
||||
self._save_deployment_status_label = ui.canvas_text(self, 240, 802, "", fill='black', font=('SF Pro Text', 12))
|
||||
self._canvas_items.append(self._save_deployment_status_label)
|
||||
|
||||
def _render_build_summary_page(self):
|
||||
# Ensure slide_area is visible for the build log console
|
||||
@ -11023,6 +11045,7 @@ class ProleSilentInstaller:
|
||||
self._cnpg_success = False
|
||||
self._managed_kubeconfig = None
|
||||
self.docker_import_dir = None
|
||||
self._repair_ran = False
|
||||
|
||||
# ---------------- Logging helpers ----------------
|
||||
def log(self, msg: str):
|
||||
@ -11041,7 +11064,7 @@ class ProleSilentInstaller:
|
||||
prole_conf = os.environ.get('PROLE_CONF')
|
||||
if prole_conf:
|
||||
return Path(_expand_path(prole_conf)) / 'prole.cfg'
|
||||
return self.project_root / 'prole' / 'conf' / 'prole.cfg'
|
||||
return self.project_root / 'conf' / 'prole.cfg'
|
||||
|
||||
def _load_inputs_from_cfg(self) -> dict:
|
||||
cfg = configparser.ConfigParser(interpolation=None)
|
||||
@ -11488,6 +11511,77 @@ class ProleSilentInstaller:
|
||||
|
||||
return env
|
||||
|
||||
def _authority_context_missing(self) -> bool:
|
||||
enabled = self._get_input_bool('kerberos_config.enabled', False) or \
|
||||
self._get_input_bool('init_cluster.kerberos_enabled', False)
|
||||
if not enabled:
|
||||
return False
|
||||
|
||||
candidates = []
|
||||
env_home = (os.environ.get('PROLE_HOME') or '').strip()
|
||||
if env_home:
|
||||
candidates.append(Path(env_home))
|
||||
candidates.append(self.project_root)
|
||||
|
||||
for base in candidates:
|
||||
try:
|
||||
if (base / 'authority').is_dir():
|
||||
return False
|
||||
if (base / 'prole' / 'authority').is_dir():
|
||||
return False
|
||||
except Exception:
|
||||
continue
|
||||
return True
|
||||
|
||||
def _dashboard_kong_missing(self, env: dict) -> bool:
|
||||
ns = "kubernetes-dashboard"
|
||||
try:
|
||||
res_ns = subprocess.run(
|
||||
['kubectl', 'get', 'ns', ns, '-o', 'name'],
|
||||
env=env, capture_output=True, text=True, timeout=6
|
||||
)
|
||||
if res_ns.returncode != 0 or ns not in (res_ns.stdout or ''):
|
||||
return True
|
||||
res = subprocess.run(
|
||||
['kubectl', '-n', ns, 'get', 'pods', '--no-headers'],
|
||||
env=env, capture_output=True, text=True, timeout=6
|
||||
)
|
||||
if res.returncode != 0:
|
||||
return True
|
||||
kong_lines = [l for l in (res.stdout or '').splitlines() if 'kong' in l.lower()]
|
||||
if not kong_lines:
|
||||
return True
|
||||
for line in kong_lines:
|
||||
parts = line.split()
|
||||
if len(parts) < 3:
|
||||
return True
|
||||
if parts[2] != 'Running':
|
||||
return True
|
||||
return False
|
||||
except Exception:
|
||||
return True
|
||||
|
||||
def _maybe_run_repair_pipeline(self, env: dict) -> None:
|
||||
if self._repair_ran:
|
||||
return
|
||||
anomalies = []
|
||||
if self._dashboard_kong_missing(env):
|
||||
anomalies.append('dashboard')
|
||||
if self._authority_context_missing():
|
||||
anomalies.append('authority')
|
||||
if not anomalies:
|
||||
return
|
||||
|
||||
self._repair_ran = True
|
||||
service_ns = self._service_namespace()
|
||||
db_ns = (self._get_input('init_password.db_namespace', '') or '').strip() or 'default'
|
||||
self.log(f"[INFO] Detected anomalies ({', '.join(anomalies)}); running repair pipeline...")
|
||||
self._run_script(
|
||||
"repair_pipeline.sh",
|
||||
args=["-n", service_ns, "--db-namespace", db_ns],
|
||||
env=env
|
||||
)
|
||||
|
||||
# ---------------- Namespace helpers ----------------
|
||||
def _get_local_owner(self) -> str:
|
||||
try:
|
||||
@ -12576,6 +12670,14 @@ class ProleSilentInstaller:
|
||||
raise Exception("Cluster is not reachable.")
|
||||
self.log(f"[OK] Cluster ready: {env_key}")
|
||||
|
||||
# Run repair pipeline if anomalies are detected on a ready cluster
|
||||
try:
|
||||
service_ns = self._service_namespace()
|
||||
env = self._script_env_for_namespace(service_ns)
|
||||
self._maybe_run_repair_pipeline(env)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if env_key == 'service':
|
||||
self._deploy_common_services(env_key)
|
||||
else:
|
||||
|
||||
33493
k8s/argocd/install.yaml
Normal file
33493
k8s/argocd/install.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@ -22,8 +22,8 @@ enum ProleEnv {
|
||||
for dir in [proleHome(), logsDir(), confDir()] {
|
||||
try? fm.createDirectory(at: dir, withIntermediateDirectories: true)
|
||||
}
|
||||
// Ensure conf/port-mappings.conf exists
|
||||
let pm = confDir().appendingPathComponent("port-mappings.conf")
|
||||
// Ensure conf/port-mapping.cfg exists
|
||||
let pm = confDir().appendingPathComponent("port-mapping.cfg")
|
||||
if !fm.fileExists(atPath: pm.path) {
|
||||
let tpl = """
|
||||
# Port mappings for Prole Tools (read by scripts).
|
||||
|
||||
@ -13,7 +13,7 @@ ui.background=img/proleLogoSepia.png
|
||||
ui.welcometxt=installer/welcome.txt
|
||||
|
||||
# Dev port-forward supervision
|
||||
# Note: Port mappings are now sourced from $PROLE_HOME/conf/port-mappings.conf.
|
||||
# Note: Port mappings are now sourced from $PROLE_HOME/conf/port-mapping.cfg.
|
||||
# The legacy pf.* keys are intentionally omitted from the bundled defaults.
|
||||
pf.enabled=true
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ ui.background=img/proleLogoSepia.png
|
||||
ui.welcometxt=installer/welcome.txt
|
||||
|
||||
# Dev port-forward supervision
|
||||
# Note: Port mappings are now sourced from $PROLE_HOME/conf/port-mappings.conf.
|
||||
# Note: Port mappings are now sourced from $PROLE_HOME/conf/port-mapping.cfg.
|
||||
# The legacy pf.* keys are intentionally omitted from the bundled defaults.
|
||||
pf.enabled=true
|
||||
|
||||
|
||||
0
prole/tests/etc/run_all.sh → tests/etc/run_all.sh
Executable file → Normal file
0
prole/tests/etc/run_all.sh → tests/etc/run_all.sh
Executable file → Normal file
2
prole/tests/etc/test_build-a-bao.sh → tests/etc/test_build-a-bao.sh
Executable file → Normal file
2
prole/tests/etc/test_build-a-bao.sh → tests/etc/test_build-a-bao.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/build-a-bao.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/build-a-bao.sh"
|
||||
|
||||
2
prole/tests/etc/test_deploy_pipeline.sh → tests/etc/test_deploy_pipeline.sh
Executable file → Normal file
2
prole/tests/etc/test_deploy_pipeline.sh → tests/etc/test_deploy_pipeline.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/deploy_pipeline.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/deploy_pipeline.sh"
|
||||
|
||||
2
prole/tests/etc/test_final_deployment.sh → tests/etc/test_final_deployment.sh
Executable file → Normal file
2
prole/tests/etc/test_final_deployment.sh → tests/etc/test_final_deployment.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/final_deployment.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/final_deployment.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_ansible.sh → tests/etc/test_init_ansible.sh
Executable file → Normal file
2
prole/tests/etc/test_init_ansible.sh → tests/etc/test_init_ansible.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_ansible.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_ansible.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_cloudnative_pg.sh → tests/etc/test_init_cloudnative_pg.sh
Executable file → Normal file
2
prole/tests/etc/test_init_cloudnative_pg.sh → tests/etc/test_init_cloudnative_pg.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_cloudnative_pg.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_cloudnative_pg.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_common_services.sh → tests/etc/test_init_common_services.sh
Executable file → Normal file
2
prole/tests/etc/test_init_common_services.sh → tests/etc/test_init_common_services.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_common_services.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_common_services.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_garage_store.sh → tests/etc/test_init_garage_store.sh
Executable file → Normal file
2
prole/tests/etc/test_init_garage_store.sh → tests/etc/test_init_garage_store.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_garage_store.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_garage_store.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_k3s_registry.sh → tests/etc/test_init_k3s_registry.sh
Executable file → Normal file
2
prole/tests/etc/test_init_k3s_registry.sh → tests/etc/test_init_k3s_registry.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_k3s_registry.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_k3s_registry.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_k8s.sh → tests/etc/test_init_k8s.sh
Executable file → Normal file
2
prole/tests/etc/test_init_k8s.sh → tests/etc/test_init_k8s.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_k8s.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_k8s.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_kdc.sh → tests/etc/test_init_kdc.sh
Executable file → Normal file
2
prole/tests/etc/test_init_kdc.sh → tests/etc/test_init_kdc.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_kdc.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_kdc.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_kerberos.sh → tests/etc/test_init_kerberos.sh
Executable file → Normal file
2
prole/tests/etc/test_init_kerberos.sh → tests/etc/test_init_kerberos.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_kerberos.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_kerberos.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_kerberos_test.sh → tests/etc/test_init_kerberos_test.sh
Executable file → Normal file
2
prole/tests/etc/test_init_kerberos_test.sh → tests/etc/test_init_kerberos_test.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_kerberos_test.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_kerberos_test.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_monitoring.sh → tests/etc/test_init_monitoring.sh
Executable file → Normal file
2
prole/tests/etc/test_init_monitoring.sh → tests/etc/test_init_monitoring.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_monitoring.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_monitoring.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_ollama.sh → tests/etc/test_init_ollama.sh
Executable file → Normal file
2
prole/tests/etc/test_init_ollama.sh → tests/etc/test_init_ollama.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_ollama.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_ollama.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_openbao.sh → tests/etc/test_init_openbao.sh
Executable file → Normal file
2
prole/tests/etc/test_init_openbao.sh → tests/etc/test_init_openbao.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_openbao.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_openbao.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_opentofu.sh → tests/etc/test_init_opentofu.sh
Executable file → Normal file
2
prole/tests/etc/test_init_opentofu.sh → tests/etc/test_init_opentofu.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_opentofu.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_opentofu.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_port_forwards.sh → tests/etc/test_init_port_forwards.sh
Executable file → Normal file
2
prole/tests/etc/test_init_port_forwards.sh → tests/etc/test_init_port_forwards.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_port_forwards.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_port_forwards.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_prole-db-backup.sh → tests/etc/test_init_prole-db-backup.sh
Executable file → Normal file
2
prole/tests/etc/test_init_prole-db-backup.sh → tests/etc/test_init_prole-db-backup.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_prole-db-backup.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_prole-db-backup.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_prole-db-reset.sh → tests/etc/test_init_prole-db-reset.sh
Executable file → Normal file
2
prole/tests/etc/test_init_prole-db-reset.sh → tests/etc/test_init_prole-db-reset.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_prole-db-reset.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_prole-db-reset.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_registry.sh → tests/etc/test_init_registry.sh
Executable file → Normal file
2
prole/tests/etc/test_init_registry.sh → tests/etc/test_init_registry.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_registry.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_registry.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_service_layer.sh → tests/etc/test_init_service_layer.sh
Executable file → Normal file
2
prole/tests/etc/test_init_service_layer.sh → tests/etc/test_init_service_layer.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_service_layer.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_service_layer.sh"
|
||||
|
||||
2
prole/tests/etc/test_init_supabase_ports.sh → tests/etc/test_init_supabase_ports.sh
Executable file → Normal file
2
prole/tests/etc/test_init_supabase_ports.sh → tests/etc/test_init_supabase_ports.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/init_supabase_ports.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_supabase_ports.sh"
|
||||
|
||||
2
prole/tests/etc/test_render_manifest.sh → tests/etc/test_render_manifest.sh
Executable file → Normal file
2
prole/tests/etc/test_render_manifest.sh → tests/etc/test_render_manifest.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/render_manifest.py
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/render_manifest.py"
|
||||
|
||||
2
prole/tests/etc/test_set-k3s-token-vault.sh → tests/etc/test_set-k3s-token-vault.sh
Executable file → Normal file
2
prole/tests/etc/test_set-k3s-token-vault.sh → tests/etc/test_set-k3s-token-vault.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/set-k3s-token-vault.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/set-k3s-token-vault.sh"
|
||||
|
||||
2
prole/tests/etc/test_status_common_services.sh → tests/etc/test_status_common_services.sh
Executable file → Normal file
2
prole/tests/etc/test_status_common_services.sh → tests/etc/test_status_common_services.sh
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# Unit test for etc/status_common_services.sh
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../../../" && pwd)
|
||||
PROLE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
||||
ETC_DIR="$PROLE_HOME/etc"
|
||||
SCRIPT_UNDER_TEST="$ETC_DIR/status_common_services.sh"
|
||||
|
||||
@ -30,14 +30,18 @@ if [[ -z "$CFG_PATH" ]]; then
|
||||
CFG_PATH="$PROLE_CONF/prole.cfg"
|
||||
elif [[ -f "$ROOT_DIR/conf/prole.cfg" ]]; then
|
||||
CFG_PATH="$ROOT_DIR/conf/prole.cfg"
|
||||
elif [[ -f "$ROOT_DIR/prole/conf/prole.cfg" ]]; then
|
||||
CFG_PATH="$ROOT_DIR/prole/conf/prole.cfg"
|
||||
else
|
||||
echo "ERROR: prole.cfg not found. Pass a path or set PROLE_CONF." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
CFG_DIR="$(cd "$(dirname "$CFG_PATH")" && pwd)"
|
||||
if [[ -z "${PROLE_CONF:-}" ]]; then
|
||||
PROLE_CONF="$CFG_DIR"
|
||||
export PROLE_CONF
|
||||
fi
|
||||
|
||||
TMP_CFG=""
|
||||
if [[ "${PROLE_CFG_INPLACE:-}" != "true" ]]; then
|
||||
TMP_CFG="$(mktemp -t prole.cfg.XXXXXX)"
|
||||
@ -205,7 +209,7 @@ fi
|
||||
|
||||
echo ""
|
||||
echo "3. Blessing sanitized gold config..."
|
||||
python3 - "$CFG_PATH" "$ROOT_DIR/prole/conf/prole-db/prole.cfg" <<'PY'
|
||||
python3 - "$CFG_PATH" "$PROLE_CONF/prole-db/prole.cfg" <<'PY'
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
Loading…
Reference in New Issue
Block a user