window_watch: wait up to 30 s for OpenBao and the API server, and name an unreachable endpoint
All checks were successful
Bounded-execution contracts / contracts (push) Successful in 1m42s
Build and Publish bounded-executor / build-and-push (push) Successful in 5s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Identity provider journey acceptance / provider (push) Successful in 53s

The first two watch runs after the deploy (2026-11-06 09:20Z, 09:30Z) exited 5 with a bare URLError:
k3s programs a new pod's NetworkPolicy a few seconds late (as for the executor, 2026-10-31). The live
policies admit the watch pod to both endpoints. NK-WP-0058-T06.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 943911@bnt-lap001
Assistant-Session: fc322940-1c8e-4bed-ab39-86cec99f23a0
This commit is contained in:
tegwick 2026-11-06 10:33:30 +01:00
parent c53de12f21
commit b4773235bc
2 changed files with 37 additions and 1 deletions

View file

@ -34,6 +34,17 @@ WATCH_ROLE = 'net-kingdom-bounded-executor-window-watch'
ROLE_PATH = '/v1/auth/kubernetes/role/' + WRITE_ROLE
RUN_JOBS = 'app.kubernetes.io/name=bounded-executor,!app.kubernetes.io/component'
GRACE = 600 # seconds: the window opens moments before its run Job is created
KUBE_API = 'https://kubernetes.default.svc'
KUBE_CA = '/var/run/secrets/kubernetes.io/serviceaccount/ca.crt'
def wait_for_network(openbao_addr: str, wait=None) -> None:
"""A new pod's NetworkPolicy is programmed a few seconds after it starts (k3s; 2026-10-31 and the first watch
runs on 2026-11-06 failed with URLError). Wait up to 30 s for each endpoint; Unreachable names the one that
stayed silent. Any HTTP answer counts."""
wait = wait or OPS.wait_reachable
wait(openbao_addr, timeout=30, path='/v1/sys/health', name='openbao')
wait(KUBE_API, timeout=30, path='/healthz', name='kubernetes-api', ca_file=KUBE_CA)
def role_present(bao) -> bool:
@ -82,10 +93,11 @@ def main(argv=None) -> int:
a = p.parse_args(argv)
bao = None
try:
wait_for_network(a.openbao_addr)
bao = OPS.OpenBao(a.openbao_addr, k8s_role=WATCH_ROLE, jwt_file=a.jwt_file)
result, code = watch(bao, OPS.Kube(), a.mode, dt.datetime.now(dt.timezone.utc))
except Exception as error: # value-free: the clients' own errors carry fixed texts
reason = str(error) if isinstance(error, OPS.OperationError) else type(error).__name__
reason = str(error) if isinstance(error, (OPS.OperationError, OPS.Unreachable)) else type(error).__name__
result, code = {'status': 'error', 'reason': reason}, 5
finally:
if bao is not None: