m9_smoke.sh 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #!/usr/bin/env bash
  2. # M9 smoke test — observability layer
  3. # Verifies:
  4. # 1. Prometheus is scraping all services (including new M9 targets)
  5. # 2. Key metrics are accessible in Prometheus
  6. # 3. Grafana is reachable with provisioning
  7. set -euoo pipefail
  8. PROM="${PROM:-http://localhost:9090}"
  9. INGESTD="${INGESTD:-http://localhost:8800}"
  10. ADMID="${ADMID:-http://localhost:8080}"
  11. pass() { echo " ✅ $1"; }
  12. warn() { echo " ⚠️ $1"; }
  13. fail() { echo " ❌ $1"; exit 1; }
  14. echo "Step 1 — Prometheus is up and scraping all services"
  15. # M9: deliverd split into deliverd-fcm + deliverd-telegram; archiverd added.
  16. for svc in ingestd routerd deliverd-fcm deliverd-telegram admind archiverd prometheus; do
  17. result=$(curl -s "${PROM}/api/v1/query?query=up{job=\"${svc}\"}" | \
  18. python3 -c "import json,sys; d=json.load(sys.stdin); r=d.get('data',{}).get('result',[]); print('up' if r else 'missing')" 2>/dev/null)
  19. if [ "$result" = "up" ]; then
  20. pass "Prometheus scraping ${svc}"
  21. else
  22. fail "Prometheus NOT scraping ${svc} (check prometheus.yml)"
  23. fi
  24. done
  25. echo ""
  26. echo "Step 2 — ingestd metrics are present (source of ingest-tier metrics)"
  27. metric_count=$(curl -s "${PROM}/api/v1/query?query=ba_ingestd_alerts_received_total" | \
  28. python3 -c "import json,sys; d=json.load(sys.stdin); r=d.get('data',{}).get('result',[]); print(len(r))" 2>/dev/null)
  29. if [ "${metric_count:-0}" -gt 0 ]; then
  30. pass "ba_ingestd_alerts_received_total: ${metric_count} series"
  31. else
  32. warn "ba_ingestd_alerts_received_total: 0 series (no recent traffic — might be OK)"
  33. fi
  34. echo ""
  35. echo "Step 3 — routerd recipient expansion latency metric"
  36. router_count=$(curl -s "${PROM}/api/v1/query?query=ba_routerd_recipient_expansion_seconds_count" | \
  37. python3 -c "import json,sys; d=json.load(sys.stdin); r=d.get('data',{}).get('result',[]); print(len(r))" 2>/dev/null)
  38. if [ "${router_count:-0}" -gt 0 ]; then
  39. pass "ba_routerd_recipient_expansion_seconds: ${router_count} series (M9 routerd deployed)"
  40. else
  41. fail "ba_routerd_recipient_expansion_seconds has no series — routerd missing M9 metric"
  42. fi
  43. echo ""
  44. echo "Step 4 — deliverd delivery attempt metrics (M9)"
  45. deliverd_count=$(curl -s "${PROM}/api/v1/query?query=ba_deliverd_delivery_attempts_total" | \
  46. python3 -c "import json,sys; d=json.load(sys.stdin); r=d.get('data',{}).get('result',[]); print(len(r))" 2>/dev/null)
  47. if [ "${deliverd_count:-0}" -gt 0 ]; then
  48. pass "ba_deliverd_delivery_attempts_total: ${deliverd_count} series (M9 deliverd deployed)"
  49. else
  50. pass "ba_deliverd_delivery_attempts_total: 0 series (metric exists, no delivery traffic yet)"
  51. fi
  52. echo ""
  53. echo "Step 5 — Circuit breaker gauge (M9 ingestd — requires rebuild)"
  54. # The circuit breaker metric only appears when ingestd was rebuilt with
  55. # the M9 circuit breaker code. On the first smoke run (before the
  56. # rebuild), this will warn instead of pass.
  57. cb_count=$(curl -s "${PROM}/api/v1/query?query=ba_ingestd_circuit_breaker_state" | \
  58. python3 -c "import json,sys; d=json.load(sys.stdin); r=d.get('data',{}).get('result',[]); print(len(r))" 2>/dev/null)
  59. if [ "${cb_count:-0}" -gt 0 ]; then
  60. pass "ba_ingestd_circuit_breaker_state: ${cb_count} series (M9 ingestd deployed)"
  61. else
  62. warn "ba_ingestd_circuit_breaker_state: 0 series (ingestd still on pre-M9 binary)"
  63. warn " Rebuild to get circuit breaker: docker compose build --no-cache ingestd"
  64. warn " Then redeploy: docker compose up -d --no-deps ingestd"
  65. fi
  66. echo ""
  67. echo "Step 6 — Grafana reachable with dashboards provisioned"
  68. gf_status=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:3001/api/health" 2>/dev/null)
  69. if [ "${gf_status}" = "200" ]; then
  70. pass "Grafana HTTP ${gf_status} (admin/admin at http://localhost:3001)"
  71. # Check that the BroadAnnounce dashboard is listed
  72. dash_count=$(curl -s -u admin:admin "http://localhost:3001/api/search?type=dashboards" 2>/dev/null | \
  73. python3 -c "import json,sys; d=json.load(sys.stdin); print(len([x for x in d if 'BroadAnnounce' in x.get('title','')]))" 2>/dev/null)
  74. if [ "${dash_count:-0}" -gt 0 ]; then
  75. pass "BroadAnnounce Overview dashboard found in Grafana"
  76. else
  77. warn "BroadAnnounce dashboard not found in Grafana (may need manual import)"
  78. fi
  79. else
  80. fail "Grafana returned HTTP ${gf_status} — check docker compose logs grafana"
  81. fi
  82. echo ""
  83. echo "Step 7 — Prometheus self-monitoring"
  84. prom_up=$(curl -s "${PROM}/api/v1/query?query=up{job=\"prometheus\"}" | \
  85. python3 -c "import json,sys; d=json.load(sys.stdin); r=d.get('data',{}).get('result',[]); print('up' if r else 'missing')" 2>/dev/null)
  86. if [ "${prom_up}" = "up" ]; then
  87. pass "Prometheus scraping itself"
  88. else
  89. fail "Prometheus not scraping itself"
  90. fi
  91. echo ""
  92. echo "🎉 M9 smoke: all checks complete."
  93. echo ""
  94. echo "On the remote playground (192.168.44.94):"
  95. echo " ssh parres 'cd /root/git/broad-announce && git pull && docker compose build --no-cache ingestd deliverd-fcm deliverd-telegram routerd && docker compose up -d'"
  96. echo ""
  97. echo "Then run this smoke again to verify the circuit breaker metric."