Skip to content

feat: native watch mode and multi-config directory support (v3.0.0) - #9

Merged
rossigee merged 1 commit into
masterfrom
feat/watch-mode
Sep 14, 2026
Merged

rossigee merged 1 commit into
masterfrom
feat/watch-mode

Conversation

@rossigee

Copy link
Copy Markdown
Owner

Summary

Adds a native, event-driven watch mode plus multi-config directory support, so fetch-k8s-cert becomes the long-running process instead of being wrapped in shell poll loops (e.g. while true; ...; sleep).

Changes

  • -w/--watch: long-running mode that
    • fetches once on startup,
    • then subscribes to the Kubernetes watch API for the configured Secret (with allowWatchBookmarks + fieldSelector=metadata.name),
    • re-runs the existing fetch → byte-compare → write → reloadCommand pipeline on every change,
    • reconnects with exponential backoff and always re-syncs on reconnection, and
    • makes zero periodic API calls while idle (a convergence net re-sync runs at --resync, default 24h, and is a no-op whenever files are unchanged).
  • -d/--config-dir: load one *.yaml config per secret and manage them all in one process. Works in both one-shot and watch mode. -f remains fully backwards-compatible.
  • --resync: duration flag (default 24h, 0 disables).
  • K8sClient:
    • GetTLSBundleWithRV exposes the secret resourceVersion so watches resume from a consistent point.
    • WatchSecret streams the watch using a dedicated http.Client without the 30s total timeout (shared transport with the ordinary client).
    • New watcher.go implements SecretWatcher (initial sync, stream decoding, backoff, periodic resync).
  • Container: adds socat to the alpine image for HAProxy Runtime API reload commands.
  • Version 3.0.0 across main.go, Makefile, README, config example, Debian package reference, rpm spec, and CHANGELOG.
  • Tests: watch reactivity (ADDED/MODIFIED update files + trigger reload), no reload when content unchanged, reconnect-on-stream-close, and loadConfigs directory ordering. go vet, gofmt -s, golangci-lint, and go test -race ./... all pass.

Motivation

Replaces external poll loops (60s–24h sleep patterns) with an event-driven daemon, enabling zero-downtime certificate updates for services like HAProxy (Runtime API set ssl cert / commit ssl cert) with no container restarts.

Notes for reviewers

  • RBAC: the ServiceAccount now needs list and watch verbs on secrets (in addition to get) for watch mode; get remains sufficient for one-shot mode.
  • Backwards compatible: no existing config format changes; -f one-shot behaves exactly as before.

- -w/--watch: long-running, event-driven re-sync via the Kubernetes watch
  API. Fetches once on startup, then re-runs the fetch pipeline only when
  the secret changes. Reconnects with exponential backoff and always
  re-syncs on reconnection; idle watchers issue no periodic API calls.
- -d/--config-dir: load one YAML config per secret in a single process.
- --resync: configurable safety-net re-sync interval (default 24h).
- K8sClient now surfaces the secret resourceVersion and uses a dedicated
  no-total-timeout client for long-lived watch streams.
- Dockerfile: add socat for HAProxy Runtime API reload commands.
- Version 3.0.0, README, CHANGELOG, config example, rpm spec updated.
- Tests: watcher event/reactivity, no-reload-on-unchanged, reconnect on
  stream close, loadConfigs directory ordering.
@rossigee
rossigee merged commit 65b5c31 into master Sep 14, 2026
15 checks passed
@rossigee
rossigee deleted the feat/watch-mode branch September 14, 2026 05:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant