diff --git a/README.md b/README.md index ee9c767..f20b2ec 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,7 @@ Run a read-only health snapshot from the Debian server with: ./jeannie status ./jeannie capacity ./jeannie recover-plan +./jeannie gitops-status ``` It reports host memory/disk, systemd services, Docker Compose stacks, @@ -300,6 +301,10 @@ guidance for deciding what can safely run next. checks, from Debian and Gitea through DNS, Pimox, Kubernetes, GitOps apps, and edge verification. +`gitops-status` prints a focused Argo CD view: application sync and health, +out-of-sync or degraded apps, repository secret presence, recent Argo CD events, +and recent repo-server/application-controller errors. + Focused doctor commands run narrower read-only checks and print the most likely next step: diff --git a/README.md.tmpl b/README.md.tmpl index c89ae7d..2151e16 100644 --- a/README.md.tmpl +++ b/README.md.tmpl @@ -272,6 +272,7 @@ Run a read-only health snapshot from the Debian server with: ./{{ main_script }} status ./{{ main_script }} capacity ./{{ main_script }} recover-plan +./{{ main_script }} gitops-status ``` It reports host memory/disk, systemd services, Docker Compose stacks, @@ -300,6 +301,10 @@ guidance for deciding what can safely run next. checks, from Debian and Gitea through DNS, Pimox, Kubernetes, GitOps apps, and edge verification. +`gitops-status` prints a focused Argo CD view: application sync and health, +out-of-sync or degraded apps, repository secret presence, recent Argo CD events, +and recent repo-server/application-controller errors. + Focused doctor commands run narrower read-only checks and print the most likely next step: diff --git a/docs/jeannie.1.md b/docs/jeannie.1.md index 2e85aec..80084a1 100644 --- a/docs/jeannie.1.md +++ b/docs/jeannie.1.md @@ -62,6 +62,11 @@ state, and practical placement guidance. checks for Debian, Gitea, RPi DNS, Pimox, Kubernetes, GitOps apps, and edge verification. +`gitops-status` +: Print a focused Argo CD status view with application sync/health, out-of-sync +or degraded apps, repository secret presence, recent events, and recent +repo-server/application-controller errors. + Prometheus alerts : High-signal alert rules are managed as the `apps/homelab-alerts` GitOps app. They cover node readiness, restart storms, unavailable deployments, storage diff --git a/jeannie b/jeannie index 58f4204..70661ea 100755 --- a/jeannie +++ b/jeannie @@ -5972,6 +5972,11 @@ recover_plan() { "${REPO_ROOT}/scripts/recover-plan" } +gitops_status() { + require_debian_server "gitops-status" + "${REPO_ROOT}/scripts/gitops-status" +} + case "${1:-}" in up) up @@ -5997,6 +6002,9 @@ case "${1:-}" in recover-plan) recover_plan ;; + gitops-status) + gitops_status + ;; validate) validate_homelab ;; @@ -6141,7 +6149,7 @@ case "${1:-}" in 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|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|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 ;; esac diff --git a/scripts/gitops-status b/scripts/gitops-status new file mode 100755 index 0000000..cfccb41 --- /dev/null +++ b/scripts/gitops-status @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +set -euo pipefail + +NAMESPACE="${ARGOCD_NAMESPACE:-argocd}" +LOG_PATTERN="${GITOPS_LOG_PATTERN:-error|failed|denied|timeout|authentication|unauthorized}" + +section() { + printf '\n== %s ==\n' "$1" +} + +have() { + command -v "$1" >/dev/null 2>&1 +} + +kubectl_ok() { + have kubectl && kubectl version --client >/dev/null 2>&1 +} + +print_if_available() { + local description="$1" + shift + + if "$@"; then + return 0 + fi + + printf '%s unavailable or returned no data.\n' "$description" +} + +if ! kubectl_ok; then + echo "kubectl is required for gitops-status." >&2 + exit 1 +fi + +if ! kubectl get namespace "$NAMESPACE" >/dev/null 2>&1; then + echo "Argo CD namespace '$NAMESPACE' was not found or the Kubernetes API is unreachable." >&2 + exit 1 +fi + +section "Argo CD Applications" +if ! kubectl -n "$NAMESPACE" get applications.argoproj.io \ + -o custom-columns='NAME:.metadata.name,SYNC:.status.sync.status,HEALTH:.status.health.status,REVISION:.status.sync.revision,PATH:.spec.source.path' \ + --no-headers 2>/dev/null; then + echo "No Argo CD Applications were found." +fi + +section "Out Of Sync Or Degraded" +apps_report="$( + kubectl -n "$NAMESPACE" get applications.argoproj.io \ + -o custom-columns='NAME:.metadata.name,SYNC:.status.sync.status,HEALTH:.status.health.status,MESSAGE:.status.conditions[-1].message' \ + --no-headers 2>/dev/null || true +)" + +if [ -z "$apps_report" ]; then + echo "No application status data available." +else + printf '%s\n' "$apps_report" | awk '$2 != "Synced" || $3 != "Healthy" { print }' +fi + +section "Repository Secrets" +print_if_available "Repository secrets" \ + kubectl -n "$NAMESPACE" get secrets -l argocd.argoproj.io/secret-type=repository \ + -o custom-columns='NAME:.metadata.name,TYPE:.metadata.labels.argocd\.argoproj\.io/secret-type' \ + --no-headers + +section "Recent Argo CD Warnings" +print_if_available "Argo CD events" \ + sh -c "kubectl -n '$NAMESPACE' get events --sort-by=.lastTimestamp 2>/dev/null | tail -40" + +section "Recent Repo Server Errors" +if kubectl -n "$NAMESPACE" get deployment argocd-repo-server >/dev/null 2>&1; then + kubectl -n "$NAMESPACE" logs deployment/argocd-repo-server --tail=120 2>/dev/null | + grep -Ei "$LOG_PATTERN" || echo "No recent repo-server errors matched '$LOG_PATTERN'." +else + echo "argocd-repo-server deployment not found." +fi + +section "Recent Application Controller Errors" +if kubectl -n "$NAMESPACE" get statefulset argocd-application-controller >/dev/null 2>&1; then + kubectl -n "$NAMESPACE" logs statefulset/argocd-application-controller --tail=120 2>/dev/null | + grep -Ei "$LOG_PATTERN" || echo "No recent application-controller errors matched '$LOG_PATTERN'." +else + echo "argocd-application-controller statefulset not found." +fi