mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 15:44:33 +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
|
# Secrets and local config
|
||||||
*.kubeconfig
|
*.kubeconfig
|
||||||
etc/secrets/
|
etc/secrets/
|
||||||
prole/conf/
|
|
||||||
*-password.txt
|
*-password.txt
|
||||||
*secret.yaml
|
*secret.yaml
|
||||||
.vault_pass
|
.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
|
; 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.
|
; This file is used as input for Ansible deployment and k8s cluster creation.
|
||||||
|
|
||||||
[User]
|
[User]
|
||||||
; User-editable values; derived values below reference these by default.
|
; User-editable values; derived values below reference these by default.
|
||||||
NAMESPACE = prole-db-a0e0d0d0
|
NAMESPACE = prole-db-101
|
||||||
PROLE_CONF = ${PROLE_HOME}/conf
|
PROLE_CONF = ${PROLE_HOME}/conf
|
||||||
PROLE_DATA = /opt/prole/data/chrisfu
|
PROLE_DATA = /opt/prole/data/chrisfu
|
||||||
PROLE_HOME = /Users/chrisfu/dev/prole
|
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.cluster_env = k3d-prole-dev-cluster
|
||||||
init_cluster.deployment_target = prole-dev-cluster
|
init_cluster.deployment_target = prole-dev-cluster
|
||||||
init_cluster.k3s_server_url = https://myrddin.prole.org:6443
|
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.kerberos_enabled = true
|
||||||
init_cluster.mode = k3d
|
init_cluster.mode = k3d
|
||||||
init_cluster.start_cluster = true
|
init_cluster.start_cluster = true
|
||||||
init_cluster.supabase_enabled = true
|
init_cluster.supabase_enabled = false
|
||||||
init_cnpg_deploy.force_rollout = false
|
init_cnpg_deploy.force_rollout = false
|
||||||
init_cnpg_deploy.run_deploy = true
|
init_cnpg_deploy.run_deploy = true
|
||||||
init_db_build.run_build = true
|
init_db_build.run_build = true
|
||||||
init_password.db_host_port = 5432
|
init_password.db_host_port = 5432
|
||||||
init_password.db_password = ${OPENBAO:kv/prole/prole-db-a0e0d0d0/db#password}
|
init_password.db_password = ${OPENBAO:kv/prole/prole-db-101/db#password}
|
||||||
init_password.db_password_confirm = ${OPENBAO:kv/prole/prole-db-a0e0d0d0/db#password}
|
init_password.db_password_confirm = ${OPENBAO:kv/prole/prole-db-101/db#password}
|
||||||
init_password.db_username = chrisfu
|
init_password.db_username = root
|
||||||
init_password.generate_ssh_key = true
|
init_password.generate_ssh_key = true
|
||||||
init_scripts.run_scripts = true
|
init_scripts.run_scripts = true
|
||||||
kerberos_config.enabled = true
|
kerberos_config.enabled = true
|
||||||
kerberos_config.kdc = 10.0.0.3
|
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.realm = PROLE.ORG
|
||||||
kerberos_config.test_connection = true
|
kerberos_config.test_connection = false
|
||||||
kerberos_config.user = chrisfu
|
kerberos_config.user =
|
||||||
network_scan.run = true
|
network_scan.run = true
|
||||||
ollama_config.model =
|
ollama_config.model =
|
||||||
ollama_config.server_host =
|
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
|
; Variables used by name in more than one place or assumed global scope
|
||||||
CLUSTER_ENV = k3d-prole-dev-cluster
|
CLUSTER_ENV = k3d-prole-dev-cluster
|
||||||
DB_HOST_PORT = 5432
|
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_MODE = k3d
|
||||||
DEPLOYMENT_TARGET = prole-dev-cluster
|
DEPLOYMENT_TARGET = prole-dev-cluster
|
||||||
DOCKER_IMPORT_DIR =
|
DOCKER_IMPORT_DIR =
|
||||||
NAMESPACE = ${NAMESPACE}
|
NAMESPACE = ${NAMESPACE}
|
||||||
PROLE_DB_USER = chrisfu
|
PROLE_DB_USER = root
|
||||||
PROLE_HOME = ${PROLE_HOME}
|
PROLE_HOME = ${PROLE_HOME}
|
||||||
PROLE_K3S_SERVER = https://myrddin.prole.org:6443
|
PROLE_K3S_SERVER = https://myrddin.prole.org:6443
|
||||||
PROLE_K3S_TOKEN = ${OPENBAO:REDACTED}
|
PROLE_K3S_TOKEN = ${OPENBAO:REDACTED}
|
||||||
@ -81,7 +81,7 @@ SERVICE_NAMESPACE = ${SERVICE_NAMESPACE}
|
|||||||
; No configuration values captured yet for this section.
|
; No configuration values captured yet for this section.
|
||||||
|
|
||||||
[Dependencies]
|
[Dependencies]
|
||||||
; No configuration values captured yet for this section.
|
STATUS = All installed
|
||||||
|
|
||||||
[Network]
|
[Network]
|
||||||
AD_DC_HOST = myrddin.prole.org
|
AD_DC_HOST = myrddin.prole.org
|
||||||
@ -96,17 +96,25 @@ KDC_AUTO_DETECTED = 10.0.0.3
|
|||||||
KERBEROS_AUTO_ENABLED = True
|
KERBEROS_AUTO_ENABLED = True
|
||||||
|
|
||||||
[Port Forwards]
|
[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]
|
[System Environment]
|
||||||
PROLE_CONF = ${PROLE_CONF}
|
PROLE_CONF = ${PROLE_CONF}
|
||||||
PROLE_DATA = ${PROLE_DATA}
|
PROLE_DATA = ${PROLE_DATA}
|
||||||
PROLE_HOME = ${PROLE_HOME}
|
PROLE_HOME = ${PROLE_HOME}
|
||||||
PROLE_LOGS = ${PROLE_LOGS}
|
PROLE_LOGS = ${PROLE_LOGS}
|
||||||
|
PROLE_OPENTOFU_URL = http://127.0.0.1:8080
|
||||||
PROLE_SERVICE = ${PROLE_SERVICE}
|
PROLE_SERVICE = ${PROLE_SERVICE}
|
||||||
|
|
||||||
[Monitoring]
|
[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]
|
[Kerberos Authentication]
|
||||||
AD_PORT_FORWARD = 1
|
AD_PORT_FORWARD = 1
|
||||||
@ -115,27 +123,27 @@ AD_PROXY_IMAGE = alpine/socat
|
|||||||
AD_PROXY_SERVICE = prole-kerberos-ad-dc
|
AD_PROXY_SERVICE = prole-kerberos-ad-dc
|
||||||
AD_TCP_PORTS = 88 389 445 464 636
|
AD_TCP_PORTS = 88 389 445 464 636
|
||||||
AD_UDP_PORTS = 88 464
|
AD_UDP_PORTS = 88 464
|
||||||
ENABLED = True
|
ENABLED = true
|
||||||
KDC = 10.0.0.3
|
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
|
REALM = PROLE.ORG
|
||||||
SERVER = 10.0.0.3
|
SERVER = 10.0.0.3
|
||||||
USER = chrisfu
|
USER =
|
||||||
|
|
||||||
[Ollama]
|
[Ollama]
|
||||||
; No configuration values captured yet for this section.
|
; No configuration values captured yet for this section.
|
||||||
|
|
||||||
[Optional Features]
|
[Optional Features]
|
||||||
AT_REST_ENCRYPTION_ENABLED = True
|
AT_REST_ENCRYPTION_ENABLED = true
|
||||||
KERBEROS_ENABLED = True
|
KERBEROS_ENABLED = true
|
||||||
SUPABASE_ENABLED = False
|
SUPABASE_ENABLED = false
|
||||||
|
|
||||||
[Database Creation]
|
[Database Creation]
|
||||||
|
|
||||||
[Initialize Cluster]
|
[Initialize Cluster]
|
||||||
ENVIRONMENT = k3d-prole-dev-cluster
|
ENVIRONMENT = k3d-prole-dev-cluster
|
||||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||||
K3S_TOKEN = ${OPENBAO:REDACTED}
|
K3S_TOKEN =
|
||||||
|
|
||||||
[Dev Cluster (k3d)]
|
[Dev Cluster (k3d)]
|
||||||
CLUSTER_ENV = k3d-prole-dev-cluster
|
CLUSTER_ENV = k3d-prole-dev-cluster
|
||||||
@ -147,12 +155,12 @@ MODE = k3d
|
|||||||
CLUSTER_ENV = prole-service-cluster
|
CLUSTER_ENV = prole-service-cluster
|
||||||
DISPLAY_NAME = prole-service-cluster
|
DISPLAY_NAME = prole-service-cluster
|
||||||
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
K3S_SERVER_URL = https://myrddin.prole.org:6443
|
||||||
K3S_TOKEN = ${OPENBAO:REDACTED}
|
K3S_TOKEN = ${OPENBAO:kv/prole/prole-db-101/k3s#token}
|
||||||
MODE = k3s
|
MODE = k3s
|
||||||
PIPELINE_URL = http://127.0.0.1:8080
|
PIPELINE_URL = http://127.0.0.1:8080
|
||||||
|
|
||||||
[Prod Cluster (k8s)]
|
[Prod Cluster (k8s)]
|
||||||
ARTIFACTS_DIR = /Users/chrisfu/dev/prole/data/staging
|
ARTIFACTS_DIR = ${PROLE_DATA}/staging
|
||||||
CLUSTER_ENV = prole-prod-cluster
|
CLUSTER_ENV = prole-prod-cluster
|
||||||
DISPLAY_NAME = prole-prod-cluster
|
DISPLAY_NAME = prole-prod-cluster
|
||||||
MODE = k8s
|
MODE = k8s
|
||||||
@ -161,9 +169,10 @@ PIPELINE_URL = http://127.0.0.1:8080
|
|||||||
[Docker Build]
|
[Docker Build]
|
||||||
LOCAL_REGISTRY = localhost:5000
|
LOCAL_REGISTRY = localhost:5000
|
||||||
LOCAL_REGISTRY_INTERNAL = k3d-prole-registry.localhost:5000
|
LOCAL_REGISTRY_INTERNAL = k3d-prole-registry.localhost:5000
|
||||||
|
STATUS = Built
|
||||||
|
|
||||||
[Initialization Scripts]
|
[Initialization Scripts]
|
||||||
STATUS = Attempted
|
; No configuration values captured yet for this section.
|
||||||
|
|
||||||
[Deployment]
|
[Deployment]
|
||||||
MODE = k3d
|
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_DATA="/opt/prole/data/chrisfu"
|
||||||
export PROLE_LOGS="/opt/prole/logs/chrisfu"
|
export PROLE_LOGS="/opt/prole/logs/chrisfu"
|
||||||
export PROLE_SERVICE="/Users/chrisfu/dev/prole/etc"
|
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.)
|
# Ensure PATH works for GUI-launched shells (Docker, etc.)
|
||||||
_prole_add_path() { case ":${PATH}:" in *":$1:"*) ;; *) PATH="$1:${PATH:-}" ;; esac; }
|
_prole_add_path() { case ":${PATH}:" in *":$1:"*) ;; *) PATH="$1:${PATH:-}" ;; esac; }
|
||||||
|
|||||||
@ -1,25 +1,79 @@
|
|||||||
#!/bin/bash
|
#!/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.
|
# This script handles post-installation deployment tasks for Prole.
|
||||||
# 1st use case: -e|--docker-export
|
# 1st use case: -e|--docker-export
|
||||||
# Runs docker image export for each image required to deploy Prole.
|
# Runs docker image export for each image required to deploy Prole.
|
||||||
# Artifacts are written to DOCKER_IMPORT_DIR.
|
# 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() {
|
usage() {
|
||||||
echo "Usage: $0 [options]"
|
echo "Usage: $0 [options]"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Options:"
|
echo "Options:"
|
||||||
echo " -e, --docker-export Export required docker images to DOCKER_IMPORT_DIR"
|
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 ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_docker_export=0
|
||||||
|
do_helm_chart=0
|
||||||
|
do_kustomize=0
|
||||||
|
export_dir=""
|
||||||
|
|
||||||
if [[ $# -eq 0 ]]; then
|
if [[ $# -eq 0 ]]; then
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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)"
|
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
export PROJECT_ROOT
|
export PROJECT_ROOT
|
||||||
|
|
||||||
@ -31,7 +85,17 @@ fi
|
|||||||
default_owner="$(id -un 2>/dev/null || echo prole)"
|
default_owner="$(id -un 2>/dev/null || echo prole)"
|
||||||
prole_data="${PROLE_DATA:-/opt/prole/data/${default_owner}}"
|
prole_data="${PROLE_DATA:-/opt/prole/data/${default_owner}}"
|
||||||
prole_data="${prole_data%/}"
|
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}"
|
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() {
|
export_docker_images() {
|
||||||
echo "Exporting Docker images to: ${DOCKER_IMPORT_DIR}"
|
echo "Exporting Docker images to: ${DOCKER_IMPORT_DIR}"
|
||||||
@ -87,12 +151,117 @@ export_docker_images() {
|
|||||||
echo "Docker export complete."
|
echo "Docker export complete."
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$1" in
|
create_helm_chart() {
|
||||||
-e|--docker-export)
|
local chart_dir="${HELM_CHART_DIR}"
|
||||||
export_docker_images
|
local chart_name="prole"
|
||||||
;;
|
local chart_version="0.1.0"
|
||||||
*)
|
local app_version
|
||||||
usage
|
app_version="$(date -u +%Y.%m.%d)"
|
||||||
exit 1
|
|
||||||
;;
|
echo "Creating Helm chart in: ${chart_dir}"
|
||||||
esac
|
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
|
cat <<EOF
|
||||||
Usage: init_common_services.sh [-n|--namespace NS] [-k|--kerberos] <update|start|status>
|
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.
|
into the given Kubernetes namespace. Use -k to include the Kerberos/KDC service.
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ fi
|
|||||||
|
|
||||||
OPENBAO_NAME=${OPENBAO_NAME:-openbao}
|
OPENBAO_NAME=${OPENBAO_NAME:-openbao}
|
||||||
OPENTOFU_NAME=${OPENTOFU_NAME:-opentofu}
|
OPENTOFU_NAME=${OPENTOFU_NAME:-opentofu}
|
||||||
REGISTRY_NAME=${REGISTRY_NAME:-registry}
|
ARGOCD_SERVER_NAME=${ARGOCD_SERVER_NAME:-argocd-server}
|
||||||
GARAGE_NAME=${GARAGE_NAME:-garage}
|
GARAGE_NAME=${GARAGE_NAME:-garage}
|
||||||
OPENTOFU_CONFIGMAP=${OPENTOFU_CONFIGMAP:-opentofu-nginx}
|
OPENTOFU_CONFIGMAP=${OPENTOFU_CONFIGMAP:-opentofu-nginx}
|
||||||
OPENTOFU_SECRET=${OPENTOFU_SECRET:-opentofu-admin}
|
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
|
kubectl delete -n "$old_ns" secret "$OPENTOFU_SECRET" --ignore-not-found >/dev/null 2>&1 || true
|
||||||
done
|
done
|
||||||
|
|
||||||
for old_ns in $(collect_other_namespaces "$REGISTRY_NAME" deployment service); do
|
for old_ns in $(collect_other_namespaces "$ARGOCD_SERVER_NAME" deployment service); do
|
||||||
echo "Found registry in namespace '$old_ns'; removing before deploy to '$NS' ..."
|
echo "Found ArgoCD in namespace '$old_ns'; removing before deploy to '$NS' ..."
|
||||||
if [ -x "$SCRIPT_DIR/init_registry.sh" ]; then
|
if [ -x "$SCRIPT_DIR/init_registry.sh" ]; then
|
||||||
"$SCRIPT_DIR/init_registry.sh" -n "$old_ns" stop || true
|
"$SCRIPT_DIR/init_registry.sh" -n "$old_ns" stop || true
|
||||||
else
|
else
|
||||||
kubectl delete -n "$old_ns" deploy "$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 "$REGISTRY_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
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ fi
|
|||||||
if [ -x "$SCRIPT_DIR/init_registry.sh" ]; then
|
if [ -x "$SCRIPT_DIR/init_registry.sh" ]; then
|
||||||
"$SCRIPT_DIR/init_registry.sh" -n "$NS" "$ACTION" || rc=$?
|
"$SCRIPT_DIR/init_registry.sh" -n "$NS" "$ACTION" || rc=$?
|
||||||
else
|
else
|
||||||
echo "WARN: init_registry.sh not found; registry deploy skipped."
|
echo "WARN: init_registry.sh not found; ArgoCD deploy skipped."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -x "$SCRIPT_DIR/init_garage_store.sh" ]; then
|
if [ -x "$SCRIPT_DIR/init_garage_store.sh" ]; then
|
||||||
|
|||||||
@ -281,10 +281,18 @@ resolve_kdc_docker_dir() {
|
|||||||
echo "$PROLE_HOME/prole/authority"
|
echo "$PROLE_HOME/prole/authority"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
if [[ -n "${PROLE_HOME:-}" && -d "$PROLE_HOME/authority" ]]; then
|
||||||
|
echo "$PROLE_HOME/authority"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
if [[ -d "$SCRIPT_DIR/../prole/authority" ]]; then
|
if [[ -d "$SCRIPT_DIR/../prole/authority" ]]; then
|
||||||
echo "$SCRIPT_DIR/../prole/authority"
|
echo "$SCRIPT_DIR/../prole/authority"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
if [[ -d "$SCRIPT_DIR/../authority" ]]; then
|
||||||
|
echo "$SCRIPT_DIR/../authority"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -205,16 +205,18 @@ scan_pairs() {
|
|||||||
if ! json=$(curl -fsS --connect-timeout "$timeout" --max-time "$timeout" "$url" 2>/dev/null); then
|
if ! json=$(curl -fsS --connect-timeout "$timeout" --max-time "$timeout" "$url" 2>/dev/null); then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
models=$(printf '%s' "$json" | python3 - <<'PY'
|
if ! models=$(printf '%s' "$json" | python3 - <<'PY'
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
data = sys.stdin.read().strip()
|
data = sys.stdin.read().strip()
|
||||||
if not data:
|
if not data:
|
||||||
sys.exit(0)
|
sys.exit(1)
|
||||||
try:
|
try:
|
||||||
payload = json.loads(data)
|
payload = json.loads(data)
|
||||||
except Exception:
|
except Exception:
|
||||||
sys.exit(0)
|
sys.exit(1)
|
||||||
|
if not isinstance(payload, dict) or "models" not in payload:
|
||||||
|
sys.exit(1)
|
||||||
models = []
|
models = []
|
||||||
for entry in payload.get("models", []):
|
for entry in payload.get("models", []):
|
||||||
name = entry.get("name") or entry.get("model") or ""
|
name = entry.get("name") or entry.get("model") or ""
|
||||||
@ -222,7 +224,9 @@ for entry in payload.get("models", []):
|
|||||||
models.append(name)
|
models.append(name)
|
||||||
print(",".join(models))
|
print(",".join(models))
|
||||||
PY
|
PY
|
||||||
)
|
); then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
printf '%s\t%s\t%s\n' "$host" "$port_val" "$models"
|
printf '%s\t%s\t%s\n' "$host" "$port_val" "$models"
|
||||||
count=$((count + 1))
|
count=$((count + 1))
|
||||||
done
|
done
|
||||||
|
|||||||
@ -42,6 +42,8 @@ Examples:
|
|||||||
Config (prole.cfg or port-mapping.cfg):
|
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_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
|
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
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,11 +192,33 @@ collect_cfg_mappings() {
|
|||||||
if (key ~ ("^" p "[0-9]+$")) {
|
if (key ~ ("^" p "[0-9]+$")) {
|
||||||
num=substr(key, length(p)+1)+0
|
num=substr(key, length(p)+1)+0
|
||||||
print num "\t" val
|
print num "\t" val
|
||||||
|
count++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
END { if (count == 0) exit 1 }
|
||||||
' "$file" | sort -n
|
' "$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() {
|
parse_cfg_mapping() {
|
||||||
local line="$1"
|
local line="$1"
|
||||||
local id="" ns="" target="" address="" hostPort="" servicePort="" protocol="" description=""
|
local id="" ns="" target="" address="" hostPort="" servicePort="" protocol="" description=""
|
||||||
@ -496,6 +520,28 @@ docker_is_running() {
|
|||||||
docker info >/dev/null 2>&1
|
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).
|
# Hard-fail with clean guidance when Docker is not up (used for start/restart).
|
||||||
ensure_docker_running() {
|
ensure_docker_running() {
|
||||||
if docker_is_running; then
|
if docker_is_running; then
|
||||||
@ -579,6 +625,19 @@ is_pid_running() {
|
|||||||
[ -n "$pid" ] && kill -0 "$pid" >/dev/null 2>&1
|
[ -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() {
|
read_pid() {
|
||||||
local pf="$1"
|
local pf="$1"
|
||||||
[ -f "$pf" ] || return 1
|
[ -f "$pf" ] || return 1
|
||||||
@ -597,48 +656,111 @@ remove_pidfile() {
|
|||||||
rm -f "$pf" >/dev/null 2>&1 || true
|
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() {
|
foreach_mapping_cfg() {
|
||||||
local callback="$1"
|
local callback="$1"
|
||||||
local file="${2:-$PORT_MAPPING_FILE_PATH}"
|
local file="${2:-$PORT_MAPPING_FILE_PATH}"
|
||||||
local prefix mappings line parsed
|
local mappings line parsed count=0
|
||||||
[ -n "$file" ] || return 1
|
[ -n "$file" ] || return 1
|
||||||
prefix="$(mapping_prefix_for_mode)"
|
if ! mappings="$(collect_cfg_mappings_for_mode "$file")"; then
|
||||||
if ! mappings="$(collect_cfg_mappings "$prefix" "$file")"; then
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
[ -z "$line" ] && continue
|
[ -z "$line" ] && continue
|
||||||
parsed="$(parse_cfg_mapping "${line#*$'\t'}")"
|
parsed="$(parse_cfg_mapping "${line#*$'\t'}")"
|
||||||
local id ns target address hostPort servicePort protocol description
|
if handle_mapping_parsed "$callback" "$parsed"; then
|
||||||
IFS=$'\t' read -r id ns target address hostPort servicePort protocol description <<<"$parsed"
|
count=$((count + 1))
|
||||||
|
|
||||||
if [ -z "$id" ] || [ -z "$ns" ] || [ -z "$target" ] || [ -z "$hostPort" ] || [ -z "$servicePort" ]; then
|
|
||||||
err "Invalid mapping (missing required fields): ${line#*$'\t'}"
|
|
||||||
exit 1
|
|
||||||
fi
|
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
|
continue
|
||||||
fi
|
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"
|
if [ -z "$address" ]; then address="127.0.0.1"; fi
|
||||||
"$callback" "$id" "$ns" "$target" "$address" "$hostPort" "$servicePort" "$protocol" "$description"
|
if [ -z "$protocol" ]; then protocol="TCP"; fi
|
||||||
done <<<"$mappings"
|
|
||||||
|
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
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach_mapping() {
|
foreach_mapping() {
|
||||||
local callback="$1"
|
local callback="$1"
|
||||||
if foreach_mapping_cfg "$callback" "$CFG_FILE"; then
|
if [ -n "${CFG_FILE:-}" ] && [ -f "$CFG_FILE" ]; then
|
||||||
return 0
|
if foreach_mapping_cfg "$callback" "$CFG_FILE"; then
|
||||||
fi
|
|
||||||
if [ -n "${PORT_MAPPING_FILE_PATH:-}" ] && [ -f "$PORT_MAPPING_FILE_PATH" ]; then
|
|
||||||
if foreach_mapping_cfg "$callback" "$PORT_MAPPING_FILE_PATH"; then
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
err "No port-forward mappings found in ${CFG_FILE:-prole.cfg}."
|
if [ -n "${PORT_MAPPING_FILE_PATH:-}" ] && [ -f "$PORT_MAPPING_FILE_PATH" ]; then
|
||||||
exit 1
|
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() {
|
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 id="$1" ns="$2" target="$3" address="$4" hostPort="$5" servicePort="$6" protocol="$7" description="$8"
|
||||||
local pidfile logfile cmd pid
|
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
|
# Aggressively stop existing processes before starting to avoid port conflicts
|
||||||
stop_port_forward "$id" "$ns" "$target" "$address" "$hostPort" "$servicePort" "$protocol" "$description"
|
stop_port_forward "$id" "$ns" "$target" "$address" "$hostPort" "$servicePort" "$protocol" "$description"
|
||||||
|
|
||||||
@ -749,6 +876,10 @@ status_one() {
|
|||||||
scan_for_collisions() {
|
scan_for_collisions() {
|
||||||
local id="$1" ns="$2" target="$3" address="$4" hostPort="$5" servicePort="$6" protocol="$7" description="$8"
|
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
|
if port_in_use "$hostPort"; then
|
||||||
# find which process is using it
|
# find which process is using it
|
||||||
local pid_info=""
|
local pid_info=""
|
||||||
@ -757,6 +888,10 @@ scan_for_collisions() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$pid_info" ]; then
|
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
|
# Check if this PID is already managed by us
|
||||||
local pidfile pid_managed
|
local pidfile pid_managed
|
||||||
pidfile="$(pid_file_for "$id")"
|
pidfile="$(pid_file_for "$id")"
|
||||||
@ -810,15 +945,23 @@ do_start() {
|
|||||||
ensure_supabase_ports
|
ensure_supabase_ports
|
||||||
|
|
||||||
vlog "Scanning for port collisions..."
|
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() {
|
do_stop() {
|
||||||
# stop doesn't require cluster access, but it does need state dirs
|
# stop doesn't require cluster access, but it does need state dirs
|
||||||
ensure_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() {
|
do_restart() {
|
||||||
@ -840,9 +983,18 @@ do_restart() {
|
|||||||
|
|
||||||
vlog "Scanning for port collisions (excluding our own)..."
|
vlog "Scanning for port collisions (excluding our own)..."
|
||||||
# During restart, we'll stop them first anyway, but let's be safe.
|
# During restart, we'll stop them first anyway, but let's be safe.
|
||||||
foreach_mapping stop_port_forward
|
if ! foreach_mapping stop_port_forward; then
|
||||||
foreach_mapping scan_for_collisions
|
err "No port-forward mappings found. Check ${CFG_FILE:-prole.cfg} or ${PORT_MAPPING_FILE_PATH:-port-mapping.cfg}."
|
||||||
foreach_mapping start_port_forward
|
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() {
|
do_status() {
|
||||||
@ -881,7 +1033,9 @@ do_status() {
|
|||||||
log ""
|
log ""
|
||||||
|
|
||||||
log "== Port-forward processes =="
|
log "== Port-forward processes =="
|
||||||
foreach_mapping status_one
|
if ! foreach_mapping status_one; then
|
||||||
|
log " (no port-forward mappings found)"
|
||||||
|
fi
|
||||||
log ""
|
log ""
|
||||||
|
|
||||||
log "== Quick k3d awareness checks (best-effort) =="
|
log "== Quick k3d awareness checks (best-effort) =="
|
||||||
|
|||||||
@ -4,7 +4,7 @@ set -euo pipefail
|
|||||||
|
|
||||||
# init_registry.sh
|
# init_registry.sh
|
||||||
# Purpose:
|
# Purpose:
|
||||||
# - Deploy a Docker registry into Kubernetes
|
# - Deploy ArgoCD into Kubernetes (replaces in-cluster Docker registry)
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
|
|
||||||
@ -20,19 +20,22 @@ fi
|
|||||||
ACTION=""
|
ACTION=""
|
||||||
NAMESPACE_OVERRIDE=""
|
NAMESPACE_OVERRIDE=""
|
||||||
|
|
||||||
REGISTRY_NAME=${REGISTRY_NAME:-registry}
|
if [[ -d "$SCRIPT_DIR/../k8s/argocd" ]]; then
|
||||||
|
ARGOCD_MANIFEST_DIR="$SCRIPT_DIR/../k8s/argocd"
|
||||||
if [[ -d "$SCRIPT_DIR/../k8s/registry" ]]; then
|
elif [[ -n "${PROLE_HOME:-}" && -d "$PROLE_HOME/k8s/argocd" ]]; then
|
||||||
REGISTRY_MANIFEST_DIR="$SCRIPT_DIR/../k8s/registry"
|
ARGOCD_MANIFEST_DIR="$PROLE_HOME/k8s/argocd"
|
||||||
elif [[ -n "${PROLE_HOME:-}" && -d "$PROLE_HOME/k8s/registry" ]]; then
|
|
||||||
REGISTRY_MANIFEST_DIR="$PROLE_HOME/k8s/registry"
|
|
||||||
else
|
else
|
||||||
REGISTRY_MANIFEST_DIR="$SCRIPT_DIR/../k8s/registry"
|
ARGOCD_MANIFEST_DIR="$SCRIPT_DIR/../k8s/argocd"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
ARGOCD_MANIFEST_FILE=${ARGOCD_MANIFEST_FILE:-"$ARGOCD_MANIFEST_DIR/install.yaml"}
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Usage: init_registry.sh [-n|--namespace NS] <start|stop|status|restart|initialize|update|reload>
|
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
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,44 +80,64 @@ while [[ $# -gt 0 ]]; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [[ -n "$NAMESPACE_OVERRIDE" ]]; then
|
if [[ -n "$NAMESPACE_OVERRIDE" ]]; then
|
||||||
NAMESPACE="$NAMESPACE_OVERRIDE"
|
ARGOCD_NAMESPACE="$NAMESPACE_OVERRIDE"
|
||||||
export NAMESPACE
|
elif [[ -n "${ARGOCD_NAMESPACE:-}" ]]; then
|
||||||
elif [[ -n "${REGISTRY_NAMESPACE:-}" ]]; then
|
ARGOCD_NAMESPACE="$ARGOCD_NAMESPACE"
|
||||||
NAMESPACE="$REGISTRY_NAMESPACE"
|
|
||||||
export NAMESPACE
|
|
||||||
elif [[ -n "${SERVICE_NAMESPACE:-}" ]]; then
|
elif [[ -n "${SERVICE_NAMESPACE:-}" ]]; then
|
||||||
NAMESPACE="$SERVICE_NAMESPACE"
|
ARGOCD_NAMESPACE="$SERVICE_NAMESPACE"
|
||||||
export NAMESPACE
|
elif [[ -n "${NAMESPACE:-}" ]]; then
|
||||||
elif [[ -z "${NAMESPACE:-}" ]]; then
|
ARGOCD_NAMESPACE="$NAMESPACE"
|
||||||
NAMESPACE="default"
|
else
|
||||||
export NAMESPACE
|
ARGOCD_NAMESPACE="default"
|
||||||
fi
|
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() {
|
ensure_tools() {
|
||||||
command -v kubectl >/dev/null || { echo "Missing required tool: kubectl" >&2; exit 1; }
|
command -v kubectl >/dev/null || { echo "Missing required tool: kubectl" >&2; exit 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_namespace() {
|
ensure_namespace() {
|
||||||
if ! kubectl get namespace "$NAMESPACE" >/dev/null 2>&1; then
|
if ! kubectl get namespace "$ARGOCD_NAMESPACE" >/dev/null 2>&1; then
|
||||||
echo "Creating namespace '$NAMESPACE' ..."
|
echo "Creating namespace '$ARGOCD_NAMESPACE' ..."
|
||||||
kubectl create namespace "$NAMESPACE" >/dev/null 2>&1 || true
|
kubectl create namespace "$ARGOCD_NAMESPACE" >/dev/null 2>&1 || true
|
||||||
fi
|
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() {
|
apply_k8s() {
|
||||||
echo "Applying registry manifest to namespace '$NAMESPACE' ..."
|
echo "Applying ArgoCD manifest to namespace '$ARGOCD_NAMESPACE' ..."
|
||||||
prole_render_manifest "$REGISTRY_MANIFEST_DIR/deployment.yaml" | kubectl apply --validate=false -n "$NAMESPACE" -f -
|
render_manifest | kubectl apply --server-side --force-conflicts --field-manager=prole-installer --validate=false -n "$ARGOCD_NAMESPACE" -f -
|
||||||
kubectl rollout status deploy/"$REGISTRY_NAME" -n "$NAMESPACE" --timeout=120s || true
|
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() {
|
delete_k8s() {
|
||||||
echo "Removing registry resources from namespace '$NAMESPACE' ..."
|
echo "Removing ArgoCD resources from namespace '$ARGOCD_NAMESPACE' ..."
|
||||||
kubectl delete -n "$NAMESPACE" -f "$REGISTRY_MANIFEST_DIR/deployment.yaml" --ignore-not-found
|
render_manifest | kubectl delete -n "$ARGOCD_NAMESPACE" -f - --ignore-not-found
|
||||||
}
|
}
|
||||||
|
|
||||||
status_k8s() {
|
status_k8s() {
|
||||||
kubectl -n "$NAMESPACE" get deploy "$REGISTRY_NAME" 2>/dev/null || true
|
kubectl -n "$ARGOCD_NAMESPACE" get deploy,statefulset,svc -l "$ARGOCD_LABEL_SELECTOR" 2>/dev/null || true
|
||||||
kubectl -n "$NAMESPACE" get svc "$REGISTRY_NAME" 2>/dev/null || true
|
kubectl -n "$ARGOCD_NAMESPACE" get pods -l "$ARGOCD_LABEL_SELECTOR" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
case "${ACTION:-}" in
|
case "${ACTION:-}" in
|
||||||
@ -122,6 +145,8 @@ case "${ACTION:-}" in
|
|||||||
ensure_tools
|
ensure_tools
|
||||||
ensure_namespace
|
ensure_namespace
|
||||||
apply_k8s
|
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)
|
stop)
|
||||||
ensure_tools
|
ensure_tools
|
||||||
|
|||||||
@ -4,9 +4,9 @@ set -euo pipefail
|
|||||||
|
|
||||||
# init_service_layer.sh
|
# init_service_layer.sh
|
||||||
# Purpose:
|
# 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
|
# - 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)
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||||
# shellcheck disable=SC1090
|
# 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
|
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() {
|
deploy_service_layer() {
|
||||||
local action="$1"
|
local action="$1"
|
||||||
@ -178,13 +149,13 @@ deploy_service_layer() {
|
|||||||
ensure_namespace "$ns"
|
ensure_namespace "$ns"
|
||||||
label_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
|
case "$action" in
|
||||||
start|initialize|update|reload) registry_action="update" ;;
|
start|initialize|update|reload) argocd_action="update" ;;
|
||||||
restart) registry_action="restart" ;;
|
restart) argocd_action="restart" ;;
|
||||||
stop) registry_action="stop" ;;
|
stop) argocd_action="stop" ;;
|
||||||
status) registry_action="status" ;;
|
status) argocd_action="status" ;;
|
||||||
*) registry_action="update" ;;
|
*) argocd_action="update" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
case "$action" in
|
case "$action" in
|
||||||
@ -214,8 +185,8 @@ deploy_service_layer() {
|
|||||||
*) kdc_action="update" ;;
|
*) kdc_action="update" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
REGISTRY_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \
|
ARGOCD_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \
|
||||||
"$SCRIPT_DIR/init_registry.sh" -n "$ns" "$registry_action" || rc=$?
|
"$SCRIPT_DIR/init_registry.sh" -n "$ns" "$argocd_action" || rc=$?
|
||||||
|
|
||||||
if [[ "$action" == "stop" ]]; then
|
if [[ "$action" == "stop" ]]; then
|
||||||
cleanup_openbao "$ns" || true
|
cleanup_openbao "$ns" || true
|
||||||
@ -241,7 +212,7 @@ deploy_service_layer() {
|
|||||||
cleanup_old_namespace() {
|
cleanup_old_namespace() {
|
||||||
local ns="$1"
|
local ns="$1"
|
||||||
log "Cleaning up service layer in old namespace '$ns' ..."
|
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
|
"$SCRIPT_DIR/init_registry.sh" -n "$ns" stop || true
|
||||||
OPENTOFU_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \
|
OPENTOFU_NAMESPACE="$ns" SERVICE_NAMESPACE="$ns" \
|
||||||
"$SCRIPT_DIR/init_opentofu.sh" -n "$ns" stop || true
|
"$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' ..."
|
log "Migrating service layer from '$from_ns' to '$to_ns' ..."
|
||||||
deploy_service_layer update "$to_ns"
|
deploy_service_layer update "$to_ns"
|
||||||
copy_registry_data "$from_ns" "$to_ns" || true
|
|
||||||
cleanup_old_namespace "$from_ns"
|
cleanup_old_namespace "$from_ns"
|
||||||
write_last_namespace "$to_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
|
cat <<EOF
|
||||||
Usage: status_common_services.sh [-n|--namespace NS] [-k|--kerberos]
|
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.
|
Use -k to include the Prole KDC (auth) checks.
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
@ -76,24 +76,24 @@ run_cmd() {
|
|||||||
|
|
||||||
echo "== Services =="
|
echo "== Services =="
|
||||||
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
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
|
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
|
fi
|
||||||
|
|
||||||
echo "== Workloads =="
|
echo "== Workloads =="
|
||||||
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
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
|
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
|
fi
|
||||||
run_cmd kubectl -n "$NS" get statefulset openbao garage
|
run_cmd kubectl -n "$NS" get statefulset argocd-application-controller openbao garage
|
||||||
|
|
||||||
echo "== Pods =="
|
echo "== Pods =="
|
||||||
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
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
|
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
|
fi
|
||||||
|
|
||||||
echo "== Health Check =="
|
echo "== Health Check =="
|
||||||
@ -161,7 +161,7 @@ check_resource() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
check_resource svc registry
|
check_resource svc argocd-server
|
||||||
check_resource svc openbao
|
check_resource svc openbao
|
||||||
check_resource svc opentofu
|
check_resource svc opentofu
|
||||||
check_resource svc garage
|
check_resource svc garage
|
||||||
@ -169,17 +169,23 @@ if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
|||||||
check_resource svc auth
|
check_resource svc auth
|
||||||
fi
|
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
|
check_resource deploy opentofu
|
||||||
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
||||||
check_resource deploy auth
|
check_resource deploy auth
|
||||||
fi
|
fi
|
||||||
|
check_resource statefulset argocd-application-controller
|
||||||
check_resource statefulset openbao
|
check_resource statefulset openbao
|
||||||
check_resource statefulset garage
|
check_resource statefulset garage
|
||||||
|
|
||||||
pod_filter="registry|openbao|opentofu|garage"
|
pod_filter="argocd|openbao|opentofu|garage"
|
||||||
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
if [[ "$ENABLE_KERBEROS" == "1" ]]; then
|
||||||
pod_filter="registry|openbao|opentofu|garage|auth"
|
pod_filter="argocd|openbao|opentofu|garage|auth"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
analyze_pods
|
analyze_pods
|
||||||
@ -200,7 +206,7 @@ fi
|
|||||||
if [ $blocked -gt 0 ]; then
|
if [ $blocked -gt 0 ]; then
|
||||||
repairable=()
|
repairable=()
|
||||||
fail_all=()
|
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
|
if [[ "$comp" == "auth" && "$ENABLE_KERBEROS" != "1" ]]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|||||||
442
install.py
442
install.py
@ -1632,6 +1632,9 @@ class ProleInstaller:
|
|||||||
self._managed_kubeconfig = None
|
self._managed_kubeconfig = None
|
||||||
self._kong_last_repair_at = 0.0
|
self._kong_last_repair_at = 0.0
|
||||||
self._kong_repair_cooldown_s = 120
|
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)
|
_ensure_ansible_vault_credentials(prompt_ui=True, root=root)
|
||||||
self._action_flags = {}
|
self._action_flags = {}
|
||||||
self.root.title("Prole Database Installer")
|
self.root.title("Prole Database Installer")
|
||||||
@ -3953,8 +3956,8 @@ class ProleInstaller:
|
|||||||
# messagebox.showerror("Invalid Port", "Please enter a valid numeric port.")
|
# messagebox.showerror("Invalid Port", "Please enter a valid numeric port.")
|
||||||
# return
|
# return
|
||||||
|
|
||||||
# Determine path: prole/conf/prole.cfg
|
# Determine path: conf/prole.cfg
|
||||||
# If PROLE_CONF is set, use it. Otherwise fallback to PROJECT_ROOT/prole/conf
|
# If PROLE_CONF is set, use it. Otherwise fallback to PROJECT_ROOT/conf
|
||||||
if self._cfg_path_override is not None:
|
if self._cfg_path_override is not None:
|
||||||
cfg_path = self._cfg_path_override
|
cfg_path = self._cfg_path_override
|
||||||
if cfg_path.is_dir():
|
if cfg_path.is_dir():
|
||||||
@ -3967,7 +3970,8 @@ class ProleInstaller:
|
|||||||
if prole_conf:
|
if prole_conf:
|
||||||
conf_dir = Path(prole_conf).expanduser()
|
conf_dir = Path(prole_conf).expanduser()
|
||||||
else:
|
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'
|
cfg_path = conf_dir / 'prole.cfg'
|
||||||
|
|
||||||
conf_dir.mkdir(parents=True, exist_ok=True)
|
conf_dir.mkdir(parents=True, exist_ok=True)
|
||||||
@ -4487,6 +4491,8 @@ class ProleInstaller:
|
|||||||
combo = getattr(self, '_ollama_model_combo', None)
|
combo = getattr(self, '_ollama_model_combo', None)
|
||||||
if not combo:
|
if not combo:
|
||||||
return
|
return
|
||||||
|
if getattr(self, '_refreshing_ollama_table', False):
|
||||||
|
return
|
||||||
values = models or []
|
values = models or []
|
||||||
try:
|
try:
|
||||||
combo.configure(values=values)
|
combo.configure(values=values)
|
||||||
@ -4544,6 +4550,13 @@ class ProleInstaller:
|
|||||||
if getattr(self, '_refreshing_ollama_table', False):
|
if getattr(self, '_refreshing_ollama_table', False):
|
||||||
return
|
return
|
||||||
self._refreshing_ollama_table = True
|
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):
|
if getattr(self, '_ollama_status_var', None):
|
||||||
self._ollama_status_var.set("Scanning...")
|
self._ollama_status_var.set("Scanning...")
|
||||||
|
|
||||||
@ -4587,8 +4600,16 @@ class ProleInstaller:
|
|||||||
notice = f"Scan error: {e}"
|
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)
|
self.safe_after(lambda: self._ollama_status_var.set("Scan failed") if getattr(self, '_ollama_status_var', None) else None)
|
||||||
finally:
|
finally:
|
||||||
self.safe_after(lambda: self._update_ollama_table(rows, notice))
|
def finish():
|
||||||
self._refreshing_ollama_table = False
|
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()
|
threading.Thread(target=worker, daemon=True).start()
|
||||||
|
|
||||||
@ -4696,6 +4717,8 @@ class ProleInstaller:
|
|||||||
self.bg_canvas.itemconfig(preview_item, text=text)
|
self.bg_canvas.itemconfig(preview_item, text=text)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
if getattr(self, '_refreshing_ollama_table', False):
|
||||||
|
return
|
||||||
current_key = self._ollama_current_key()
|
current_key = self._ollama_current_key()
|
||||||
models = self._ollama_model_options.get(current_key, [])
|
models = self._ollama_model_options.get(current_key, [])
|
||||||
if models:
|
if models:
|
||||||
@ -5596,7 +5619,7 @@ class ProleInstaller:
|
|||||||
font=('SF Pro Text', 18), anchor='ne')
|
font=('SF Pro Text', 18), anchor='ne')
|
||||||
|
|
||||||
self._render_title('Cluster Environment', y=150)
|
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)
|
# Cluster Selection (Radio Buttons)
|
||||||
x_label = 48
|
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))
|
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
|
y += 30
|
||||||
|
|
||||||
# Docker/K3D Status (only if dev)
|
# Cluster Status (only if dev)
|
||||||
if selected_env_key == 'dev':
|
if selected_env_key == 'dev':
|
||||||
y += 10
|
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.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)
|
self._canvas_items.append(self.k3d_status_label)
|
||||||
|
|
||||||
y += 30
|
y += 30
|
||||||
self.registry_status_label = ui.canvas_text(self, x_label, y, 'Local Registry: Checking...', fill='#6e6e73', font=('SF Pro Text', 12))
|
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.registry_status_label)
|
self._canvas_items.append(self.common_services_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)
|
|
||||||
|
|
||||||
y += 30
|
y += 30
|
||||||
self._cluster_env_message_label = ui.canvas_text(self, x_label, y, '', fill='#34c759', font=('SF Pro Text', 11))
|
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)
|
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 ''):
|
if rc_ns != 0 or ns not in (out_ns or ''):
|
||||||
return {
|
return {
|
||||||
'ok': True,
|
'ok': False,
|
||||||
'msg': 'Dashboard (Kong): Not installed',
|
'msg': 'Dashboard (Kong): Missing',
|
||||||
'fill': '#6e6e73',
|
'fill': '#ff9f0a',
|
||||||
'reset_pods': [],
|
'reset_pods': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5916,9 +5931,9 @@ class ProleInstaller:
|
|||||||
|
|
||||||
if not kong_pods:
|
if not kong_pods:
|
||||||
return {
|
return {
|
||||||
'ok': True,
|
'ok': False,
|
||||||
'msg': 'Dashboard (Kong): Not installed',
|
'msg': 'Dashboard (Kong): Missing',
|
||||||
'fill': '#6e6e73',
|
'fill': '#ff9f0a',
|
||||||
'reset_pods': [],
|
'reset_pods': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5969,6 +5984,79 @@ class ProleInstaller:
|
|||||||
pass
|
pass
|
||||||
self.safe_after(_clear, delay=clear_after_ms)
|
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:
|
def _check_opentofu_health(self) -> bool:
|
||||||
"""Check OpenTofu readiness in the selected namespace."""
|
"""Check OpenTofu readiness in the selected namespace."""
|
||||||
try:
|
try:
|
||||||
@ -6115,7 +6203,7 @@ class ProleInstaller:
|
|||||||
threading.Thread(target=worker, daemon=True).start()
|
threading.Thread(target=worker, daemon=True).start()
|
||||||
|
|
||||||
def _deploy_k3s_services(self):
|
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():
|
def _deploy():
|
||||||
console = self._k3s_service_deploy_console
|
console = self._k3s_service_deploy_console
|
||||||
if console:
|
if console:
|
||||||
@ -6228,39 +6316,6 @@ class ProleInstaller:
|
|||||||
def _cluster_status_snapshot(self) -> dict:
|
def _cluster_status_snapshot(self) -> dict:
|
||||||
env = self._cluster_env_key()
|
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
|
cluster_ok = False
|
||||||
if env == 'dev':
|
if env == 'dev':
|
||||||
cluster_name = "prole-dev-cluster"
|
cluster_name = "prole-dev-cluster"
|
||||||
@ -6274,33 +6329,24 @@ class ProleInstaller:
|
|||||||
cluster_ok, cluster_msg = self._check_k8s_cluster(env)
|
cluster_ok, cluster_msg = self._check_k8s_cluster(env)
|
||||||
cluster_fill = '#34c759' if cluster_ok else '#ff9f0a'
|
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 {
|
return {
|
||||||
'env': env,
|
'env': env,
|
||||||
'docker_ok': docker_ok,
|
|
||||||
'docker_msg': docker_msg,
|
|
||||||
'docker_fill': docker_fill,
|
|
||||||
'cluster_ok': cluster_ok,
|
'cluster_ok': cluster_ok,
|
||||||
'cluster_msg': cluster_msg,
|
'cluster_msg': cluster_msg,
|
||||||
'cluster_fill': cluster_fill,
|
'cluster_fill': cluster_fill,
|
||||||
'registry_ok': registry_ok,
|
'common_ok': common_ok,
|
||||||
'registry_msg': registry_msg,
|
'common_msg': common_msg,
|
||||||
'registry_fill': registry_fill,
|
'common_fill': common_fill,
|
||||||
'openbao_ok': openbao_ok,
|
|
||||||
'openbao_msg': openbao_msg,
|
|
||||||
'openbao_fill': openbao_fill,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def _cluster_ready_for_navigation(self) -> bool:
|
def _cluster_ready_for_navigation(self) -> bool:
|
||||||
status = self._cluster_status_snapshot()
|
status = self._cluster_status_snapshot()
|
||||||
env = status['env']
|
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']:
|
if not status['cluster_ok']:
|
||||||
try:
|
try:
|
||||||
messagebox.showerror('Cluster', 'Cluster is not reachable. Please verify your cluster and try again.')
|
messagebox.showerror('Cluster', 'Cluster is not reachable. Please verify your cluster and try again.')
|
||||||
@ -6308,48 +6354,6 @@ class ProleInstaller:
|
|||||||
pass
|
pass
|
||||||
return False
|
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
|
# Refresh status display for any changes
|
||||||
self.check_cluster_status_async()
|
self.check_cluster_status_async()
|
||||||
return True
|
return True
|
||||||
@ -6387,15 +6391,17 @@ class ProleInstaller:
|
|||||||
else:
|
else:
|
||||||
self._set_cluster_env_message("Execute Actions (REPAIR): none needed", '#34c759', clear_after_ms=1500)
|
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():
|
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'):
|
if hasattr(self, 'k3d_status_label'):
|
||||||
self.bg_canvas.itemconfig(self.k3d_status_label, text=status['cluster_msg'], fill=status['cluster_fill'])
|
self.bg_canvas.itemconfig(self.k3d_status_label, text=status['cluster_msg'], fill=status['cluster_fill'])
|
||||||
if hasattr(self, 'registry_status_label'):
|
if hasattr(self, 'common_services_status_label'):
|
||||||
self.bg_canvas.itemconfig(self.registry_status_label, text=status['registry_msg'], fill=status['registry_fill'])
|
self.bg_canvas.itemconfig(self.common_services_status_label, text=status['common_msg'], fill=status['common_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, '_init_cluster_button'):
|
if hasattr(self, '_init_cluster_button'):
|
||||||
try:
|
try:
|
||||||
self._init_cluster_button.configure(text='Save')
|
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.'))
|
self.root.after(0, lambda: messagebox.showerror('Docker', 'Could not start Docker. Please start it manually.'))
|
||||||
return
|
return
|
||||||
|
|
||||||
# 2. Ensure OpenBao container is running (local-only)
|
# 2. Manage or verify cluster
|
||||||
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
|
|
||||||
cluster_name = 'prole-dev-cluster'
|
cluster_name = 'prole-dev-cluster'
|
||||||
res = subprocess.run(['k3d', 'cluster', 'list', '--no-headers'], capture_output=True, text=True)
|
res = subprocess.run(['k3d', 'cluster', 'list', '--no-headers'], capture_output=True, text=True)
|
||||||
if cluster_name not in (res.stdout or ''):
|
if cluster_name not in (res.stdout or ''):
|
||||||
@ -6716,7 +6704,7 @@ class ProleInstaller:
|
|||||||
self._overlay_widgets.append(owner_entry)
|
self._overlay_widgets.append(owner_entry)
|
||||||
|
|
||||||
y += 42
|
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
|
# Use tk.Entry on canvas
|
||||||
p1 = tk.Entry(self.bg_canvas, textvariable=self.db_password, show='*', bg='white', fg='black',
|
p1 = tk.Entry(self.bg_canvas, textvariable=self.db_password, show='*', bg='white', fg='black',
|
||||||
insertbackground='black', highlightbackground='#CCCCCC', highlightthickness=1,
|
insertbackground='black', highlightbackground='#CCCCCC', highlightthickness=1,
|
||||||
@ -6895,20 +6883,26 @@ class ProleInstaller:
|
|||||||
# Output Console
|
# Output Console
|
||||||
self._cnpg_deploy_console = self._create_console_output(y=260, title="Deployment Output", width=900, height=520)
|
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
|
# Use tk.Button
|
||||||
self._cnpg_deploy_button = tk.Button(self.bg_canvas, text='Run Deployment', command=self.run_cnpg_deploy,
|
self._cnpg_deploy_button = tk.Button(self.bg_canvas, text='Run Deployment', command=self.run_cnpg_deploy,
|
||||||
bg='#F5F5DC', fg='black', activebackground='#E5E5D5',
|
bg='#F5F5DC', fg='black', activebackground='#E5E5D5',
|
||||||
highlightbackground='#F5F5DC', highlightthickness=0,
|
highlightbackground='#F5F5DC', highlightthickness=0,
|
||||||
relief='flat', font=('SF Pro Text', 11), padx=16, pady=8)
|
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)
|
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._canvas_items.append(btn_window)
|
||||||
self._overlay_widgets.append(self._cnpg_deploy_button)
|
self._overlay_widgets.append(self._cnpg_deploy_button)
|
||||||
@ -6922,9 +6916,20 @@ class ProleInstaller:
|
|||||||
self._canvas_items.append(rollout_btn_window)
|
self._canvas_items.append(rollout_btn_window)
|
||||||
self._overlay_widgets.append(self._cnpg_rollout_button)
|
self._overlay_widgets.append(self._cnpg_rollout_button)
|
||||||
|
|
||||||
# Status Label
|
# Save Deployment Button (moved from Post Install)
|
||||||
self._cnpg_deploy_status_label = ui.canvas_text(self, 600, 812, "", fill='black', font=('SF Pro Text', 12))
|
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._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):
|
def run_cnpg_deploy(self):
|
||||||
self._action_flags['init_cnpg_deploy.run_deploy'] = True
|
self._action_flags['init_cnpg_deploy.run_deploy'] = True
|
||||||
@ -9177,6 +9182,30 @@ echo "-------------------------------------------------------------------";
|
|||||||
|
|
||||||
# ---------------- Build Summary page ----------------
|
# ---------------- Build Summary page ----------------
|
||||||
def run_final_deployment(self):
|
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():
|
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._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)
|
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 = os.environ.copy()
|
||||||
env["PROLE_HOME"] = str(PROJECT_ROOT)
|
env["PROLE_HOME"] = str(PROJECT_ROOT)
|
||||||
import_dir = self.docker_import_dir.get().strip()
|
env["DOCKER_IMPORT_DIR"] = docker_export_dir
|
||||||
if import_dir:
|
env["HELM_CHART_DIR"] = helm_export_dir
|
||||||
env["DOCKER_IMPORT_DIR"] = import_dir
|
env["KUSTOMIZE_DIR"] = kustomize_export_dir
|
||||||
|
|
||||||
console = getattr(self, 'install_consoles', {}).get(script_name)
|
console = getattr(self, 'install_consoles', {}).get(script_name)
|
||||||
if console:
|
if console:
|
||||||
console.clear()
|
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):
|
def _on_line(line):
|
||||||
if console:
|
if console:
|
||||||
@ -9202,7 +9235,7 @@ echo "-------------------------------------------------------------------";
|
|||||||
|
|
||||||
rc = self.controller.run_script(
|
rc = self.controller.run_script(
|
||||||
script_name,
|
script_name,
|
||||||
args=['--docker-export'],
|
args=['--docker-export', '--helm-chart', '--kustomize', '--output-dir', export_base],
|
||||||
env=env,
|
env=env,
|
||||||
on_line=_on_line
|
on_line=_on_line
|
||||||
)
|
)
|
||||||
@ -9385,20 +9418,9 @@ echo "-------------------------------------------------------------------";
|
|||||||
self._canvas_items.append(bao_btn_window)
|
self._canvas_items.append(bao_btn_window)
|
||||||
self._overlay_widgets.append(self._build_a_bao_button)
|
self._overlay_widgets.append(self._build_a_bao_button)
|
||||||
|
|
||||||
# Save Deployment Button
|
# Status Label
|
||||||
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
|
|
||||||
self._build_a_bao_status_label = ui.canvas_text(self, 48, 802, "", fill='black', font=('SF Pro Text', 12))
|
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._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):
|
def _render_build_summary_page(self):
|
||||||
# Ensure slide_area is visible for the build log console
|
# Ensure slide_area is visible for the build log console
|
||||||
@ -11023,6 +11045,7 @@ class ProleSilentInstaller:
|
|||||||
self._cnpg_success = False
|
self._cnpg_success = False
|
||||||
self._managed_kubeconfig = None
|
self._managed_kubeconfig = None
|
||||||
self.docker_import_dir = None
|
self.docker_import_dir = None
|
||||||
|
self._repair_ran = False
|
||||||
|
|
||||||
# ---------------- Logging helpers ----------------
|
# ---------------- Logging helpers ----------------
|
||||||
def log(self, msg: str):
|
def log(self, msg: str):
|
||||||
@ -11041,7 +11064,7 @@ class ProleSilentInstaller:
|
|||||||
prole_conf = os.environ.get('PROLE_CONF')
|
prole_conf = os.environ.get('PROLE_CONF')
|
||||||
if prole_conf:
|
if prole_conf:
|
||||||
return Path(_expand_path(prole_conf)) / 'prole.cfg'
|
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:
|
def _load_inputs_from_cfg(self) -> dict:
|
||||||
cfg = configparser.ConfigParser(interpolation=None)
|
cfg = configparser.ConfigParser(interpolation=None)
|
||||||
@ -11488,6 +11511,77 @@ class ProleSilentInstaller:
|
|||||||
|
|
||||||
return env
|
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 ----------------
|
# ---------------- Namespace helpers ----------------
|
||||||
def _get_local_owner(self) -> str:
|
def _get_local_owner(self) -> str:
|
||||||
try:
|
try:
|
||||||
@ -12576,6 +12670,14 @@ class ProleSilentInstaller:
|
|||||||
raise Exception("Cluster is not reachable.")
|
raise Exception("Cluster is not reachable.")
|
||||||
self.log(f"[OK] Cluster ready: {env_key}")
|
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':
|
if env_key == 'service':
|
||||||
self._deploy_common_services(env_key)
|
self._deploy_common_services(env_key)
|
||||||
else:
|
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()] {
|
for dir in [proleHome(), logsDir(), confDir()] {
|
||||||
try? fm.createDirectory(at: dir, withIntermediateDirectories: true)
|
try? fm.createDirectory(at: dir, withIntermediateDirectories: true)
|
||||||
}
|
}
|
||||||
// Ensure conf/port-mappings.conf exists
|
// Ensure conf/port-mapping.cfg exists
|
||||||
let pm = confDir().appendingPathComponent("port-mappings.conf")
|
let pm = confDir().appendingPathComponent("port-mapping.cfg")
|
||||||
if !fm.fileExists(atPath: pm.path) {
|
if !fm.fileExists(atPath: pm.path) {
|
||||||
let tpl = """
|
let tpl = """
|
||||||
# Port mappings for Prole Tools (read by scripts).
|
# Port mappings for Prole Tools (read by scripts).
|
||||||
|
|||||||
@ -13,7 +13,7 @@ ui.background=img/proleLogoSepia.png
|
|||||||
ui.welcometxt=installer/welcome.txt
|
ui.welcometxt=installer/welcome.txt
|
||||||
|
|
||||||
# Dev port-forward supervision
|
# 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.
|
# The legacy pf.* keys are intentionally omitted from the bundled defaults.
|
||||||
pf.enabled=true
|
pf.enabled=true
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ ui.background=img/proleLogoSepia.png
|
|||||||
ui.welcometxt=installer/welcome.txt
|
ui.welcometxt=installer/welcome.txt
|
||||||
|
|
||||||
# Dev port-forward supervision
|
# 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.
|
# The legacy pf.* keys are intentionally omitted from the bundled defaults.
|
||||||
pf.enabled=true
|
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
|
# Unit test for etc/build-a-bao.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/build-a-bao.sh"
|
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
|
# Unit test for etc/deploy_pipeline.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/deploy_pipeline.sh"
|
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
|
# Unit test for etc/final_deployment.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/final_deployment.sh"
|
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
|
# Unit test for etc/init_ansible.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_ansible.sh"
|
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
|
# Unit test for etc/init_cloudnative_pg.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_cloudnative_pg.sh"
|
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
|
# Unit test for etc/init_common_services.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_common_services.sh"
|
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
|
# Unit test for etc/init_garage_store.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_garage_store.sh"
|
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
|
# Unit test for etc/init_k3s_registry.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_k3s_registry.sh"
|
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
|
# Unit test for etc/init_k8s.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_k8s.sh"
|
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
|
# Unit test for etc/init_kdc.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_kdc.sh"
|
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
|
# Unit test for etc/init_kerberos.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_kerberos.sh"
|
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
|
# Unit test for etc/init_kerberos_test.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_kerberos_test.sh"
|
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
|
# Unit test for etc/init_monitoring.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_monitoring.sh"
|
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
|
# Unit test for etc/init_ollama.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_ollama.sh"
|
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
|
# Unit test for etc/init_openbao.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_openbao.sh"
|
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
|
# Unit test for etc/init_opentofu.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_opentofu.sh"
|
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
|
# Unit test for etc/init_port_forwards.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_port_forwards.sh"
|
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
|
# Unit test for etc/init_prole-db-backup.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_prole-db-backup.sh"
|
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
|
# Unit test for etc/init_prole-db-reset.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_prole-db-reset.sh"
|
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
|
# Unit test for etc/init_registry.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_registry.sh"
|
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
|
# Unit test for etc/init_service_layer.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_service_layer.sh"
|
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
|
# Unit test for etc/init_supabase_ports.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/init_supabase_ports.sh"
|
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
|
# Unit test for etc/render_manifest.py
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/render_manifest.py"
|
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
|
# Unit test for etc/set-k3s-token-vault.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/set-k3s-token-vault.sh"
|
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
|
# Unit test for etc/status_common_services.sh
|
||||||
|
|
||||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
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"
|
ETC_DIR="$PROLE_HOME/etc"
|
||||||
SCRIPT_UNDER_TEST="$ETC_DIR/status_common_services.sh"
|
SCRIPT_UNDER_TEST="$ETC_DIR/status_common_services.sh"
|
||||||
|
|
||||||
@ -30,14 +30,18 @@ if [[ -z "$CFG_PATH" ]]; then
|
|||||||
CFG_PATH="$PROLE_CONF/prole.cfg"
|
CFG_PATH="$PROLE_CONF/prole.cfg"
|
||||||
elif [[ -f "$ROOT_DIR/conf/prole.cfg" ]]; then
|
elif [[ -f "$ROOT_DIR/conf/prole.cfg" ]]; then
|
||||||
CFG_PATH="$ROOT_DIR/conf/prole.cfg"
|
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
|
else
|
||||||
echo "ERROR: prole.cfg not found. Pass a path or set PROLE_CONF." >&2
|
echo "ERROR: prole.cfg not found. Pass a path or set PROLE_CONF." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
CFG_DIR="$(cd "$(dirname "$CFG_PATH")" && pwd)"
|
||||||
|
if [[ -z "${PROLE_CONF:-}" ]]; then
|
||||||
|
PROLE_CONF="$CFG_DIR"
|
||||||
|
export PROLE_CONF
|
||||||
|
fi
|
||||||
|
|
||||||
TMP_CFG=""
|
TMP_CFG=""
|
||||||
if [[ "${PROLE_CFG_INPLACE:-}" != "true" ]]; then
|
if [[ "${PROLE_CFG_INPLACE:-}" != "true" ]]; then
|
||||||
TMP_CFG="$(mktemp -t prole.cfg.XXXXXX)"
|
TMP_CFG="$(mktemp -t prole.cfg.XXXXXX)"
|
||||||
@ -205,7 +209,7 @@ fi
|
|||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "3. Blessing sanitized gold config..."
|
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 re
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user