Files
home-network-k3s-impl/platform/cloudflared/alerts.promtool-test.yaml
T
jakman85andClaude Opus 5.5 aabc8c60b6 feat(cloudflared): Cloudflare Tunnel connector, Phase 1 (isolated, no traffic change)
Adds platform/cloudflared: a locally-managed tunnel whose ingress rules live in
git. LAN/VPN-only hosts (plex, plex-vip, jackett, pihole, pihole-dns, semaphore,
qbittorrent, radarr, sonarr, headlamp, unifi, crafty-mc) map to 404. The apex
and *.home go to cilium-gateway-shared.gateway over TLS with matchSNItoHost.
Last comes a catch-all 404. Nothing routes to the Kubernetes API.

- 2-replica Deployment, hard node spread, non-root, pinned digest, PDB
- default-deny plus an egress CNP: Cloudflare edge 7844/443, the Gateway, and
  Gateway backends by gateway-access=shared minus the LAN-only namespaces
  (needed because of the CVE-2025-30162 L7LB egress re-check)
- PodMonitor plus two alerts that fire on absent series, with promtool tests
- its own Flux Kustomization (dependsOn platform-config, wait:false, nothing
  depends on it), plus SOPS decryption patches in both overlays
- placeholder credentials (SOPS-encrypted) so it can merge before enrolment
- L0 cloudflared-ingress-rules, and a cloudflared_ scrape owner
- runbooks/cloudflare-tunnel.md and decisions/2026-11-08-cloudflare-tunnel.md

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-08 12:38:22 -06:00

129 lines
5.8 KiB
YAML

---
# promtool unit tests for platform/cloudflared/alerts.yaml.
#
# Found by platform/monitoring/tests/run.sh through the COMPANION convention
# (`<manifest>.promtool-test.yaml` beside `<manifest>.yaml`). Run just this file with
# platform/monitoring/tests/run.sh platform/cloudflared/alerts.promtool-test.yaml
# The harness flattens the PrometheusRule's `.spec.groups` into alerts.rules.yaml. Assertions query
# the synthetic ALERTS series (not exp_alerts), so annotation wording is not pinned here.
#
# Each rule is pinned BOTH ways, plus the two self-silencing traps:
# * series ABSENT (nothing scraped) must FIRE, not read as healthy;
# * working-then-broken must RE-FIRE, not latch cleared.
rule_files:
- alerts.rules.yaml
evaluation_interval: 1m
tests:
- interval: 1m
name: healthy - two replicas, four edge connections each, both rules quiet
input_series:
- series: 'cloudflared_tunnel_ha_connections{namespace="cloudflared",pod="cloudflared-a"}'
values: '4x60'
- series: 'cloudflared_tunnel_ha_connections{namespace="cloudflared",pod="cloudflared-b"}'
values: '4x60'
- series: 'kube_deployment_status_replicas_available{namespace="cloudflared",deployment="cloudflared"}'
values: '2x60'
promql_expr_test:
- expr: 'count(ALERTS{alertname=~"Cloudflared.*"})'
eval_time: 50m
exp_samples: []
- interval: 1m
name: nothing scraped at all - TunnelDown still fires (no self-silencing on absence)
input_series:
# kube-state-metrics says both pods are Available, but no cloudflared series exists — the
# broken-PodMonitor / dropped-scrape case. The rule must not read this as healthy.
- series: 'kube_deployment_status_replicas_available{namespace="cloudflared",deployment="cloudflared"}'
values: '2x60'
promql_expr_test:
- expr: 'ALERTS{alertname="CloudflaredTunnelDown"}'
eval_time: 5m
exp_samples:
- labels: 'ALERTS{alertname="CloudflaredTunnelDown", alertstate="pending", severity="warning"}'
value: 1
- expr: 'ALERTS{alertname="CloudflaredTunnelDown", alertstate="firing"}'
eval_time: 12m
exp_samples:
- labels: 'ALERTS{alertname="CloudflaredTunnelDown", alertstate="firing", severity="warning"}'
value: 1
- expr: 'ALERTS{alertname="CloudflaredReplicasDegraded"}'
eval_time: 30m
exp_samples: []
- interval: 1m
name: scraped but zero edge connections - TunnelDown fires after 10m
input_series:
- series: 'cloudflared_tunnel_ha_connections{namespace="cloudflared",pod="cloudflared-a"}'
values: '0x60'
- series: 'cloudflared_tunnel_ha_connections{namespace="cloudflared",pod="cloudflared-b"}'
values: '0x60'
- series: 'kube_deployment_status_replicas_available{namespace="cloudflared",deployment="cloudflared"}'
values: '0x60'
promql_expr_test:
- expr: 'ALERTS{alertname="CloudflaredTunnelDown", alertstate="firing"}'
eval_time: 9m
exp_samples: []
- expr: 'ALERTS{alertname="CloudflaredTunnelDown", alertstate="firing"}'
eval_time: 12m
exp_samples:
- labels: 'ALERTS{alertname="CloudflaredTunnelDown", alertstate="firing", severity="warning"}'
value: 1
- expr: 'ALERTS{alertname="CloudflaredReplicasDegraded", alertstate="firing"}'
eval_time: 17m
exp_samples:
- labels: 'ALERTS{alertname="CloudflaredReplicasDegraded", alertstate="firing", severity="warning"}'
value: 1
- interval: 1m
name: working then the series vanish - TunnelDown re-fires instead of latching cleared
input_series:
# 20 healthy samples, then the series stop (stale) — the scrape broke or the pods died.
- series: 'cloudflared_tunnel_ha_connections{namespace="cloudflared",pod="cloudflared-a"}'
values: '4x20 stale'
- series: 'cloudflared_tunnel_ha_connections{namespace="cloudflared",pod="cloudflared-b"}'
values: '4x20 stale'
- series: 'kube_deployment_status_replicas_available{namespace="cloudflared",deployment="cloudflared"}'
values: '2x60'
promql_expr_test:
- expr: 'ALERTS{alertname="CloudflaredTunnelDown"}'
eval_time: 15m
exp_samples: []
- expr: 'ALERTS{alertname="CloudflaredTunnelDown", alertstate="firing"}'
eval_time: 35m
exp_samples:
- labels: 'ALERTS{alertname="CloudflaredTunnelDown", alertstate="firing", severity="warning"}'
value: 1
- interval: 1m
name: one replica lost - ReplicasDegraded fires after 15m, tunnel itself still up
input_series:
- series: 'cloudflared_tunnel_ha_connections{namespace="cloudflared",pod="cloudflared-a"}'
values: '4x60'
- series: 'kube_deployment_status_replicas_available{namespace="cloudflared",deployment="cloudflared"}'
values: '1x60'
promql_expr_test:
- expr: 'ALERTS{alertname="CloudflaredReplicasDegraded", alertstate="firing"}'
eval_time: 14m
exp_samples: []
- expr: 'ALERTS{alertname="CloudflaredReplicasDegraded", alertstate="firing"}'
eval_time: 17m
exp_samples:
- labels: 'ALERTS{alertname="CloudflaredReplicasDegraded", alertstate="firing", severity="warning"}'
value: 1
- expr: 'ALERTS{alertname="CloudflaredTunnelDown"}'
eval_time: 30m
exp_samples: []
- interval: 1m
name: kube-state-metrics series absent - ReplicasDegraded fires rather than going quiet
input_series:
- series: 'cloudflared_tunnel_ha_connections{namespace="cloudflared",pod="cloudflared-a"}'
values: '4x60'
promql_expr_test:
- expr: 'ALERTS{alertname="CloudflaredReplicasDegraded", alertstate="firing"}'
eval_time: 17m
exp_samples:
- labels: 'ALERTS{alertname="CloudflaredReplicasDegraded", alertstate="firing", severity="warning"}'
value: 1