From e3c2e625f16906ce2b27905e63c5155745fc992b Mon Sep 17 00:00:00 2001 From: chrisfu Date: Sat, 11 Apr 2026 22:20:45 -0700 Subject: [PATCH] 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 --- CLAUDE.md | 2 +- conf/{prod/prole.cfg => gke.cfg} | 0 conf/{dev/prole.cfg => k3d.cfg} | 0 conf/{service/prole.cfg => k3s.cfg} | 0 conf/prod/gcp.cfg | 2 +- conf/service/port-mapping.cfg | 2 +- docs/config-environments.md | 44 +++-- etc/build-a-bao.sh | 18 +- etc/init_certmgr.sh | 11 +- etc/init_common_services.sh | 9 +- etc/init_db_manager.sh | 2 +- etc/init_forgejo.sh | 13 +- etc/init_gitea.sh | 13 +- etc/init_gitlab.sh | 9 +- etc/init_kerberos.sh | 24 ++- etc/init_kong.sh | 11 +- etc/init_openbao.sh | 11 +- etc/init_port_forwards.sh | 29 ++-- etc/init_redis.sh | 9 +- etc/init_registry.sh | 9 +- etc/init_service_layer.sh | 9 +- etc/knoe-db-passwwd.sh | 16 +- etc/lib/shell/common_core_lib.sh | 39 ++++- etc/prole_cfg.sh | 135 +++++++++++++-- etc/status.sh | 18 +- etc/status_common_services.sh | 9 +- etc/sync-prole-cfg.py | 2 +- gitea/deploy.sh | 20 ++- infrastructure/roles/k3s/tasks/cnpg.yml | 8 +- infrastructure/roles/k3s/tasks/configure.yml | 22 +-- infrastructure/roles/k3s/tasks/install.yml | 8 +- infrastructure/roles/k3s/tasks/sync.yml | 8 +- knoe/config.py | 2 +- knoe/prole_conf.py | 155 ++++++++++++++---- knoe/ui/screens/cfg.py | 2 +- prole.sh | 40 +++-- prole/etc/gitea.sh | 22 ++- scripts/patch_garage_cross_cluster.sh | 10 +- status.py | 4 +- supabase/deploy.sh | 21 ++- .../test_prole_cfg_bootstrap_env_layout.sh | 31 +--- update.sh | 14 +- 42 files changed, 561 insertions(+), 252 deletions(-) rename conf/{prod/prole.cfg => gke.cfg} (100%) rename conf/{dev/prole.cfg => k3d.cfg} (100%) rename conf/{service/prole.cfg => k3s.cfg} (100%) diff --git a/CLAUDE.md b/CLAUDE.md index b679984..b3daddc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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: diff --git a/conf/prod/prole.cfg b/conf/gke.cfg similarity index 100% rename from conf/prod/prole.cfg rename to conf/gke.cfg diff --git a/conf/dev/prole.cfg b/conf/k3d.cfg similarity index 100% rename from conf/dev/prole.cfg rename to conf/k3d.cfg diff --git a/conf/service/prole.cfg b/conf/k3s.cfg similarity index 100% rename from conf/service/prole.cfg rename to conf/k3s.cfg diff --git a/conf/prod/gcp.cfg b/conf/prod/gcp.cfg index b00812e..128f4f3 100644 --- a/conf/prod/gcp.cfg +++ b/conf/prod/gcp.cfg @@ -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" diff --git a/conf/service/port-mapping.cfg b/conf/service/port-mapping.cfg index 88ed6be..de6a327 100644 --- a/conf/service/port-mapping.cfg +++ b/conf/service/port-mapping.cfg @@ -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 diff --git a/docs/config-environments.md b/docs/config-environments.md index df76519..dde7e37 100644 --- a/docs/config-environments.md +++ b/docs/config-environments.md @@ -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//*.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//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 environment’s 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.` and switches to the symlink-based layout. +If a legacy `prole.cfg` regular file is detected, migration preserves it as `prole.cfg.legacy.` and promotes content into the appropriate named file. #### Override layering (deterministic merge) -For a selected environment directory `$PROLE_CONF//`: +- 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//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 environment’s 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. diff --git a/etc/build-a-bao.sh b/etc/build-a-bao.sh index 8a30c0e..eaabbdc 100755 --- a/etc/build-a-bao.sh +++ b/etc/build-a-bao.sh @@ -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 diff --git a/etc/init_certmgr.sh b/etc/init_certmgr.sh index 42152c0..87b7612 100755 --- a/etc/init_certmgr.sh +++ b/etc/init_certmgr.sh @@ -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 </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] diff --git a/etc/init_forgejo.sh b/etc/init_forgejo.sh index 65837a4..6000107 100644 --- a/etc/init_forgejo.sh +++ b/etc/init_forgejo.sh @@ -20,7 +20,7 @@ Usage: Options: --mode Deployment mode (default: ${MODE:-k3d}) -n, --namespace Target namespace (default: forgejo) - -c, --config Path to prole.cfg (defaults to detected) + -c, --config 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 diff --git a/etc/init_gitea.sh b/etc/init_gitea.sh index 67eeff4..292f93d 100755 --- a/etc/init_gitea.sh +++ b/etc/init_gitea.sh @@ -20,7 +20,7 @@ Usage: Options: --mode Deployment mode (default: ${MODE:-k3d}) -n, --namespace Target namespace (default: gitea) - -c, --config Path to prole.cfg (defaults to detected) + -c, --config 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 diff --git a/etc/init_gitlab.sh b/etc/init_gitlab.sh index 01a1d82..c8b6c43 100755 --- a/etc/init_gitlab.sh +++ b/etc/init_gitlab.sh @@ -25,7 +25,7 @@ Usage: Options: --mode Deployment mode (default: ${MODE:-k3d}) -n, --namespace Target namespace (default: gitlab) - -c, --config Path to prole.cfg (defaults to detected) + -c, --config Path to config file (defaults to detected) --node-selector 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) diff --git a/etc/init_kerberos.sh b/etc/init_kerberos.sh index ead0645..a2c00c6 100755 --- a/etc/init_kerberos.sh +++ b/etc/init_kerberos.sh @@ -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 } diff --git a/etc/init_kong.sh b/etc/init_kong.sh index f3cc064..e98a01b 100755 --- a/etc/init_kong.sh +++ b/etc/init_kong.sh @@ -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 </...}` references resolve consistently across scripts. OPENBAO_PATH_NAMESPACE=${OPENBAO_PATH_NAMESPACE:-${PROLE_NAMESPACE:-${NAMESPACE:-default}}} OPENBAO_RESOURCE_NAMESPACE="$OPENBAO_NAMESPACE" diff --git a/etc/init_port_forwards.sh b/etc/init_port_forwards.sh index d76e874..fb04073 100755 --- a/etc/init_port_forwards.sh +++ b/etc/init_port_forwards.sh @@ -32,16 +32,16 @@ Usage: $PROG [-v|--verbose] [-f|--force] [-c|--config-file=FILE] [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,13 +60,22 @@ 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" - return 0 - fi - if [ -n "${PROLE_HOME:-}" ] && [ -f "$PROLE_HOME/conf/prole.cfg" ]; then - printf '%s' "$PROLE_HOME/conf/prole.cfg" - return 0 + 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 + 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 } diff --git a/etc/init_redis.sh b/etc/init_redis.sh index b56a115..98903a1 100755 --- a/etc/init_redis.sh +++ b/etc/init_redis.sh @@ -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 "$@" diff --git a/etc/init_registry.sh b/etc/init_registry.sh index aec5b10..787a491 100755 --- a/etc/init_registry.sh +++ b/etc/init_registry.sh @@ -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 "$@" diff --git a/etc/init_service_layer.sh b/etc/init_service_layer.sh index a355bda..b85a41d 100755 --- a/etc/init_service_layer.sh +++ b/etc/init_service_layer.sh @@ -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 "$@" diff --git a/etc/knoe-db-passwwd.sh b/etc/knoe-db-passwwd.sh index ebec095..5145e07 100755 --- a/etc/knoe-db-passwwd.sh +++ b/etc/knoe-db-passwwd.sh @@ -14,7 +14,7 @@ Usage: $0 [-k|--kdc] [-f|--force] [-c|--config ] 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 diff --git a/etc/lib/shell/common_core_lib.sh b/etc/lib/shell/common_core_lib.sh index 0977603..c69ddec 100644 --- a/etc/lib/shell/common_core_lib.sh +++ b/etc/lib/shell/common_core_lib.sh @@ -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")" diff --git a/etc/prole_cfg.sh b/etc/prole_cfg.sh index 2c45ec3..51ce052 100644 --- a/etc/prole_cfg.sh +++ b/etc/prole_cfg.sh @@ -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. - _prole_cfg_bootstrap_env_layout "$PROLE_CONF" - _prole_cfg_file="$PROLE_CONF/prole.cfg" + # 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_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 diff --git a/etc/status.sh b/etc/status.sh index 0a389a6..b39e858 100755 --- a/etc/status.sh +++ b/etc/status.sh @@ -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 <] [-v|--verbose] [-h|--help] +Usage: $(basename "$0") [-c ] [-v|--verbose] [-h|--help] Overall deployment health check. - -c, --config Path to prole.cfg (default: conf/prole.cfg) + -c, --config 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="" diff --git a/etc/status_common_services.sh b/etc/status_common_services.sh index 9a94a01..7e9b4d5 100755 --- a/etc/status_common_services.sh +++ b/etc/status_common_services.sh @@ -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 "$@" diff --git a/etc/sync-prole-cfg.py b/etc/sync-prole-cfg.py index 2e951c5..6c74ab3 100644 --- a/etc/sync-prole-cfg.py +++ b/etc/sync-prole-cfg.py @@ -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) diff --git a/gitea/deploy.sh b/gitea/deploy.sh index 8462a3e..09926ff 100755 --- a/gitea/deploy.sh +++ b/gitea/deploy.sh @@ -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 to prole.cfg (loads environment defaults) + -c, --config 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 diff --git a/infrastructure/roles/k3s/tasks/cnpg.yml b/infrastructure/roles/k3s/tasks/cnpg.yml index 02823c5..f272e8e 100644 --- a/infrastructure/roles/k3s/tasks/cnpg.yml +++ b/infrastructure/roles/k3s/tasks/cnpg.yml @@ -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 '' }} diff --git a/infrastructure/roles/k3s/tasks/configure.yml b/infrastructure/roles/k3s/tasks/configure.yml index e7be5c4..35333d7 100644 --- a/infrastructure/roles/k3s/tasks/configure.yml +++ b/infrastructure/roles/k3s/tasks/configure.yml @@ -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: diff --git a/infrastructure/roles/k3s/tasks/install.yml b/infrastructure/roles/k3s/tasks/install.yml index 74d2484..5441367 100644 --- a/infrastructure/roles/k3s/tasks/install.yml +++ b/infrastructure/roles/k3s/tasks/install.yml @@ -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 '' }} diff --git a/infrastructure/roles/k3s/tasks/sync.yml b/infrastructure/roles/k3s/tasks/sync.yml index 880687c..40f7720 100644 --- a/infrastructure/roles/k3s/tasks/sync.yml +++ b/infrastructure/roles/k3s/tasks/sync.yml @@ -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 '' }} diff --git a/knoe/config.py b/knoe/config.py index 87774c3..52ae3f3 100644 --- a/knoe/config.py +++ b/knoe/config.py @@ -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}"', diff --git a/knoe/prole_conf.py b/knoe/prole_conf.py index 6b3e016..d03d50d 100644 --- a/knoe/prole_conf.py +++ b/knoe/prole_conf.py @@ -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 -- `/prole.cfg` -> base config for that environment -- `/*.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//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//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//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,7 +241,8 @@ def layered_cfg_files(cfg_path: Path) -> list[Path]: files.extend(overrides) except Exception: pass - return files + if files: + return files # Legacy/standalone: load only the given 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) 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 diff --git a/knoe/ui/screens/cfg.py b/knoe/ui/screens/cfg.py index 2f39f87..93167b9 100644 --- a/knoe/ui/screens/cfg.py +++ b/knoe/ui/screens/cfg.py @@ -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 diff --git a/prole.sh b/prole.sh index 60e0bd5..03bb04f 100755 --- a/prole.sh +++ b/prole.sh @@ -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 diff --git a/prole/etc/gitea.sh b/prole/etc/gitea.sh index 39dff78..8542990 100755 --- a/prole/etc/gitea.sh +++ b/prole/etc/gitea.sh @@ -26,7 +26,7 @@ Commands: prod Production-specific commands (e.g., prod verify). Options: - -c, --config Path to prole.cfg (defaults to PROLE_CONF/prole.cfg) + -c, --config Path to config file (defaults to named conf/{k3d|k3s|gke}.cfg) --mode Override deployment mode (default: ${MODE}) -n, --namespace 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")" diff --git a/scripts/patch_garage_cross_cluster.sh b/scripts/patch_garage_cross_cluster.sh index 1920613..9252b0f 100755 --- a/scripts/patch_garage_cross_cluster.sh +++ b/scripts/patch_garage_cross_cluster.sh @@ -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) diff --git a/status.py b/status.py index 7152d85..baed47d 100755 --- a/status.py +++ b/status.py @@ -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. ``/conf/prole.cfg`` fallback. + 2. ``$PROLE_CONF/{k3d|k3s|gke}.cfg`` environment variable directory. + 3. ``/conf/{k3d|k3s|gke}.cfg`` fallback. """ if cfg_path is None: try: diff --git a/supabase/deploy.sh b/supabase/deploy.sh index 4d6d3f1..293e276 100755 --- a/supabase/deploy.sh +++ b/supabase/deploy.sh @@ -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 diff --git a/tests/etc/test_prole_cfg_bootstrap_env_layout.sh b/tests/etc/test_prole_cfg_bootstrap_env_layout.sh index a266035..36d6b34 100644 --- a/tests/etc/test_prole_cfg_bootstrap_env_layout.sh +++ b/tests/etc/test_prole_cfg_bootstrap_env_layout.sh @@ -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 diff --git a/update.sh b/update.sh index 6a667c4..deaa6fb 100755 --- a/update.sh +++ b/update.sh @@ -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 }