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
### `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:

View File

@ -1,7 +1,7 @@
# Generated by knoe/config.py --mode k8s --provider gcp
# Copy org_id, billing_account, billing_project into:
# 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_id = "584001916389"

View File

@ -1,5 +1,5 @@
; 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]
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

View File

@ -1,44 +1,42 @@
### 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
Under `$PROLE_CONF`:
```text
$PROLE_CONF/prole.cfg -> symlink entrypoint (active env)
$PROLE_CONF/dev/prole.cfg -> base config (dev)
$PROLE_CONF/service/prole.cfg -> base config (service)
$PROLE_CONF/prod/prole.cfg -> base config (prod)
$PROLE_CONF/test/prole.cfg -> base config (test)
# Optional overrides (conf.d-style) per environment:
$PROLE_CONF/<env>/*.cfg -> applied as layered overrides
$PROLE_CONF/k3d.cfg -> base config (k3d / dev)
$PROLE_CONF/k3s.cfg -> base config (k3s / service)
$PROLE_CONF/gke.cfg -> base config (k8s / prod)
$PROLE_CONF/test.cfg -> base config (test, optional)
```
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)
- The active environment is determined by what `$PROLE_CONF/prole.cfg` points to.
- The Cluster Environment screen activates the selected env by updating the symlink (via `installer/prole_conf.py`).
- Switching environments only changes the symlink target; it does not overwrite any other environments curated files.
- The active environment is inferred from `CLUSTER_ENV`, `PROLE_MODE`, or `DEPLOYMENT_MODE`.
- Resolution prefers named root files (`k3d.cfg`, `k3s.cfg`, `gke.cfg`) and only falls back to legacy `prole.cfg` paths.
- 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)
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)
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.
Later files override earlier values (last write wins).
#### Why this prevents accidental namespace drift
- Tests can target an isolated environment (`test`) with its own base config and overrides.
- Environment switching is explicit (symlink target changes) and stable (entrypoint path stays the same).
- Updates that need to modify config write through the entrypoint symlink to the active environments base file, avoiding hidden cross-environment mutations.
- The `test` environment defaults to a non-`default` namespace (`prole-test`), reducing the chance that unit/integration runs revert to Kubernetes `default`.
- k3d, k3s, and k8s/GKE are cleanly separated by dedicated config files.
- Mode/environment selection is explicit via deployment hints instead of mutable symlink state.
- Legacy configs remain readable during transition, reducing migration risk.

View File

@ -4,9 +4,9 @@ set -euo pipefail
# build-a-bao.sh
# 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
# - Replace prole.cfg secrets with OpenBao placeholders
# - Replace config-file secrets with OpenBao placeholders
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"
cfg_path=""
if [[ -n "${PROLE_CONF:-}" && -f "$PROLE_CONF/prole.cfg" ]]; then
cfg_path="$PROLE_CONF/prole.cfg"
elif [[ -n "${PROLE_HOME:-}" && -f "$PROLE_HOME/conf/prole.cfg" ]]; then
cfg_path="$PROLE_HOME/conf/prole.cfg"
elif [[ -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then
cfg_path="$SCRIPT_DIR/../conf/prole.cfg"
if [[ -n "${PROLE_CONF:-}" ]]; then
cfg_path="$(_prole_cfg_select_cfg_file "$PROLE_CONF")"
elif [[ -n "${PROLE_HOME:-}" ]]; then
cfg_path="$(_prole_cfg_select_cfg_file "$PROLE_HOME/conf")"
else
cfg_path="$(_prole_cfg_select_cfg_file "$SCRIPT_DIR/../conf")"
fi
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
fi

View File

@ -18,10 +18,13 @@ _has_config=0
for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@"
if [[ $_has_config -eq 0 ]]; then
_default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi
unset _has_config _arg
unset _has_config _arg _default_cfg
common_core_preparse_config "$@"
@ -61,7 +64,7 @@ fi
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:
start Install cert-manager (CRDs + controller)

View File

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

View File

@ -5,7 +5,7 @@ set -euo pipefail
# - Build and deploy the knoe-db-manager Node.js REST endpoint
# - 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 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:
# ./init_db_manager.sh [--mode MODE] <start|stop|status|restart|build>

View File

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

View File

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

View File

@ -25,7 +25,7 @@ Usage:
Options:
--mode <k3d|k3s|k8s|local> Deployment mode (default: ${MODE:-k3d})
-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)
--force Remove existing GitLab and Gitea releases before deploy
--help Show this help
@ -68,9 +68,10 @@ done
# Resolve config path
# ---------------------------------------------------------------------------
if [[ -z "$CFG_PATH" && -n "${PROLE_CONF:-}" && -f "${PROLE_CONF}/prole.cfg" ]]; then
CFG_PATH="${PROLE_CONF}/prole.cfg"
elif [[ -z "$CFG_PATH" && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then
CFG_PATH="$SCRIPT_DIR/../conf/prole.cfg"
CFG_PATH="$(_prole_cfg_select_cfg_file "${PROLE_CONF}")"
fi
if [[ -z "$CFG_PATH" ]]; then
CFG_PATH="$(_prole_cfg_select_cfg_file "$SCRIPT_DIR/../conf")"
fi
# cfg-based namespace override (only GITLAB_NAMESPACE; GITOPS_NAMESPACE intentionally excluded)

View File

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

View File

@ -22,10 +22,13 @@ _has_config=0
for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@"
if [[ $_has_config -eq 0 ]]; then
_default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi
unset _has_config _arg
unset _has_config _arg _default_cfg
common_core_preparse_config "$@"
@ -102,7 +105,7 @@ KNOE_AUTH_UPSTREAM_URL="${KNOE_AUTH_UPSTREAM_URL:-http://knoe-auth.${SERVICE_NAM
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:
start Create ConfigMap and deploy Kong

View File

@ -20,10 +20,13 @@ _has_config=0
for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@"
if [[ $_has_config -eq 0 ]]; then
_default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi
unset _has_config _arg
unset _has_config _arg _default_cfg
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 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_PATH_NAMESPACE=${OPENBAO_PATH_NAMESPACE:-${PROLE_NAMESPACE:-${NAMESPACE:-default}}}
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]
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
-f, --force Force: kill existing processes blocking ports
Examples:
$PROG -c ./prole.cfg start
$PROG -c ./k3d.cfg start
$PROG stop openbao
$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_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:
@ -60,14 +60,23 @@ have() { command -v "$1" >/dev/null 2>&1; }
# ---- Config helpers / derived defaults ----
cfg_file() {
if [ -n "${PROLE_CONF:-}" ] && [ -f "$PROLE_CONF/prole.cfg" ]; then
printf '%s' "$PROLE_CONF/prole.cfg"
local cfg=""
if declare -F _prole_cfg_select_cfg_file >/dev/null 2>&1; then
if [ -n "${PROLE_CONF:-}" ]; then
cfg="$(_prole_cfg_select_cfg_file "$PROLE_CONF")"
if [ -n "$cfg" ]; then
printf '%s' "$cfg"
return 0
fi
if [ -n "${PROLE_HOME:-}" ] && [ -f "$PROLE_HOME/conf/prole.cfg" ]; then
printf '%s' "$PROLE_HOME/conf/prole.cfg"
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
return 1
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,13 +1,44 @@
#!/usr/bin/env bash
# Shared helpers for common core init scripts (ArgoCD, OpenBao, OpenTofu, Garage).
# 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
# - resolve and apply namespaces consistently
# Actions supported by all common core scripts
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.
# Sets:
# 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
# have it survive even when init scripts inject a generic fallback -c path.
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
else
PROLE_CONF="$cfg_dir"
@ -117,7 +148,7 @@ common_core_parse_args() {
common_core_usage() {
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
@ -130,7 +161,7 @@ common_core_resolve_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
# 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:-}"
if declare -F prole_normalize_mode >/dev/null 2>&1; then
mode="$(prole_normalize_mode "$mode")"

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
# Standard include for Prole etc scripts.
# - 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
if [[ "${_PROLE_CFG_LOADED:-}" == "1" ]]; then
@ -221,19 +221,107 @@ _prole_cfg_realpath() {
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() {
local entry="$1"
[[ -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")
env_dir=$(cd "$(dirname "$resolved")" 2>/dev/null && pwd || true)
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
printf '%s\n' "$base"
for f in "$env_dir"/*.cfg; do
[[ -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")" == .* ]] && continue
printf '%s\n' "$f"
@ -290,8 +378,14 @@ EOF
_prole_cfg_bootstrap_env_layout() {
local conf_dir="$1"
local entry="$conf_dir/prole.cfg"
local existing_selected=""
[[ -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).
# In that case, skip creating env subdirectories to avoid self-referential
# 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.
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
base="$conf_dir/prole.cfg"
base="$conf_dir/$env_cfg"
else
base="$conf_dir/$env/prole.cfg"
base="$conf_dir/$env_cfg"
fi
# 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=""
if [[ -n "${PROLE_CONF:-}" && -f "$PROLE_CONF/prole.cfg" ]]; then
_prole_cfg_file="$PROLE_CONF/prole.cfg"
elif [[ -n "${PROLE_HOME:-}" && -f "$PROLE_HOME/conf/prole.cfg" ]]; then
_prole_cfg_file="$PROLE_HOME/conf/prole.cfg"
elif [[ -f "$_prole_cfg_home_guess/conf/prole.cfg" ]]; then
_prole_cfg_file="$_prole_cfg_home_guess/conf/prole.cfg"
if [[ -n "${PROLE_CONF:-}" ]]; then
_prole_cfg_file="$(_prole_cfg_select_cfg_file "$PROLE_CONF")"
fi
if [[ -z "$_prole_cfg_file" && -n "${PROLE_HOME:-}" ]]; then
_prole_cfg_file="$(_prole_cfg_select_cfg_file "$PROLE_HOME/conf")"
fi
if [[ -z "$_prole_cfg_file" ]]; then
_prole_cfg_file="$(_prole_cfg_select_cfg_file "$_prole_cfg_home_guess/conf")"
fi
if [[ -n "$_prole_cfg_file" ]]; then
@ -467,9 +566,11 @@ if [[ -n "$_prole_cfg_file" ]]; then
export PROLE_CONF
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.
if [[ "$(basename "$_prole_cfg_file")" == "prole.cfg" ]]; then
_prole_cfg_bootstrap_env_layout "$PROLE_CONF"
_prole_cfg_file="$PROLE_CONF/prole.cfg"
_prole_cfg_file="$(_prole_cfg_select_cfg_file "$PROLE_CONF")"
fi
_prole_cfg_files=()
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
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[@]}")
if [[ -n "$_cfg_ns" ]]; then
export PROLE_NAMESPACE="$_cfg_ns"
@ -499,7 +600,7 @@ if [[ -n "$_prole_cfg_file" ]]; then
export SERVICE_NAMESPACE="$_cfg_sns"
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.
_cfg_dm=$(_prole_cfg_extract_key_in_files "DEPLOYMENT_MODE" "${_prole_cfg_files[@]}")
if [[ -z "$_cfg_dm" ]]; then

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
# 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 1 = score < 100%
set -u
@ -8,6 +8,9 @@ set -u
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck disable=SC1090
source "$SCRIPT_DIR/prole_cfg.sh"
# ── colours (disabled when stdout is not a tty) ─────────────────────────
if [[ -t 1 ]] || [[ "${CLICOLOR_FORCE:-0}" == "1" ]]; then
RED='\033[0;31m'
@ -30,10 +33,10 @@ CNPG_CLUSTER_NAME="${CNPG_CLUSTER_NAME:-knoe-db}"
# ── helpers ──────────────────────────────────────────────────────────────
usage() {
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.
-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
-h, --help Show this help
EOF
@ -81,17 +84,18 @@ while [[ $# -gt 0 ]]; do
esac
done
# ── load prole.cfg (always) ─────────────────────────────────────────────
# ── load config (always) ────────────────────────────────────────────────
if [[ -z "$CFG_PATH" ]]; then
CFG_PATH="$PROJECT_ROOT/conf/prole.cfg"
CFG_PATH="$(_prole_cfg_select_cfg_file "$PROJECT_ROOT/conf")"
fi
[[ -z "$CFG_PATH" ]] && CFG_PATH="$PROJECT_ROOT/conf/k3d.cfg"
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
fi
# 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() {
local key="$1"
local val=""

View File

@ -11,10 +11,13 @@ _has_config=0
for _arg in "$@"; do
[[ "$_arg" == "-c" || "$_arg" == "--config" || "$_arg" == -c=* || "$_arg" == --config=* ]] && _has_config=1
done
if [[ $_has_config -eq 0 && -f "$SCRIPT_DIR/../conf/prole.cfg" ]]; then
set -- "-c" "$SCRIPT_DIR/../conf/prole.cfg" "$@"
if [[ $_has_config -eq 0 ]]; then
_default_cfg="$(common_core_default_config_path "$SCRIPT_DIR" || true)"
if [[ -n "$_default_cfg" ]]; then
set -- "-c" "$_default_cfg" "$@"
fi
fi
unset _has_config _arg
unset _has_config _arg _default_cfg
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")
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("Inputs", "init_cluster.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)
-f, --force Reset the gitea namespace before applying manifests (k3d only; default)
--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
Notes:
@ -95,10 +95,26 @@ apply_defaults() {
load_prole_cfg() {
local cfg_loader="$PROJECT_ROOT/etc/prole_cfg.sh"
local cfg_path="${PROLE_CFG_PATH:-}"
local candidate=""
if [[ -z "$cfg_path" ]]; 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
cfg_path="$PROJECT_ROOT/conf/prole.cfg"
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:
path: "{{ role_path }}/../../../conf/prole.cfg"
path: "{{ role_path }}/../../../conf/k3s.cfg"
register: _k3s_prole_cfg_stat
delegate_to: localhost
@ -11,7 +11,7 @@
cnpg_version_raw: >-
{{ lookup(
'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')),
errors='ignore'
) 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: >-
{{ lookup(
'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='',
errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }}

View File

@ -12,36 +12,36 @@
ansible.builtin.set_fact:
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:
path: "{{ role_path }}/../../../conf/prole.cfg"
path: "{{ role_path }}/../../../conf/k3s.cfg"
register: _k3s_prole_cfg_stat
delegate_to: localhost
- name: Load service namespace from prole.cfg (controller)
- name: Load service namespace from k3s.cfg (controller)
ansible.builtin.set_fact:
k3s_prole_service_namespace_cfg: >-
{{ lookup(
'ansible.builtin.ini',
'SERVICE_NAMESPACE section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'),
'SERVICE_NAMESPACE section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='',
errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }}
changed_when: false
- name: Load service hostname from prole.cfg (controller)
- name: Load service hostname from k3s.cfg (controller)
ansible.builtin.set_fact:
k3s_prole_service_hostname_user_cfg: >-
{{ lookup(
'ansible.builtin.ini',
'SERVICE_HOSTNAME section=User file=' ~ (role_path ~ '/../../../conf/prole.cfg'),
'SERVICE_HOSTNAME section=User file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='',
errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }}
k3s_prole_service_hostname_global_cfg: >-
{{ lookup(
'ansible.builtin.ini',
'SERVICE_HOSTNAME section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'),
'SERVICE_HOSTNAME section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='',
errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }}
@ -59,7 +59,7 @@
else (k3s_service_hostname | default('svc.prole.org')) }}
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:
_k3s_service_namespace_resolved: >-
{{ (k3s_prole_service_namespace_cfg | default(''))
@ -89,7 +89,7 @@
- k3s_kong_namespace | length > 0
- k3s_svc_check_kong_namespace | length > 0
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.
- name: Pre-stage critical images (registry:2, kong, etc.)
@ -158,7 +158,7 @@
k3s_optional_workloads_min_nodes_cfg: >-
{{ lookup(
'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='',
errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }}
@ -176,7 +176,7 @@
- (k3s_optional_workloads_min_nodes_cfg | int) > 0
fail_msg: >-
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('') }}').
changed_when: false
when:

View File

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

View File

@ -60,9 +60,9 @@
when:
- 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:
path: "{{ role_path }}/../../../conf/prole.cfg"
path: "{{ role_path }}/../../../conf/k3s.cfg"
register: _k3s_prole_cfg_stat
delegate_to: localhost
when: k3s_registry_config_enabled | bool
@ -72,14 +72,14 @@
k3s_prole_k3s_server_cfg: >-
{{ lookup(
'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='',
errors='ignore'
) if _k3s_prole_cfg_stat.stat.exists else '' }}
k3s_prole_service_namespace_cfg: >-
{{ lookup(
'ansible.builtin.ini',
'SERVICE_NAMESPACE section=Global file=' ~ (role_path ~ '/../../../conf/prole.cfg'),
'SERVICE_NAMESPACE section=Global file=' ~ (role_path ~ '/../../../conf/k3s.cfg'),
default='',
errors='ignore'
) 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}",
"# Copy org_id, billing_account, billing_project into:",
"# 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_id = "{org_id}"',

View File

@ -5,11 +5,12 @@ loads configuration with per-environment layering.
Target on-disk layout (under `$PROLE_CONF`):
- `prole.cfg` -> symlink entrypoint to the active environment
- `<env>/prole.cfg` -> base config for that environment
- `<env>/*.cfg` -> optional overrides applied in deterministic order
- `k3d.cfg` -> local development configuration
- `k3s.cfg` -> k3s/service configuration
- `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
@ -20,6 +21,25 @@ import time
from pathlib import Path
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:
@ -73,7 +93,7 @@ def normalize_environment(env: str | None) -> str:
s = str(env).strip().lower()
if s in ("dev", "k3d") or s.startswith(("k3d-", "prole-dev-")) or s == "knoe-dev-cluster":
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"
if s in ("prod", "production", "k8s", "prole-prod-cluster") or s.startswith("prole-prod-"):
return "prod"
@ -90,12 +110,11 @@ def resolve_prole_conf_dir(project_root: 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
CLUSTER_ENV or PROLE_MODE so that no symlink is required. Falls back to
the legacy conf/prole.cfg entrypoint (symlink or plain file) for backward
compatibility.
Prefers named root config files (`k3d.cfg`, `k3s.cfg`, `gke.cfg`) resolved
from CLUSTER_ENV/PROLE_MODE/DEPLOYMENT_MODE. Falls back to legacy env-dir
`prole.cfg` files and finally `conf/prole.cfg` for compatibility.
"""
conf_dir = Path(conf_dir)
# 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:
env = _env_from_mode_or_env_hint(hint)
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"
if env_path.exists():
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:
@ -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]:
"""Return (conf_dir, env_name, env_dir).
Supports both:
- `$PROLE_CONF/prole.cfg` entrypoint (symlink)
- `$PROLE_CONF/<env>/prole.cfg` base file (direct)
Supports:
- `$PROLE_CONF/{k3d.cfg|k3s.cfg|gke.cfg|test.cfg}` base files
- legacy `$PROLE_CONF/prole.cfg` entrypoint (symlink/plain)
- legacy `$PROLE_CONF/<env>/prole.cfg` base files
"""
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.
try:
if cfg_path.is_symlink():
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
conf_dir = env_dir.parent
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
except Exception:
pass
@ -145,7 +194,8 @@ def resolve_env_dir_from_cfg_path(cfg_path: Path) -> tuple[Path, str, Path]:
env_dir = cfg_path.parent
conf_dir = env_dir.parent
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
except Exception:
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)
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:
skip_names = {
"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
for p in env_dir.iterdir()
if p.is_file()
and p.name != "prole.cfg"
and p.name != base.name
and p.name not in skip_names
and p.suffix == ".cfg"
and not p.name.startswith(".")
@ -180,6 +241,7 @@ def layered_cfg_files(cfg_path: Path) -> list[Path]:
files.extend(overrides)
except Exception:
pass
if files:
return files
# Legacy/standalone: load only the given path.
@ -267,9 +329,9 @@ def ensure_base_cfg(conf_dir: Path, env: str, *, create_if_missing: bool = True)
env_key = normalize_environment(env)
if env_key not in ENVIRONMENTS:
raise ValueError(f"Unsupported environment: {env!r}")
env_dir = conf_dir / env_key
env_dir.mkdir(parents=True, exist_ok=True)
base = env_dir / "prole.cfg"
conf_dir.mkdir(parents=True, exist_ok=True)
cfg_name = cfg_file_for_env(env_key)
base = conf_dir / cfg_name
if not base.exists() and create_if_missing:
base.write_text(_default_base_cfg_text(env_key), encoding="utf-8")
return base
@ -282,10 +344,10 @@ def activate_environment(
create_base_if_missing: bool = True,
migrate_legacy_entrypoint: bool = True,
) -> 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
entrypoint_path() calls resolve the correct env directory without
entrypoint_path() calls resolve the correct config without
needing a conf/prole.cfg symlink.
This never overwrites another environment's curated config.
"""
@ -296,11 +358,9 @@ def activate_environment(
raise ValueError(f"Unsupported environment: {env!r}")
ensure_environment_dirs(conf_dir)
env_dir = conf_dir / env_key
env_dir.mkdir(parents=True, exist_ok=True)
base = env_dir / "prole.cfg"
base = ensure_base_cfg(conf_dir, env_key, create_if_missing=create_base_if_missing)
# 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:
legacy_entry = conf_dir / "prole.cfg"
if legacy_entry.exists() and not legacy_entry.is_symlink():
@ -315,6 +375,18 @@ def activate_environment(
except Exception:
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:
base.write_text(_default_base_cfg_text(env_key), encoding="utf-8")
@ -333,13 +405,13 @@ def ensure_entrypoint(
preferred_env: str | None = None,
create_base_if_missing: bool = True,
) -> 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.
- Infers the environment from preferred_env, env vars, or existing config.
- 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)
@ -351,6 +423,12 @@ def ensure_entrypoint(
legacy = conf_dir / "prole.cfg"
if legacy.exists() and not legacy.is_symlink():
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:
env = "dev"
@ -366,7 +444,7 @@ def active_environment(conf_dir: Path) -> str:
"""Return the currently active environment name.
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)
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)
if not entry.exists():
return ""
env = env_for_cfg_file(entry.name)
if env in ENVIRONMENTS:
return env
try:
target = entry.resolve()
env = env_for_cfg_file(target.name)
if env in ENVIRONMENTS:
return env
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
except Exception:
pass

View File

@ -76,7 +76,7 @@ class ConfigMixin:
_prole_conf_mod.activate_environment(conf_dir, self.cluster_env.get())
except Exception:
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)
# 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 " -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 " -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 " -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'"
@ -114,8 +114,30 @@ if [[ "${DEBUG}" -eq 1 ]]; then
INSTALL_ONLY_ARGS+=("--debug")
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
_cfg="${CONFIG_PATH:-${ROOT_DIR}/conf/prole.cfg}"
_cfg="${CONFIG_PATH:-$(default_cfg_path)}"
if [[ ! -f "${_cfg}" ]]; then
echo "Error: --silent requires ${_cfg}" >&2
exit 1
@ -154,18 +176,14 @@ prepare_ansible_color() {
export CLICOLOR_FORCE=1
}
PROLE_CFG_DEFAULT="${ROOT_DIR}/conf/prole.cfg"
PROLE_CFG_DEFAULT="$(default_cfg_path)"
resolve_cfg_path() {
if [[ -n "${CONFIG_PATH:-}" ]]; then
printf '%s' "${CONFIG_PATH}"
return 0
fi
if [[ -n "${PROLE_CONF:-}" && -f "${PROLE_CONF}/prole.cfg" ]]; then
printf '%s' "${PROLE_CONF}/prole.cfg"
return 0
fi
printf '%s' "${PROLE_CFG_DEFAULT}"
printf '%s' "$(default_cfg_path)"
}
log_msg() {
@ -795,7 +813,7 @@ PY
echo "========================================"
echo " Post-Install Status Check"
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=()
if [[ -f "${_status_cfg}" ]]; then
_post_status_args+=("-c" "${_status_cfg}")
@ -878,7 +896,7 @@ PY
echo "Step 3/3: Running silent installer..."
# 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!"
) | tee "${LOGFILE}"
@ -1279,7 +1297,7 @@ PY
;;
status)
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
status_args+=("-c" "${_status_cfg}")
fi

View File

@ -26,7 +26,7 @@ Commands:
prod Production-specific commands (e.g., prod verify).
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})
-n, --namespace <name> Target namespace (default: from config or gitea-prod)
-h, --help Show this help.
@ -71,11 +71,23 @@ while [[ $# -gt 0 ]]; do
done
# --- defaults ---
if [[ -z "$CFG_PATH" && -n "${PROLE_CONF:-}" && -f "${PROLE_CONF}/prole.cfg" ]]; then
CFG_PATH="${PROLE_CONF}/prole.cfg"
elif [[ -z "$CFG_PATH" && -f "$PROJECT_ROOT/conf/prole.cfg" ]]; then
CFG_PATH="$PROJECT_ROOT/conf/prole.cfg"
if [[ -z "$CFG_PATH" && -n "${PROLE_CONF:-}" ]]; then
for _cfg in "${PROLE_CONF}/k3d.cfg" "${PROLE_CONF}/k3s.cfg" "${PROLE_CONF}/gke.cfg" "${PROLE_CONF}/prole.cfg"; do
if [[ -f "$_cfg" ]]; then
CFG_PATH="$_cfg"
break
fi
done
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
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:
#
# 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.
#
# Fix applied by this script:
# 1. Remove Garage from knoe-cnpg-0 (statefulset, service, configmap, PVC)
# 2. Apply cnpg-backup-sa ServiceAccount with Workload Identity annotation
# 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
# the GCP console). If not, run:
@ -60,7 +60,7 @@ if [[ "${CONFIRM}" != "true" ]]; then
echo " 1. Remove Garage from ${DB_CLUSTER}/${SERVICE_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 " 4. Refresh CNPG_ELIGIBLE_NODES in conf/prod/prole.cfg"
echo " 4. Refresh CNPG_ELIGIBLE_NODES in conf/gke.cfg"
echo ""
echo " Set CONFIRM=true to proceed:"
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."
# ---------------------------------------------------------------------------
# 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} ..."
@ -142,7 +142,7 @@ CNPG_NODES=$(kubectl --context="${DB_CTX}" get nodes \
-o jsonpath='{range .items[*]}{.metadata.name}{","}{end}' 2>/dev/null \
| 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
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:
1. Explicit *cfg_path* argument (from ``-c`` CLI flag).
2. ``$PROLE_CONF/prole.cfg`` environment variable.
3. ``<PROJECT_ROOT>/conf/prole.cfg`` fallback.
2. ``$PROLE_CONF/{k3d|k3s|gke}.cfg`` environment variable directory.
3. ``<PROJECT_ROOT>/conf/{k3d|k3s|gke}.cfg`` fallback.
"""
if cfg_path is None:
try:

View File

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

View File

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

View File

@ -9,7 +9,7 @@
# - PostgreSQL users: prole, postgres (via CNPG primary pod)
# - k8s secret: prometheus-grafana (knoe-dev-0, monitoring)
# - 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)
#
# 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_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:-}"
DB_CTX="${DB_CLUSTER_KUBECONTEXT:-}"
@ -96,7 +96,7 @@ b64dec() {
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() {
local file="$1" key="$2"
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"
resolve_contexts() {
@ -482,9 +482,9 @@ PY
}
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
update_cfg "${ROOT_DIR}/conf/prod/prole.cfg"
update_cfg "${ROOT_DIR}/conf/gke.cfg"
update_cfg "${ROOT_DIR}/conf/service/prod.cfg"
fi
}