#!/usr/bin/env bash # Quick homelab status check # Usage: homelab-status [--full] set -e FULL=false [[ "$1" == "--full" || "$1" == "-f" ]] && FULL=true # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color ok() { echo -e "${GREEN}✓${NC} $1"; } warn() { echo -e "${YELLOW}⚠${NC} $1"; } fail() { echo -e "${RED}✗${NC} $1"; } info() { echo -e "${BLUE}ℹ${NC} $1"; } echo "═══════════════════════════════════════" echo " 🏠 HOMELAB STATUS" echo "═══════════════════════════════════════" echo "" # K8s Cluster echo "☸️ KUBERNETES" echo "───────────────────────────────────────" if ! kubectl cluster-info &>/dev/null; then fail "Cluster unreachable" else # Nodes NODES_TOTAL=$(kubectl get nodes --no-headers 2>/dev/null | wc -l) NODES_READY=$(kubectl get nodes --no-headers 2>/dev/null | grep -c " Ready" || echo 0) if [[ "$NODES_READY" == "$NODES_TOTAL" ]]; then ok "Nodes: $NODES_READY/$NODES_TOTAL Ready" else warn "Nodes: $NODES_READY/$NODES_TOTAL Ready" fi # Pods PODS_RUNNING=$(kubectl get pods -A --no-headers 2>/dev/null | grep -c "Running" || echo 0) PODS_NOT_RUNNING=$(kubectl get pods -A --no-headers 2>/dev/null | grep -cvE "Running|Completed" || echo 0) if [[ "$PODS_NOT_RUNNING" == "0" ]]; then ok "Pods: $PODS_RUNNING Running" else warn "Pods: $PODS_RUNNING Running, $PODS_NOT_RUNNING not ready" fi # Show failed pods if any if [[ "$PODS_FAILED" != "0" ]] || $FULL; then kubectl get pods -A --no-headers 2>/dev/null | grep -E "(Error|CrashLoop|Failed|Pending)" | head -5 | while read -r line; do echo " $line" done fi fi echo "" # Alertmanager echo "🚨 ALERTS" echo "───────────────────────────────────────" ALERTMANAGER_URL="http://alertmanager.monitoring.192.168.153.240.nip.io" ALERTS=$(curl -sf "$ALERTMANAGER_URL/api/v2/alerts?active=true&silenced=false" 2>/dev/null || echo "[]") ALERT_COUNT=$(echo "$ALERTS" | jq 'length' 2>/dev/null || echo "?") if [[ "$ALERT_COUNT" == "0" ]]; then ok "No active alerts" elif [[ "$ALERT_COUNT" == "?" ]]; then warn "Alertmanager unreachable" else warn "$ALERT_COUNT active alert(s)" echo "$ALERTS" | jq -r '.[].labels.alertname' 2>/dev/null | head -5 | while read -r alert; do echo " - $alert" done fi echo "" # Key Services echo "🔌 SERVICES" echo "───────────────────────────────────────" check_service() { local name="$1" local url="$2" if curl -sf --max-time 3 "$url" >/dev/null 2>&1; then ok "$name" else fail "$name" fi } check_service "Grafana" "http://grafana.monitoring.192.168.153.240.nip.io/api/health" check_service "ArgoCD" "https://argocd.taildb3494.ts.net" 2>/dev/null || check_service "ArgoCD" "http://argocd-server.argocd.svc:80" 2>/dev/null || warn "ArgoCD (via Tailscale only)" check_service "Longhorn" "http://ui.longhorn-system.192.168.153.240.nip.io" # Ollama (homelab) if curl -sf --max-time 3 "http://100.85.116.57:11434/api/tags" >/dev/null 2>&1; then ok "Ollama (homelab)" else warn "Ollama (homelab) - unreachable" fi echo "" # Local LLM echo "🤖 LOCAL LLM" echo "───────────────────────────────────────" if curl -sf "http://127.0.0.1:8080/health" >/dev/null 2>&1; then ok "llama-swap running" MODELS=$(curl -s "http://127.0.0.1:8080/v1/models" | jq -r '.data[].id' 2>/dev/null | tr '\n' ', ' | sed 's/,$//') info "Models: $MODELS" else warn "llama-swap not running" info "Start: systemctl --user start llama-swap" fi echo "" # Storage (if full) if $FULL; then echo "💾 STORAGE" echo "───────────────────────────────────────" kubectl get pvc -A --no-headers 2>/dev/null | head -10 | while read -r ns name status vol cap mode class age; do if [[ "$status" == "Bound" ]]; then ok "$ns/$name ($cap)" else warn "$ns/$name - $status" fi done echo "" fi echo "═══════════════════════════════════════" echo " $(date '+%Y-%m-%d %H:%M:%S %Z')" echo "═══════════════════════════════════════"