Add homelab dependency map command

This commit is contained in:
juvdiaz 2026-06-29 17:26:57 -06:00
parent 41498150ea
commit 7efa7a0452
5 changed files with 154 additions and 1 deletions

View File

@ -275,6 +275,7 @@ Run a read-only health snapshot from the Debian server with:
./jeannie gitops-status ./jeannie gitops-status
./jeannie cert-check ./jeannie cert-check
./jeannie release-snapshot ./jeannie release-snapshot
./jeannie map
``` ```
It reports host memory/disk, systemd services, Docker Compose stacks, It reports host memory/disk, systemd services, Docker Compose stacks,
@ -314,6 +315,10 @@ HTTP status, and DuckDNS-to-OCI edge IP drift from the canonical inventory.
state directory with Git state, Kubernetes/Argo CD/Helm state, workload images, state directory with Git state, Kubernetes/Argo CD/Helm state, workload images,
public URL status, and pointers to the latest Gitea/OpenTofu backups. public URL status, and pointers to the latest Gitea/OpenTofu backups.
`map` prints a dependency map from the canonical inventory, covering public
entry, GitOps automation, cluster foundation, DNS, observability, and security
learning paths. `./jeannie map --dot` emits Graphviz DOT.
Focused doctor commands run narrower read-only checks and print the most likely Focused doctor commands run narrower read-only checks and print the most likely
next step: next step:

View File

@ -275,6 +275,7 @@ Run a read-only health snapshot from the Debian server with:
./{{ main_script }} gitops-status ./{{ main_script }} gitops-status
./{{ main_script }} cert-check ./{{ main_script }} cert-check
./{{ main_script }} release-snapshot ./{{ main_script }} release-snapshot
./{{ main_script }} map
``` ```
It reports host memory/disk, systemd services, Docker Compose stacks, It reports host memory/disk, systemd services, Docker Compose stacks,
@ -314,6 +315,10 @@ HTTP status, and DuckDNS-to-OCI edge IP drift from the canonical inventory.
state directory with Git state, Kubernetes/Argo CD/Helm state, workload images, state directory with Git state, Kubernetes/Argo CD/Helm state, workload images,
public URL status, and pointers to the latest Gitea/OpenTofu backups. public URL status, and pointers to the latest Gitea/OpenTofu backups.
`map` prints a dependency map from the canonical inventory, covering public
entry, GitOps automation, cluster foundation, DNS, observability, and security
learning paths. `./{{ main_script }} map --dot` emits Graphviz DOT.
Focused doctor commands run narrower read-only checks and print the most likely Focused doctor commands run narrower read-only checks and print the most likely
next step: next step:

View File

@ -76,6 +76,10 @@ and DuckDNS-to-OCI edge IP drift from the canonical inventory.
state, workload images, public URL status, and latest Gitea/OpenTofu backup state, workload images, public URL status, and latest Gitea/OpenTofu backup
pointers. pointers.
`map`
: Print a dependency map from the canonical inventory. Use `map --dot` for a
Graphviz DOT graph.
Prometheus alerts Prometheus alerts
: High-signal alert rules are managed as the `apps/homelab-alerts` GitOps app. : High-signal alert rules are managed as the `apps/homelab-alerts` GitOps app.
They cover node readiness, restart storms, unavailable deployments, storage They cover node readiness, restart storms, unavailable deployments, storage

View File

@ -5986,6 +5986,10 @@ release_snapshot() {
"${REPO_ROOT}/scripts/release-snapshot" "${REPO_ROOT}/scripts/release-snapshot"
} }
homelab_map() {
"${REPO_ROOT}/scripts/homelab-map" "${@:2}"
}
case "${1:-}" in case "${1:-}" in
up) up)
up up
@ -6020,6 +6024,9 @@ case "${1:-}" in
release-snapshot) release-snapshot)
release_snapshot release_snapshot
;; ;;
map)
homelab_map "$@"
;;
validate) validate)
validate_homelab validate_homelab
;; ;;
@ -6164,7 +6171,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|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|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

132
scripts/homelab-map Executable file
View File

@ -0,0 +1,132 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
INVENTORY_FILE="${HOMELAB_INVENTORY_FILE:-${REPO_ROOT}/homelab.yml}"
FORMAT="${1:-text}"
inventory() {
local path="$1"
local fallback="$2"
if command -v ruby >/dev/null 2>&1 && [ -f "$INVENTORY_FILE" ]; then
value="$(
ruby -ryaml -e '
data = YAML.load_file(ARGV[0])
value = ARGV[1].split(".").reduce(data) { |memo, key| memo.respond_to?(:[]) ? memo[key] : nil }
puts value if value.is_a?(String) || value.is_a?(Integer)
' "$INVENTORY_FILE" "$path" 2>/dev/null || true
)"
if [ -n "$value" ]; then
printf '%s\n' "$value"
return 0
fi
fi
printf '%s\n' "$fallback"
}
domain="$(inventory domain.base lab2025.duckdns.org)"
debian="$(inventory hosts.debian.lan_ip 192.168.100.73)"
debian_ts="$(inventory hosts.debian.tailscale_ip 100.85.138.30)"
rpi="$(inventory hosts.rpi4.lan_ip 192.168.100.89)"
oci="$(inventory hosts.oci_edge.public_ip 132.145.170.74)"
oci_ts="$(inventory hosts.oci_edge.tailscale_ip 100.118.255.19)"
pimox="$(inventory hosts.opi5_pimox.lan_ip 192.168.100.80)"
traefik="$(inventory network.metallb.traefik_ip 192.168.100.240)"
registry="$(inventory services.local_registry.endpoint 192.168.100.73:30500)"
gitea_http="$(inventory services.gitea.http_port 3000)"
gitea_ssh="$(inventory services.gitea.ssh_port 32222)"
pihole_web="$(inventory services.rpi_dns.pihole_web_port 8081)"
kuma="$(inventory services.rpi_dns.uptime_kuma_port 3001)"
if [ "$FORMAT" = "--dot" ] || [ "$FORMAT" = "dot" ]; then
cat <<EOF
digraph homelab {
rankdir=LR;
"Internet" -> "OCI edge ${oci}";
"OCI edge ${oci}" -> "Traefik ${traefik}";
"OCI edge ${oci}" -> "Debian Tailscale ${debian_ts}";
"Debian ${debian}" -> "Gitea :${gitea_http}/git";
"Debian ${debian}" -> "Local registry ${registry}";
"Debian ${debian}" -> "Kubernetes control plane";
"Debian ${debian}" -> "Pimox ${pimox}";
"Pimox ${pimox}" -> "Worker VMs";
"Worker VMs" -> "Kubernetes apps";
"Kubernetes apps" -> "Traefik ${traefik}";
"Gitea :${gitea_http}/git" -> "Argo CD";
"Argo CD" -> "Kubernetes apps";
"Clients" -> "Pi-hole ${rpi}:53";
"Pi-hole ${rpi}:53" -> "Unbound";
"Pi-hole ${rpi}:53" -> "Public DNS fallback";
"Uptime Kuma ${rpi}:${kuma}" -> "Public URLs";
"Uptime Kuma ${rpi}:${kuma}" -> "LAN services";
}
EOF
exit 0
fi
cat <<EOF
Homelab dependency map
======================
Public entry
Internet
-> ${domain}
-> OCI edge ${oci} / tailscale ${oci_ts}
-> Traefik LoadBalancer ${traefik}
-> Kubernetes ingress routes
-> website, demos, Heimdall, observability, Argo CD, arr routes
Git and automation
Debian ${debian}
-> Gitea HTTP :${gitea_http}/git and SSH :${gitea_ssh}
-> Gitea Actions runner
-> local registry ${registry}
-> jeannie orchestration
Gitea repository
-> Argo CD applications
-> Kubernetes manifests under apps/
-> edge/provisioning/cluster/platform Terraform stacks
Cluster foundation
Debian ${debian}
-> kubeadm control plane
-> container registry
-> provisioning HTTP/TFTP
Orange Pi Pimox ${pimox}
-> worker VM template
-> worker VM clones
-> Kubernetes worker capacity
DNS and always-on health
Clients and lab hosts
-> RPi4 Pi-hole ${rpi}:53
-> Unbound resolver
-> public fallback DNS if Unbound is unhealthy
RPi4
-> Pi-hole web ${rpi}:${pihole_web}
-> Uptime Kuma ${rpi}:${kuma}
-> monitors public URLs, LAN services, DNS, Traefik, Gitea, arr
Observability and operations
Prometheus stack
-> nodes, pods, Traefik, website probes, Gitea/Pi-hole scrape coverage
-> homelab-alerts
-> Grafana dashboards
jeannie status
-> host/bootstrap checks
-> local services
-> RPi DNS and Kuma
-> Pimox and Kubernetes
-> platform/apps
-> edge/public URLs
Security learning loop
security-lab namespace
-> isolated OWASP practice targets
-> ZAP/nuclei/trivy/lynis helper commands
-> report-only findings before manual fixes
Use './jeannie map --dot' to emit a Graphviz DOT version.
EOF