mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 12:03:59 +00:00
296 lines
7.2 KiB
Bash
296 lines
7.2 KiB
Bash
#!/usr/bin/env bash
|
|
# Unit test for etc/init_monitoring.sh
|
|
|
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
KNOE_HOME=$(cd "$SCRIPT_DIR/../.." && pwd)
|
|
ETC_DIR="$KNOE_HOME/etc"
|
|
SCRIPT_UNDER_TEST="$ETC_DIR/init_monitoring.sh"
|
|
|
|
TMP_DIR=$(mktemp -d)
|
|
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
|
|
MOCK_CALLS_LOG="$TMP_DIR/mock_calls.log"
|
|
HELM_STATUS_DIR="$TMP_DIR/helm_status"
|
|
NS_EXISTS_FILE="$TMP_DIR/ns_exists"
|
|
|
|
mkdir -p "$HELM_STATUS_DIR"
|
|
echo "pending-install" > "$HELM_STATUS_DIR/kps"
|
|
echo "1" > "$NS_EXISTS_FILE"
|
|
|
|
export MOCK_CALLS_LOG
|
|
export HELM_STATUS_DIR
|
|
export NS_EXISTS_FILE
|
|
export TMP_DIR
|
|
|
|
write_mock() {
|
|
local name="$1"
|
|
cat > "$TMP_DIR/$name"
|
|
chmod +x "$TMP_DIR/$name"
|
|
}
|
|
|
|
write_mock kubectl <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
echo "Mocked kubectl called with $*" >> "$MOCK_CALLS_LOG"
|
|
|
|
capture_apply_file() {
|
|
# Capture `kubectl apply -f <file>` payloads for assertions.
|
|
local f="$1"
|
|
[[ -n "$f" && -f "$f" ]] || return 0
|
|
local i=0
|
|
while [[ -f "${TMP_DIR}/kubectl_apply_${i}.yaml" ]]; do
|
|
i=$((i+1))
|
|
done
|
|
cp "$f" "${TMP_DIR}/kubectl_apply_${i}.yaml" 2>/dev/null || true
|
|
}
|
|
|
|
# Handle optional namespace flag
|
|
if [[ "${1:-}" == "-n" ]]; then
|
|
shift 2
|
|
fi
|
|
|
|
if [[ "${1:-}" == "get" && "${2:-}" == "namespace" && "${3:-}" == "monitoring" ]]; then
|
|
if [[ "$(cat "$NS_EXISTS_FILE" 2>/dev/null || echo 0)" == "1" ]]; then
|
|
exit 0
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${1:-}" == "create" && "${2:-}" == "namespace" && "${3:-}" == "monitoring" ]]; then
|
|
echo 1 > "$NS_EXISTS_FILE"
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "${1:-}" == "delete" && "${2:-}" == "namespace" && "${3:-}" == "monitoring" ]]; then
|
|
echo 0 > "$NS_EXISTS_FILE"
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "${1:-}" == "get" && "${2:-}" == "pvc" && "${3:-}" == "-o" && "${4:-}" == "json" ]]; then
|
|
echo '{"items":[]}'
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "${1:-}" == "get" && "${2:-}" == "nodes" ]]; then
|
|
# Used by monitoring_nodes_available(). Provide at least one node.
|
|
echo "node/k3d-test"
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "${1:-}" == "apply" ]]; then
|
|
# Capture the YAML applied when the script provisions Grafana datasources/dashboards.
|
|
for ((i=1; i<=$#; i++)); do
|
|
if [[ "${!i}" == "-f" ]]; then
|
|
j=$((i+1))
|
|
f="${!j:-}"
|
|
capture_apply_file "$f"
|
|
fi
|
|
done
|
|
exit 0
|
|
fi
|
|
|
|
exit 0
|
|
EOF
|
|
|
|
write_mock helm <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
echo "Mocked helm called with $*" >> "$MOCK_CALLS_LOG"
|
|
|
|
cmd="${1:-}"
|
|
shift || true
|
|
|
|
status_file_for_release() {
|
|
local release="$1"
|
|
echo "$HELM_STATUS_DIR/$release"
|
|
}
|
|
|
|
case "$cmd" in
|
|
status)
|
|
release="${1:-}"
|
|
st="$(cat "$(status_file_for_release "$release")" 2>/dev/null || true)"
|
|
if [[ -z "$st" ]]; then
|
|
echo '{}'
|
|
exit 0
|
|
fi
|
|
echo '{"info":{"status":"'"$st"'"}}'
|
|
;;
|
|
history)
|
|
echo "REVISION UPDATED STATUS CHART"
|
|
echo "1 2026-01-01 00:00:00 unknown kube-prometheus-stack"
|
|
;;
|
|
repo)
|
|
exit 0
|
|
;;
|
|
upgrade)
|
|
# Support: helm upgrade --install <release> <chart> ...
|
|
release=""
|
|
if [[ "${1:-}" == "--install" ]]; then
|
|
release="${2:-}"
|
|
else
|
|
release="${1:-}"
|
|
fi
|
|
|
|
# Capture the values file(s) for assertions in tests.
|
|
values_i=0
|
|
for ((i=1; i<=$#; i++)); do
|
|
if [[ "${!i}" == "-f" ]]; then
|
|
j=$((i+1))
|
|
vf="${!j:-}"
|
|
if [[ -n "${vf}" && -f "${vf}" && -n "${release}" ]]; then
|
|
values_i=$((values_i+1))
|
|
cp "${vf}" "${TMP_DIR}/helm_values_${release}_${values_i}.yaml" 2>/dev/null || true
|
|
cp "${vf}" "${TMP_DIR}/helm_values_${release}.yaml" 2>/dev/null || true
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [[ -n "$release" ]]; then
|
|
echo "deployed" > "$(status_file_for_release "$release")"
|
|
fi
|
|
echo "Release upgraded"
|
|
exit 0
|
|
;;
|
|
uninstall)
|
|
release="${1:-}"
|
|
if [[ -n "$release" ]]; then
|
|
: > "$(status_file_for_release "$release")"
|
|
fi
|
|
echo "Release uninstalled"
|
|
exit 0
|
|
;;
|
|
*)
|
|
exit 0
|
|
;;
|
|
esac
|
|
EOF
|
|
|
|
write_mock jq <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
echo "Mocked jq called with $*" >> "$MOCK_CALLS_LOG"
|
|
|
|
query=""
|
|
for arg in "$@"; do
|
|
query="$arg"
|
|
done
|
|
|
|
input="$(cat)"
|
|
|
|
if [[ "$query" == *".info.status"* ]]; then
|
|
echo "$input" | sed -n 's/.*"status"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p'
|
|
exit 0
|
|
fi
|
|
|
|
exit 0
|
|
EOF
|
|
|
|
# Create mocks for other tools that may be on PATH in knoe_cfg.sh
|
|
for tool in curl docker k3d ansible-playbook tofu terraform ollama; do
|
|
cat > "$TMP_DIR/$tool" <<EOF
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
echo "Mocked $tool called with \$*" >> "$MOCK_CALLS_LOG"
|
|
exit 0
|
|
EOF
|
|
chmod +x "$TMP_DIR/$tool"
|
|
done
|
|
|
|
# Mock knoe.cfg
|
|
mkdir -p "$TMP_DIR/conf"
|
|
cat <<C_EOF > "$TMP_DIR/conf/knoe.cfg"
|
|
[globals]
|
|
knoe.home = $KNOE_HOME
|
|
knoe.mode = k3d
|
|
[k3s]
|
|
server = https://localhost:6443
|
|
token = test-token
|
|
C_EOF
|
|
|
|
export PATH="$TMP_DIR:$PATH"
|
|
export KNOE_HOME="$KNOE_HOME"
|
|
export KNOE_CONF="$TMP_DIR/conf"
|
|
export KNOE_SERVICE="$KNOE_HOME"
|
|
export NAMESPACE="test-ns"
|
|
export PROLE_PASSWD="test-password"
|
|
|
|
# Force fast timeouts so the test completes quickly
|
|
export HELM_WAIT_TIMEOUT=1
|
|
export HELM_WAIT_INTERVAL=0.2
|
|
export MONITORING_RESET_TIMEOUT=2
|
|
export MONITORING_RESET_INTERVAL=0.2
|
|
export MONITORING_STABILIZE_TIMEOUT=1
|
|
export MONITORING_READY_TIMEOUT=1s
|
|
export MONITORING_RESET_RETRIES=1
|
|
export HELM_UPGRADE_RETRIES=2
|
|
export HELM_RETRY_DELAY=0
|
|
export MONITORING_HELM_TIMEOUT=1s
|
|
|
|
# Run the script (initialize)
|
|
set +e
|
|
bash "$SCRIPT_UNDER_TEST" initialize > "$TMP_DIR/stdout" 2> "$TMP_DIR/stderr"
|
|
RC=$?
|
|
set -e
|
|
|
|
if [[ $RC -ne 0 ]]; then
|
|
echo "FAILURE with RC $RC"
|
|
echo "--- stderr ---"
|
|
cat "$TMP_DIR/stderr"
|
|
echo "--- stdout ---"
|
|
cat "$TMP_DIR/stdout"
|
|
exit 1
|
|
fi
|
|
|
|
# Assert that we emitted diagnostics and performed a reset (pending-install timeout path)
|
|
if ! grep -q "Monitoring diagnostics" "$TMP_DIR/stdout"; then
|
|
echo "FAILURE: expected diagnostics section in stdout"
|
|
cat "$TMP_DIR/stdout"
|
|
exit 1
|
|
fi
|
|
|
|
if ! grep -q "Resetting monitoring" "$TMP_DIR/stdout"; then
|
|
echo "FAILURE: expected reset section in stdout"
|
|
cat "$TMP_DIR/stdout"
|
|
exit 1
|
|
fi
|
|
|
|
# In k3d mode, we should not pin monitoring to the merlin hostname.
|
|
if [[ -f "$TMP_DIR/helm_values_kps.yaml" ]]; then
|
|
if grep -q "kubernetes.io/hostname: merlin.knoe.org" "$TMP_DIR/helm_values_kps.yaml"; then
|
|
echo "FAILURE: did not expect merlin hostname pinning in k3d mode"
|
|
sed -n '1,200p' "$TMP_DIR/helm_values_kps.yaml" || true
|
|
exit 1
|
|
fi
|
|
|
|
# Grafana must have datasource provisioning enabled so dashboards can bind to a stable Prometheus UID.
|
|
if ! grep -q "grafana_datasource" "$TMP_DIR/helm_values_kps.yaml"; then
|
|
echo "FAILURE: expected grafana datasource sidecar label in Helm values"
|
|
sed -n '1,220p' "$TMP_DIR/helm_values_kps.yaml" || true
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Assert we applied a ConfigMap that provisions the Prometheus datasource.
|
|
if ! grep -q "name: knoe-grafana-datasource" "$TMP_DIR"/kubectl_apply_*.yaml 2>/dev/null; then
|
|
echo "FAILURE: expected Grafana datasource ConfigMap to be applied"
|
|
ls -la "$TMP_DIR" || true
|
|
for f in "$TMP_DIR"/kubectl_apply_*.yaml; do
|
|
[[ -f "$f" ]] || continue
|
|
echo "--- $f ---"
|
|
sed -n '1,200p' "$f" || true
|
|
done
|
|
exit 1
|
|
fi
|
|
|
|
if ! grep -q "kubectl called with delete namespace monitoring" "$MOCK_CALLS_LOG"; then
|
|
echo "FAILURE: expected namespace deletion"
|
|
cat "$MOCK_CALLS_LOG"
|
|
exit 1
|
|
fi
|
|
|
|
echo "SUCCESS"
|
|
exit 0
|