diff --git a/kubernetes/apps/uptime-monitor/pilot-endpointmonitors.yaml b/kubernetes/apps/uptime-monitor/pilot-endpointmonitors.yaml index 1b269b69..d9435487 100644 --- a/kubernetes/apps/uptime-monitor/pilot-endpointmonitors.yaml +++ b/kubernetes/apps/uptime-monitor/pilot-endpointmonitors.yaml @@ -1,4 +1,34 @@ --- +# ============================================================================ +# REN-7 CRITERION 3 — THE REMOVAL TEST. THIS COMMIT DELETES THE `audiobooks` +# ENDPOINTMONITOR ON PURPOSE. IT IS NOT A CLEANUP AND NOT AN ABANDONMENT. +# +# The card requires proof in both directions: an EndpointMonitor creates a +# monitor, and DELETING the EndpointMonitor removes it again. "A monitor that +# cannot be removed is a leak." Create is proven — `audiobooks.renner.uno- +# uptime-monitor`, UptimeRobot id 804092841, created 2026-09-26 03:26:27, +# controller log `Monitor Added`. Removing the object here is the other half. +# +# What must be observed after this merges: the public feed +# `https://uptime.renner.uno/api/getMonitorList/UgMXmP1iRV` goes from +# `psp.totalMonitors: 10` to `9`, and id 804092841 is absent. The controller +# log shows `Deleting Monitor: audiobooks.renner.uno-uptime-monitor`. +# +# PRECONDITION, CHECKED BEFORE THIS COMMIT WAS WRITTEN: v2.2.13 has no +# finalizer, so a delete while the controller is down orphans the monitor +# forever (see the caveat at the end of this header). Pod +# `ingressmonitorcontroller-5d577cc58-pgqwg` was `Ready=True`, `restarts=0`, +# up since 2026-09-26T00:43:45Z when this was authored. Anyone merging this +# must re-check that the pod is Ready first; if it is not, hold the merge. +# +# RE-CREATING IT IS THE REVERT: revert this commit and Flux re-applies the +# object, and the controller creates the monitor again under the same name. +# That round trip is also the `idempotent reconcile` check, so the revert is +# worth doing deliberately rather than only if something goes wrong. Expect a +# NEW UptimeRobot id — the friendly name is what binds object to monitor, not +# the id. +# ============================================================================ +# # REN-7 — the pilot batch. Two of the 14 monitors from the survey's §A0 page # list, chosen because they are the two lowest-risk rows on it: # @@ -135,6 +165,31 @@ # unavailable. Check `kube_deployment_status_replicas_available{namespace= # "uptime-monitor"}` first, and if a monitor is orphaned anyway, delete it by id # through the API rather than hoping a later reconcile finds it. +# +# --- +# STATE OF THE OBJECT BELOW: ITS CREATE IS BEING REJECTED, AND IT RETRIES +# FOREVER. TRACKED ON REN-155 — LEFT IN PLACE DELIBERATELY. +# +# `www.renner.uno-uptime-monitor` does not exist in UptimeRobot. Controller log, +# every 300s since 2026-09-26T03:26:27Z: +# +# Creating Monitor: www.renner.uno-uptime-monitor +# AddMonitor Request failed. Status Code: 403 +# +# That is the `else` branch of `Add()` (uptime-monitor.go:187) — a NON-200, and +# therefore NOT the provider's own validation path, which returns HTTP 200 with +# `{"stat":"fail", ...}` and is logged at :174 with the message text. So the +# common guesses are excluded: a duplicate URL, a monitor-count cap and a bad +# parameter would all arrive as 200 + `stat: fail`, not as 403. The 403 body is +# discarded by that branch, so the provider's reason is not recoverable from the +# log; settling it needs the API key or the account dashboard. +# +# It is left in git rather than removed because it is harmless and it is the +# reproducer: `Add()` is fire-and-forget (`handleCreate` returns nil regardless, +# endpointmonitor_created.go:12-31), so there is no error, no status and no +# alert — only that log line, at INFO. Nothing pages, nothing degrades, and the +# object is the only remaining evidence. Anyone tempted to "clean it up" should +# close REN-155 first. apiVersion: endpointmonitor.stakater.com/v1alpha1 kind: EndpointMonitor metadata: @@ -157,18 +212,15 @@ spec: # matches the interval of the nine monitors already in the account. Written # out rather than left implicit so the value is reviewable here. interval: 300 ---- -apiVersion: endpointmonitor.stakater.com/v1alpha1 -kind: EndpointMonitor -metadata: - name: audiobooks.renner.uno - namespace: uptime-monitor -spec: - # The path is in the URL rather than in `spec.healthEndpoint`, because - # `healthEndpoint` is only consulted on the ref-discovery path and is - # explicitly ignored when `spec.url` is set (pkg/kube/util/url.go:31-33). - # Endpoint taken from the existing Gatus check (apps/gatus/configmap.yaml:134). - url: https://audiobooks.renner.uno/healthcheck - uptimeRobotConfig: - monitorType: http - interval: 300 +# The `audiobooks.renner.uno` EndpointMonitor was here. It is removed by this +# commit as REN-7's criterion-3 removal test — see the header block at the top +# of this file for what that proves, what to observe, and how to put it back. +# Its spec, for the revert: +# +# url: https://audiobooks.renner.uno/healthcheck # Gatus check, +# # apps/gatus/configmap.yaml:134 +# uptimeRobotConfig: { monitorType: http, interval: 300 } +# +# The path belongs in `spec.url` and not in `spec.healthEndpoint`, because +# `healthEndpoint` is only consulted on the ref-discovery path and is explicitly +# ignored when `spec.url` is set (pkg/kube/util/url.go:31-33).