refactor(config): separate k3d k3s and gke config entrypoints

Rename env config files from conf/*/prole.cfg to conf/k3d.cfg, conf/k3s.cfg, and conf/gke.cfg. Update shell/Python loaders and etc/deploy scripts to resolve named configs cleanly while keeping legacy fallback behavior. Align k3s Ansible tasks, docs, and regression coverage with the new configuration layout.

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
chrisfu 2026-04-11 22:20:45 -07:00
parent b1755f4e7b
commit e3c2e625f1
42 changed files with 561 additions and 252 deletions

View File

@ -65,7 +65,7 @@ gcloud container fleet mesh update \
## install.sh / deploy.sh pre-flight checklist ## install.sh / deploy.sh pre-flight checklist
### `conf/prod/prole.cfg` (interactive installer — `./install.sh`) ### `conf/gke.cfg` (interactive installer — `./install.sh`)
Before running `./install.sh` (especially "Initialization Scripts"), confirm these are correct: Before running `./install.sh` (especially "Initialization Scripts"), confirm these are correct:

View File

@ -1,7 +1,7 @@
# Generated by knoe/config.py --mode k8s --provider gcp # Generated by knoe/config.py --mode k8s --provider gcp
# Copy org_id, billing_account, billing_project into: # Copy org_id, billing_account, billing_project into:
# deploy/gcp/terraform/cloud-setup.auto.tfvars # deploy/gcp/terraform/cloud-setup.auto.tfvars
# Loaded automatically by the installer into conf/prod/prole.cfg [GCP] # Loaded automatically by the installer into conf/gke.cfg [GCP]
# Org: knoey.com # Org: knoey.com
org_id = "584001916389" org_id = "584001916389"

View File

@ -1,5 +1,5 @@
; Port mappings generated by init_port_forwards ; Port mappings generated by init_port_forwards
; Source: /Users/chrisfu/dev/prole/conf/service/prole.cfg ; Source: /Users/chrisfu/dev/prole/conf/k3s.cfg
[PortMappings] [PortMappings]
PORT_FORWARD_K3S_MAPPING_1 = id=argocd;namespace=argocd;target=svc/argocd-server;address=0.0.0.0;hostPort=8081;servicePort=80;protocol=TCP;description=ArgoCD PORT_FORWARD_K3S_MAPPING_1 = id=argocd;namespace=argocd;target=svc/argocd-server;address=0.0.0.0;hostPort=8081;servicePort=80;protocol=TCP;description=ArgoCD
PORT_FORWARD_K3S_MAPPING_10 = id=supabase-studio;namespace=supabase;target=svc/studio;address=0.0.0.0;hostPort=18080;servicePort=3000;protocol=TCP;description=Supabase Studio PORT_FORWARD_K3S_MAPPING_10 = id=supabase-studio;namespace=supabase;target=svc/studio;address=0.0.0.0;hostPort=18080;servicePort=3000;protocol=TCP;description=Supabase Studio

View File

@ -1,44 +1,42 @@
### Prole configuration environments ### Prole configuration environments
Prole treats `$PROLE_CONF` as an explicit, switchable set of isolated environment configs. Prole treats `$PROLE_CONF` as an explicit set of deployment-specific configs.
#### Directory layout #### Directory layout
Under `$PROLE_CONF`: Under `$PROLE_CONF`:
```text ```text
$PROLE_CONF/prole.cfg -> symlink entrypoint (active env) $PROLE_CONF/k3d.cfg -> base config (k3d / dev)
$PROLE_CONF/dev/prole.cfg -> base config (dev) $PROLE_CONF/k3s.cfg -> base config (k3s / service)
$PROLE_CONF/service/prole.cfg -> base config (service) $PROLE_CONF/gke.cfg -> base config (k8s / prod)
$PROLE_CONF/prod/prole.cfg -> base config (prod) $PROLE_CONF/test.cfg -> base config (test, optional)
$PROLE_CONF/test/prole.cfg -> base config (test)
# Optional overrides (conf.d-style) per environment:
$PROLE_CONF/<env>/*.cfg -> applied as layered overrides
``` ```
Existing code continues to read `.../prole.cfg` via the single stable entrypoint path: `$PROLE_CONF/prole.cfg`. Legacy layouts are still recognized for compatibility:
```text
$PROLE_CONF/prole.cfg -> legacy entrypoint
$PROLE_CONF/<env>/prole.cfg -> legacy env base config
```
#### Activation (selecting the active environment) #### Activation (selecting the active environment)
- The active environment is determined by what `$PROLE_CONF/prole.cfg` points to. - The active environment is inferred from `CLUSTER_ENV`, `PROLE_MODE`, or `DEPLOYMENT_MODE`.
- The Cluster Environment screen activates the selected env by updating the symlink (via `installer/prole_conf.py`). - Resolution prefers named root files (`k3d.cfg`, `k3s.cfg`, `gke.cfg`) and only falls back to legacy `prole.cfg` paths.
- Switching environments only changes the symlink target; it does not overwrite any other environments curated files. - Switching environments changes which named file is selected; it does not overwrite other environment configs.
If the entrypoint is a regular file (legacy layout), activation preserves it as `prole.cfg.legacy.<timestamp>` and switches to the symlink-based layout. If a legacy `prole.cfg` regular file is detected, migration preserves it as `prole.cfg.legacy.<timestamp>` and promotes content into the appropriate named file.
#### Override layering (deterministic merge) #### Override layering (deterministic merge)
For a selected environment directory `$PROLE_CONF/<env>/`: - Named root configs (`k3d.cfg`, `k3s.cfg`, `gke.cfg`, `test.cfg`) are loaded directly.
- Legacy env-directory layout still supports layered `*.cfg` overrides in lexicographic filename order.
1. Load `$PROLE_CONF/<env>/prole.cfg` (base) Later files override earlier values (last write wins).
2. Load every other `*.cfg` file in the same directory, in lexicographic filename order
Later files override earlier values (last write wins). This makes overrides predictable and reviewable.
#### Why this prevents accidental namespace drift #### Why this prevents accidental namespace drift
- Tests can target an isolated environment (`test`) with its own base config and overrides. - k3d, k3s, and k8s/GKE are cleanly separated by dedicated config files.
- Environment switching is explicit (symlink target changes) and stable (entrypoint path stays the same). - Mode/environment selection is explicit via deployment hints instead of mutable symlink state.
- Updates that need to modify config write through the entrypoint symlink to the active environments base file, avoiding hidden cross-environment mutations. - Legacy configs remain readable during transition, reducing migration risk.
- The `test` environment defaults to a non-`default` namespace (`prole-test`), reducing the chance that unit/integration runs revert to Kubernetes `default`.

View File

@ -4,9 +4,9 @@ set -euo pipefail
# build-a-bao.sh # build-a-bao.sh
# Purpose: # Purpose:
# - Decrypt temporary secrets stored in prole.cfg # - Decrypt temporary secrets stored in the active config file
# - Store them in OpenBao for the current namespace # - Store them in OpenBao for the current namespace
# - Replace prole.cfg secrets with OpenBao placeholders # - Replace config-file secrets with OpenBao placeholders
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
@ -15,16 +15,16 @@ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
source "$SCRIPT_DIR/prole_cfg.sh" source "$SCRIPT_DIR/prole_cfg.sh"
cfg_path="" cfg_path=""
if [[ -n "${PROLE_CONF:-}" && -f "$PROLE_CONF/prole.cfg" ]]; then if [[ -n "${PROLE_CONF:-}" ]]; then
cfg_path="$PROLE_CONF/prole.cfg" cfg_path="$(_prole_cfg_select_cfg_file "$PROLE_CONF")"
elif [[ -n "${PROLE_HOME:-}" && -f "$PROLE_HOME/conf/prole.cfg" ]]; then elif [[ -n "${PROLE_HOME:-}" ]]; then
cfg_path="$PROLE_HOME/conf/prole.cfg" cfg_path="$(_prole_cfg_select_cfg_file "$PROLE_HOME/conf")"
elif [[ -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then else
cfg_path="$SCRIPT_DIR/../conf/prole.cfg" cfg_path="$(_prole_cfg_select_cfg_file "$SCRIPT_DIR/../conf")"
fi fi
if [[ -z "$cfg_path" || ! -f "$cfg_path" ]]; then if [[ -z "$cfg_path" || ! -f "$cfg_path" ]]; then
echo "ERROR: prole.cfg not found. Set PROLE_CONF or PROLE_HOME." >&2 echo "ERROR: config file not found. Set PROLE_CONF or PROLE_HOME." >&2
exit 1 exit 1
fi fi

View File

@ -18,10 +18,13 @@ _has_config=0
for _arg in "$@"; do for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1 [[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then if [[ $_has_config -eq 0 ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@" _default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi fi
unset _has_config _arg unset _has_config _arg _default_cfg
common_core_preparse_config "$@" common_core_preparse_config "$@"
@ -61,7 +64,7 @@ fi
usage() { usage() {
cat <<USAGE cat <<USAGE
Usage: $0 [--mode MODE] [-n NAMESPACE] [${COMMON_CORE_ACTIONS//|/|}] [-c conf/prole.cfg] Usage: $0 [--mode MODE] [-n NAMESPACE] [${COMMON_CORE_ACTIONS//|/|}] [-c conf/{k3d|k3s|gke}.cfg]
Actions: Actions:
start Install cert-manager (CRDs + controller) start Install cert-manager (CRDs + controller)

View File

@ -11,10 +11,13 @@ _has_config=0
for _arg in "$@"; do for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1 [[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then if [[ $_has_config -eq 0 ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@" _default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi fi
unset _has_config _arg unset _has_config _arg _default_cfg
common_core_preparse_config "$@" common_core_preparse_config "$@"

View File

@ -5,7 +5,7 @@ set -euo pipefail
# - Build and deploy the knoe-db-manager Node.js REST endpoint # - Build and deploy the knoe-db-manager Node.js REST endpoint
# - Provides /backup/<cluster>/full to trigger barman full backups into Garage # - Provides /backup/<cluster>/full to trigger barman full backups into Garage
# - Deploys to the knoe-db namespace; accessible via Kong endpoint /backup # - Deploys to the knoe-db namespace; accessible via Kong endpoint /backup
# - Deploys to the current cluster (k3d or k3s) based on PROLE_MODE from conf/prole.cfg # - Deploys to the current cluster (k3d or k3s) based on PROLE_MODE from active config
# #
# Usage: # Usage:
# ./init_db_manager.sh [--mode MODE] <start|stop|status|restart|build> # ./init_db_manager.sh [--mode MODE] <start|stop|status|restart|build>

View File

@ -20,7 +20,7 @@ Usage:
Options: Options:
--mode <k3d|k3s|k8s|local> Deployment mode (default: ${MODE:-k3d}) --mode <k3d|k3s|k8s|local> Deployment mode (default: ${MODE:-k3d})
-n, --namespace <name> Target namespace (default: forgejo) -n, --namespace <name> Target namespace (default: forgejo)
-c, --config <prole.cfg> Path to prole.cfg (defaults to detected) -c, --config <config.cfg> Path to config file (defaults to detected)
--force Delete existing Forgejo resources before deploy --force Delete existing Forgejo resources before deploy
--help Show this help --help Show this help
@ -49,11 +49,12 @@ while [[ $# -gt 0 ]]; do
esac esac
done done
# Resolve config path and namespace defaults from prole.cfg when present # Resolve config path and namespace defaults when present
if [[ -z "$CFG_PATH" && -n "${PROLE_CONF:-}" && -f "${PROLE_CONF}/prole.cfg" ]]; then if [[ -z "$CFG_PATH" && -n "${PROLE_CONF:-}" ]]; then
CFG_PATH="${PROLE_CONF}/prole.cfg" CFG_PATH="$(_prole_cfg_select_cfg_file "${PROLE_CONF}")"
elif [[ -z "$CFG_PATH" && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then fi
CFG_PATH="$SCRIPT_DIR/../conf/prole.cfg" if [[ -z "$CFG_PATH" ]]; then
CFG_PATH="$(_prole_cfg_select_cfg_file "$SCRIPT_DIR/../conf")"
fi fi
if [[ -z "$NAMESPACE" && -n "$CFG_PATH" ]]; then if [[ -z "$NAMESPACE" && -n "$CFG_PATH" ]]; then

View File

@ -20,7 +20,7 @@ Usage:
Options: Options:
--mode <k3d|k3s|k8s|local> Deployment mode (default: ${MODE:-k3d}) --mode <k3d|k3s|k8s|local> Deployment mode (default: ${MODE:-k3d})
-n, --namespace <name> Target namespace (default: gitea) -n, --namespace <name> Target namespace (default: gitea)
-c, --config <prole.cfg> Path to prole.cfg (defaults to detected) -c, --config <config.cfg> Path to config file (defaults to detected)
--force Delete existing release before deploy --force Delete existing release before deploy
--help Show this help --help Show this help
@ -49,11 +49,12 @@ while [[ $# -gt 0 ]]; do
esac esac
done done
# Resolve config path and namespace defaults from prole.cfg when present # Resolve config path and namespace defaults when present
if [[ -z "$CFG_PATH" && -n "${PROLE_CONF:-}" && -f "${PROLE_CONF}/prole.cfg" ]]; then if [[ -z "$CFG_PATH" && -n "${PROLE_CONF:-}" ]]; then
CFG_PATH="${PROLE_CONF}/prole.cfg" CFG_PATH="$(_prole_cfg_select_cfg_file "${PROLE_CONF}")"
elif [[ -z "$CFG_PATH" && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then fi
CFG_PATH="$SCRIPT_DIR/../conf/prole.cfg" if [[ -z "$CFG_PATH" ]]; then
CFG_PATH="$(_prole_cfg_select_cfg_file "$SCRIPT_DIR/../conf")"
fi fi
if [[ -z "$NAMESPACE" && -n "$CFG_PATH" ]]; then if [[ -z "$NAMESPACE" && -n "$CFG_PATH" ]]; then

View File

@ -25,7 +25,7 @@ Usage:
Options: Options:
--mode <k3d|k3s|k8s|local> Deployment mode (default: ${MODE:-k3d}) --mode <k3d|k3s|k8s|local> Deployment mode (default: ${MODE:-k3d})
-n, --namespace <name> Target namespace (default: gitlab) -n, --namespace <name> Target namespace (default: gitlab)
-c, --config <prole.cfg> Path to prole.cfg (defaults to detected) -c, --config <config.cfg> Path to config file (defaults to detected)
--node-selector <node> Node to pin GitLab workloads (default: gandalf.prole.org) --node-selector <node> Node to pin GitLab workloads (default: gandalf.prole.org)
--force Remove existing GitLab and Gitea releases before deploy --force Remove existing GitLab and Gitea releases before deploy
--help Show this help --help Show this help
@ -68,9 +68,10 @@ done
# Resolve config path # Resolve config path
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
if [[ -z "$CFG_PATH" && -n "${PROLE_CONF:-}" && -f "${PROLE_CONF}/prole.cfg" ]]; then if [[ -z "$CFG_PATH" && -n "${PROLE_CONF:-}" && -f "${PROLE_CONF}/prole.cfg" ]]; then
CFG_PATH="${PROLE_CONF}/prole.cfg" CFG_PATH="$(_prole_cfg_select_cfg_file "${PROLE_CONF}")"
elif [[ -z "$CFG_PATH" && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then fi
CFG_PATH="$SCRIPT_DIR/../conf/prole.cfg" if [[ -z "$CFG_PATH" ]]; then
CFG_PATH="$(_prole_cfg_select_cfg_file "$SCRIPT_DIR/../conf")"
fi fi
# cfg-based namespace override (only GITLAB_NAMESPACE; GITOPS_NAMESPACE intentionally excluded) # cfg-based namespace override (only GITLAB_NAMESPACE; GITOPS_NAMESPACE intentionally excluded)

View File

@ -156,12 +156,24 @@ is_ip_address() {
} }
detect_prole_cfg() { detect_prole_cfg() {
if [[ -n "${PROLE_CONF:-}" && -f "$PROLE_CONF/prole.cfg" ]]; then local cfg=""
printf '%s' "$PROLE_CONF/prole.cfg" if [[ -n "${PROLE_CONF:-}" ]]; then
elif [[ -n "${PROLE_HOME:-}" && -f "$PROLE_HOME/conf/prole.cfg" ]]; then cfg="$(_prole_cfg_select_cfg_file "$PROLE_CONF")"
printf '%s' "$PROLE_HOME/conf/prole.cfg" if [[ -n "$cfg" ]]; then
elif [[ -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then printf '%s' "$cfg"
printf '%s' "$SCRIPT_DIR/../conf/prole.cfg" return 0
fi
fi
if [[ -n "${PROLE_HOME:-}" ]]; then
cfg="$(_prole_cfg_select_cfg_file "$PROLE_HOME/conf")"
if [[ -n "$cfg" ]]; then
printf '%s' "$cfg"
return 0
fi
fi
cfg="$(_prole_cfg_select_cfg_file "$SCRIPT_DIR/../conf")"
if [[ -n "$cfg" ]]; then
printf '%s' "$cfg"
fi fi
} }

View File

@ -22,10 +22,13 @@ _has_config=0
for _arg in "$@"; do for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1 [[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then if [[ $_has_config -eq 0 ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@" _default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi fi
unset _has_config _arg unset _has_config _arg _default_cfg
common_core_preparse_config "$@" common_core_preparse_config "$@"
@ -102,7 +105,7 @@ KNOE_AUTH_UPSTREAM_URL="${KNOE_AUTH_UPSTREAM_URL:-http://knoe-auth.${SERVICE_NAM
usage() { usage() {
cat <<USAGE cat <<USAGE
Usage: $0 [--mode MODE] [-n NAMESPACE] [${COMMON_CORE_ACTIONS//|/|}] [-c conf/prole.cfg] Usage: $0 [--mode MODE] [-n NAMESPACE] [${COMMON_CORE_ACTIONS//|/|}] [-c conf/{k3d|k3s|gke}.cfg]
Actions: Actions:
start Create ConfigMap and deploy Kong start Create ConfigMap and deploy Kong

View File

@ -20,10 +20,13 @@ _has_config=0
for _arg in "$@"; do for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1 [[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then if [[ $_has_config -eq 0 ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@" _default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi fi
unset _has_config _arg unset _has_config _arg _default_cfg
common_core_preparse_config "$@" common_core_preparse_config "$@"
@ -100,7 +103,7 @@ root_token_file="$SECRETS_DIR/openbao-root-token"
OPENBAO_NAMESPACE=${OPENBAO_NAMESPACE:-${SERVICE_NAMESPACE:-${NAMESPACE:-default}}} OPENBAO_NAMESPACE=${OPENBAO_NAMESPACE:-${SERVICE_NAMESPACE:-${NAMESPACE:-default}}}
# OpenBao resources (StatefulSet/Service) live in `OPENBAO_NAMESPACE` (usually the service namespace), # OpenBao resources (StatefulSet/Service) live in `OPENBAO_NAMESPACE` (usually the service namespace),
# but secret *paths* must be keyed by the Prole workload namespace from `conf/prole.cfg` so that # but secret *paths* must be keyed by the Prole workload namespace from the active config file so that
# `${OPENBAO:kv/prole/<PROLE_NAMESPACE>/...}` references resolve consistently across scripts. # `${OPENBAO:kv/prole/<PROLE_NAMESPACE>/...}` references resolve consistently across scripts.
OPENBAO_PATH_NAMESPACE=${OPENBAO_PATH_NAMESPACE:-${PROLE_NAMESPACE:-${NAMESPACE:-default}}} OPENBAO_PATH_NAMESPACE=${OPENBAO_PATH_NAMESPACE:-${PROLE_NAMESPACE:-${NAMESPACE:-default}}}
OPENBAO_RESOURCE_NAMESPACE="$OPENBAO_NAMESPACE" OPENBAO_RESOURCE_NAMESPACE="$OPENBAO_NAMESPACE"

View File

@ -32,16 +32,16 @@ Usage:
$PROG [-v|--verbose] [-f|--force] [-c|--config-file=FILE] <start|stop|restart|status> [component] $PROG [-v|--verbose] [-f|--force] [-c|--config-file=FILE] <start|stop|restart|status> [component]
Options: Options:
-c, --config-file=FILE Path to a prole.cfg file to source when generating port-mapping.cfg -c, --config-file=FILE Path to a config file to source when generating port-mapping.cfg
-v, --verbose Verbose output -v, --verbose Verbose output
-f, --force Force: kill existing processes blocking ports -f, --force Force: kill existing processes blocking ports
Examples: Examples:
$PROG -c ./prole.cfg start $PROG -c ./k3d.cfg start
$PROG stop openbao $PROG stop openbao
$PROG --verbose status $PROG --verbose status
Config (prole.cfg or port-mapping.cfg): Config (k3d.cfg/k3s.cfg/gke.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: Legacy port-mapping.cfg:
@ -60,13 +60,22 @@ have() { command -v "$1" >/dev/null 2>&1; }
# ---- Config helpers / derived defaults ---- # ---- Config helpers / derived defaults ----
cfg_file() { cfg_file() {
if [ -n "${PROLE_CONF:-}" ] && [ -f "$PROLE_CONF/prole.cfg" ]; then local cfg=""
printf '%s' "$PROLE_CONF/prole.cfg" if declare -F _prole_cfg_select_cfg_file >/dev/null 2>&1; then
return 0 if [ -n "${PROLE_CONF:-}" ]; then
fi cfg="$(_prole_cfg_select_cfg_file "$PROLE_CONF")"
if [ -n "${PROLE_HOME:-}" ] && [ -f "$PROLE_HOME/conf/prole.cfg" ]; then if [ -n "$cfg" ]; then
printf '%s' "$PROLE_HOME/conf/prole.cfg" printf '%s' "$cfg"
return 0 return 0
fi
fi
if [ -n "${PROLE_HOME:-}" ]; then
cfg="$(_prole_cfg_select_cfg_file "$PROLE_HOME/conf")"
if [ -n "$cfg" ]; then
printf '%s' "$cfg"
return 0
fi
fi
fi fi
return 1 return 1
} }

View File

@ -20,10 +20,13 @@ _has_config=0
for _arg in "$@"; do for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1 [[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then if [[ $_has_config -eq 0 ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@" _default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi fi
unset _has_config _arg unset _has_config _arg _default_cfg
common_core_preparse_config "$@" common_core_preparse_config "$@"

View File

@ -19,10 +19,13 @@ _has_config=0
for _arg in "$@"; do for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1 [[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then if [[ $_has_config -eq 0 ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@" _default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi fi
unset _has_config _arg unset _has_config _arg _default_cfg
common_core_preparse_config "$@" common_core_preparse_config "$@"

View File

@ -18,10 +18,13 @@ _has_config=0
for _arg in "$@"; do for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1 [[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then if [[ $_has_config -eq 0 ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@" _default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi fi
unset _has_config _arg unset _has_config _arg _default_cfg
common_core_preparse_config "$@" common_core_preparse_config "$@"

View File

@ -14,7 +14,7 @@ Usage: $0 [-k|--kdc] [-f|--force] [-c|--config <path>]
Options: Options:
-k, --kdc Authenticate current password against a running KDC -k, --kdc Authenticate current password against a running KDC
-f, --force Skip current password verification -f, --force Skip current password verification
-c, --config Path to prole.cfg (default: detected) -c, --config Path to config file (default: detected)
USAGE USAGE
} }
@ -49,17 +49,17 @@ while [[ $# -gt 0 ]]; do
done done
if [[ -z "$CFG_PATH" ]]; then if [[ -z "$CFG_PATH" ]]; then
if [[ -n "${PROLE_CONF:-}" && -f "$PROLE_CONF/prole.cfg" ]]; then if [[ -n "${PROLE_CONF:-}" ]]; then
CFG_PATH="$PROLE_CONF/prole.cfg" CFG_PATH="$(_prole_cfg_select_cfg_file "$PROLE_CONF")"
elif [[ -n "${PROLE_HOME:-}" && -f "$PROLE_HOME/conf/prole.cfg" ]]; then elif [[ -n "${PROLE_HOME:-}" ]]; then
CFG_PATH="$PROLE_HOME/conf/prole.cfg" CFG_PATH="$(_prole_cfg_select_cfg_file "$PROLE_HOME/conf")"
elif [[ -f "$ROOT_DIR/conf/prole.cfg" ]]; then else
CFG_PATH="$ROOT_DIR/conf/prole.cfg" CFG_PATH="$(_prole_cfg_select_cfg_file "$ROOT_DIR/conf")"
fi fi
fi fi
if [[ -z "$CFG_PATH" || ! -f "$CFG_PATH" ]]; then if [[ -z "$CFG_PATH" || ! -f "$CFG_PATH" ]]; then
echo "ERROR: prole.cfg not found. Use -c to specify path." >&2 echo "ERROR: config file not found. Use -c to specify path." >&2
exit 1 exit 1
fi fi

View File

@ -1,13 +1,44 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Shared helpers for common core init scripts (ArgoCD, OpenBao, OpenTofu, Garage). # Shared helpers for common core init scripts (ArgoCD, OpenBao, OpenTofu, Garage).
# Responsibilities: # Responsibilities:
# - handle [-c|--config] early so prole_cfg.sh loads the right prole.cfg # - handle [-c|--config] early so prole_cfg.sh loads the right config file
# - parse standard actions/options # - parse standard actions/options
# - resolve and apply namespaces consistently # - resolve and apply namespaces consistently
# Actions supported by all common core scripts # Actions supported by all common core scripts
COMMON_CORE_ACTIONS="start|stop|status|restart|initialize|update|reload" COMMON_CORE_ACTIONS="start|stop|status|restart|initialize|update|reload"
common_core_default_config_path() {
local script_dir="${1:-}"
local mode_hint="${PROLE_MODE:-${DEPLOYMENT_MODE:-${CLUSTER_ENV:-}}}"
local mode="${mode_hint,,}"
if declare -F prole_normalize_mode >/dev/null 2>&1; then
mode="$(prole_normalize_mode "$mode_hint")"
fi
case "$mode" in
k3d)
[[ -f "$script_dir/../conf/k3d.cfg" ]] && { printf '%s' "$script_dir/../conf/k3d.cfg"; return 0; }
;;
k3s)
[[ -f "$script_dir/../conf/k3s.cfg" ]] && { printf '%s' "$script_dir/../conf/k3s.cfg"; return 0; }
;;
k8s)
[[ -f "$script_dir/../conf/gke.cfg" ]] && { printf '%s' "$script_dir/../conf/gke.cfg"; return 0; }
;;
esac
local cfg
for cfg in k3d.cfg k3s.cfg gke.cfg prole.cfg; do
if [[ -f "$script_dir/../conf/$cfg" ]]; then
printf '%s' "$script_dir/../conf/$cfg"
return 0
fi
done
return 1
}
# Parse -c/--config before loading prole_cfg.sh so PROLE_CONF is set in time. # Parse -c/--config before loading prole_cfg.sh so PROLE_CONF is set in time.
# Sets: # Sets:
# COMMON_CORE_CONFIG_PATH - path to prole.cfg (if provided) # COMMON_CORE_CONFIG_PATH - path to prole.cfg (if provided)
@ -47,7 +78,7 @@ common_core_preparse_config() {
# parent shell / Python milestone to pass the correct env-specific conf dir and # parent shell / Python milestone to pass the correct env-specific conf dir and
# have it survive even when init scripts inject a generic fallback -c path. # have it survive even when init scripts inject a generic fallback -c path.
local _current_conf="${PROLE_CONF:-}" local _current_conf="${PROLE_CONF:-}"
if [[ -n "$_current_conf" && "$_current_conf" == "${cfg_dir}/"* && -f "$_current_conf/prole.cfg" ]]; then if [[ -n "$_current_conf" && "$_current_conf" == "${cfg_dir}/"* && ( -f "$_current_conf/k3d.cfg" || -f "$_current_conf/k3s.cfg" || -f "$_current_conf/gke.cfg" || -f "$_current_conf/prole.cfg" ) ]]; then
: # keep inherited PROLE_CONF — it is already more specific than cfg_dir : # keep inherited PROLE_CONF — it is already more specific than cfg_dir
else else
PROLE_CONF="$cfg_dir" PROLE_CONF="$cfg_dir"
@ -117,7 +148,7 @@ common_core_parse_args() {
common_core_usage() { common_core_usage() {
local prog="${1:-$0}" local prog="${1:-$0}"
echo "Usage: ${prog##*/} [${COMMON_CORE_ACTIONS//|/|}] [-n namespace] [--mode k3d|k3s|k8s] [-c conf/prole.cfg]" >&2 echo "Usage: ${prog##*/} [${COMMON_CORE_ACTIONS//|/|}] [-n namespace] [--mode k3d|k3s|k8s] [-c conf/{k3d|k3s|gke}.cfg]" >&2
} }
# Resolve namespace with precedence: CLI override -> SERVICE_NAMESPACE -> NAMESPACE -> provided default # Resolve namespace with precedence: CLI override -> SERVICE_NAMESPACE -> NAMESPACE -> provided default
@ -130,7 +161,7 @@ common_core_resolve_namespace() {
# In k3s mode, common core services must not default into the `default` namespace. # In k3s mode, common core services must not default into the `default` namespace.
# If the caller didn't supply an explicit namespace, normalize `default` -> SERVICE_NAMESPACE # If the caller didn't supply an explicit namespace, normalize `default` -> SERVICE_NAMESPACE
# from prole.cfg (Explicit `-n default` is treated as a legacy/mistake and will be corrected). # from config (Explicit `-n default` is treated as a legacy/mistake and will be corrected).
local mode="${PROLE_MODE:-}" local mode="${PROLE_MODE:-}"
if declare -F prole_normalize_mode >/dev/null 2>&1; then if declare -F prole_normalize_mode >/dev/null 2>&1; then
mode="$(prole_normalize_mode "$mode")" mode="$(prole_normalize_mode "$mode")"

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Standard include for Prole etc scripts. # Standard include for Prole etc scripts.
# - Loads environment from env.sh (if available) # - Loads environment from env.sh (if available)
# - Loads values from PROLE_CONF/prole.cfg (INI-style) # - Loads values from mode-specific config files in PROLE_CONF (INI-style)
# - Does not override already-set env vars # - Does not override already-set env vars
if [[ "${_PROLE_CFG_LOADED:-}" == "1" ]]; then if [[ "${_PROLE_CFG_LOADED:-}" == "1" ]]; then
@ -221,19 +221,107 @@ _prole_cfg_realpath() {
printf '%s' "$p" printf '%s' "$p"
} }
_prole_cfg_named_file_for_env() {
case "${1:-}" in
dev) printf '%s' "k3d.cfg" ;;
service|services) printf '%s' "k3s.cfg" ;;
prod|production) printf '%s' "gke.cfg" ;;
test|testing) printf '%s' "test.cfg" ;;
*) printf '%s' "" ;;
esac
}
_prole_cfg_named_file_for_mode() {
local mode="${1:-}"
if command -v prole_normalize_mode >/dev/null 2>&1; then
mode=$(prole_normalize_mode "$mode")
fi
case "$mode" in
k3d) printf '%s' "k3d.cfg" ;;
k3s) printf '%s' "k3s.cfg" ;;
k8s) printf '%s' "gke.cfg" ;;
*) printf '%s' "" ;;
esac
}
_prole_cfg_select_cfg_file() {
local conf_dir="$1"
[[ -z "$conf_dir" ]] && return 0
local mode_hint mode_file env_hint env_file cfg
mode_hint="${PROLE_MODE:-${DEPLOYMENT_MODE:-${CLUSTER_ENV:-}}}"
mode_file="$(_prole_cfg_named_file_for_mode "$mode_hint")"
if [[ -n "$mode_file" && -f "$conf_dir/$mode_file" ]]; then
printf '%s' "$conf_dir/$mode_file"
return 0
fi
for cfg in k3d.cfg k3s.cfg gke.cfg test.cfg; do
if [[ -f "$conf_dir/$cfg" ]]; then
printf '%s' "$conf_dir/$cfg"
return 0
fi
done
env_hint="$(_prole_cfg_env_from_hint "$mode_hint")"
if [[ -n "$env_hint" ]]; then
env_file="$(_prole_cfg_named_file_for_env "$env_hint")"
if [[ -n "$env_file" && -f "$conf_dir/$env_hint/$env_file" ]]; then
printf '%s' "$conf_dir/$env_hint/$env_file"
return 0
fi
if [[ -f "$conf_dir/$env_hint/prole.cfg" ]]; then
printf '%s' "$conf_dir/$env_hint/prole.cfg"
return 0
fi
fi
for cfg in dev service prod test; do
env_file="$(_prole_cfg_named_file_for_env "$cfg")"
if [[ -n "$env_file" && -f "$conf_dir/$cfg/$env_file" ]]; then
printf '%s' "$conf_dir/$cfg/$env_file"
return 0
fi
if [[ -f "$conf_dir/$cfg/prole.cfg" ]]; then
printf '%s' "$conf_dir/$cfg/prole.cfg"
return 0
fi
done
if [[ -f "$conf_dir/prole.cfg" ]]; then
printf '%s' "$conf_dir/prole.cfg"
return 0
fi
}
_prole_cfg_layer_files() { _prole_cfg_layer_files() {
local entry="$1" local entry="$1"
[[ -z "$entry" ]] && return 0 [[ -z "$entry" ]] && return 0
local resolved env_dir env_name base f local resolved env_dir env_name base base_name f env_base
resolved=$(_prole_cfg_realpath "$entry") resolved=$(_prole_cfg_realpath "$entry")
env_dir=$(cd "$(dirname "$resolved")" 2>/dev/null && pwd || true) env_dir=$(cd "$(dirname "$resolved")" 2>/dev/null && pwd || true)
env_name=$(basename "$env_dir") env_name=$(basename "$env_dir")
base="$env_dir/prole.cfg" base_name=$(basename "$resolved")
if [[ "$base_name" =~ ^(k3d|k3s|gke|test)\.cfg$ ]]; then
printf '%s\n' "$resolved"
return 0
fi
base="$env_dir/$base_name"
if [[ "$env_name" =~ ^(dev|service|prod|test)$ ]]; then
env_base="$(_prole_cfg_named_file_for_env "$env_name")"
if [[ "$base_name" == "prole.cfg" && -n "$env_base" && -f "$env_dir/$env_base" ]]; then
base="$env_dir/$env_base"
elif [[ ! -f "$base" && -n "$env_base" && -f "$env_dir/$env_base" ]]; then
base="$env_dir/$env_base"
fi
fi
if [[ "$env_name" =~ ^(dev|service|prod|test)$ && -f "$base" ]]; then if [[ "$env_name" =~ ^(dev|service|prod|test)$ && -f "$base" ]]; then
printf '%s\n' "$base" printf '%s\n' "$base"
for f in "$env_dir"/*.cfg; do for f in "$env_dir"/*.cfg; do
[[ -f "$f" ]] || continue [[ -f "$f" ]] || continue
[[ "$(basename "$f")" == "prole.cfg" ]] && continue [[ "$(basename "$f")" == "$(basename "$base")" ]] && continue
[[ "$(basename "$f")" == "prod.cfg" ]] && continue # standalone GKE deploy config, not a prole.cfg overlay [[ "$(basename "$f")" == "prod.cfg" ]] && continue # standalone GKE deploy config, not a prole.cfg overlay
[[ "$(basename "$f")" == .* ]] && continue [[ "$(basename "$f")" == .* ]] && continue
printf '%s\n' "$f" printf '%s\n' "$f"
@ -290,8 +378,14 @@ EOF
_prole_cfg_bootstrap_env_layout() { _prole_cfg_bootstrap_env_layout() {
local conf_dir="$1" local conf_dir="$1"
local entry="$conf_dir/prole.cfg" local entry="$conf_dir/prole.cfg"
local existing_selected=""
[[ -z "$conf_dir" ]] && return 0 [[ -z "$conf_dir" ]] && return 0
existing_selected="$(_prole_cfg_select_cfg_file "$conf_dir")"
if [[ -n "$existing_selected" && "$(basename "$existing_selected")" != "prole.cfg" ]]; then
return 0
fi
# Detect if conf_dir is already an env-specific directory (e.g. conf/service). # Detect if conf_dir is already an env-specific directory (e.g. conf/service).
# In that case, skip creating env subdirectories to avoid self-referential # In that case, skip creating env subdirectories to avoid self-referential
# nesting like conf/service/service/. # nesting like conf/service/service/.
@ -346,10 +440,13 @@ _prole_cfg_bootstrap_env_layout() {
# If conf_dir is already the env directory, the base config lives here directly. # If conf_dir is already the env directory, the base config lives here directly.
local base local base
local env_cfg
env_cfg="$(_prole_cfg_named_file_for_env "$env")"
[[ -z "$env_cfg" ]] && env_cfg="prole.cfg"
if [[ "$is_env_dir" == true ]]; then if [[ "$is_env_dir" == true ]]; then
base="$conf_dir/prole.cfg" base="$conf_dir/$env_cfg"
else else
base="$conf_dir/$env/prole.cfg" base="$conf_dir/$env_cfg"
fi fi
# If conf_dir is already the env dir, the entry IS the base — just ensure it exists. # If conf_dir is already the env dir, the entry IS the base — just ensure it exists.
@ -453,12 +550,14 @@ prole_render_manifest() {
} }
_prole_cfg_file="" _prole_cfg_file=""
if [[ -n "${PROLE_CONF:-}" && -f "$PROLE_CONF/prole.cfg" ]]; then if [[ -n "${PROLE_CONF:-}" ]]; then
_prole_cfg_file="$PROLE_CONF/prole.cfg" _prole_cfg_file="$(_prole_cfg_select_cfg_file "$PROLE_CONF")"
elif [[ -n "${PROLE_HOME:-}" && -f "$PROLE_HOME/conf/prole.cfg" ]]; then fi
_prole_cfg_file="$PROLE_HOME/conf/prole.cfg" if [[ -z "$_prole_cfg_file" && -n "${PROLE_HOME:-}" ]]; then
elif [[ -f "$_prole_cfg_home_guess/conf/prole.cfg" ]]; then _prole_cfg_file="$(_prole_cfg_select_cfg_file "$PROLE_HOME/conf")"
_prole_cfg_file="$_prole_cfg_home_guess/conf/prole.cfg" fi
if [[ -z "$_prole_cfg_file" ]]; then
_prole_cfg_file="$(_prole_cfg_select_cfg_file "$_prole_cfg_home_guess/conf")"
fi fi
if [[ -n "$_prole_cfg_file" ]]; then if [[ -n "$_prole_cfg_file" ]]; then
@ -467,9 +566,11 @@ if [[ -n "$_prole_cfg_file" ]]; then
export PROLE_CONF export PROLE_CONF
fi fi
# Ensure env-dir layout exists and a stable entrypoint symlink is active. # Migrate legacy prole.cfg layouts only when a legacy entrypoint is selected.
_prole_cfg_bootstrap_env_layout "$PROLE_CONF" if [[ "$(basename "$_prole_cfg_file")" == "prole.cfg" ]]; then
_prole_cfg_file="$PROLE_CONF/prole.cfg" _prole_cfg_bootstrap_env_layout "$PROLE_CONF"
_prole_cfg_file="$(_prole_cfg_select_cfg_file "$PROLE_CONF")"
fi
_prole_cfg_files=() _prole_cfg_files=()
while IFS= read -r _prole_cfg_f || [[ -n "$_prole_cfg_f" ]]; do while IFS= read -r _prole_cfg_f || [[ -n "$_prole_cfg_f" ]]; do
@ -489,7 +590,7 @@ if [[ -n "$_prole_cfg_file" ]]; then
export KERBEROS_ENABLED export KERBEROS_ENABLED
fi fi
# Always prefer namespace from prole.cfg (single source of truth). # Always prefer namespace from the selected config file(s) (single source of truth).
_cfg_ns=$(_prole_cfg_extract_key_in_files "NAMESPACE" "${_prole_cfg_files[@]}") _cfg_ns=$(_prole_cfg_extract_key_in_files "NAMESPACE" "${_prole_cfg_files[@]}")
if [[ -n "$_cfg_ns" ]]; then if [[ -n "$_cfg_ns" ]]; then
export PROLE_NAMESPACE="$_cfg_ns" export PROLE_NAMESPACE="$_cfg_ns"
@ -499,7 +600,7 @@ if [[ -n "$_prole_cfg_file" ]]; then
export SERVICE_NAMESPACE="$_cfg_sns" export SERVICE_NAMESPACE="$_cfg_sns"
fi fi
# Always prefer deployment/mode hint from prole.cfg (single source of truth). # Always prefer deployment/mode hint from selected config file(s) (single source of truth).
# This prevents leaked environment values (e.g. PROLE_MODE=k3d) from forcing the wrong mode. # This prevents leaked environment values (e.g. PROLE_MODE=k3d) from forcing the wrong mode.
_cfg_dm=$(_prole_cfg_extract_key_in_files "DEPLOYMENT_MODE" "${_prole_cfg_files[@]}") _cfg_dm=$(_prole_cfg_extract_key_in_files "DEPLOYMENT_MODE" "${_prole_cfg_files[@]}")
if [[ -z "$_cfg_dm" ]]; then if [[ -z "$_cfg_dm" ]]; then

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# etc/status.sh — Overall deployment health check for the Prole k3d environment. # etc/status.sh — Overall deployment health check for the Prole k3d environment.
# Usage: status.sh [-c conf/prole.cfg] [-v|--verbose] # Usage: status.sh [-c conf/{k3d|k3s|gke}.cfg] [-v|--verbose]
# Exit 0 = score of 100% (all components healthy) # Exit 0 = score of 100% (all components healthy)
# Exit 1 = score < 100% # Exit 1 = score < 100%
set -u set -u
@ -8,6 +8,9 @@ set -u
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck disable=SC1090
source "$SCRIPT_DIR/prole_cfg.sh"
# ── colours (disabled when stdout is not a tty) ───────────────────────── # ── colours (disabled when stdout is not a tty) ─────────────────────────
if [[ -t 1 ]] || [[ "${CLICOLOR_FORCE:-0}" == "1" ]]; then if [[ -t 1 ]] || [[ "${CLICOLOR_FORCE:-0}" == "1" ]]; then
RED='\033[0;31m' RED='\033[0;31m'
@ -30,10 +33,10 @@ CNPG_CLUSTER_NAME="${CNPG_CLUSTER_NAME:-knoe-db}"
# ── helpers ────────────────────────────────────────────────────────────── # ── helpers ──────────────────────────────────────────────────────────────
usage() { usage() {
cat <<EOF cat <<EOF
Usage: $(basename "$0") [-c <prole.cfg>] [-v|--verbose] [-h|--help] Usage: $(basename "$0") [-c <config.cfg>] [-v|--verbose] [-h|--help]
Overall deployment health check. Overall deployment health check.
-c, --config <path> Path to prole.cfg (default: conf/prole.cfg) -c, --config <path> Path to config file (default: conf/{k3d|k3s|gke}.cfg)
-v, --verbose Show full stdout/stderr from each status check -v, --verbose Show full stdout/stderr from each status check
-h, --help Show this help -h, --help Show this help
EOF EOF
@ -81,17 +84,18 @@ while [[ $# -gt 0 ]]; do
esac esac
done done
# ── load prole.cfg (always) ───────────────────────────────────────────── # ── load config (always) ────────────────────────────────────────────────
if [[ -z "$CFG_PATH" ]]; then if [[ -z "$CFG_PATH" ]]; then
CFG_PATH="$PROJECT_ROOT/conf/prole.cfg" CFG_PATH="$(_prole_cfg_select_cfg_file "$PROJECT_ROOT/conf")"
fi fi
[[ -z "$CFG_PATH" ]] && CFG_PATH="$PROJECT_ROOT/conf/k3d.cfg"
if [[ ! -f "$CFG_PATH" ]]; then if [[ ! -f "$CFG_PATH" ]]; then
echo "FATAL: prole.cfg not found at $CFG_PATH" >&2 echo "FATAL: config file not found at $CFG_PATH" >&2
exit 1 exit 1
fi fi
# Minimal INI reader — pull NAMESPACE, KUBECONFIG, KERBEROS_ENABLED, # Minimal INI reader — pull NAMESPACE, KUBECONFIG, KERBEROS_ENABLED,
# SUPABASE_ENABLED from prole.cfg if not already set in the environment. # SUPABASE_ENABLED from config file if not already set in the environment.
_read_cfg_value() { _read_cfg_value() {
local key="$1" local key="$1"
local val="" local val=""

View File

@ -11,10 +11,13 @@ _has_config=0
for _arg in "$@"; do for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1 [[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then if [[ $_has_config -eq 0 ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@" _default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi fi
unset _has_config _arg unset _has_config _arg _default_cfg
common_core_preparse_config "$@" common_core_preparse_config "$@"

View File

@ -21,7 +21,7 @@ def main():
token = inst_config._try_read_ansible_vault_value(vault_path, "vault_k3s_token") token = inst_config._try_read_ansible_vault_value(vault_path, "vault_k3s_token")
if token: if token:
print(f"Syncing K3S_TOKEN to conf/prole.cfg...") print("Syncing K3S_TOKEN to active config...")
inst_config._update_prole_cfg_value("Global", "PROLE_K3S_TOKEN", token) inst_config._update_prole_cfg_value("Global", "PROLE_K3S_TOKEN", token)
inst_config._update_prole_cfg_value("Inputs", "init_cluster.k3s_token", token) inst_config._update_prole_cfg_value("Inputs", "init_cluster.k3s_token", token)
inst_config._update_prole_cfg_value("Service Cluster (k3s)", "K3S_TOKEN", token) inst_config._update_prole_cfg_value("Service Cluster (k3s)", "K3S_TOKEN", token)

View File

@ -34,7 +34,7 @@ Options:
--foreground Run docker compose in the foreground (default: detached, local mode only) --foreground Run docker compose in the foreground (default: detached, local mode only)
-f, --force Reset the gitea namespace before applying manifests (k3d only; default) -f, --force Reset the gitea namespace before applying manifests (k3d only; default)
--no-force Skip namespace reset (k3d only) --no-force Skip namespace reset (k3d only)
-c, --config <path> Path to prole.cfg (loads environment defaults) -c, --config <path> Path to config file (loads environment defaults)
-h, --help Show help -h, --help Show help
Notes: Notes:
@ -95,10 +95,26 @@ apply_defaults() {
load_prole_cfg() { load_prole_cfg() {
local cfg_loader="$PROJECT_ROOT/etc/prole_cfg.sh" local cfg_loader="$PROJECT_ROOT/etc/prole_cfg.sh"
local cfg_path="${PROLE_CFG_PATH:-}" local cfg_path="${PROLE_CFG_PATH:-}"
local candidate=""
if [[ -z "$cfg_path" ]]; then if [[ -z "$cfg_path" ]]; then
if [[ -n "${PROLE_CONF:-}" ]]; then if [[ -n "${PROLE_CONF:-}" ]]; then
cfg_path="${PROLE_CONF%/}/prole.cfg" for candidate in \
"${PROLE_CONF%/}/k3d.cfg" \
"${PROLE_CONF%/}/k3s.cfg" \
"${PROLE_CONF%/}/gke.cfg" \
"${PROLE_CONF%/}/prole.cfg"; do
if [[ -f "$candidate" ]]; then
cfg_path="$candidate"
break
fi
done
elif [[ -f "$PROJECT_ROOT/conf/k3d.cfg" ]]; then
cfg_path="$PROJECT_ROOT/conf/k3d.cfg"
elif [[ -f "$PROJECT_ROOT/conf/k3s.cfg" ]]; then
cfg_path="$PROJECT_ROOT/conf/k3s.cfg"
elif [[ -f "$PROJECT_ROOT/conf/gke.cfg" ]]; then
cfg_path="$PROJECT_ROOT/conf/gke.cfg"
elif [[ -f "$PROJECT_ROOT/conf/prole.cfg" ]]; then elif [[ -f "$PROJECT_ROOT/conf/prole.cfg" ]]; then
cfg_path="$PROJECT_ROOT/conf/prole.cfg" cfg_path="$PROJECT_ROOT/conf/prole.cfg"
fi fi

View File

@ -1,8 +1,8 @@
--- ---
- name: Check if controller has conf/prole.cfg (optional) - name: Check if controller has conf/k3s.cfg (optional)
ansible.builtin.stat: ansible.builtin.stat:
path: "{{ role_path }}/../../../conf/prole.cfg" path: "{{ role_path }}/../../../conf/k3s.cfg"
register: _k3s_prole_cfg_stat register: _k3s_prole_cfg_stat
delegate_to: localhost delegate_to: localhost
@ -11,7 +11,7 @@
cnpg_version_raw: >- cnpg_version_raw: >-
{{ lookup( {{ lookup(
'ansible.builtin.ini', 'ansible.builtin.ini',
'CNPG_VERSION section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'), 'CNPG_VERSION section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default=(k3s_cnpg_version_default | default('1.28.1')), default=(k3s_cnpg_version_default | default('1.28.1')),
errors='ignore' errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else (k3s_cnpg_version_default | default('1.28.1')) }} ) if _k3s_prole_cfg_stat.stat.exists else (k3s_cnpg_version_default | default('1.28.1')) }}
@ -33,7 +33,7 @@
cnpg_prole_k3s_server_cfg: >- cnpg_prole_k3s_server_cfg: >-
{{ lookup( {{ lookup(
'ansible.builtin.ini', 'ansible.builtin.ini',
'PROLE_K3S_SERVER section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'), 'PROLE_K3S_SERVER section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='', default='',
errors='ignore' errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }} ) if _k3s_prole_cfg_stat.stat.exists else '' }}

View File

@ -12,36 +12,36 @@
ansible.builtin.set_fact: ansible.builtin.set_fact:
k3s_service_name: "{{ 'k3s' if k3s_role == 'server' else 'k3s-agent' }}" k3s_service_name: "{{ 'k3s' if k3s_role == 'server' else 'k3s-agent' }}"
- name: Check if controller has conf/prole.cfg (optional) - name: Check if controller has conf/k3s.cfg (optional)
ansible.builtin.stat: ansible.builtin.stat:
path: "{{ role_path }}/../../../conf/prole.cfg" path: "{{ role_path }}/../../../conf/k3s.cfg"
register: _k3s_prole_cfg_stat register: _k3s_prole_cfg_stat
delegate_to: localhost delegate_to: localhost
- name: Load service namespace from prole.cfg (controller) - name: Load service namespace from k3s.cfg (controller)
ansible.builtin.set_fact: ansible.builtin.set_fact:
k3s_prole_service_namespace_cfg: >- k3s_prole_service_namespace_cfg: >-
{{ lookup( {{ lookup(
'ansible.builtin.ini', 'ansible.builtin.ini',
'SERVICE_NAMESPACE section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'), 'SERVICE_NAMESPACE section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='', default='',
errors='ignore' errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }} ) if _k3s_prole_cfg_stat.stat.exists else '' }}
changed_when: false changed_when: false
- name: Load service hostname from prole.cfg (controller) - name: Load service hostname from k3s.cfg (controller)
ansible.builtin.set_fact: ansible.builtin.set_fact:
k3s_prole_service_hostname_user_cfg: >- k3s_prole_service_hostname_user_cfg: >-
{{ lookup( {{ lookup(
'ansible.builtin.ini', 'ansible.builtin.ini',
'SERVICE_HOSTNAME section=User file=' ~ (role_path ~ '/../../../conf/prole.cfg'), 'SERVICE_HOSTNAME section=User file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='', default='',
errors='ignore' errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }} ) if _k3s_prole_cfg_stat.stat.exists else '' }}
k3s_prole_service_hostname_global_cfg: >- k3s_prole_service_hostname_global_cfg: >-
{{ lookup( {{ lookup(
'ansible.builtin.ini', 'ansible.builtin.ini',
'SERVICE_HOSTNAME section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'), 'SERVICE_HOSTNAME section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='', default='',
errors='ignore' errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }} ) if _k3s_prole_cfg_stat.stat.exists else '' }}
@ -59,7 +59,7 @@
else (k3s_service_hostname | default('svc.prole.org')) }} else (k3s_service_hostname | default('svc.prole.org')) }}
changed_when: false changed_when: false
- name: Resolve Kong namespaces from prole.cfg (avoid implicit default namespace) - name: Resolve Kong namespaces from k3s.cfg (avoid implicit default namespace)
ansible.builtin.set_fact: ansible.builtin.set_fact:
_k3s_service_namespace_resolved: >- _k3s_service_namespace_resolved: >-
{{ (k3s_prole_service_namespace_cfg | default('')) {{ (k3s_prole_service_namespace_cfg | default(''))
@ -89,7 +89,7 @@
- k3s_kong_namespace | length > 0 - k3s_kong_namespace | length > 0
- k3s_svc_check_kong_namespace | length > 0 - k3s_svc_check_kong_namespace | length > 0
fail_msg: >- fail_msg: >-
Resolved Kong namespace variables are empty. Ensure `SERVICE_NAMESPACE` is set in `conf/prole.cfg` Resolved Kong namespace variables are empty. Ensure `SERVICE_NAMESPACE` is set in `conf/k3s.cfg`
or explicitly set `k3s_kong_namespace` / `k3s_svc_check_kong_namespace` in Ansible inventory. or explicitly set `k3s_kong_namespace` / `k3s_svc_check_kong_namespace` in Ansible inventory.
- name: Pre-stage critical images (registry:2, kong, etc.) - name: Pre-stage critical images (registry:2, kong, etc.)
@ -158,7 +158,7 @@
k3s_optional_workloads_min_nodes_cfg: >- k3s_optional_workloads_min_nodes_cfg: >-
{{ lookup( {{ lookup(
'ansible.builtin.ini', 'ansible.builtin.ini',
'OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'), 'OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='', default='',
errors='ignore' errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }} ) if _k3s_prole_cfg_stat.stat.exists else '' }}
@ -176,7 +176,7 @@
- (k3s_optional_workloads_min_nodes_cfg | int) > 0 - (k3s_optional_workloads_min_nodes_cfg | int) > 0
fail_msg: >- fail_msg: >-
Missing or invalid optional-workloads policy configuration. Missing or invalid optional-workloads policy configuration.
Expected [Global] OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES in conf/prole.cfg Expected [Global] OPTIONAL_WORKLOADS_MIN_READY_SCHEDULABLE_NODES in conf/k3s.cfg
(got '{{ k3s_optional_workloads_min_nodes_cfg | default('') }}'). (got '{{ k3s_optional_workloads_min_nodes_cfg | default('') }}').
changed_when: false changed_when: false
when: when:

View File

@ -432,9 +432,9 @@
state: directory state: directory
mode: "0755" mode: "0755"
- name: Check if controller has conf/prole.cfg (optional) - name: Check if controller has conf/k3s.cfg (optional)
ansible.builtin.stat: ansible.builtin.stat:
path: "{{ role_path }}/../../../conf/prole.cfg" path: "{{ role_path }}/../../../conf/k3s.cfg"
register: _k3s_prole_cfg_stat register: _k3s_prole_cfg_stat
delegate_to: localhost delegate_to: localhost
when: k3s_state == "present" and k3s_registry_config_enabled | bool when: k3s_state == "present" and k3s_registry_config_enabled | bool
@ -444,14 +444,14 @@
k3s_prole_k3s_server_cfg: >- k3s_prole_k3s_server_cfg: >-
{{ lookup( {{ lookup(
'ansible.builtin.ini', 'ansible.builtin.ini',
'PROLE_K3S_SERVER section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'), 'PROLE_K3S_SERVER section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='', default='',
errors='ignore' errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }} ) if _k3s_prole_cfg_stat.stat.exists else '' }}
k3s_prole_service_namespace_cfg: >- k3s_prole_service_namespace_cfg: >-
{{ lookup( {{ lookup(
'ansible.builtin.ini', 'ansible.builtin.ini',
'SERVICE_NAMESPACE section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'), 'SERVICE_NAMESPACE section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='', default='',
errors='ignore' errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }} ) if _k3s_prole_cfg_stat.stat.exists else '' }}

View File

@ -60,9 +60,9 @@
when: when:
- k3s_server_url | default('') | length > 0 - k3s_server_url | default('') | length > 0
- name: Check if controller has conf/prole.cfg (optional) - name: Check if controller has conf/k3s.cfg (optional)
ansible.builtin.stat: ansible.builtin.stat:
path: "{{ role_path }}/../../../conf/prole.cfg" path: "{{ role_path }}/../../../conf/k3s.cfg"
register: _k3s_prole_cfg_stat register: _k3s_prole_cfg_stat
delegate_to: localhost delegate_to: localhost
when: k3s_registry_config_enabled | bool when: k3s_registry_config_enabled | bool
@ -72,14 +72,14 @@
k3s_prole_k3s_server_cfg: >- k3s_prole_k3s_server_cfg: >-
{{ lookup( {{ lookup(
'ansible.builtin.ini', 'ansible.builtin.ini',
'PROLE_K3S_SERVER section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'), 'PROLE_K3S_SERVER section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='', default='',
errors='ignore' errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }} ) if _k3s_prole_cfg_stat.stat.exists else '' }}
k3s_prole_service_namespace_cfg: >- k3s_prole_service_namespace_cfg: >-
{{ lookup( {{ lookup(
'ansible.builtin.ini', 'ansible.builtin.ini',
'SERVICE_NAMESPACE section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'), 'SERVICE_NAMESPACE section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='', default='',
errors='ignore' errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }} ) if _k3s_prole_cfg_stat.stat.exists else '' }}

View File

@ -1571,7 +1571,7 @@ def write_gcp_config(path: str, summary: dict, mode: str, provider: str):
f"# Generated by knoe/config.py --mode {mode} --provider {provider}", f"# Generated by knoe/config.py --mode {mode} --provider {provider}",
"# Copy org_id, billing_account, billing_project into:", "# Copy org_id, billing_account, billing_project into:",
"# deploy/gcp/terraform/cloud-setup.auto.tfvars", "# deploy/gcp/terraform/cloud-setup.auto.tfvars",
"# Loaded automatically by the installer into conf/prod/prole.cfg [GCP]", "# Loaded automatically by the installer into conf/gke.cfg [GCP]",
"", "",
f"# Org: {org_name}", f"# Org: {org_name}",
f'org_id = "{org_id}"', f'org_id = "{org_id}"',

View File

@ -5,11 +5,12 @@ loads configuration with per-environment layering.
Target on-disk layout (under `$PROLE_CONF`): Target on-disk layout (under `$PROLE_CONF`):
- `prole.cfg` -> symlink entrypoint to the active environment - `k3d.cfg` -> local development configuration
- `<env>/prole.cfg` -> base config for that environment - `k3s.cfg` -> k3s/service configuration
- `<env>/*.cfg` -> optional overrides applied in deterministic order - `gke.cfg` -> production/GKE configuration
The entrypoint path remains stable for all existing code: `$PROLE_CONF/prole.cfg`. Legacy `prole.cfg` and `conf/<env>/prole.cfg` paths are still recognized for
backward compatibility.
""" """
from __future__ import annotations from __future__ import annotations
@ -20,6 +21,25 @@ import time
from pathlib import Path from pathlib import Path
ENVIRONMENTS: tuple[str, ...] = ("dev", "service", "prod", "test") ENVIRONMENTS: tuple[str, ...] = ("dev", "service", "prod", "test")
ENV_TO_CFG_FILE: dict[str, str] = {
"dev": "k3d.cfg",
"service": "k3s.cfg",
"prod": "gke.cfg",
"test": "test.cfg",
}
CFG_FILE_TO_ENV: dict[str, str] = {cfg: env for env, cfg in ENV_TO_CFG_FILE.items()}
PREFERRED_CFG_ORDER: tuple[str, ...] = ("k3d.cfg", "k3s.cfg", "gke.cfg", "test.cfg")
def cfg_file_for_env(env: str | None) -> str:
env_key = normalize_environment(env)
return ENV_TO_CFG_FILE.get(env_key, "")
def env_for_cfg_file(name: str | None) -> str:
if not name:
return ""
return CFG_FILE_TO_ENV.get(str(name).strip().lower(), "")
def _env_from_mode_or_env_hint(raw: str | None) -> str: def _env_from_mode_or_env_hint(raw: str | None) -> str:
@ -73,7 +93,7 @@ def normalize_environment(env: str | None) -> str:
s = str(env).strip().lower() s = str(env).strip().lower()
if s in ("dev", "k3d") or s.startswith(("k3d-", "prole-dev-")) or s == "knoe-dev-cluster": if s in ("dev", "k3d") or s.startswith(("k3d-", "prole-dev-")) or s == "knoe-dev-cluster":
return "dev" return "dev"
if s in ("service", "k3s", "prole-service-cluster") or s.startswith("prole-service-"): if s in ("service", "services", "k3s", "prole-service-cluster") or s.startswith("prole-service-"):
return "service" return "service"
if s in ("prod", "production", "k8s", "prole-prod-cluster") or s.startswith("prole-prod-"): if s in ("prod", "production", "k8s", "prole-prod-cluster") or s.startswith("prole-prod-"):
return "prod" return "prod"
@ -90,12 +110,11 @@ def resolve_prole_conf_dir(project_root: Path) -> Path:
def entrypoint_path(conf_dir: Path) -> Path: def entrypoint_path(conf_dir: Path) -> Path:
"""Return the active env-specific prole.cfg path. """Return the active configuration file path.
Prefers a direct env-specific file (conf/{env}/prole.cfg) resolved from Prefers named root config files (`k3d.cfg`, `k3s.cfg`, `gke.cfg`) resolved
CLUSTER_ENV or PROLE_MODE so that no symlink is required. Falls back to from CLUSTER_ENV/PROLE_MODE/DEPLOYMENT_MODE. Falls back to legacy env-dir
the legacy conf/prole.cfg entrypoint (symlink or plain file) for backward `prole.cfg` files and finally `conf/prole.cfg` for compatibility.
compatibility.
""" """
conf_dir = Path(conf_dir) conf_dir = Path(conf_dir)
# Determine active env from environment variables (set by the UI on save). # Determine active env from environment variables (set by the UI on save).
@ -104,11 +123,31 @@ def entrypoint_path(conf_dir: Path) -> Path:
if hint: if hint:
env = _env_from_mode_or_env_hint(hint) env = _env_from_mode_or_env_hint(hint)
if env in ENVIRONMENTS: if env in ENVIRONMENTS:
named = cfg_file_for_env(env)
if named:
named_path = conf_dir / named
if named_path.exists():
return named_path
env_path = conf_dir / env / "prole.cfg" env_path = conf_dir / env / "prole.cfg"
if env_path.exists(): if env_path.exists():
return env_path return env_path
# Fallback: legacy symlink or plain file at conf/prole.cfg.
return conf_dir / "prole.cfg" for cfg_name in PREFERRED_CFG_ORDER:
path = conf_dir / cfg_name
if path.exists():
return path
for env in ENVIRONMENTS:
env_path = conf_dir / env / "prole.cfg"
if env_path.exists():
return env_path
legacy = conf_dir / "prole.cfg"
if legacy.exists():
return legacy
# Default target when creating a fresh config.
return conf_dir / "k3d.cfg"
def _is_known_env_dir(conf_dir: Path, env_dir: Path) -> bool: def _is_known_env_dir(conf_dir: Path, env_dir: Path) -> bool:
@ -121,21 +160,31 @@ def _is_known_env_dir(conf_dir: Path, env_dir: Path) -> bool:
def resolve_env_dir_from_cfg_path(cfg_path: Path) -> tuple[Path, str, Path]: def resolve_env_dir_from_cfg_path(cfg_path: Path) -> tuple[Path, str, Path]:
"""Return (conf_dir, env_name, env_dir). """Return (conf_dir, env_name, env_dir).
Supports both: Supports:
- `$PROLE_CONF/prole.cfg` entrypoint (symlink) - `$PROLE_CONF/{k3d.cfg|k3s.cfg|gke.cfg|test.cfg}` base files
- `$PROLE_CONF/<env>/prole.cfg` base file (direct) - legacy `$PROLE_CONF/prole.cfg` entrypoint (symlink/plain)
- legacy `$PROLE_CONF/<env>/prole.cfg` base files
""" """
cfg_path = Path(cfg_path) cfg_path = Path(cfg_path)
# New layout: named config directly in conf dir.
env_from_name = env_for_cfg_file(cfg_path.name)
if env_from_name:
return cfg_path.parent, env_from_name, cfg_path.parent / env_from_name
# If cfg_path is an entrypoint symlink, resolve its target. # If cfg_path is an entrypoint symlink, resolve its target.
try: try:
if cfg_path.is_symlink(): if cfg_path.is_symlink():
target = cfg_path.resolve() target = cfg_path.resolve()
target_env_from_name = env_for_cfg_file(target.name)
if target_env_from_name:
return target.parent, target_env_from_name, target.parent / target_env_from_name
env_dir = target.parent env_dir = target.parent
conf_dir = env_dir.parent conf_dir = env_dir.parent
env = normalize_environment(env_dir.name) env = normalize_environment(env_dir.name)
if env and _is_known_env_dir(conf_dir, env_dir) and target.name == "prole.cfg": expected = cfg_file_for_env(env)
if env and _is_known_env_dir(conf_dir, env_dir) and target.name in {"prole.cfg", expected}:
return conf_dir, env, env_dir return conf_dir, env, env_dir
except Exception: except Exception:
pass pass
@ -145,7 +194,8 @@ def resolve_env_dir_from_cfg_path(cfg_path: Path) -> tuple[Path, str, Path]:
env_dir = cfg_path.parent env_dir = cfg_path.parent
conf_dir = env_dir.parent conf_dir = env_dir.parent
env = normalize_environment(env_dir.name) env = normalize_environment(env_dir.name)
if env and env in ENVIRONMENTS and cfg_path.name == "prole.cfg" and _is_known_env_dir(conf_dir, env_dir): expected = cfg_file_for_env(env)
if env and env in ENVIRONMENTS and cfg_path.name in {"prole.cfg", expected} and _is_known_env_dir(conf_dir, env_dir):
return conf_dir, env, env_dir return conf_dir, env, env_dir
except Exception: except Exception:
pass pass
@ -160,8 +210,19 @@ def layered_cfg_files(cfg_path: Path) -> list[Path]:
conf_dir, env, env_dir = resolve_env_dir_from_cfg_path(cfg_path) conf_dir, env, env_dir = resolve_env_dir_from_cfg_path(cfg_path)
files: list[Path] = [] files: list[Path] = []
if env and (env_dir / "prole.cfg").exists():
files.append(env_dir / "prole.cfg") # New layout uses single named config files in conf dir (no overlays).
if env_for_cfg_file(cfg_path.name):
files.append(cfg_path)
return files
if env and _is_known_env_dir(conf_dir, env_dir):
base_name = cfg_file_for_env(env)
base = env_dir / base_name if base_name else env_dir / "prole.cfg"
if not base.exists():
base = env_dir / "prole.cfg"
if base.exists():
files.append(base)
try: try:
skip_names = { skip_names = {
"prod.cfg", # standalone deploy config, not an overlay for prole.cfg "prod.cfg", # standalone deploy config, not an overlay for prole.cfg
@ -171,7 +232,7 @@ def layered_cfg_files(cfg_path: Path) -> list[Path]:
p p
for p in env_dir.iterdir() for p in env_dir.iterdir()
if p.is_file() if p.is_file()
and p.name != "prole.cfg" and p.name != base.name
and p.name not in skip_names and p.name not in skip_names
and p.suffix == ".cfg" and p.suffix == ".cfg"
and not p.name.startswith(".") and not p.name.startswith(".")
@ -180,7 +241,8 @@ def layered_cfg_files(cfg_path: Path) -> list[Path]:
files.extend(overrides) files.extend(overrides)
except Exception: except Exception:
pass pass
return files if files:
return files
# Legacy/standalone: load only the given path. # Legacy/standalone: load only the given path.
files.append(cfg_path) files.append(cfg_path)
@ -267,9 +329,9 @@ def ensure_base_cfg(conf_dir: Path, env: str, *, create_if_missing: bool = True)
env_key = normalize_environment(env) env_key = normalize_environment(env)
if env_key not in ENVIRONMENTS: if env_key not in ENVIRONMENTS:
raise ValueError(f"Unsupported environment: {env!r}") raise ValueError(f"Unsupported environment: {env!r}")
env_dir = conf_dir / env_key conf_dir.mkdir(parents=True, exist_ok=True)
env_dir.mkdir(parents=True, exist_ok=True) cfg_name = cfg_file_for_env(env_key)
base = env_dir / "prole.cfg" base = conf_dir / cfg_name
if not base.exists() and create_if_missing: if not base.exists() and create_if_missing:
base.write_text(_default_base_cfg_text(env_key), encoding="utf-8") base.write_text(_default_base_cfg_text(env_key), encoding="utf-8")
return base return base
@ -282,10 +344,10 @@ def activate_environment(
create_base_if_missing: bool = True, create_base_if_missing: bool = True,
migrate_legacy_entrypoint: bool = True, migrate_legacy_entrypoint: bool = True,
) -> Path: ) -> Path:
"""Activate `env` and return the env-specific prole.cfg path. """Activate `env` and return its named root config path.
Sets CLUSTER_ENV in the process environment so that subsequent Sets CLUSTER_ENV in the process environment so that subsequent
entrypoint_path() calls resolve the correct env directory without entrypoint_path() calls resolve the correct config without
needing a conf/prole.cfg symlink. needing a conf/prole.cfg symlink.
This never overwrites another environment's curated config. This never overwrites another environment's curated config.
""" """
@ -296,11 +358,9 @@ def activate_environment(
raise ValueError(f"Unsupported environment: {env!r}") raise ValueError(f"Unsupported environment: {env!r}")
ensure_environment_dirs(conf_dir) ensure_environment_dirs(conf_dir)
env_dir = conf_dir / env_key base = ensure_base_cfg(conf_dir, env_key, create_if_missing=create_base_if_missing)
env_dir.mkdir(parents=True, exist_ok=True)
base = env_dir / "prole.cfg"
# Migrate any legacy plain-file entrypoint into the env-specific base. # Migrate any legacy plain-file entrypoint into the target base.
if migrate_legacy_entrypoint: if migrate_legacy_entrypoint:
legacy_entry = conf_dir / "prole.cfg" legacy_entry = conf_dir / "prole.cfg"
if legacy_entry.exists() and not legacy_entry.is_symlink(): if legacy_entry.exists() and not legacy_entry.is_symlink():
@ -315,6 +375,18 @@ def activate_environment(
except Exception: except Exception:
pass pass
# Migrate legacy env-dir base into new named root config when helpful.
legacy_env_base = conf_dir / env_key / "prole.cfg"
if legacy_env_base.exists() and legacy_env_base.is_file():
try:
legacy_text = legacy_env_base.read_text(encoding="utf-8")
if not base.exists() or _looks_like_generated_base_cfg(base, env_key) or not base.read_text(
encoding="utf-8", errors="ignore"
).strip():
base.write_text(legacy_text, encoding="utf-8")
except Exception:
pass
if not base.exists() and create_base_if_missing: if not base.exists() and create_base_if_missing:
base.write_text(_default_base_cfg_text(env_key), encoding="utf-8") base.write_text(_default_base_cfg_text(env_key), encoding="utf-8")
@ -333,13 +405,13 @@ def ensure_entrypoint(
preferred_env: str | None = None, preferred_env: str | None = None,
create_base_if_missing: bool = True, create_base_if_missing: bool = True,
) -> Path: ) -> Path:
"""Ensure the active env-specific prole.cfg exists and return its path. """Ensure the active named config exists and return its path.
- Creates missing env directories. - Creates missing env directories.
- Infers the environment from preferred_env, env vars, or existing config. - Infers the environment from preferred_env, env vars, or existing config.
- If the env-specific base is missing, creates a default placeholder. - If the env-specific base is missing, creates a default placeholder.
Returns the resolved entrypoint path (conf/{env}/prole.cfg). Returns the resolved config path (e.g. conf/k3d.cfg).
""" """
conf_dir = Path(conf_dir) conf_dir = Path(conf_dir)
@ -351,6 +423,12 @@ def ensure_entrypoint(
legacy = conf_dir / "prole.cfg" legacy = conf_dir / "prole.cfg"
if legacy.exists() and not legacy.is_symlink(): if legacy.exists() and not legacy.is_symlink():
env = _infer_env_from_cfg_file(legacy) env = _infer_env_from_cfg_file(legacy)
if not env:
for cfg_name in PREFERRED_CFG_ORDER:
if (conf_dir / cfg_name).exists():
env = env_for_cfg_file(cfg_name)
if env:
break
if not env: if not env:
env = "dev" env = "dev"
@ -366,7 +444,7 @@ def active_environment(conf_dir: Path) -> str:
"""Return the currently active environment name. """Return the currently active environment name.
Resolves from CLUSTER_ENV/PROLE_MODE env vars first (set by activate_environment), Resolves from CLUSTER_ENV/PROLE_MODE env vars first (set by activate_environment),
then falls back to inferring from the entrypoint config file. then falls back to inferring from the resolved config file path.
""" """
conf_dir = Path(conf_dir) conf_dir = Path(conf_dir)
for var in ("CLUSTER_ENV", "PROLE_MODE", "DEPLOYMENT_MODE"): for var in ("CLUSTER_ENV", "PROLE_MODE", "DEPLOYMENT_MODE"):
@ -378,10 +456,19 @@ def active_environment(conf_dir: Path) -> str:
entry = entrypoint_path(conf_dir) entry = entrypoint_path(conf_dir)
if not entry.exists(): if not entry.exists():
return "" return ""
env = env_for_cfg_file(entry.name)
if env in ENVIRONMENTS:
return env
try: try:
target = entry.resolve() target = entry.resolve()
env = env_for_cfg_file(target.name)
if env in ENVIRONMENTS:
return env
env = normalize_environment(target.parent.name) env = normalize_environment(target.parent.name)
if env in ENVIRONMENTS and _is_known_env_dir(conf_dir, target.parent) and target.name == "prole.cfg": expected = cfg_file_for_env(env)
if env in ENVIRONMENTS and _is_known_env_dir(conf_dir, target.parent) and target.name in {"prole.cfg", expected}:
return env return env
except Exception: except Exception:
pass pass

View File

@ -76,7 +76,7 @@ class ConfigMixin:
_prole_conf_mod.activate_environment(conf_dir, self.cluster_env.get()) _prole_conf_mod.activate_environment(conf_dir, self.cluster_env.get())
except Exception: except Exception:
pass pass
# Resolve the correct env-specific path (e.g. conf/prod/prole.cfg). # Resolve the correct env-specific path (e.g. conf/gke.cfg).
cfg_path = _prole_conf_mod.entrypoint_path(conf_dir) cfg_path = _prole_conf_mod.entrypoint_path(conf_dir)
# Identify global candidates # Identify global candidates

View File

@ -46,7 +46,7 @@ usage() {
echo " -l, --log Create a datestamped logfile in prole/logs including all stdout/stderr" echo " -l, --log Create a datestamped logfile in prole/logs including all stdout/stderr"
echo " -v, --verbose Pass a verbose switch to all functions called by ansible and install.sh" echo " -v, --verbose Pass a verbose switch to all functions called by ansible and install.sh"
echo " -d, --debug Enable a debug logfile in prole/logs with high verbosity from install.sh" echo " -d, --debug Enable a debug logfile in prole/logs with high verbosity from install.sh"
echo " -c, --config Path to prole.cfg config file (default: conf/prole.cfg)" echo " -c, --config Path to config file (default: conf/{k3d|k3s|gke}.cfg)"
echo " --coverage Create a coverage report for the run of install.sh" echo " --coverage Create a coverage report for the run of install.sh"
echo " -s, --silent Run unattended install (passes -S to install.sh)" echo " -s, --silent Run unattended install (passes -S to install.sh)"
echo " -r, --reset Perform a reset before action (site/deploy/install); for canonical full reset run use './prole.sh --reset'" echo " -r, --reset Perform a reset before action (site/deploy/install); for canonical full reset run use './prole.sh --reset'"
@ -114,8 +114,30 @@ if [[ "${DEBUG}" -eq 1 ]]; then
INSTALL_ONLY_ARGS+=("--debug") INSTALL_ONLY_ARGS+=("--debug")
fi fi
default_cfg_path() {
local conf_dir mode_hint mode cfg
conf_dir="${PROLE_CONF:-${ROOT_DIR}/conf}"
mode_hint="${PROLE_MODE:-${DEPLOYMENT_MODE:-${CLUSTER_ENV:-}}}"
mode="${mode_hint,,}"
case "$mode" in
k3d) [[ -f "$conf_dir/k3d.cfg" ]] && { printf '%s' "$conf_dir/k3d.cfg"; return 0; } ;;
k3s|service|services) [[ -f "$conf_dir/k3s.cfg" ]] && { printf '%s' "$conf_dir/k3s.cfg"; return 0; } ;;
k8s|gke|prod|production) [[ -f "$conf_dir/gke.cfg" ]] && { printf '%s' "$conf_dir/gke.cfg"; return 0; } ;;
esac
for cfg in k3d.cfg k3s.cfg gke.cfg prole.cfg; do
if [[ -f "$conf_dir/$cfg" ]]; then
printf '%s' "$conf_dir/$cfg"
return 0
fi
done
printf '%s' "$conf_dir/k3d.cfg"
}
if [[ "${SILENT}" -eq 1 ]]; then if [[ "${SILENT}" -eq 1 ]]; then
_cfg="${CONFIG_PATH:-${ROOT_DIR}/conf/prole.cfg}" _cfg="${CONFIG_PATH:-$(default_cfg_path)}"
if [[ ! -f "${_cfg}" ]]; then if [[ ! -f "${_cfg}" ]]; then
echo "Error: --silent requires ${_cfg}" >&2 echo "Error: --silent requires ${_cfg}" >&2
exit 1 exit 1
@ -154,18 +176,14 @@ prepare_ansible_color() {
export CLICOLOR_FORCE=1 export CLICOLOR_FORCE=1
} }
PROLE_CFG_DEFAULT="${ROOT_DIR}/conf/prole.cfg" PROLE_CFG_DEFAULT="$(default_cfg_path)"
resolve_cfg_path() { resolve_cfg_path() {
if [[ -n "${CONFIG_PATH:-}" ]]; then if [[ -n "${CONFIG_PATH:-}" ]]; then
printf '%s' "${CONFIG_PATH}" printf '%s' "${CONFIG_PATH}"
return 0 return 0
fi fi
if [[ -n "${PROLE_CONF:-}" && -f "${PROLE_CONF}/prole.cfg" ]]; then printf '%s' "$(default_cfg_path)"
printf '%s' "${PROLE_CONF}/prole.cfg"
return 0
fi
printf '%s' "${PROLE_CFG_DEFAULT}"
} }
log_msg() { log_msg() {
@ -795,7 +813,7 @@ PY
echo "========================================" echo "========================================"
echo " Post-Install Status Check" echo " Post-Install Status Check"
echo "========================================" echo "========================================"
_status_cfg="${CONFIG_PATH:-${PROLE_CFG_DEFAULT:-${ROOT_DIR}/conf/prole.cfg}}" _status_cfg="${CONFIG_PATH:-${PROLE_CFG_DEFAULT:-$(default_cfg_path)}}"
_post_status_args=() _post_status_args=()
if [[ -f "${_status_cfg}" ]]; then if [[ -f "${_status_cfg}" ]]; then
_post_status_args+=("-c" "${_status_cfg}") _post_status_args+=("-c" "${_status_cfg}")
@ -878,7 +896,7 @@ PY
echo "Step 3/3: Running silent installer..." echo "Step 3/3: Running silent installer..."
# INSTALL_ONLY_ARGS includes -S and --reset if flags were set # INSTALL_ONLY_ARGS includes -S and --reset if flags were set
"${ROOT_DIR}/install.sh" "--no-gui" "-c" "${ROOT_DIR}/conf/prole.cfg" "${INSTALL_ONLY_ARGS[@]}" "${CMD_ARGS[@]}" "${ROOT_DIR}/install.sh" "--no-gui" "-c" "${PROLE_CFG_DEFAULT}" "${INSTALL_ONLY_ARGS[@]}" "${CMD_ARGS[@]}"
echo "Deployment completed successfully!" echo "Deployment completed successfully!"
) | tee "${LOGFILE}" ) | tee "${LOGFILE}"
@ -1279,7 +1297,7 @@ PY
;; ;;
status) status)
status_args=() status_args=()
_status_cfg="${CONFIG_PATH:-${PROLE_CFG_DEFAULT:-${ROOT_DIR}/conf/prole.cfg}}" _status_cfg="${CONFIG_PATH:-${PROLE_CFG_DEFAULT:-$(default_cfg_path)}}"
if [[ -f "${_status_cfg}" ]]; then if [[ -f "${_status_cfg}" ]]; then
status_args+=("-c" "${_status_cfg}") status_args+=("-c" "${_status_cfg}")
fi fi

View File

@ -26,7 +26,7 @@ Commands:
prod Production-specific commands (e.g., prod verify). prod Production-specific commands (e.g., prod verify).
Options: Options:
-c, --config <prole.cfg> Path to prole.cfg (defaults to PROLE_CONF/prole.cfg) -c, --config <config.cfg> Path to config file (defaults to named conf/{k3d|k3s|gke}.cfg)
--mode <k3d|k3s|k8s> Override deployment mode (default: ${MODE}) --mode <k3d|k3s|k8s> Override deployment mode (default: ${MODE})
-n, --namespace <name> Target namespace (default: from config or gitea-prod) -n, --namespace <name> Target namespace (default: from config or gitea-prod)
-h, --help Show this help. -h, --help Show this help.
@ -71,11 +71,23 @@ while [[ $# -gt 0 ]]; do
done done
# --- defaults --- # --- defaults ---
if [[ -z "$CFG_PATH" && -n "${PROLE_CONF:-}" && -f "${PROLE_CONF}/prole.cfg" ]]; then if [[ -z "$CFG_PATH" && -n "${PROLE_CONF:-}" ]]; then
CFG_PATH="${PROLE_CONF}/prole.cfg" for _cfg in "${PROLE_CONF}/k3d.cfg" "${PROLE_CONF}/k3s.cfg" "${PROLE_CONF}/gke.cfg" "${PROLE_CONF}/prole.cfg"; do
elif [[ -z "$CFG_PATH" && -f "$PROJECT_ROOT/conf/prole.cfg" ]]; then if [[ -f "$_cfg" ]]; then
CFG_PATH="$PROJECT_ROOT/conf/prole.cfg" CFG_PATH="$_cfg"
break
fi
done
fi fi
if [[ -z "$CFG_PATH" ]]; then
for _cfg in "$PROJECT_ROOT/conf/k3d.cfg" "$PROJECT_ROOT/conf/k3s.cfg" "$PROJECT_ROOT/conf/gke.cfg" "$PROJECT_ROOT/conf/prole.cfg"; do
if [[ -f "$_cfg" ]]; then
CFG_PATH="$_cfg"
break
fi
done
fi
unset _cfg
if [[ -z "$NAMESPACE" && -n "$CFG_PATH" ]]; then if [[ -z "$NAMESPACE" && -n "$CFG_PATH" ]]; then
maybe_ns="$(_prole_cfg_extract_key "$CFG_PATH" "GITEA_NAMESPACE")" maybe_ns="$(_prole_cfg_extract_key "$CFG_PATH" "GITEA_NAMESPACE")"

View File

@ -4,14 +4,14 @@
# One-shot patch for the dual-cluster garage/barman situation: # One-shot patch for the dual-cluster garage/barman situation:
# #
# Problem: install.sh incorrectly deployed Garage into knoe-cnpg-0 (DB cluster) # Problem: install.sh incorrectly deployed Garage into knoe-cnpg-0 (DB cluster)
# because app_cluster_kubecontext was not persisted in conf/prod/prole.cfg. # because app_cluster_kubecontext was not persisted in conf/gke.cfg.
# CNPG backups should use GCS with Workload Identity, not Garage. # CNPG backups should use GCS with Workload Identity, not Garage.
# #
# Fix applied by this script: # Fix applied by this script:
# 1. Remove Garage from knoe-cnpg-0 (statefulset, service, configmap, PVC) # 1. Remove Garage from knoe-cnpg-0 (statefulset, service, configmap, PVC)
# 2. Apply cnpg-backup-sa ServiceAccount with Workload Identity annotation # 2. Apply cnpg-backup-sa ServiceAccount with Workload Identity annotation
# 3. Apply the GCS barman ObjectStore in knoe-db-0 # 3. Apply the GCS barman ObjectStore in knoe-db-0
# 4. Refresh CNPG_ELIGIBLE_NODES in conf/prod/prole.cfg from live knoe-cnpg-0 nodes # 4. Refresh CNPG_ELIGIBLE_NODES in conf/gke.cfg from live knoe-cnpg-0 nodes
# #
# Note: GCS buckets and GCP SA must already exist (created by init_cnpg_gke.sh or # Note: GCS buckets and GCP SA must already exist (created by init_cnpg_gke.sh or
# the GCP console). If not, run: # the GCP console). If not, run:
@ -60,7 +60,7 @@ if [[ "${CONFIRM}" != "true" ]]; then
echo " 1. Remove Garage from ${DB_CLUSTER}/${SERVICE_NS}" echo " 1. Remove Garage from ${DB_CLUSTER}/${SERVICE_NS}"
echo " 2. Apply cnpg-backup-sa (Workload Identity) in ${DB_CLUSTER}/${DB_NS}" echo " 2. Apply cnpg-backup-sa (Workload Identity) in ${DB_CLUSTER}/${DB_NS}"
echo " 3. Apply the GCS barman ObjectStore in ${DB_CLUSTER}/${DB_NS}" echo " 3. Apply the GCS barman ObjectStore in ${DB_CLUSTER}/${DB_NS}"
echo " 4. Refresh CNPG_ELIGIBLE_NODES in conf/prod/prole.cfg" echo " 4. Refresh CNPG_ELIGIBLE_NODES in conf/gke.cfg"
echo "" echo ""
echo " Set CONFIRM=true to proceed:" echo " Set CONFIRM=true to proceed:"
echo " CONFIRM=true ./scripts/patch_garage_cross_cluster.sh" echo " CONFIRM=true ./scripts/patch_garage_cross_cluster.sh"
@ -134,7 +134,7 @@ kubectl --context="${DB_CTX}" -n "${DB_NS}" apply -f "${GCS_OBJ_MANIFEST}"
log " GCS ObjectStore applied." log " GCS ObjectStore applied."
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Phase 4: Refresh CNPG_ELIGIBLE_NODES in conf/prod/prole.cfg # Phase 4: Refresh CNPG_ELIGIBLE_NODES in conf/gke.cfg
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
log "[phase 4] Refreshing CNPG_ELIGIBLE_NODES from ${DB_CLUSTER} ..." log "[phase 4] Refreshing CNPG_ELIGIBLE_NODES from ${DB_CLUSTER} ..."
@ -142,7 +142,7 @@ CNPG_NODES=$(kubectl --context="${DB_CTX}" get nodes \
-o jsonpath='{range .items[*]}{.metadata.name}{","}{end}' 2>/dev/null \ -o jsonpath='{range .items[*]}{.metadata.name}{","}{end}' 2>/dev/null \
| sed 's/,$//' || true) | sed 's/,$//' || true)
PROLE_CFG="${REPO_ROOT}/conf/prod/prole.cfg" PROLE_CFG="${REPO_ROOT}/conf/gke.cfg"
if [[ -n "${CNPG_NODES}" && -f "${PROLE_CFG}" ]]; then if [[ -n "${CNPG_NODES}" && -f "${PROLE_CFG}" ]]; then
STAGE1_NODE=$(echo "${CNPG_NODES}" | cut -d',' -f1) STAGE1_NODE=$(echo "${CNPG_NODES}" | cut -d',' -f1)

View File

@ -41,8 +41,8 @@ def _load_prole_cfg(cfg_path: Path | None = None) -> configparser.ConfigParser:
Resolution order for the config file: Resolution order for the config file:
1. Explicit *cfg_path* argument (from ``-c`` CLI flag). 1. Explicit *cfg_path* argument (from ``-c`` CLI flag).
2. ``$PROLE_CONF/prole.cfg`` environment variable. 2. ``$PROLE_CONF/{k3d|k3s|gke}.cfg`` environment variable directory.
3. ``<PROJECT_ROOT>/conf/prole.cfg`` fallback. 3. ``<PROJECT_ROOT>/conf/{k3d|k3s|gke}.cfg`` fallback.
""" """
if cfg_path is None: if cfg_path is None:
try: try:

View File

@ -97,21 +97,26 @@ load_prole_cfg() {
if [[ -z "$cfg_path" ]]; then if [[ -z "$cfg_path" ]]; then
if [[ -n "${PROLE_CONF:-}" ]]; then if [[ -n "${PROLE_CONF:-}" ]]; then
for candidate in \ for candidate in \
"${PROLE_CONF%/}/k3d.cfg" \
"${PROLE_CONF%/}/k3s.cfg" \
"${PROLE_CONF%/}/gke.cfg" \
"${PROLE_CONF%/}/prole.cfg" \ "${PROLE_CONF%/}/prole.cfg" \
"${PROLE_CONF%/}/service/prod.cfg" \ "${PROLE_CONF%/}/service/prod.cfg"; do
"${PROLE_CONF%/}/service/prole.cfg" \
"${PROLE_CONF%/}/prod/prole.cfg"; do
if [[ -f "$candidate" ]]; then if [[ -f "$candidate" ]]; then
cfg_path="$candidate" cfg_path="$candidate"
break break
fi fi
done done
elif [[ -f "$PROJECT_ROOT/conf/k3d.cfg" ]]; then
cfg_path="$PROJECT_ROOT/conf/k3d.cfg"
elif [[ -f "$PROJECT_ROOT/conf/k3s.cfg" ]]; then
cfg_path="$PROJECT_ROOT/conf/k3s.cfg"
elif [[ -f "$PROJECT_ROOT/conf/gke.cfg" ]]; then
cfg_path="$PROJECT_ROOT/conf/gke.cfg"
elif [[ -f "$PROJECT_ROOT/conf/prole.cfg" ]]; then elif [[ -f "$PROJECT_ROOT/conf/prole.cfg" ]]; then
cfg_path="$PROJECT_ROOT/conf/prole.cfg" cfg_path="$PROJECT_ROOT/conf/prole.cfg"
elif [[ -f "$PROJECT_ROOT/conf/service/prod.cfg" ]]; then elif [[ -f "$PROJECT_ROOT/conf/service/prod.cfg" ]]; then
cfg_path="$PROJECT_ROOT/conf/service/prod.cfg" cfg_path="$PROJECT_ROOT/conf/service/prod.cfg"
elif [[ -f "$PROJECT_ROOT/conf/service/prole.cfg" ]]; then
cfg_path="$PROJECT_ROOT/conf/service/prole.cfg"
fi fi
fi fi
@ -122,10 +127,12 @@ load_prole_cfg() {
if [[ -n "$cfg_path" ]]; then if [[ -n "$cfg_path" ]]; then
if [[ -d "$cfg_path" ]]; then if [[ -d "$cfg_path" ]]; then
for candidate in \ for candidate in \
"$cfg_path/k3d.cfg" \
"$cfg_path/k3s.cfg" \
"$cfg_path/gke.cfg" \
"$cfg_path/prole.cfg" \ "$cfg_path/prole.cfg" \
"$cfg_path/prod.cfg" \ "$cfg_path/prod.cfg" \
"$cfg_path/service/prod.cfg" \ "$cfg_path/service/prod.cfg"; do
"$cfg_path/service/prole.cfg"; do
if [[ -f "$candidate" ]]; then if [[ -f "$candidate" ]]; then
cfg_path="$candidate" cfg_path="$candidate"
break break

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Regression test: sourcing etc/prole_cfg.sh should bootstrap env-dir layout # Regression test: sourcing etc/prole_cfg.sh should bootstrap config layout
# and migrate a legacy regular-file prole.cfg entrypoint into the right env. # and migrate a legacy regular-file prole.cfg entrypoint into the right root file.
set -euo pipefail set -euo pipefail
@ -33,32 +33,19 @@ EOF
export PROLE_HOME="$TEST_HOME" export PROLE_HOME="$TEST_HOME"
export PROLE_CONF="$TEST_HOME/conf" export PROLE_CONF="$TEST_HOME/conf"
# Source the shared loader (this should bootstrap the env-dir layout) # Source the shared loader (this should bootstrap the config layout)
# shellcheck disable=SC1090 # shellcheck disable=SC1090
source "$PROLE_REPO_ROOT/etc/prole_cfg.sh" source "$PROLE_REPO_ROOT/etc/prole_cfg.sh"
if [[ ! -L "$PROLE_CONF/prole.cfg" ]]; then if [[ ! -f "$PROLE_CONF/k3d.cfg" ]]; then
echo "FAILURE: expected $PROLE_CONF/prole.cfg to be a symlink after bootstrap" >&2 echo "FAILURE: expected $PROLE_CONF/k3d.cfg to exist" >&2
ls -la "$PROLE_CONF" >&2 || true
exit 1 exit 1
fi fi
resolved=$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$PROLE_CONF/prole.cfg") if ! grep -q "NAMESPACE = knoe-db-legacy" "$PROLE_CONF/k3d.cfg"; then
expected=$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$PROLE_CONF/dev/prole.cfg") echo "FAILURE: expected migrated k3d base to contain legacy content" >&2
if [[ "$resolved" != "$expected" ]]; then echo "--- k3d.cfg ---" >&2
echo "FAILURE: expected entrypoint to resolve to $expected, got $resolved" >&2 cat "$PROLE_CONF/k3d.cfg" >&2 || true
exit 1
fi
if [[ ! -f "$PROLE_CONF/dev/prole.cfg" ]]; then
echo "FAILURE: expected $PROLE_CONF/dev/prole.cfg to exist" >&2
exit 1
fi
if ! grep -q "NAMESPACE = knoe-db-legacy" "$PROLE_CONF/dev/prole.cfg"; then
echo "FAILURE: expected migrated dev base to contain legacy content" >&2
echo "--- dev/prole.cfg ---" >&2
cat "$PROLE_CONF/dev/prole.cfg" >&2 || true
exit 1 exit 1
fi fi

View File

@ -9,7 +9,7 @@
# - PostgreSQL users: prole, postgres (via CNPG primary pod) # - PostgreSQL users: prole, postgres (via CNPG primary pod)
# - k8s secret: prometheus-grafana (knoe-dev-0, monitoring) # - k8s secret: prometheus-grafana (knoe-dev-0, monitoring)
# - Grafana CLI reset (via grafana pod exec) # - Grafana CLI reset (via grafana pod exec)
# - prole.cfg password fields (conf/prod/prole.cfg, conf/service/prod.cfg) # - config password fields (conf/gke.cfg, conf/service/prod.cfg)
# - OpenBao kv secrets (if reachable) # - OpenBao kv secrets (if reachable)
# #
# Usage: # Usage:
@ -45,7 +45,7 @@ VAULT_PASS_FILE="${ROOT_DIR}/.vault_pass"
VAULT_FILE="${ROOT_DIR}/infrastructure/inventory/group_vars/all/vault_db_master.yml" VAULT_FILE="${ROOT_DIR}/infrastructure/inventory/group_vars/all/vault_db_master.yml"
VAULT_KEY="vault_prole_db_master_password" VAULT_KEY="vault_prole_db_master_password"
# Cluster contexts — override via env or auto-detect from prole.cfg # Cluster contexts — override via env or auto-detect from config files
APP_CTX="${APP_CLUSTER_KUBECONTEXT:-}" APP_CTX="${APP_CLUSTER_KUBECONTEXT:-}"
DB_CTX="${DB_CLUSTER_KUBECONTEXT:-}" DB_CTX="${DB_CLUSTER_KUBECONTEXT:-}"
@ -96,7 +96,7 @@ b64dec() {
fi fi
} }
# Read a key from any section of an INI-style prole.cfg # Read a key from any section of an INI-style config
cfg_get() { cfg_get() {
local file="$1" key="$2" local file="$1" key="$2"
python3 - "$file" "$key" <<'PY' python3 - "$file" "$key" <<'PY'
@ -112,9 +112,9 @@ PY
} }
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Step 0: Resolve cluster contexts from prole.cfg if not set in env # Step 0: Resolve cluster contexts from config if not set in env
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
_cfg_prod="${ROOT_DIR}/conf/prod/prole.cfg" _cfg_prod="${ROOT_DIR}/conf/gke.cfg"
_cfg_svc="${ROOT_DIR}/conf/service/prod.cfg" _cfg_svc="${ROOT_DIR}/conf/service/prod.cfg"
resolve_contexts() { resolve_contexts() {
@ -482,9 +482,9 @@ PY
} }
if [[ "$DRY_RUN" == "true" ]]; then if [[ "$DRY_RUN" == "true" ]]; then
log " [DRY-RUN] Would update password fields in conf/prod/prole.cfg and conf/service/prod.cfg" log " [DRY-RUN] Would update password fields in conf/gke.cfg and conf/service/prod.cfg"
else else
update_cfg "${ROOT_DIR}/conf/prod/prole.cfg" update_cfg "${ROOT_DIR}/conf/gke.cfg"
update_cfg "${ROOT_DIR}/conf/service/prod.cfg" update_cfg "${ROOT_DIR}/conf/service/prod.cfg"
fi fi
} }