first commit

This commit is contained in:
2026-10-09 02:35:14 +07:00
commit 4ca7a9a58e
108 changed files with 23035 additions and 0 deletions
+168
View File
@@ -0,0 +1,168 @@
#!/usr/bin/env bash
# =============================================================================
# test-bootstrap-host.sh — penjagaan untuk `bootstrap.sh --host` (Fase 2b/2c)
# -----------------------------------------------------------------------------
# Latar: `generate_runtime_credentials()` menulis TIGA berkas ke `config/` BERSAMA.
# Dalam mode `--host`, endpoint-nya milik host itu, sehingga berkas bersama tertimpa
# alamat host lain — dan itu TIDAK terlihat di `git status` karena
# `config/airflow/sling/env.yaml` memang gitignored. Dampaknya: deploy single-host
# yang sedang berjalan menunjuk alamat yang tidak ada.
#
# Uji ini punya dua lapis:
# A. STATIS — membaca bootstrap.sh dan memastikan ketiga penulisan memakai
# `${cfg_base}` (bukan `${SCRIPT_DIR}/config` langsung). Tidak butuh
# apa pun, selalu jalan.
# B. DINAMIS — bila stack SiCABE sedang berjalan: hash ketiga berkas bersama,
# jalankan `bootstrap.sh --host state` (hanya step 2 = pastikan bucket,
# idempoten), lalu pastikan hash TIDAK berubah.
#
# Jalankan: ./scripts/test-bootstrap-host.sh
# =============================================================================
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEPLOY_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
GRN=$'\e[32m'; RED=$'\e[31m'; YLW=$'\e[33m'; BLD=$'\e[1m'; NC=$'\e[0m'
PASS_N=0; FAIL_N=0
ok() { printf " ${GRN}✅${NC} %s\n" "$1"; PASS_N=$((PASS_N + 1)); }
bad() { printf " ${RED}❌${NC} %s\n" "$1"; FAIL_N=$((FAIL_N + 1)); }
inf() { printf " ${YLW}[..]${NC} %s\n" "$1"; }
SHARED_FILES=(
"config/airflow/sling/env.yaml"
"config/airflow/simple_auth_manager_passwords.json"
"config/trino/password.db"
)
echo -e "${BLD}Uji bootstrap.sh --host${NC}"
echo
echo "── A. penjagaan statis (tanpa dependensi) ──"
# Ekstrak badan fungsi generate_runtime_credentials.
body="$(awk '/^generate_runtime_credentials\(\) \{/{f=1} f{print} f&&/^\}/{exit}' "${DEPLOY_DIR}/bootstrap.sh")"
if [[ -z "${body}" ]]; then
bad "fungsi generate_runtime_credentials() tidak ditemukan"
else
ok "fungsi generate_runtime_credentials() ditemukan"
for target in 'airflow/sling' 'airflow/simple_auth_manager_passwords.json' 'trino/password.db'; do
if grep -q 'local .*="\${cfg_base}/'"${target}"'"' <<<"${body}"; then
ok "penulisan ${target} memakai \${cfg_base}"
else
bad "penulisan ${target} TIDAK memakai \${cfg_base} (rawan menimpa config bersama)"
fi
done
if grep -q 'HOST_NAME' <<<"${body}" && grep -q 'generated/host-' <<<"${body}"; then
ok "cfg_base dialihkan ke bundle host saat HOST_NAME diisi"
else
bad "cfg_base tidak dialihkan berdasarkan HOST_NAME"
fi
# Tidak boleh ada penulisan langsung ke ${SCRIPT_DIR}/config (selain default cfg_base).
if grep -nE '(cat >|: >|>>) *"\$\{SCRIPT_DIR\}/config' <<<"${body}"; then
bad "masih ada penulisan langsung ke \${SCRIPT_DIR}/config"
else
ok "tidak ada penulisan langsung ke \${SCRIPT_DIR}/config"
fi
fi
# step_tiers harus memetakan seluruh step 1..9. Bentuk pattern bisa berkelompok
# (mis. `1|3)`, `4|5)`, `7|8)`), jadi diambil hanya bagian sebelum ')' lalu dipecah
# pada '|' — regex "baris diawali angka" akan salah untuk bentuk berkelompok.
patterns="$(awk '/^step_tiers\(\) \{/{f=1} f{print} f&&/^\}/{exit}' "${DEPLOY_DIR}/bootstrap.sh" \
| grep -E '\)' | sed 's/).*//' | tr '|' '\n' | tr -d ' ')"
missing=""
for s in 1 2 3 4 5 6 7 8 9; do
grep -qx "${s}" <<<"${patterns}" || missing+=" ${s}"
done
if [[ -z "${missing}" ]]; then
ok "step_tiers() memetakan step 1..9"
else
bad "step_tiers() belum memetakan step:${missing}"
fi
echo
echo "── B. penjagaan dinamis (butuh stack SiCABE berjalan) ──"
if ! docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^sicabe-'; then
inf "tidak ada container sicabe- yang berjalan — lapis dinamis DILEWATI"
echo
printf " ${YLW}Ringkasan:${NC} %s PASS · %s FAIL (lapis dinamis dilewati)\n" "${PASS_N}" "${FAIL_N}"
[[ ${FAIL_N} -eq 0 ]] && exit 0 || exit 1
fi
GEN_DIR="${DEPLOY_DIR}/generated"
created_gen=0
if [[ ! -f "${GEN_DIR}/host-state/.env" ]]; then
inf "bundle host belum ada — generate dulu (sementara, akan dihapus)"
if python3 "${DEPLOY_DIR}/lib/cluster/generate.py" render \
"${DEPLOY_DIR}/cluster.example.yml" "${DEPLOY_DIR}/docker-compose.yml" \
"${DEPLOY_DIR}/.env" "${GEN_DIR}" "${DEPLOY_DIR}/scripts/render-config.sh" \
>/dev/null 2>&1; then
created_gen=1
else
bad "gagal menyiapkan bundle host untuk uji dinamis"
GEN_DIR=""
fi
fi
if [[ -n "${GEN_DIR}" ]]; then
declare -A before=()
for f in "${SHARED_FILES[@]}"; do
[[ -f "${DEPLOY_DIR}/${f}" ]] && before["${f}"]="$(sha256sum "${DEPLOY_DIR}/${f}" | cut -c1-16)"
done
inf "menjalankan: bootstrap.sh --host state (hanya step 2 — pastikan bucket)"
"${DEPLOY_DIR}/bootstrap.sh" --host state >/tmp/test-bootstrap-host.log 2>&1 || true
touched=0
for f in "${SHARED_FILES[@]}"; do
[[ -z "${before[${f}]:-}" ]] && continue
now="$(sha256sum "${DEPLOY_DIR}/${f}" | cut -c1-16)"
if [[ "${before[${f}]}" != "${now}" ]]; then
bad "${f} BERUBAH setelah --host state (bug config bersama kembali)"
touched=1
fi
done
[[ ${touched} -eq 0 ]] && ok "ketiga berkas config bersama tidak berubah (sha256 identik)"
# Kredensial host harus mendarat di bundle host.
if [[ -f "${GEN_DIR}/host-state/config/airflow/sling/env.yaml" ]]; then
ok "kredensial runtime ditulis ke bundle host (generated/host-state/config/...)"
else
bad "kredensial runtime TIDAK ditemukan di bundle host"
fi
fi
[[ ${created_gen} -eq 1 ]] && rm -rf "${GEN_DIR}" && inf "artefak uji generated/ dihapus"
rm -f /tmp/test-bootstrap-host.log
# ── install.sh --host: profil `edge` ikut saat bundle memuat traefik (T-20) ─────
# Traefik berada di profile `edge`. Bila run_host hanya memakai `--profile all`,
# Traefik tidak pernah start sehingga SELURUH rute publik tidak ada — padahal label
# sudah terpasang di setiap layanan dan sertifikat sudah bisa diterbitkan.
run_host_body="$(sed -n '/^run_host()/,/^}/p' "${DEPLOY_DIR}/install.sh")"
if grep -q 'traefik:' <<<"${run_host_body}" && grep -q 'profile edge' <<<"${run_host_body}"; then
ok "run_host menyertakan profile edge bila bundle memuat traefik"
else
bad "run_host tidak mendeteksi profile edge (Traefik tidak akan pernah start)"
fi
# ── install.sh: nama LOGIS harus diuraikan di EXTERNAL_SERVICES/LOCAL_SERVICES ──
# Tanpa ini, `starrocks` (dan dulu hanya `trino` yang istimewa) diam-diam tidak
# berefek: filter mencocokkan nama SERVICE (`starrocks-fe`, `starrocks-cn`).
if grep -q 'expand_service_names()' "${DEPLOY_DIR}/install.sh" \
&& grep -q 'starrocks-fe starrocks-cn' "${DEPLOY_DIR}/install.sh" \
&& grep -q 'expand_service_names ${LOCAL_SERVICES' "${DEPLOY_DIR}/install.sh" \
&& grep -q 'expand_service_names ${EXTERNAL_SERVICES' "${DEPLOY_DIR}/install.sh"; then
ok "nama logis diuraikan di EXTERNAL_SERVICES & LOCAL_SERVICES (starrocks/trino/…)"
else
bad "pemetaan nama logis hilang — setelan seperti LOCAL_SERVICES=starrocks akan diabaikan"
fi
echo
if [[ ${FAIL_N} -eq 0 ]]; then
echo -e " ${GRN}${BLD}SEMUA LULUS${NC} (${PASS_N} cek)"
exit 0
fi
echo -e " ${RED}${BLD}GAGAL${NC}: ${FAIL_N} masalah · ${PASS_N} lulus"
exit 1