223 lines
12 KiB
Bash
Executable File
223 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
# ==============================================================================================
|
|
# ================================= CONFIGURATION LOADER =======================================
|
|
# ==============================================================================================
|
|
#
|
|
# PURPOSE
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Single entry point for all configuration sourcing across the ecosystem.
|
|
# Every script sources this file instead of sourcing conf files directly.
|
|
#
|
|
# ==============================================================================================
|
|
# OPERATIONAL MODEL
|
|
# ==============================================================================================
|
|
#
|
|
# Sourcing order (order is load-bearing):
|
|
# 1. Detects OS platform → PLATFORM=unraid|truenas|unknown; exports SCRIPTS_DIR
|
|
# 2. Sources master.conf — shared config: hostnames, thresholds, toggles, profiles, job lists
|
|
# 3. Auto-discovers and sources all host*.conf files present in Configurations/
|
|
# Each host conf extends the shared profile arrays and adds host-specific credentials
|
|
# 4. Sources common.sh — shared functions: detect_hosts, logging, notifications, etc.
|
|
# 5. Sources Plugin/<platform>/adapter.sh — platform_*() functions for OS-specific ops
|
|
#
|
|
# USAGE IN SCRIPTS
|
|
# Scripts in subdirectories (Rsync/, Docker_Essentials/ etc.):
|
|
# SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# source "$SCRIPT_DIR/../load_config.sh"
|
|
#
|
|
# Scripts in the repo root:
|
|
# SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# source "$SCRIPT_DIR/load_config.sh"
|
|
#
|
|
# SPARSE CHECKOUT NOTE
|
|
# Sparse checkout controls which host*.conf files each server receives.
|
|
# HOST1 only pulls Configurations/host1.conf — never HOST2's credentials.
|
|
# HOST2 only pulls Configurations/host2.conf — never HOST1's credentials.
|
|
# This loader sources whatever conf files ARE present — sparse checkout handles the rest.
|
|
#
|
|
# ==============================================================================================
|
|
# OPERATIONAL SAFEGUARDS
|
|
# ==============================================================================================
|
|
#
|
|
# No Root, No Lock, No detect_hosts on Load — Deliberate
|
|
# Sourced by every script in the ecosystem, including read-only ones. A root check here
|
|
# would gate all of them, a lock would be taken on every source, and auto-calling
|
|
# detect_hosts() would exit the caller on an unknown hostname before it could handle that
|
|
# itself. The executable scripts own those gates. Do not add them here.
|
|
#
|
|
# Fatal on Missing common.sh
|
|
# Aborts loudly if common.sh is absent. Every downstream script assumes log(), error(),
|
|
# acquire_lock() and detect_hosts() exist; continuing without them would produce
|
|
# command-not-found errors scattered through unrelated scripts instead of one clear cause.
|
|
#
|
|
# Adapter Load Is Optional
|
|
# A missing Plugin/$PLATFORM/adapter.sh is tolerated so the ecosystem can run before the
|
|
# plugin directory exists — bootstrap and early install paths depend on that.
|
|
#
|
|
# Load Order Is Enforced, Not Incidental
|
|
# confs before common.sh before adapter. common.sh needs HOST* to already be set, and the
|
|
# adapter needs common.sh's output helpers. Reordering breaks both silently.
|
|
#
|
|
# Partner Confs Are Cache-Only
|
|
# Partner host*.conf files load from the tmpfs RAM cache, never from disk. Sparse checkout
|
|
# means this host has no partner conf in the repo, and reading a stale on-disk copy would
|
|
# resurrect credentials the partner has since rotated.
|
|
#
|
|
# ==============================================================================================
|
|
# CONFIGURATION
|
|
# ==============================================================================================
|
|
#
|
|
# This file is the thing that loads configuration, so it consumes almost none itself. The one
|
|
# input it must find on its own:
|
|
#
|
|
# /boot/config/plugins/varaverk/varaverk.cfg
|
|
# SCRIPTS_DIR the authoritative install path — everything else derives from it
|
|
# PLATFORM selects which Plugin/<platform>/adapter.sh gets sourced
|
|
#
|
|
# It then defines the paths the rest of the ecosystem builds on:
|
|
#
|
|
# VV_CACHE_ROOT everything Varaverk keeps in RAM, one root, defined in master.conf
|
|
# CONF_RAM_CACHE_DIR $VV_CACHE_ROOT/conf — partner conf cache, chmod 700, snapshotted
|
|
# ARR_CACHE_DIR $VV_CACHE_ROOT/arr — restored from DATA_DIR on demand
|
|
#
|
|
# Everything else (STATE_DIR, DATA_DIR, thresholds, credentials) comes out of master.conf and
|
|
# host*.conf, which this file sources rather than defines.
|
|
#
|
|
# ==============================================================================================
|
|
# RUNTIME MODES
|
|
# ==============================================================================================
|
|
#
|
|
# None — sourced, never executed. Every script begins with:
|
|
#
|
|
# SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# source "$SCRIPT_DIR/../load_config.sh"
|
|
#
|
|
# It takes no arguments and honours no flags. parse_args() arrives via common.sh and is
|
|
# called by the script itself afterwards.
|
|
#
|
|
# ==============================================================================================
|
|
# DESIGN PRINCIPLES
|
|
# ==============================================================================================
|
|
#
|
|
# Zero-Script Expansion
|
|
# Without this loader, adding a new server required updating every script to
|
|
# source the new host conf. With this loader: create host3.conf in the repo,
|
|
# commit and push — all servers auto-discover it on next git pull. No script
|
|
# changes required.
|
|
#
|
|
# ==============================================================================================
|
|
|
|
# ━━━ Locate config root ━━━
|
|
# load_config.sh always lives in the repo root.
|
|
# Scripts call it from subdirectories using ../ — resolve to the actual root.
|
|
LOAD_CONFIG_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
# ━━━ Platform detection ━━━
|
|
# PLATFORM drives the adapter layer — Plugin/<platform>/adapter.sh
|
|
# Each platform adapter provides the same function API; scripts stay OS-agnostic.
|
|
if [[ -f /etc/unraid-version ]]; then PLATFORM="unraid"
|
|
elif [[ -f /etc/truenas ]]; then PLATFORM="truenas"
|
|
else PLATFORM="unknown"
|
|
fi
|
|
export PLATFORM SCRIPTS_DIR="$LOAD_CONFIG_DIR"
|
|
|
|
# ━━━ Source shared config ━━━
|
|
# master.conf must be sourced first — it declares the shared PROFILE_* arrays
|
|
# that Host confs extend. Sourcing host confs before master.conf would fail.
|
|
if [[ ! -f "$LOAD_CONFIG_DIR/Configurations/master.conf" ]]; then
|
|
echo "[FATAL] master.conf not found at $LOAD_CONFIG_DIR/Configurations/master.conf" >&2
|
|
echo "[FATAL] Check TARGET_DIR and git pull status" >&2
|
|
exit 1
|
|
fi
|
|
source "$LOAD_CONFIG_DIR/Configurations/master.conf"
|
|
|
|
# ━━━ Cache roots ━━━
|
|
# Resolved here, immediately after master.conf, rather than with the other derived paths further
|
|
# down — the partner-conf cache is read a few lines below to source HOST2_* vars, and that block
|
|
# used to carry its own copy of the path precisely because the variable did not exist yet at that
|
|
# point. Defining these the moment master.conf provides them removes the reason for the copy.
|
|
#
|
|
# The fallbacks are the pre-consolidation paths: an installation whose conf has not been through
|
|
# conf_upgrade keeps using what it is already using rather than silently relocating its caches.
|
|
# The PHP layer reads the same keys out of the same file, with the same fallbacks.
|
|
VV_CACHE_ROOT="${VV_CACHE_ROOT:-/tmp/varaverk}"
|
|
VV_CACHE_DIR="${VV_CACHE_DIR:-/tmp/vv_cache}"
|
|
CONF_RAM_CACHE_DIR="${CONF_RAM_CACHE_DIR:-/tmp/.cache/vv/d}"
|
|
ARR_CACHE_DIR="${ARR_CACHE_DIR:-/tmp/arr_cache}"
|
|
AI_TOKEN_CACHE_DIR="${AI_TOKEN_CACHE_DIR:-/tmp/.cache/vv/ai}"
|
|
AI_JOB_DIR="${AI_JOB_DIR:-/tmp/varaverk_ai_jobs}"
|
|
DOCKER_JOB_DIR="${DOCKER_JOB_DIR:-/tmp/varaverk_dk_jobs}"
|
|
|
|
# ━━━ Auto-discover and source all host*.conf files ━━━
|
|
# Sorted for consistent load order — HOST1 before HOST2 before HOST3 etc.
|
|
# Each host conf extends the shared PROFILE_* arrays and adds host-specific vars.
|
|
# Missing files are silently skipped — sparse checkout intentionally withholds some.
|
|
# At least one host conf must be present or the ecosystem has no identity to work with.
|
|
_host_confs_loaded=0
|
|
declare -A _disk_conf_basenames=()
|
|
|
|
# Use a sorted array glob — avoids word-splitting on paths with spaces
|
|
while IFS= read -r _conf; do
|
|
[[ -f "$_conf" ]] || continue
|
|
source "$_conf"
|
|
(( _host_confs_loaded++ ))
|
|
_disk_conf_basenames["$(basename "$_conf")"]=1
|
|
[[ "${ENABLE_LOGGING:-false}" == "true" ]] && \
|
|
echo "[LOG] Loaded host config: $(basename "$_conf")" >&2
|
|
done < <(printf '%s\n' "$LOAD_CONFIG_DIR/Configurations"/host*.conf 2>/dev/null | sort)
|
|
|
|
if [[ "$_host_confs_loaded" -eq 0 ]]; then
|
|
echo "[FATAL] No host*.conf files found in $LOAD_CONFIG_DIR" >&2
|
|
echo "[FATAL] At least one host conf required — check git pull and sparse checkout" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ━━━ Source partner confs from /tmp cache ━━━
|
|
# conf_sync.sh pulls partner host*.conf files into /tmp/.cache/vv/d/
|
|
# on array start and after any conf save. Sourcing them here makes partner vars
|
|
# (HOST2_*, HOST3_*, …) available without committing credentials to the git repo
|
|
# or violating sparse checkout — partner confs live in RAM only, cleared on reboot.
|
|
# Confs already loaded from disk are skipped — disk copy is authoritative.
|
|
_VV_CONF_CACHE="$CONF_RAM_CACHE_DIR"
|
|
if [[ -d "$_VV_CONF_CACHE" ]]; then
|
|
while IFS= read -r _conf; do
|
|
[[ -f "$_conf" ]] || continue
|
|
_conf_base="$(basename "$_conf")"
|
|
# Skip if already sourced from disk
|
|
[[ -n "${_disk_conf_basenames[$_conf_base]:-}" ]] && continue
|
|
source "$_conf"
|
|
[[ "${ENABLE_LOGGING:-false}" == "true" ]] && \
|
|
echo "[LOG] Loaded cached partner config: $_conf_base" >&2
|
|
done < <(printf '%s\n' "$_VV_CONF_CACHE"/host*.conf 2>/dev/null | sort)
|
|
fi
|
|
unset _VV_CONF_CACHE _conf_base _disk_conf_basenames
|
|
|
|
# ━━━ Source shared functions ━━━
|
|
# common.sh sourced last — it defines detect_hosts(), which needs HOST* vars to be set.
|
|
# It does NOT call it. Each script calls detect_hosts() itself, so MY_ID and REMOTE_ID
|
|
# are unset until it does — anything building HOST*-prefixed variable names must come after.
|
|
if [[ ! -f "$LOAD_CONFIG_DIR/common.sh" ]]; then
|
|
echo "[FATAL] common.sh not found at $LOAD_CONFIG_DIR/common.sh" >&2
|
|
exit 1
|
|
fi
|
|
source "$LOAD_CONFIG_DIR/common.sh"
|
|
|
|
# ━━━ Source platform adapter ━━━
|
|
# Provides platform_*() functions used by common.sh and scripts.
|
|
# Guard lets the ecosystem run before Plugin/<platform>/adapter.sh exists.
|
|
_adapter="$LOAD_CONFIG_DIR/Plugin/$PLATFORM/adapter.sh"
|
|
[[ -f "$_adapter" ]] && source "$_adapter"
|
|
|
|
# ━━━ Derived path constants ━━━
|
|
# Centralised here so every script that sources load_config.sh has them without
|
|
# re-deriving from SCRIPTS_DIR or hardcoding /var/log or /tmp paths inline.
|
|
CONF_DIR="${SCRIPTS_DIR}/Configurations"
|
|
LOG_DIR="/var/log/varaverk"
|
|
|
|
# Cache roots were resolved right after master.conf was sourced, because the partner-conf
|
|
# cache is read before this point. Exported here with the rest.
|
|
export CONF_DIR LOG_DIR VV_CACHE_ROOT VV_CACHE_DIR CONF_RAM_CACHE_DIR ARR_CACHE_DIR \
|
|
AI_TOKEN_CACHE_DIR AI_JOB_DIR DOCKER_JOB_DIR
|
|
|
|
# ━━━ Cleanup ━━━
|
|
unset _conf _host_confs_loaded _adapter LOAD_CONFIG_DIR |