2026-01-14 13:23:05 -08:00
|
|
|
#!/usr/bin/env bash
|
2026-02-04 07:49:15 -08:00
|
|
|
#MISE description="Check that all services are online and responding"
|
2026-01-14 13:23:05 -08:00
|
|
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
# Colors for output
|
|
|
|
|
RED='\033[0;31m'
|
|
|
|
|
GREEN='\033[0;32m'
|
|
|
|
|
NC='\033[0m' # No Color
|
|
|
|
|
|
|
|
|
|
FAILED=0
|
|
|
|
|
|
|
|
|
|
check_service() {
|
|
|
|
|
local name="$1"
|
|
|
|
|
local check_cmd="$2"
|
|
|
|
|
|
2026-01-22 12:06:02 -08:00
|
|
|
printf "%-24s " "$name..."
|
2026-01-14 13:23:05 -08:00
|
|
|
if eval "$check_cmd" > /dev/null 2>&1; then
|
|
|
|
|
echo -e "${GREEN}OK${NC}"
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}FAILED${NC}"
|
|
|
|
|
FAILED=1
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check_http() {
|
|
|
|
|
local name="$1"
|
|
|
|
|
local url="$2"
|
|
|
|
|
|
2026-01-22 12:06:02 -08:00
|
|
|
printf "%-24s " "$name..."
|
2026-01-14 13:23:05 -08:00
|
|
|
if curl -sf --max-time 5 "$url" > /dev/null 2>&1; then
|
|
|
|
|
echo -e "${GREEN}OK${NC}"
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}FAILED${NC}"
|
|
|
|
|
FAILED=1
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-04 07:49:15 -08:00
|
|
|
echo "Checking services..."
|
|
|
|
|
echo "===================="
|
2026-01-14 13:23:05 -08:00
|
|
|
echo ""
|
|
|
|
|
|
2026-01-22 12:06:02 -08:00
|
|
|
# Local services on indri
|
|
|
|
|
echo "Local services on indri:"
|
|
|
|
|
check_service "forgejo (brew)" "ssh indri 'brew services list | grep forgejo | grep started'"
|
|
|
|
|
check_service "alloy" "ssh indri 'launchctl list mcquack.eblume.alloy | grep -v \"^-\"'"
|
|
|
|
|
check_service "borgmatic" "ssh indri 'launchctl list mcquack.eblume.borgmatic | grep -v \"^-\"'"
|
|
|
|
|
check_service "borgmatic-metrics" "ssh indri 'launchctl list mcquack.borgmatic-metrics | grep -v \"^-\"'"
|
|
|
|
|
check_service "zot" "ssh indri 'launchctl list mcquack.eblume.zot | grep -v \"^-\"'"
|
|
|
|
|
check_service "zot-metrics" "ssh indri 'launchctl list mcquack.zot-metrics | grep -v \"^-\"'"
|
|
|
|
|
check_service "minikube-metrics" "ssh indri 'launchctl list mcquack.minikube-metrics | grep -v \"^-\"'"
|
2026-01-30 17:06:00 -08:00
|
|
|
check_service "jellyfin-metrics" "ssh indri 'launchctl list mcquack.eblume.jellyfin-metrics | grep -v \"^-\"'"
|
2026-01-14 13:23:05 -08:00
|
|
|
|
|
|
|
|
echo ""
|
2026-01-22 12:06:02 -08:00
|
|
|
echo "Metrics textfiles:"
|
|
|
|
|
check_service "borgmatic.prom" "ssh indri 'test -f /opt/homebrew/var/node_exporter/textfile/borgmatic.prom'"
|
|
|
|
|
check_service "zot.prom" "ssh indri 'test -f /opt/homebrew/var/node_exporter/textfile/zot.prom'"
|
|
|
|
|
check_service "minikube.prom" "ssh indri 'test -f /opt/homebrew/var/node_exporter/textfile/minikube.prom'"
|
2026-01-30 17:06:00 -08:00
|
|
|
check_service "jellyfin.prom" "ssh indri 'test -f /opt/homebrew/var/node_exporter/textfile/jellyfin.prom'"
|
2026-01-18 12:06:28 -08:00
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
echo "Kubernetes cluster:"
|
|
|
|
|
check_service "minikube" "ssh indri 'minikube status --format={{.Host}} | grep -q Running'"
|
|
|
|
|
check_service "k8s-apiserver (indri)" "ssh indri 'kubectl get --raw /healthz'"
|
|
|
|
|
check_service "k8s-apiserver (remote)" "kubectl --kubeconfig=$HOME/.kube/minikube-indri/config.yml --context=minikube-indri get --raw /healthz"
|
2026-01-14 13:23:05 -08:00
|
|
|
|
2026-01-19 09:49:52 -08:00
|
|
|
echo ""
|
2026-01-25 12:56:31 -08:00
|
|
|
echo "HTTP endpoints (via Caddy):"
|
|
|
|
|
check_http "Prometheus" "https://prometheus.ops.eblu.me/-/healthy"
|
|
|
|
|
check_http "Loki" "https://loki.ops.eblu.me/ready"
|
|
|
|
|
check_http "Grafana" "https://grafana.ops.eblu.me/api/health"
|
|
|
|
|
check_http "ArgoCD" "https://argocd.ops.eblu.me/healthz"
|
2026-01-25 11:37:23 -08:00
|
|
|
check_http "Forgejo" "https://forge.ops.eblu.me/"
|
2026-01-25 12:06:15 -08:00
|
|
|
check_http "Zot Registry" "https://registry.ops.eblu.me/v2/_catalog"
|
2026-01-25 12:56:31 -08:00
|
|
|
check_http "Kiwix" "https://kiwix.ops.eblu.me/"
|
|
|
|
|
check_http "Miniflux" "https://feed.ops.eblu.me/healthcheck"
|
|
|
|
|
check_http "TeslaMate" "https://tesla.ops.eblu.me/"
|
|
|
|
|
check_http "Devpi" "https://pypi.ops.eblu.me/+api"
|
|
|
|
|
check_http "Transmission" "https://torrent.ops.eblu.me/"
|
2026-02-08 22:12:50 -08:00
|
|
|
check_http "Immich" "https://photos.ops.eblu.me/"
|
|
|
|
|
check_http "Navidrome" "https://dj.ops.eblu.me/"
|
2026-02-12 14:10:03 -08:00
|
|
|
check_http "CV" "https://cv.ops.eblu.me/"
|
Deploy Frigate NVR stack with Mosquitto, Ntfy, and frigate-notify (#190)
## Summary
Deploy a cloud-free NVR stack for the GableCam (ReoLink Elite Floodlight at 192.168.1.159):
- **Mosquitto** — shared MQTT broker in `mqtt` namespace (cluster-internal, no auth)
- **Ntfy** — self-hosted push notifications in `ntfy` namespace, exposed at `ntfy.tail8d86e.ts.net` / `ntfy.ops.eblu.me`
- **Frigate** — NVR with GableCam via HTTP-FLV, ONNX CPU detection, NFS recordings on sifaka, exposed at `nvr.tail8d86e.ts.net` / `nvr.ops.eblu.me`
- **frigate-notify** — bridges Frigate detection events (person, car, dog, cat) to Ntfy alerts via MQTT
Also includes:
- Prometheus scrape target for Frigate metrics
- Grafana dashboard for Frigate (status, inference speed, FPS, CPU/memory, storage)
- Caddy reverse proxy entries for `nvr.ops.eblu.me` and `ntfy.ops.eblu.me`
## Prerequisites
- [ ] Create NFS share `frigate` on sifaka (`/volume1/frigate`, RW for indri)
- [ ] Create 1Password item "Reolink Floodlight Camera" in `blumeops` vault with `username` and `password` fields
## Deployment (after merge)
```bash
argocd app sync apps
argocd app sync mosquitto
argocd app sync ntfy
argocd app sync frigate
argocd app sync grafana-config
argocd app sync prometheus
mise run provision-indri -- --tags caddy
mise run services-check
```
## Verification
- [ ] Mosquitto pod running, accepting connections on 1883
- [ ] Ntfy web UI accessible at `ntfy.ops.eblu.me`
- [ ] Frigate web UI at `nvr.ops.eblu.me` showing GableCam live feed
- [ ] Object detection working (ONNX, person/car/dog/cat)
- [ ] Recordings appearing in NFS share on sifaka
- [ ] frigate-notify sending detection alerts to Ntfy
- [ ] Prometheus scraping Frigate metrics
- [ ] Grafana dashboard showing Frigate data
Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/190
2026-02-14 21:27:44 -08:00
|
|
|
check_http "Ntfy" "https://ntfy.ops.eblu.me/v1/health"
|
|
|
|
|
check_http "Frigate" "https://nvr.ops.eblu.me/api/version"
|
2026-01-22 12:06:02 -08:00
|
|
|
|
2026-02-08 02:48:15 -08:00
|
|
|
echo ""
|
|
|
|
|
echo "Public services (via Fly.io):"
|
|
|
|
|
check_http "Docs (public)" "https://docs.eblu.me/"
|
2026-02-12 14:10:03 -08:00
|
|
|
check_http "CV (public)" "https://cv.eblu.me/"
|
2026-02-08 02:48:15 -08:00
|
|
|
check_http "Fly.io healthz" "https://blumeops-proxy.fly.dev/healthz"
|
|
|
|
|
|
2026-01-22 12:06:02 -08:00
|
|
|
echo ""
|
|
|
|
|
echo "Database:"
|
2026-01-25 12:56:31 -08:00
|
|
|
check_service "PostgreSQL (k8s)" "pg_isready -h pg.ops.eblu.me -p 5432"
|
2026-01-22 12:06:02 -08:00
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
echo "Kubernetes pods:"
|
|
|
|
|
check_service "prometheus-0" "kubectl --context=minikube-indri -n monitoring get pod prometheus-0 -o jsonpath='{.status.phase}' | grep -q Running"
|
|
|
|
|
check_service "loki-0" "kubectl --context=minikube-indri -n monitoring get pod loki-0 -o jsonpath='{.status.phase}' | grep -q Running"
|
|
|
|
|
check_service "grafana" "kubectl --context=minikube-indri -n monitoring get pods -l app.kubernetes.io/name=grafana -o jsonpath='{.items[0].status.phase}' | grep -q Running"
|
|
|
|
|
check_service "miniflux" "kubectl --context=minikube-indri -n miniflux get pods -l app=miniflux -o jsonpath='{.items[0].status.phase}' | grep -q Running"
|
2026-01-22 21:31:11 -08:00
|
|
|
check_service "teslamate" "kubectl --context=minikube-indri -n teslamate get pods -l app=teslamate -o jsonpath='{.items[0].status.phase}' | grep -q Running"
|
2026-01-22 12:06:02 -08:00
|
|
|
check_service "blumeops-pg" "kubectl --context=minikube-indri -n databases get pods -l cnpg.io/cluster=blumeops-pg -o jsonpath='{.items[0].status.phase}' | grep -q Running"
|
Deploy Frigate NVR stack with Mosquitto, Ntfy, and frigate-notify (#190)
## Summary
Deploy a cloud-free NVR stack for the GableCam (ReoLink Elite Floodlight at 192.168.1.159):
- **Mosquitto** — shared MQTT broker in `mqtt` namespace (cluster-internal, no auth)
- **Ntfy** — self-hosted push notifications in `ntfy` namespace, exposed at `ntfy.tail8d86e.ts.net` / `ntfy.ops.eblu.me`
- **Frigate** — NVR with GableCam via HTTP-FLV, ONNX CPU detection, NFS recordings on sifaka, exposed at `nvr.tail8d86e.ts.net` / `nvr.ops.eblu.me`
- **frigate-notify** — bridges Frigate detection events (person, car, dog, cat) to Ntfy alerts via MQTT
Also includes:
- Prometheus scrape target for Frigate metrics
- Grafana dashboard for Frigate (status, inference speed, FPS, CPU/memory, storage)
- Caddy reverse proxy entries for `nvr.ops.eblu.me` and `ntfy.ops.eblu.me`
## Prerequisites
- [ ] Create NFS share `frigate` on sifaka (`/volume1/frigate`, RW for indri)
- [ ] Create 1Password item "Reolink Floodlight Camera" in `blumeops` vault with `username` and `password` fields
## Deployment (after merge)
```bash
argocd app sync apps
argocd app sync mosquitto
argocd app sync ntfy
argocd app sync frigate
argocd app sync grafana-config
argocd app sync prometheus
mise run provision-indri -- --tags caddy
mise run services-check
```
## Verification
- [ ] Mosquitto pod running, accepting connections on 1883
- [ ] Ntfy web UI accessible at `ntfy.ops.eblu.me`
- [ ] Frigate web UI at `nvr.ops.eblu.me` showing GableCam live feed
- [ ] Object detection working (ONNX, person/car/dog/cat)
- [ ] Recordings appearing in NFS share on sifaka
- [ ] frigate-notify sending detection alerts to Ntfy
- [ ] Prometheus scraping Frigate metrics
- [ ] Grafana dashboard showing Frigate data
Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/190
2026-02-14 21:27:44 -08:00
|
|
|
check_service "mosquitto" "kubectl --context=minikube-indri -n mqtt get pods -l app=mosquitto -o jsonpath='{.items[0].status.phase}' | grep -q Running"
|
|
|
|
|
check_service "ntfy" "kubectl --context=minikube-indri -n ntfy get pods -l app=ntfy -o jsonpath='{.items[0].status.phase}' | grep -q Running"
|
|
|
|
|
check_service "frigate" "kubectl --context=minikube-indri -n frigate get pods -l app=frigate -o jsonpath='{.items[0].status.phase}' | grep -q Running"
|
|
|
|
|
check_service "frigate-notify" "kubectl --context=minikube-indri -n frigate get pods -l app=frigate-notify -o jsonpath='{.items[0].status.phase}' | grep -q Running"
|
2026-01-22 12:06:02 -08:00
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
echo "ArgoCD app sync status:"
|
|
|
|
|
printf "%-20s %-12s %-12s %s\n" "NAME" "SYNC" "HEALTH" "TARGET"
|
|
|
|
|
while read -r name sync health target; do
|
|
|
|
|
if [[ "$sync" == "Synced" ]]; then
|
|
|
|
|
printf "%-20s ${GREEN}%-12s${NC} %-12s %s\n" "$name" "$sync" "$health" "$target"
|
|
|
|
|
elif [[ "$sync" == "OutOfSync" ]]; then
|
|
|
|
|
printf "%-20s ${RED}%-12s${NC} %-12s %s\n" "$name" "$sync" "$health" "$target"
|
|
|
|
|
FAILED=1
|
|
|
|
|
else
|
|
|
|
|
printf "%-20s %-12s %-12s %s\n" "$name" "$sync" "$health" "$target"
|
|
|
|
|
fi
|
|
|
|
|
done < <(kubectl --context=minikube-indri get applications -n argocd --no-headers -o custom-columns='NAME:.metadata.name,SYNC:.status.sync.status,HEALTH:.status.health.status,TARGET:.spec.source.targetRevision' 2>/dev/null)
|
2026-01-19 09:49:52 -08:00
|
|
|
|
2026-01-14 13:23:05 -08:00
|
|
|
echo ""
|
|
|
|
|
if [ $FAILED -eq 0 ]; then
|
|
|
|
|
echo -e "${GREEN}All services healthy!${NC}"
|
|
|
|
|
exit 0
|
|
|
|
|
else
|
|
|
|
|
echo -e "${RED}Some services failed health check${NC}"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|