Add ingress route inventory check

This commit is contained in:
juvdiaz 2026-06-29 17:51:43 -06:00
parent b1855d4928
commit 479be7fc47
5 changed files with 106 additions and 1 deletions

View File

@ -280,6 +280,7 @@ Run a read-only health snapshot from the Debian server with:
./jeannie resource-budget ./jeannie resource-budget
./jeannie artifact-cache status ./jeannie artifact-cache status
./jeannie golden-ledger check ./jeannie golden-ledger check
./jeannie route-inventory
./jeannie workers list ./jeannie workers list
./jeannie change-journal list ./jeannie change-journal list
./jeannie map ./jeannie map
@ -343,6 +344,10 @@ cache. Use `artifact-cache instructions` for client configuration snippets.
reviewable record of template VMID, storage, OS release, Kubernetes pins, reviewable record of template VMID, storage, OS release, Kubernetes pins,
runtime versions, and build metadata for Pimox worker golden images. runtime versions, and build metadata for Pimox worker golden images.
`route-inventory` reports Kubernetes ingress hosts, paths, backend services,
TLS coverage, and visible Uptime Kuma monitor coverage so stale routes and
missing monitors are easier to spot.
`workers` provides named Kubernetes/Pimox worker lifecycle operations: `workers` provides named Kubernetes/Pimox worker lifecycle operations:
`list`, `start`, `stop`, `drain`, `uncordon`, `recreate-plan`, and `rebalance`. `list`, `start`, `stop`, `drain`, `uncordon`, `recreate-plan`, and `rebalance`.
Use `recreate-plan <index>` before replacing one broken Pimox worker so the Use `recreate-plan <index>` before replacing one broken Pimox worker so the

View File

@ -280,6 +280,7 @@ Run a read-only health snapshot from the Debian server with:
./{{ main_script }} resource-budget ./{{ main_script }} resource-budget
./{{ main_script }} artifact-cache status ./{{ main_script }} artifact-cache status
./{{ main_script }} golden-ledger check ./{{ main_script }} golden-ledger check
./{{ main_script }} route-inventory
./{{ main_script }} workers list ./{{ main_script }} workers list
./{{ main_script }} change-journal list ./{{ main_script }} change-journal list
./{{ main_script }} map ./{{ main_script }} map
@ -343,6 +344,10 @@ cache. Use `artifact-cache instructions` for client configuration snippets.
reviewable record of template VMID, storage, OS release, Kubernetes pins, reviewable record of template VMID, storage, OS release, Kubernetes pins,
runtime versions, and build metadata for Pimox worker golden images. runtime versions, and build metadata for Pimox worker golden images.
`route-inventory` reports Kubernetes ingress hosts, paths, backend services,
TLS coverage, and visible Uptime Kuma monitor coverage so stale routes and
missing monitors are easier to spot.
`workers` provides named Kubernetes/Pimox worker lifecycle operations: `workers` provides named Kubernetes/Pimox worker lifecycle operations:
`list`, `start`, `stop`, `drain`, `uncordon`, `recreate-plan`, and `rebalance`. `list`, `start`, `stop`, `drain`, `uncordon`, `recreate-plan`, and `rebalance`.
Use `recreate-plan <index>` before replacing one broken Pimox worker so the Use `recreate-plan <index>` before replacing one broken Pimox worker so the

View File

@ -97,6 +97,10 @@ Docker Hub pull-through image caching.
`golden-ledger {show|check}` `golden-ledger {show|check}`
: Show or validate the Pimox golden image version ledger. : Show or validate the Pimox golden image version ledger.
`route-inventory`
: Report Kubernetes ingress hosts, paths, backend services, TLS coverage, and
visible Uptime Kuma monitor coverage.
`workers <command>` `workers <command>`
: Manage Kubernetes/Pimox worker lifecycle operations. Commands include `list`, : Manage Kubernetes/Pimox worker lifecycle operations. Commands include `list`,
`start`, `stop`, `drain`, `uncordon`, `recreate-plan`, and `rebalance`. `start`, `stop`, `drain`, `uncordon`, `recreate-plan`, and `rebalance`.

10
jeannie
View File

@ -6011,6 +6011,11 @@ golden_ledger() {
"${REPO_ROOT}/scripts/golden-ledger" "${@:2}" "${REPO_ROOT}/scripts/golden-ledger" "${@:2}"
} }
route_inventory() {
require_debian_server "route-inventory"
"${REPO_ROOT}/scripts/route-inventory"
}
workers_manage() { workers_manage() {
require_debian_server "workers" require_debian_server "workers"
"${REPO_ROOT}/scripts/workers" "${@:2}" "${REPO_ROOT}/scripts/workers" "${@:2}"
@ -6085,6 +6090,9 @@ case "${1:-}" in
golden-ledger) golden-ledger)
golden_ledger "$@" golden_ledger "$@"
;; ;;
route-inventory)
route_inventory
;;
workers) workers)
workers_manage "$@" workers_manage "$@"
;; ;;
@ -6242,7 +6250,7 @@ case "${1:-}" in
echo "Log: ${JEANNIE_LOG_FILE}" echo "Log: ${JEANNIE_LOG_FILE}"
;; ;;
*) *)
echo "Usage: $0 {up|plan [all|provisioning|cluster|platform|apps|edge]|rebuild-cluster|stop-cluster|start-cluster|status|capacity|recover-plan|gitops-status|cert-check|release-snapshot|backup-status|synthetic-checks|resource-budget|artifact-cache {status|up|down|instructions}|golden-ledger {show|check}|workers <list|start|stop|drain|uncordon|recreate-plan|rebalance>|change-journal {list|path}|map [--dot]|validate|access-audit|kubeconfig-readonly|apps|website-translation-model|website-ollama-listen|ollama-setup|deploy-gitea|rpi-services|bootstrap-gitea-repo|backup-gitea|drill-restore|drill-gitea-restore|drill-pihole-restore|install-gitea-runner|move-prometheus-stack-workers|doctor-versions|doctor-edge|doctor-gitea|doctor-rpi|doctor-cluster|preflight|doctor-preapply|inventory-check|state-backup|fix-debian-docker-root|secrets-init|secrets-check|tailnet-policy-check|ai-index|ai-check|security-scan|security-prepare|security-zap|security-k8s|security-host|security-trivy|security-secrets|security-nuclei|security-web|security-logs|security-runtime|security-attack-path|openwrt|nuke}" echo "Usage: $0 {up|plan [all|provisioning|cluster|platform|apps|edge]|rebuild-cluster|stop-cluster|start-cluster|status|capacity|recover-plan|gitops-status|cert-check|release-snapshot|backup-status|synthetic-checks|resource-budget|artifact-cache {status|up|down|instructions}|golden-ledger {show|check}|route-inventory|workers <list|start|stop|drain|uncordon|recreate-plan|rebalance>|change-journal {list|path}|map [--dot]|validate|access-audit|kubeconfig-readonly|apps|website-translation-model|website-ollama-listen|ollama-setup|deploy-gitea|rpi-services|bootstrap-gitea-repo|backup-gitea|drill-restore|drill-gitea-restore|drill-pihole-restore|install-gitea-runner|move-prometheus-stack-workers|doctor-versions|doctor-edge|doctor-gitea|doctor-rpi|doctor-cluster|preflight|doctor-preapply|inventory-check|state-backup|fix-debian-docker-root|secrets-init|secrets-check|tailnet-policy-check|ai-index|ai-check|security-scan|security-prepare|security-zap|security-k8s|security-host|security-trivy|security-secrets|security-nuclei|security-web|security-logs|security-runtime|security-attack-path|openwrt|nuke}"
exit 1 exit 1
;; ;;
esac esac

83
scripts/route-inventory Executable file
View File

@ -0,0 +1,83 @@
#!/usr/bin/env bash
set -euo pipefail
KUBECONFIG_PATH="${KUBECONFIG:-${LAB_KUBECONFIG_PATH:-/home/jv/.kube/config}}"
KUMA_MONITORS_FILE="${LAB_UPTIME_KUMA_MONITORS_FILE:-infra/rpi-services/uptime-kuma-monitors.json}"
INGRESS_JSON=""
cleanup() {
if [ -n "$INGRESS_JSON" ] && [ -f "$INGRESS_JSON" ]; then
rm -f "$INGRESS_JSON"
fi
}
trap cleanup EXIT
section() {
printf '\n== %s ==\n' "$1"
}
if ! command -v kubectl >/dev/null 2>&1 || [ ! -s "$KUBECONFIG_PATH" ]; then
echo "kubectl and kubeconfig are required for route-inventory." >&2
exit 1
fi
if ! kubectl --kubeconfig "$KUBECONFIG_PATH" get --raw=/readyz >/dev/null 2>&1; then
echo "Kubernetes API is unavailable." >&2
exit 1
fi
section "Ingress Routes"
INGRESS_JSON="$(mktemp "${TMPDIR:-/tmp}/homelab-ingress.XXXXXX.json")"
kubectl --kubeconfig "$KUBECONFIG_PATH" get ingress -A -o json >"$INGRESS_JSON"
python3 - "$INGRESS_JSON" "$KUMA_MONITORS_FILE" <<'PY'
import json
import sys
ingress_file, monitors_file = sys.argv[1:3]
with open(ingress_file, encoding="utf-8") as handle:
doc = json.load(handle)
monitors = []
try:
with open(monitors_file, encoding="utf-8") as handle:
data = json.load(handle)
for item in data if isinstance(data, list) else data.get("monitors", []):
url = item.get("url") or item.get("hostname") or ""
monitors.append(url)
except (OSError, json.JSONDecodeError):
pass
print(f"{'NAMESPACE':20} {'NAME':28} {'HOST':36} {'PATH':16} {'SERVICE':28} {'TLS':6} {'KUMA':6}")
missing = []
for ingress in doc.get("items", []):
ns = ingress["metadata"]["namespace"]
name = ingress["metadata"]["name"]
tls_hosts = {
host
for tls in ingress.get("spec", {}).get("tls", [])
for host in tls.get("hosts", [])
}
for rule in ingress.get("spec", {}).get("rules", []):
host = rule.get("host", "")
paths = rule.get("http", {}).get("paths", [])
if not paths:
paths = [{"path": "/", "backend": {}}]
for path in paths:
backend = path.get("backend", {}).get("service", {})
service = backend.get("name", "")
port = backend.get("port", {}).get("number") or backend.get("port", {}).get("name") or ""
route_path = path.get("path", "/")
tls = "yes" if host in tls_hosts else "no"
kuma = "yes" if any(host and host in monitor for monitor in monitors) else "no"
print(f"{ns:20} {name:28} {host:36} {route_path:16} {(service + ':' + str(port)):28} {tls:6} {kuma:6}")
if kuma == "no":
missing.append(f"{host}{route_path}")
if missing:
print("\nRoutes missing visible Uptime Kuma monitor coverage:")
for route in sorted(set(missing)):
print(f" {route}")
PY
section "Services Behind Ingress"
kubectl --kubeconfig "$KUBECONFIG_PATH" get svc -A \
-o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORTS:.spec.ports[*].port' |
sed -n '1,120p'