From 6241a14bac399e0320729dedc0745a2a71c1f2ac Mon Sep 17 00:00:00 2001 From: juvdiaz Date: Mon, 29 Jun 2026 13:44:59 -0600 Subject: [PATCH] Refine cascade status health probes --- docs/jeannie.1.md | 4 ++++ jeannie | 51 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/docs/jeannie.1.md b/docs/jeannie.1.md index bd9b9f9..23a54d1 100644 --- a/docs/jeannie.1.md +++ b/docs/jeannie.1.md @@ -180,6 +180,10 @@ tables after the normal status cascade. : Show short command output for successful cascade checks. Failed and warning checks already show short output by default. +`LAB_PIHOLE_STATUS_QUERY` +: DNS name used by `status` and `doctor-preapply` for the Pi-hole resolver +smoke test. Defaults to `cloudflare.com`. + `LAB_AUTO_APPROVE=false` : Disable automatic OpenTofu approval for apply paths that support confirmation. diff --git a/jeannie b/jeannie index 99f3df9..9c427af 100755 --- a/jeannie +++ b/jeannie @@ -1481,13 +1481,22 @@ fi" check_pihole_dns_query() { local rpi_host="${LAB_RPI_HOST:-${LAB_RASPBERRY_HOST:-192.168.100.89}}" + local query_name="${LAB_PIHOLE_STATUS_QUERY:-cloudflare.com}" + local output if command -v dig >/dev/null 2>&1; then - dig @"${rpi_host}" pi.hole A +time=3 +tries=1 >/dev/null - return $? + output="$(dig @"${rpi_host}" "${query_name}" A +time=3 +tries=1 +short 2>&1)" || { + printf '%s\n' "${output}" >&2 + return 1 + } + if [[ -z "${output}" ]]; then + echo "Pi-hole returned no A records for ${query_name}" >&2 + return 1 + fi + return 0 fi if command -v nslookup >/dev/null 2>&1; then - nslookup pi.hole "${rpi_host}" >/dev/null + nslookup "${query_name}" "${rpi_host}" >/dev/null return $? fi @@ -4624,6 +4633,38 @@ status_http_ok() { esac } +status_http_reachable() { + local url="$1" + local status + + if ! command -v curl >/dev/null 2>&1; then + echo "curl not installed" >&2 + return 1 + fi + + status="$(curl -k -sS -o /dev/null --connect-timeout 5 --max-time 10 -w '%{http_code}' "${url}")" || { + echo "unreachable ${url}" >&2 + return 1 + } + case "${status}" in + 2* | 3* | 4*) + return 0 + ;; + *) + echo "HTTP ${status} from ${url}" >&2 + return 1 + ;; + esac +} + +status_gitea_public_repo_ok() { + local root_url="${LAB_GITEA_ROOT_URL:-${LAB_PUBLIC_URL:-https://lab2025.duckdns.org}/git/}" + local repo_owner="${LAB_GITEA_REPO_OWNER:-jv}" + local repo_name="${LAB_GITEA_REPO_NAME:-my-homelab-configs}" + + status_http_ok "${root_url%/}/${repo_owner}/${repo_name}" +} + status_cascade_check() { local description="$1" local output @@ -4811,9 +4852,9 @@ status_cascade_report() { status_section "Edge And Public URLs" status_cascade_check "OCI edge SSH" check_edge_ssh || failures=$((failures + 1)) - status_cascade_check "Traefik LoadBalancer HTTP" status_http_ok "http://${LAB_TRAEFIK_LB_IP:-192.168.100.240}/" || failures=$((failures + 1)) + status_cascade_check "Traefik LoadBalancer HTTP" status_http_reachable "http://${LAB_TRAEFIK_LB_IP:-192.168.100.240}/" || failures=$((failures + 1)) status_cascade_check "Website public URL" status_http_ok "${LAB_PUBLIC_URL:-https://lab2025.duckdns.org}/" || failures=$((failures + 1)) - status_cascade_check "Gitea public URL" status_http_ok "${LAB_GITEA_ROOT_URL:-${LAB_PUBLIC_URL:-https://lab2025.duckdns.org}/git/}" || failures=$((failures + 1)) + status_cascade_check "Gitea public repo URL" status_gitea_public_repo_ok || failures=$((failures + 1)) if ((failures > 0)); then printf '\nStatus cascade found %s blocking failure(s).\n' "${failures}" >&2