#!/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")" 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'