berth init
This commit is contained in:
94
berth/ctrl/lib/config.sh
Normal file
94
berth/ctrl/lib/config.sh
Normal file
@@ -0,0 +1,94 @@
|
||||
# Shared config loading. Sourced, never executed. Run from ctrl/.
|
||||
#
|
||||
# Precedence, weakest first:
|
||||
# ctrl/versions.env pinned toolchain (committed)
|
||||
# ctrl/env.d/<target>.env provider shape: aws|gcp (committed)
|
||||
# ctrl/.env machine-local + secrets (gitignored)
|
||||
# the caller's env `make estate plan TARGET=gcp` (always wins)
|
||||
|
||||
CONFIG_OVERRIDABLE="TARGET ESTATE CLOUD REGION INSTANCE_TYPE
|
||||
HOST HOST_ADMIN AWS_PROFILE AWS_HOSTED_ZONE_ID
|
||||
GCP_PROJECT GCP_ZONE TOFU_WORKSPACE"
|
||||
|
||||
# rig's port formula, reproduced rather than imported. cksum because it is
|
||||
# POSIX and gives the same value on every machine. Used to verify, not allocate.
|
||||
derive_port_base() {
|
||||
local h; h=$(printf '%s' "$1" | cksum | awk '{print $1}')
|
||||
echo $((20000 + (h % 200) * 10))
|
||||
}
|
||||
|
||||
_config_restore() {
|
||||
local line
|
||||
while IFS= read -r line; do
|
||||
if [ -n "$line" ]; then
|
||||
eval "export $line"
|
||||
fi
|
||||
done <<< "$1"
|
||||
# A while loop returns its last body command's status; the trailing empty
|
||||
# line would otherwise make this return 1 and trip `set -e` in the caller.
|
||||
return 0
|
||||
}
|
||||
|
||||
load_config() {
|
||||
local k saved=""
|
||||
for k in $CONFIG_OVERRIDABLE; do
|
||||
# ${!k+x} distinguishes "set but empty" from "unset" — an explicit
|
||||
# FOO= on the command line is a real choice and must survive.
|
||||
if [ -n "${!k+x}" ]; then
|
||||
saved+="$k=$(printf '%q' "${!k}")"$'\n'
|
||||
fi
|
||||
done
|
||||
|
||||
set -a
|
||||
source ./versions.env
|
||||
[ -f ./.env ] && source ./.env
|
||||
set +a
|
||||
|
||||
# Re-apply overrides now so TARGET is the caller's before we pick the file.
|
||||
_config_restore "$saved"
|
||||
|
||||
local target="${TARGET:-aws}"
|
||||
if [ ! -f "./env.d/${target}.env" ]; then
|
||||
echo "no such target: env.d/${target}.env" >&2
|
||||
echo "available: $(ls env.d/*.env 2>/dev/null | xargs -n1 basename | sed 's/\.env$//' | tr '\n' ' ')" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -a
|
||||
source "./env.d/${target}.env"
|
||||
[ -f ./.env ] && source ./.env
|
||||
set +a
|
||||
|
||||
_config_restore "$saved"
|
||||
|
||||
TARGET="$target"
|
||||
|
||||
# Identity is explicit: berth never guesses which estate it is acting on.
|
||||
# The one convenience: a single estate/*.json is used without being asked.
|
||||
if [ -z "${ESTATE:-}" ]; then
|
||||
local n; n=$(ls ../estate/*.json 2>/dev/null | wc -l)
|
||||
if [ "$n" = "1" ]; then
|
||||
ESTATE=$(basename "$(ls ../estate/*.json)" .json)
|
||||
else
|
||||
echo "ESTATE is not set and estate/ holds $n candidates — refusing to guess." >&2
|
||||
echo "available: $(ls ../estate/*.json 2>/dev/null | xargs -n1 basename | sed 's/\.json$//' | tr '\n' ' ')" >&2
|
||||
echo "set it: make estate show ESTATE=<name>, or ESTATE= in ctrl/.env" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
ESTATE_FILE="../estate/${ESTATE}.json"
|
||||
if [ ! -f "$ESTATE_FILE" ]; then
|
||||
echo "no such estate: estate/${ESTATE}.json" >&2
|
||||
echo "available: $(ls ../estate/*.json 2>/dev/null | xargs -n1 basename | sed 's/\.json$//' | tr '\n' ' ')" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Facts come from the estate file, never restated in a target env.
|
||||
DOMAIN=$(estate_get "domain")
|
||||
HOST="${HOST:-$(estate_get "host")}"
|
||||
HOST_ADMIN="${HOST_ADMIN:-$(estate_get "host_admin")}"
|
||||
|
||||
# Workspace == target, so the two can never mean different things.
|
||||
TOFU_WORKSPACE="${TOFU_WORKSPACE:-$TARGET}"
|
||||
}
|
||||
Reference in New Issue
Block a user