first commit
This commit is contained in:
Executable
+195
@@ -0,0 +1,195 @@
|
||||
#!/usr/bin/env bash
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# render-config.sh — render config/** untuk deploy multi-host (Fase 0/1, R10 §4.9)
|
||||
#
|
||||
# MASALAH: file config/** yang dibaca CONTAINER (.properties/.yaml/.cfg/.json/rego)
|
||||
# TIDAK dapat melakukan ekspansi env saat runtime, berbeda dari docker-compose.yml.
|
||||
# Pada deploy multi-host, hostname nama container (mis. `nessie:19120`) harus
|
||||
# menjadi alamat host sebenarnya (mis. `10.20.0.10:19120`).
|
||||
#
|
||||
# SOLUSI (Opsi (i) R10 §4.9): `config/` dibiarkan LITERAL (single-host tidak
|
||||
# tersentuh); script ini menyalinnya ke direktori output sambil mengganti
|
||||
# hostname TERDAFTAR, menghasilkan `generated/host-<x>/config/` (gitignored).
|
||||
#
|
||||
# PRINSIP KEAMANAN
|
||||
# 1. Hanya hostname yang di-`--map` yang diganti → tidak ada kejutan.
|
||||
# 2. Penggantian ANCHORED: `host` diganti hanya bila diikuti `:` atau `/`
|
||||
# (posisi target jaringan). Karena itu `KC_DB: postgres` (dialek DB),
|
||||
# `DB_SCHEME: postgresql`, dan `postgres:15` (tag image di compose) TIDAK
|
||||
# ikut berubah.
|
||||
# 3. `config/` sumber tidak pernah ditulis — hanya dibaca.
|
||||
# 4. Baris KOMENTAR (`#`) tidak ditulis ulang: komentar sering menyebut nilai
|
||||
# default lokal, dan menimpanya akan membuat komentar itu justru salah.
|
||||
#
|
||||
# PEMAKAIAN
|
||||
# # Uji tanpa menulis (perlihatkan rencana):
|
||||
# ./scripts/render-config.sh --out /tmp/render --dry-run \
|
||||
# --map postgres=10.20.0.12 --map nessie=10.20.0.10
|
||||
#
|
||||
# # Render sungguhan:
|
||||
# ./scripts/render-config.sh --out generated/host-compute/config \
|
||||
# --map postgres=10.20.0.12 --map minio=10.20.0.12
|
||||
#
|
||||
# # Fase 1 akan menambah: --inventory cluster.yml --host <nama>
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DEPLOY_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
SRC_CONFIG="${DEPLOY_DIR}/config"
|
||||
OUT_DIR=""
|
||||
DRY_RUN=0
|
||||
declare -A MAP=()
|
||||
|
||||
# Hostname yang SAH dipetakan ke alamat host. Daftar sengaja tetap (bukan bebas)
|
||||
# supaya salah ketik --map tidak diam-diam menulis ulang file config.
|
||||
KNOWN_HOSTS=(
|
||||
postgres minio nessie keycloak openldap opa
|
||||
trino trino-coordinator trino-worker
|
||||
starrocks-fe starrocks-cn airflow-webserver
|
||||
openmetadata-server openmetadata-opensearch dremio grafana prometheus
|
||||
# Sidecar observabilitas (M2/M3): target di config/prometheus dipetakan ke alamat
|
||||
# HOST-nya saat multi-host. WAJIB ada di sini — generate.py meng-`--map` setiap
|
||||
# RENDER_HOSTS, dan hostname yang tak terdaftar membuat render-config menolak,
|
||||
# sehingga `install.sh --generate` GAGAL TOTAL (bug M2/M3 yang diperbaiki di sini).
|
||||
statsd-exporter trino-jmx-exporter
|
||||
)
|
||||
|
||||
# Tidak di-render: skrip yang sanggup ekspansi env sendiri + dokumentasi.
|
||||
# environment.defaults.sh — di-source shell, memakai ${VAR:-...}
|
||||
# buckets.sh — skrip mc, memakai ${MINIO_ENDPOINT:-...}
|
||||
SKIP_FILES=(environment.defaults.sh buckets.sh)
|
||||
SKIP_PATTERNS=("*.md")
|
||||
|
||||
RED=$'\e[31m'; GRN=$'\e[32m'; YLW=$'\e[33m'; BLD=$'\e[1m'; NC=$'\e[0m'
|
||||
ok() { echo -e " ${GRN}[OK]${NC} $*"; }
|
||||
inf() { echo -e " ${YLW}[..]${NC} $*"; }
|
||||
err() { echo -e " ${RED}[!!]${NC} $*" >&2; }
|
||||
|
||||
usage() {
|
||||
sed -n '2,30p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
||||
echo
|
||||
echo "Hostname yang dikenal: ${KNOWN_HOSTS[*]}"
|
||||
}
|
||||
|
||||
is_known_host() {
|
||||
local h="$1" k
|
||||
for k in "${KNOWN_HOSTS[@]}"; do [[ "${k}" == "${h}" ]] && return 0; done
|
||||
return 1
|
||||
}
|
||||
|
||||
add_map() {
|
||||
local pair="$1" host addr
|
||||
if [[ "${pair}" != *"="* ]]; then
|
||||
err "--map harus berformat host=alamat (diberikan: '${pair}')"; exit 2
|
||||
fi
|
||||
host="${pair%%=*}"; addr="${pair#*=}"
|
||||
[[ -n "${host}" && -n "${addr}" ]] || { err "--map kosong: '${pair}'"; exit 2; }
|
||||
is_known_host "${host}" || { err "hostname '${host}' tidak dikenal (lihat --help)"; exit 2; }
|
||||
MAP["${host}"]="${addr}"
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--out) OUT_DIR="${2:-}"; shift 2 ;;
|
||||
--map) add_map "${2:-}"; shift 2 ;;
|
||||
--dry-run) DRY_RUN=1; shift ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) err "Argumen tidak dikenal: $1"; usage; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
[[ -n "${OUT_DIR}" ]] || { err "--out wajib diisi"; exit 2; }
|
||||
[[ ${#MAP[@]} -gt 0 ]] || { err "minimal satu --map host=alamat wajib diisi"; exit 2; }
|
||||
}
|
||||
|
||||
# Satu pass perl untuk semua host. Anchor diperketat ke TIGA konteks jaringan —
|
||||
# tanpa ini, path filesystem seperti `/etc/trino/` atau `/data/trino/` ikut
|
||||
# terkorupsi (hostname `trino` diikuti `/`):
|
||||
# 1. setelah skema URL `//` → http://nessie:19120, jdbc:postgresql://postgres:5432
|
||||
# 2. setelah `@` (JDBC) → user:pw@postgres:5432
|
||||
# 3. bare `host:port` → nessie:19120, starrocks-fe:8030 (bukan bagian token lain)
|
||||
# Baris komentar (`#`) tidak ditulis ulang.
|
||||
render_file() {
|
||||
local src="$1" dst="$2"
|
||||
local -a pairs=()
|
||||
local k
|
||||
for k in "${!MAP[@]}"; do pairs+=("${k}=${MAP[$k]}"); done
|
||||
perl -e '
|
||||
my ($src, $dst, @pairs) = @ARGV;
|
||||
my %map = map { split(/=/, $_, 2) } @pairs;
|
||||
my $alt = join "|", sort { length($b) <=> length($a) } map { quotemeta } keys %map;
|
||||
open(my $in, "<", $src) or die "buka gagal: $src\n";
|
||||
open(my $out, ">", $dst) or die "tulis gagal: $dst\n";
|
||||
while (my $l = <$in>) {
|
||||
unless ($l =~ /^\s*#/) {
|
||||
$l =~ s{(?<=//)(${alt})(?=[:/])}{$map{$1}}g; # 1. setelah skema //
|
||||
$l =~ s{(?<=@)(${alt})(?=[:/])}{$map{$1}}g; # 2. setelah @ (JDBC)
|
||||
$l =~ s{(?<![\w/.:-])(${alt})(?=:\d)}{$map{$1}}g; # 3. bare host:port
|
||||
# 4. nilai BARE untuk key yang jelas host (host, hostname, *_HOST).
|
||||
# `host: postgres` (Sling) tidak punya ':' atau '/', sehingga aturan 1-3
|
||||
# tidak mengenainya -> di host lain Sling mencari nama container yang tidak
|
||||
# ada (kelas bug yang sama dengan DB_HOST OpenMetadata). Hanya key ber-'host'
|
||||
# yang disentuh, supaya `type: postgres` / `KC_DB: postgres` (dialek) aman.
|
||||
$l =~ s{^(\s*(?:-\s*)?[A-Za-z_.\-]*(?:host|hostname)[A-Za-z_.\-]*\s*[:=]\s*)(${alt})(\s*)$}{$1 . $map{$2} . $3}gie;
|
||||
}
|
||||
print $out $l;
|
||||
}
|
||||
close $in; close $out;
|
||||
' "${src}" "${dst}" "${pairs[@]}"
|
||||
}
|
||||
|
||||
# Jumlah baris sumber yang berubah di file tujuan.
|
||||
count_subs() {
|
||||
local src="$1" dst="$2"
|
||||
diff "${src}" "${dst}" 2>/dev/null | grep -c '^<' || true
|
||||
}
|
||||
|
||||
should_skip() {
|
||||
local name="$1" pat skip
|
||||
for skip in "${SKIP_FILES[@]}"; do [[ "${name}" == "${skip}" ]] && return 0; done
|
||||
for pat in "${SKIP_PATTERNS[@]}"; do
|
||||
# shellcheck disable=SC2053
|
||||
[[ "${name}" == ${pat} ]] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Render satu file; cetak jumlah baris berubah bila ada.
|
||||
process_file() {
|
||||
local src="$1" rel="${1#${SRC_CONFIG}/}" dst="$2" n tmp
|
||||
if [[ ${DRY_RUN} -eq 1 ]]; then
|
||||
tmp="$(mktemp)"; render_file "${src}" "${tmp}"; n="$(count_subs "${src}" "${tmp}")"; rm -f "${tmp}"
|
||||
else
|
||||
dst="${OUT_DIR}/${rel}"
|
||||
mkdir -p "$(dirname "${dst}")"
|
||||
render_file "${src}" "${dst}"
|
||||
n="$(count_subs "${src}" "${dst}")"
|
||||
fi
|
||||
CHANGED_TOTAL=$((CHANGED_TOTAL + n))
|
||||
if [[ "${n}" -gt 0 ]]; then ok "${rel} — ${n} baris"; FILES_CHANGED=$((FILES_CHANGED + 1)); fi
|
||||
}
|
||||
|
||||
main() {
|
||||
parse_args "$@"
|
||||
echo -e "${BLD}Render config/** untuk multi-host${NC}"
|
||||
echo " sumber : ${SRC_CONFIG}"
|
||||
echo " tujuan : ${OUT_DIR}$([[ ${DRY_RUN} -eq 1 ]] && echo ' (DRY-RUN)')"
|
||||
echo -n " peta : "; for k in "${!MAP[@]}"; do printf '%s→%s ' "${k}" "${MAP[$k]}"; done; echo; echo
|
||||
[[ ${DRY_RUN} -eq 0 ]] && mkdir -p "${OUT_DIR}"
|
||||
|
||||
FILES_CHANGED=0; CHANGED_TOTAL=0
|
||||
local src scanned=0 skipped=0
|
||||
while IFS= read -r -d '' src; do
|
||||
scanned=$((scanned + 1))
|
||||
if should_skip "$(basename "${src}")"; then skipped=$((skipped + 1)); continue; fi
|
||||
process_file "${src}" ""
|
||||
done < <(find "${SRC_CONFIG}" -type f -print0 | sort -z)
|
||||
|
||||
echo
|
||||
inf "dipindai ${scanned} file · ${FILES_CHANGED} berubah (${CHANGED_TOTAL} baris) · ${skipped} dilewati"
|
||||
echo -e " ${GRN}${BLD}Selesai.${NC} config/ sumber tidak tersentuh."
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user