100 Commits
Author SHA1 Message Date
lukaszraczylo 121535663d ci(deps): update dependencies with Renovate [skip ci] 2026-10-03 18:44:44 +01:00
lukaszraczyloandGitHub 42a13fde37 Update go.mod and go.sum (#87) 2026-10-03 04:29:11 +01:00
lukaszraczylo c8c1ddbcf0 fix(ci): replace broken setup-kind action
engineerd/setup-kind v0.6.2 fails with a missing dist/main/index.js file.
Use helm/kind-action instead.
2026-10-02 04:11:26 +01:00
lukaszraczyloandGitHub 007cb0a1b7 Update go.mod and go.sum (#86) 2026-10-02 03:01:09 +01:00
lukaszraczyloandGitHub 766e18a2e7 Update go.mod and go.sum (#85) 2026-09-04 04:22:30 +01:00
lukaszraczyloandGitHub cac9c373fb Update go.mod and go.sum (#84) 2026-09-01 04:25:16 +01:00
lukaszraczylo 08bb0f985a fix(docker): declare ARG TARGETARCH so buildx cross-builds work
TARGETARCH was referenced but never declared, so every platform in a
multi-arch buildx run received an amd64 binary. The arm64 image
crashed on Raspberry Pi nodes with an exec format error.
2026-08-29 13:54:07 +01:00
lukaszraczylo 14b61fa962 fix(docker): bump builder image to go 1.26
go.mod requires go >= 1.26.0 since the dependency updates, and the
golang alpine images set GOTOOLCHAIN=local, so the 1.25 builder failed
at go mod download.
2026-08-29 13:50:16 +01:00
lukaszraczylo 8988893160 perf(controller): repair mirror drift from watch events instead of resync
Mirror update events were filtered out, so an in-place edit of a
mirrored copy was invisible to the controller. The periodic resync did
not catch it either: NeedsSync only compares the source content hash
with the recorded annotation, and tampered mirror data leaves both
unchanged.

Changes:
- The mirror watch now passes real update events (resourceVersion
  changed, object is a managed mirror) and maps them to the source.
  Informer resync replays keep an unchanged resourceVersion and stay
  filtered.
- reconcileMirror detects in-place drift by rebuilding the expected
  mirror in memory and comparing content hashes. Metadata differences
  never count as drift, so the controller's own writes converge in one
  no-op pass.
- The resync-period default moves from 10m to 1h. Watches now cover
  source changes, mirror deletion, mirror drift, and namespace changes,
  so the resync is only a safety net for missed watch events. The chart
  default moves with it.
- Add predicate and tamper-repair regression tests; drift repair is
  verified to make no direct apiserver reads.
2026-08-29 13:44:57 +01:00
lukaszraczylo eaa1246fb7 perf(controller): stop per-target apiserver reads in mirror reconcile
The mirror reconcile path issued one direct apiserver GET per target
namespace on every pass. With N sources and M target namespaces each
resync produced N*M GET requests. On a 65-namespace cluster this
generated 63 GET/s and overloaded one control-plane node.

Changes:
- reconcileMirror now trusts the informer cache. Content drift is
  detected via the source hash annotation. A stale resourceVersion
  makes Update return a conflict, which requeues the source.
- The verify-source-freshness flag now defaults to false. The Helm
  chart passes the value explicitly, so the chart default of false
  matches the binary behaviour.
- Reconcile performs one namespace LIST per pass. Target resolution
  and orphan cleanup share the result.
- Add load regression tests that count direct API reads in the
  reconcile hot path.
2026-08-29 13:44:54 +01:00
lukaszraczyloandGitHub 8c0bb0c5b0 Update go.mod and go.sum (#83) 2026-08-29 04:20:19 +01:00
lukaszraczyloandGitHub 198c6c8492 Update go.mod and go.sum (#82) 2026-08-27 05:58:26 +01:00
lukaszraczyloandGitHub 3df05913ed Update go.mod and go.sum (#81) 2026-08-26 04:27:17 +01:00
lukaszraczyloandGitHub 53075d8914 Update go.mod and go.sum (#80) 2026-08-22 04:22:15 +01:00
lukaszraczyloandGitHub 23b164e731 Update go.mod and go.sum (#79) 2026-08-21 04:26:32 +01:00
lukaszraczyloandGitHub 8c09081914 Update go.mod and go.sum (#78) 2026-08-20 04:22:51 +01:00
lukaszraczyloandGitHub 5f4a5bf233 Update go.mod and go.sum (#77) 2026-08-18 04:21:51 +01:00
lukaszraczyloandGitHub 0285f9f62d Update go.mod and go.sum (#76) 2026-08-13 04:50:56 +01:00
lukaszraczyloandGitHub c23b3af4f9 Update go.mod and go.sum (#75) 2026-08-12 04:50:01 +01:00
lukaszraczyloandGitHub 58d7170742 Update go.mod and go.sum (#74) 2026-08-11 04:38:28 +01:00
lukaszraczyloandGitHub 6ad42ddf89 Update go.mod and go.sum (#73) 2026-07-28 06:54:43 +01:00
lukaszraczyloandGitHub 5b848b24ad Update go.mod and go.sum (#72) 2026-07-27 07:36:51 +01:00
lukaszraczyloandGitHub 6f880e7ade Update go.mod and go.sum (#71) 2026-07-25 06:48:17 +01:00
lukaszraczyloandGitHub ce4d3aff86 Update go.mod and go.sum (#70) 2026-07-23 07:08:06 +01:00
lukaszraczyloandGitHub 441b05def5 Update go.mod and go.sum (#69) 2026-07-22 06:57:07 +01:00
lukaszraczyloandGitHub 4c0af68f60 Update go.mod and go.sum (#68) 2026-07-21 06:58:04 +01:00
lukaszraczyloandGitHub a0e37ec5d8 Update go.mod and go.sum (#67) 2026-07-20 07:24:30 +01:00
lukaszraczyloandGitHub e0ff007e2a Update go.mod and go.sum (#66) 2026-07-19 07:05:12 +01:00
lukaszraczyloandGitHub 390e199ae0 Update go.mod and go.sum (#65) 2026-07-11 05:06:38 +01:00
lukaszraczyloandGitHub 5919e14c18 Update go.mod and go.sum (#64) 2026-07-09 05:25:57 +01:00
lukaszraczyloandGitHub fc97f34cea Update go.mod and go.sum (#63) 2026-07-08 05:08:51 +01:00
lukaszraczyloandGitHub fb1fa9e255 Update go.mod and go.sum (#62) 2026-07-07 05:26:55 +01:00
lukaszraczyloandGitHub ebb2365a88 Update go.mod and go.sum (#61) 2026-07-01 05:40:41 +01:00
lukaszraczyloandGitHub 3b9637bd37 Update go.mod and go.sum (#60) 2026-06-30 05:33:10 +01:00
lukaszraczyloandGitHub ae90f09aef Update go.mod and go.sum (#59) 2026-06-29 05:40:48 +01:00
lukaszraczyloandGitHub 8bcce1bff8 Update go.mod and go.sum (#58) 2026-06-28 05:38:46 +01:00
lukaszraczyloandGitHub 7ce5b71406 Update go.mod and go.sum (#57) 2026-06-27 05:28:30 +01:00
lukaszraczyloandGitHub 3a713a6388 Update go.mod and go.sum (#56) 2026-06-25 05:33:25 +01:00
lukaszraczyloandGitHub 8adec76ce8 Update go.mod and go.sum (#55) 2026-06-24 05:32:57 +01:00
lukaszraczylo 6a41222b34 docs: fix flag defaults, drop phantom annotations, add chart README
Correct two wrong CLI flag defaults (leader-elect, verify-source-freshness) and add missing flags/Helm values. Remove documented-but-nonexistent annotations (excluded-namespaces, namespace-pattern) that silently did nothing, document the real exclude/paused and glob targeting, fix the mirror ownership-check example, and add the missing charts/kubemirror/README.md that README linked to.
2026-06-21 13:27:00 +01:00
lukaszraczylo 28896ab1d6 fix(monitoring): match real controller label values in dashboards and alerts
kubemirror overrides controller names to <Kind>.<version>.<group> (e.g. Secret.v1.), but the dashboards, alerts, and recording rules filtered controller=~"secret|configmap" (the controller-runtime default name), so every panel and alert matched nothing. Switch all selectors to Secret.*|ConfigMap.* and document the naming convention.
2026-06-21 13:26:49 +01:00
lukaszraczylo 6d27d7dfe7 fix(cmd): log the actual build version on startup
The startup log hardcoded version="dev", so release builds always reported dev. Use the ldflags-set Version variable. Also modernise interface{} to any.
2026-06-21 13:26:41 +01:00
lukaszraczylo 330666336f feat(controller): add exclude and paused source annotations
exclude="true" opts a resource out of mirroring and tears down its existing mirrors; paused="true" freezes mirrors in place (no updates, no cleanup). Both respected by the source and namespace reconcilers. Also dedup target-namespace resolution via delegation, remove 8 unused annotation constants and their misleading godoc, and silence gosec G101 false positives on base64 test fixtures.
2026-06-21 13:26:33 +01:00
lukaszraczylo 3628929871 refactor(controller): extract shared mirror-deletion and naming helpers
Replace the triplicated ownership-verified delete guard with deleteOwnedMirror, and hand-built controller-name strings with gvkControllerName. Use constants.Domain/ControllerName over magic strings and maps.Copy/Clone for plain copy loops. Behaviour-preserving; tests green.
2026-06-21 13:26:23 +01:00
lukaszraczyloandGitHub c8ca8c41b6 Update go.mod and go.sum (#54) 2026-06-19 05:40:27 +01:00
lukaszraczyloandGitHub e5aa084c14 Update go.mod and go.sum (#53) 2026-06-18 05:38:47 +01:00
lukaszraczyloandGitHub 417258630a Update go.mod and go.sum (#52) 2026-06-13 05:37:25 +01:00
lukaszraczyloandGitHub 778be24c13 Update go.mod and go.sum (#51) 2026-06-11 05:37:49 +01:00
lukaszraczyloandGitHub d2b8ab4a2d Update go.mod and go.sum (#50) 2026-06-09 05:31:57 +01:00
lukaszraczyloandGitHub ea71c1e839 Update go.mod and go.sum (#49) 2026-06-08 05:38:43 +01:00
lukaszraczyloandGitHub 2fc7d23d40 Update go.mod and go.sum (#48) 2026-06-04 05:38:32 +01:00
lukaszraczyloandGitHub 557c6cfc9b Update go.mod and go.sum (#47) 2026-06-01 05:40:57 +01:00
lukaszraczyloandGitHub 3179a25e41 Update go.mod and go.sum (#46) 2026-05-31 05:38:15 +01:00
lukaszraczyloandGitHub 711713bf76 Update go.mod and go.sum (#45) 2026-05-30 05:28:13 +01:00
lukaszraczyloandGitHub 0e8a9fd0a0 Update go.mod and go.sum (#44) 2026-05-23 05:23:34 +01:00
lukaszraczyloandGitHub d97132a111 Update go.mod and go.sum (#43) 2026-05-22 05:32:49 +01:00
lukaszraczyloandGitHub 3ab86c34b6 Update go.mod and go.sum (#42) 2026-05-21 05:37:43 +01:00
lukaszraczylo 76237c6bf6 docs: add Telemetry section linking to oss-telemetry opt-out docs
Discloses the single anonymous adoption ping sent on startup and points
users to the upstream README section for full opt-out instructions
instead of duplicating the table here.
2026-05-21 04:06:40 +01:00
lukaszraczylo d552e45e2f feat: anonymous usage telemetry via oss-telemetry
Send a single fire-and-forget ping at startup to help track adoption
and version spread. No persistent identifiers are collected.

Adds main.Version var (defaulting to "dev") so the existing goreleaser
ldflags injection (-X main.Version={{.Version}}) now binds to a real
symbol.

Opt out via any of:
  DO_NOT_TRACK=1
  OSS_TELEMETRY_DISABLED=1
  KUBEMIRROR_DISABLE_TELEMETRY=1
2026-05-21 03:05:58 +01:00
lukaszraczyloandGitHub 1836381d9d Update go.mod and go.sum (#41) 2026-05-20 05:33:53 +01:00
lukaszraczyloandGitHub 9240167386 Update go.mod and go.sum (#40) 2026-05-13 05:26:51 +01:00
lukaszraczyloandGitHub 5e360d80c6 Update go.mod and go.sum (#39) 2026-05-12 05:23:43 +01:00
lukaszraczyloandGitHub e5a0846165 Update go.mod and go.sum (#38) 2026-05-10 05:28:40 +01:00
lukaszraczyloandGitHub 64b14b84e0 Update go.mod and go.sum (#37) 2026-05-09 05:16:48 +01:00
lukaszraczyloandGitHub 2a1575f5c9 Update go.mod and go.sum (#36) 2026-05-08 05:11:10 +01:00
lukaszraczyloandGitHub 8feb93146b Update go.mod and go.sum (#35) 2026-05-06 05:22:35 +01:00
lukaszraczyloandGitHub d055f11bd4 Update go.mod and go.sum (#34) 2026-05-05 05:11:34 +01:00
lukaszraczyloandGitHub e886143429 Update go.mod and go.sum (#33) 2026-05-03 05:26:25 +01:00
lukaszraczylo ba0797f5af chore: remove unreachable SetupWithManager(secret-only) on SourceReconciler
All registration goes through SetupWithManagerForResourceType (eager and
lazy paths in main.go); the legacy single-resource SetupWithManager and
its corev1 import were dead code that misled readers about how the
controller wires up.
2026-05-02 22:50:02 +01:00
lukaszraczylo 75f7c18f3c fix: hash drift, transformer leak guard, prod logger, ctx-aware wait
M7: extractUnstructuredContent only hashed 'spec' when present, dropping
all other top-level content fields. Resources with both spec and data
(or any non-spec content) silently drifted until the next 10m resync.
Now hashes every non-Kubernetes-managed top-level field, matching the
fields updateUnstructuredMirror copies.

M6: when a source has a transform annotation, also hash the source's
labels and annotations (filtered of kubemirror.raczylo.com/* keys to
avoid the controller's own bookkeeping churning the hash). Templates
read these via TransformContext; without this a label change wouldn't
re-render the transformed mirror.

H3: text/template.Execute is not context-aware, so applyTemplateRule's
timeout cancels the select but leaks the executor goroutine. Added a
process-wide semaphore (cap 64) so a runaway template can't spawn an
unbounded number of stuck goroutines on every reconcile.

M4: zap dev mode (DPanic-on-error, console output, stacktraces on
warning) was hardcoded on. Defaulted to production; --zap-devel flag
remains for opt-in.

M5: WaitForInitialDiscovery was anchored on context.Background() with
its own WithTimeout, so SIGTERM during startup couldn't abort the wait.
Now anchors on signalCtx.
2026-05-02 22:49:15 +01:00
lukaszraczylo cf095e93f4 fix(dynamic-manager): release mu before invoking registration
H2: scanAndRegister held d.mu (write lock) across registerController
and registerMirrorControllerOnly. Those calls enter controller-runtime's
manager state machine, which takes its own internal locks and can block
on cache sync — holding our application-level write lock across them
is a latent deadlock the moment any reentrant access happens (health
checks reading GetRegisteredCount, factories that introspect state).

Restructured into three phases: snapshot work under RLock, perform
registrations with NO lock held, then commit results under Lock.
Registration step routed through funcs to keep tests honest about
the lock state at the moment of invocation.
2026-05-02 22:45:27 +01:00
lukaszraczylo a8e48a9eb6 fix(controller): forward APIReader+CircuitBreaker through NamespaceReconciler
H4: NamespaceReconciler.reconcileMirror builds an ad-hoc SourceReconciler
to delegate mirror creation. The previous version left APIReader and
CircuitBreaker as nil, which silently disabled freshness verification
on the namespace-driven path (a label change to a target namespace
would mirror cached, possibly stale source data) and bypassed circuit
breaker accounting for those reconciles.

Construction extracted into newSourceReconciler so the forwarding is
covered by a unit test that pins both fields by identity.
2026-05-02 22:41:11 +01:00
lukaszraczylo dfe08b35d1 fix(controller): stop self-triggered reconcile loops
C2: updateLastSyncStatus wrote the sync-status annotation on every
successful reconcile. Because the source's watch predicate is the
'enabled' label (server-side filter), that Update fires a watch event
that re-enters Reconcile. With reconciled/error counts varying across
cycles, the value differs each time, so the API server bumps RV and
the loop never quiesces. Now skips the Update when the value matches
the existing annotation.

C3: NamespaceReconciler's happy-path returned RequeueAfter=3s
unconditionally. Every namespace in the cluster re-reconciled every
3 seconds forever, generating constant List calls per source kind.
Now returns ctrl.Result{}; cache-staleness windows are handled by
the manager's resync period and source freshness verification.
2026-05-02 22:39:09 +01:00
lukaszraczylo 99c0eccd53 fix: default verify-source-freshness=true; honor opt-out for glob
H1: --verify-source-freshness used to default to false, so any source
update whose annotation was still in the informer cache (5-20s lag)
would resolve the wrong target list. cleanupOrphanedMirrors then ran
against the stale list and missed orphans (manifested in e2e as
'Orphaned mirror in kubemirror-e2e-app-1 not deleted within timeout'
after target-namespaces was changed). Defaulting to true fixes the
race; the trade-off is one extra API read per stale-cache reconcile.

M2: ResolveTargetNamespaces glob branch checked filter.IsAllowed but
not the opt-out map, so a namespace labeled allow-mirrors=false would
still receive a mirror through patterns like 'app-*'. The 'all' branch
already had the guard; the glob branch now does too. Direct namespace
listings still bypass opt-out by design (explicit author intent).
2026-05-02 22:36:50 +01:00
lukaszraczylo 4277c8ac39 fix(controller): guard mirror deletion + enforce secret blacklist
C1: deleteAllMirrors used to issue a blind Delete on every namespace
matching the source name+GVK, which would destroy unrelated resources
(e.g. a 'default' SA, 'ca-bundle' ConfigMap) sharing the source name.
Now reads each candidate, verifies managed-by label and source-reference
annotation, and only deletes confirmed mirrors.

M1: BlacklistedSecretTypes was declared but never enforced. Enabling
mirroring on a service-account-token / bootstrap-token / helm release
Secret would mirror credentials cluster-wide. Now refused at Reconcile.

M3: deleteAllMirrors swallowed per-namespace errors and returned nil,
so callers removed the finalizer even on partial failure (orphans).
Errors are now joined and returned.
2026-05-02 22:35:40 +01:00
lukaszraczylo b555d84d32 ci: bump go-version constraint to >=1.26
k8s.io/api v0.36.0 requires Go 1.26.0; autoupdate has been failing
since 2026-04-23 because setup-go's cached 1.25.9 fell behind.
2026-05-02 22:03:19 +01:00
lukaszraczyloandGitHub 30ffc823d9 Update go.mod and go.sum (#32) 2026-04-19 05:09:27 +01:00
lukaszraczyloandGitHub c3450e2af2 Update go.mod and go.sum (#31) 2026-04-17 05:09:22 +01:00
lukaszraczyloandGitHub d0857e4f4a Update go.mod and go.sum (#30) 2026-04-16 05:10:11 +01:00
lukaszraczyloandGitHub 36c9e859af Update go.mod and go.sum (#29) 2026-04-15 05:07:38 +01:00
lukaszraczyloandGitHub 05aacddeab Update go.mod and go.sum (#28) 2026-04-10 05:08:23 +01:00
lukaszraczyloandGitHub a9838e9156 Update go.mod and go.sum (#27) 2026-04-09 05:02:31 +01:00
lukaszraczyloandGitHub 317143c458 Update go.mod and go.sum (#26) 2026-03-31 05:04:13 +01:00
lukaszraczyloandGitHub 42358a3743 Update go.mod and go.sum (#25) 2026-03-20 03:54:18 +00:00
lukaszraczyloandGitHub f2ecc5d56a Update go.mod and go.sum (#24) 2026-03-19 03:57:48 +00:00
lukaszraczyloandGitHub 30de592c0c Update go.mod and go.sum (#23) 2026-03-18 03:57:33 +00:00
lukaszraczyloandGitHub ea405f44a2 Update go.mod and go.sum (#22) 2026-03-12 03:52:50 +00:00
lukaszraczyloandGitHub f62bec57f5 Update go.mod and go.sum (#21) 2026-03-09 03:53:52 +00:00
lukaszraczyloandGitHub c9cf81e4fd Update go.mod and go.sum (#20) 2026-03-07 03:46:46 +00:00
lukaszraczyloandGitHub 7c8a12958d Update go.mod and go.sum (#19) 2026-03-06 03:52:51 +00:00
lukaszraczyloandGitHub 0bac0f4645 Update go.mod and go.sum (#18) 2026-03-05 03:52:56 +00:00
lukaszraczyloandGitHub afe6602ddd Update go.mod and go.sum (#17) 2026-03-03 03:53:14 +00:00
lukaszraczyloandGitHub 91a1d05a92 Update go.mod and go.sum (#16) 2026-03-01 03:59:02 +00:00
lukaszraczyloandGitHub 3c7f25bc16 Update go.mod and go.sum (#15) 2026-02-28 03:44:26 +00:00
lukaszraczyloandGitHub 1a40783e36 Update go.mod and go.sum (#14) 2026-02-26 03:54:10 +00:00
lukaszraczyloandGitHub 56809700fb Update go.mod and go.sum (#13) 2026-02-11 04:03:15 +00:00
lukaszraczyloandGitHub 5db9fa8653 Update go.mod and go.sum (#12) 2026-02-10 04:04:06 +00:00
lukaszraczyloandGitHub 1e4af7df0c Update go.mod and go.sum (#11) 2026-02-09 03:59:24 +00:00
lukaszraczyloandGitHub 668a84b070 Update go.mod and go.sum (#10) 2026-02-07 03:51:55 +00:00
lukaszraczyloandGitHub 9dea7a1022 Update go.mod and go.sum (#9) 2026-01-28 03:40:46 +00:00