#!/usr/bin/env python3 """S-16c (#124): prove the golden-signal metrics pipeline works end to end. Generate anonymous BFF traffic (GET /openbaar/register — no auth, no OpenZaak egress), then query Prometheus and assert (1) every .NET service's scrape target is UP, and (2) the http.server.request.duration histogram is actually being scraped — i.e. the services expose /metrics AND Prometheus collects it, which is exactly what the golden-signal dashboard reads. Stdlib only (urllib/json) so it runs in a bare python:3-slim container in-network. """ import json import os import sys import time import urllib.error import urllib.parse import urllib.request BFF = os.environ["BFF"] # http://:8080 PROM = os.environ["PROMETHEUS"] # http://:9090 TIMEOUT = int(os.environ.get("METRICS_TIMEOUT", "90")) SERVICES = {"acl", "domain", "bff", "event-subscriber", "projection-api"} def _get(url): with urllib.request.urlopen(url, timeout=10) as r: return r.read() def generate_traffic(): for _ in range(3): try: _get(f"{BFF}/openbaar/register") except urllib.error.HTTPError: pass # a non-2xx still records an http.server metric def query(promql): q = urllib.parse.quote(promql) try: data = json.loads(_get(f"{PROM}/api/v1/query?query={q}")) except Exception: return [] return data.get("data", {}).get("result", []) def jobs_up(): return {r["metric"].get("job") for r in query("up == 1")} def jobs_with_request_metric(): return {r["metric"].get("job") for r in query("http_server_request_duration_seconds_count")} def main(): deadline = time.time() + TIMEOUT while time.time() < deadline: generate_traffic() up = jobs_up() scraped = jobs_with_request_metric() if SERVICES.issubset(up) and SERVICES.issubset(scraped): print(f"OK — targets up: {sorted(up & SERVICES)}; " f"request metric scraped from: {sorted(scraped & SERVICES)}") return 0 time.sleep(3) print(f"FAIL — up: {sorted(jobs_up() & SERVICES)}; " f"request metric from: {sorted(jobs_with_request_metric() & SERVICES)}; " f"expected all of {sorted(SERVICES)}", file=sys.stderr) return 1 if __name__ == "__main__": sys.exit(main())