Skip to content

fix(operator): stop the KapeAgentServer reconcile hot loop on API defaults - #271

Merged
dzungtr merged 1 commit into
mainfrom
fix/agentserver-patch-loop
Oct 22, 2026
Merged

dzungtr merged 1 commit into
mainfrom
fix/agentserver-patch-loop

Conversation

@dzungtr

@dzungtr dzungtr commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Symptom (live cluster, kape 0.1.0 operator, kape #261 close-out)

The operator rendered kape-controller-default fine, the pod was 1/1 Ready, but the Deployment never became available and the CR sat at Ready=False (Progressing: controller Deployment is not available yet). metadata.generation climbed 1309 → 1511 in 20 s — a patch hot loop.

Cause

applySpec does live.Spec = d.Spec for Deployments. The rendered spec omits everything the API server defaults:

  • pod: dnsPolicy, restartPolicy, terminationGracePeriodSeconds, securityContext
  • container: terminationMessagePath, terminationMessagePolicy
  • probes: successThreshold, failureThreshold, timeoutSeconds
  • secret/emptyDir volumes: defaultMode, sizeLimit

A merge patch computed against a live object therefore always differs (armor: the containers list is replaced wholesale, so the defaults are dropped and re-applied every time), so ensure patched on every reconcile. Each patch bumped generation → the writer's DeploymentStatus check (ObservedGeneration >= Generation with available replicas) never converged → CR never Ready.

Fix

Before assigning, inherit the live values for every field the renderer does not own (inheritPodDefaults → containers/probes/volumes, plus strategy/ingressClassName). A re-apply against a defaulted Deployment is now a true no-op.

  • new test TestAgentServerAdapterApplyIgnoresAPIDefaults: applies, simulates API defaulting on the stored object, re-applies, asserts resourceVersion and generation are unchanged
  • go test ./operator/infra/k8s/ passes; the two failures in operator/controller/reconcile and operator/infra/qdrant reproduce on unmodified main (env-dependent, unrelated)

Follow-up (not in this PR)

KAPE_MONITOR_* env emitted by the chart reaches the controller, but the chart's controllerWiring.extraEnv path is untested against a real Deployment; separate issue if it bites.

…aults

applySpec assigned the rendered Deployment.Spec wholesale, which zeroes every
field the API server defaults (dnsPolicy, restartPolicy, probe
successThreshold/timeoutSeconds, terminationMessagePath, volume defaultMode).
The merge-patch diff against a live object was therefore never empty, so every
reconcile patched the Deployment, bumping metadata.generation ~10/s. The
Deployment never reported availability, so the CR stayed
Ready=False (Progressing) forever — observed on the live cluster as generation
1309 -> 1511 in 20s.

Inherit those defaults from the live object into the rendered spec before
assigning (pod-level scalars, per-container/probe/volume defaults), and keep
the live strategy/ingressClassName when the renderer does not set them. A
re-apply against a defaulted object is now a no-op, pinned by
TestAgentServerAdapterApplyIgnoresAPIDefaults.
@dzungtr
dzungtr merged commit ec8d679 into main Oct 22, 2026
1 check failed
@dzungtr
dzungtr deleted the fix/agentserver-patch-loop branch October 22, 2026 04:36
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