Skip to content

THREESCALE-14652 Prevent perpetual reconcile by hardcoding K8s-defaulted fields in component specs#1174

Open
urbanikb wants to merge 1 commit into3scale:masterfrom
urbanikb:THREESCALE-14652
Open

THREESCALE-14652 Prevent perpetual reconcile by hardcoding K8s-defaulted fields in component specs#1174
urbanikb wants to merge 1 commit into3scale:masterfrom
urbanikb:THREESCALE-14652

Conversation

@urbanikb
Copy link
Copy Markdown
Contributor

@urbanikb urbanikb commented May 6, 2026

https://redhat.atlassian.net/browse/THREESCALE-14652

Summary

Fixes perpetual Deployment update loops caused by the K8s API server silently filling zero-value fields with defaults on write. Mutators using reflect.DeepEqual then always see a mismatch between the desired spec (Go zero values) and the live spec (K8s-filled defaults), triggering an update on every reconcile cycle.

Root cause fields explicitly set in all component Deployment specs:

  • Probe fields: Scheme, TimeoutSeconds, PeriodSeconds, SuccessThreshold, FailureThreshold
  • Container / init-container fields: TerminationMessagePath, TerminationMessagePolicy, ImagePullPolicy (init containers most sensitive — DeploymentPodInitContainerMutator does a full struct DeepEqual)
  • Pod spec fields: RestartPolicy, DNSPolicy, SecurityContext, TerminationGracePeriodSeconds, SchedulerName
  • Volume source fields: DefaultMode on Secret, ConfigMap, and Projected volume sources
  • Use nil (not []T{}) for optional volume/volumemount slices

Observability: UpdateResource now logs namespace and APIManager owner name as structured fields, enabling the integration test counter to attribute each Deployment update to the correct CR instance.

Regression test: ReconcileCounter + verifyNoDeploymentUpdates assert that total Deployment update calls per APIManager install stay within [1, 50]. The floor of 1 guards against a silent counter misconfiguration; the ceiling of 50 stays well below what the perpetual-reconcile bug produced (hundreds of updates per install).

Test plan

  • Integration test passes: WATCH_NAMESPACE=dummy make test-integration
  • Deployment Update Report shows Total between 1 and 50
  • No backend/zync/system deployments cycling in cluster logs after APIManager becomes Available

🤖 Generated with Claude Code

@urbanikb urbanikb requested a review from a team as a code owner May 6, 2026 00:18
@urbanikb urbanikb force-pushed the THREESCALE-14652 branch 3 times, most recently from f0e8544 to 2efbfb9 Compare May 7, 2026 06:05
@urbanikb
Copy link
Copy Markdown
Contributor Author

urbanikb commented May 7, 2026

@tkan145 the required tests on prow are failing due to CI already using go 1.25

# golang.org/x/tools/internal/tokeninternal
/go/pkg/mod/golang.org/x/tools@v0.16.1/internal/tokeninternal/tokeninternal.go:78:9: invalid array length -delta * delta (constant -256 of type int64)

Other than this the PR is ready for review. I will rebase this on master when #1173 is merged to clear the CI errors.

@urbanikb urbanikb changed the title THREESCALE-14652: Prevent perpetual reconcile by hardcoding K8s-defaulted fields in component specs THREESCALE-14224/THREESCALE-14652: Prevent perpetual reconcile by hardcoding K8s-defaulted fields in component specs May 7, 2026
@urbanikb urbanikb changed the title THREESCALE-14224/THREESCALE-14652: Prevent perpetual reconcile by hardcoding K8s-defaulted fields in component specs THREESCALE-14652 - Prevent perpetual reconcile by hardcoding K8s-defaulted fields in component specs May 8, 2026
@urbanikb urbanikb changed the title THREESCALE-14652 - Prevent perpetual reconcile by hardcoding K8s-defaulted fields in component specs THREESCALE-14652 Prevent perpetual reconcile by hardcoding K8s-defaulted fields in component specs May 8, 2026
…ponent specs

The K8s API server fills zero-value fields with defaults when a resource is
written. Mutators using reflect.DeepEqual then see a mismatch between the
desired spec (Go zero values) and the live spec (K8s-filled defaults),
triggering an update on every reconcile cycle.

Explicitly set all K8s-defaulted fields in every component Deployment spec:

- Probe fields: Scheme, TimeoutSeconds, PeriodSeconds, SuccessThreshold,
  FailureThreshold
- Container / init-container fields: TerminationMessagePath,
  TerminationMessagePolicy, ImagePullPolicy (init containers are most
  sensitive — DeploymentPodInitContainerMutator does a full struct DeepEqual)
- Pod spec fields: RestartPolicy, DNSPolicy, SecurityContext,
  TerminationGracePeriodSeconds, SchedulerName
- Volume source fields: DefaultMode on Secret, ConfigMap, and Projected
  volume sources
- Use nil (not []T{}) for optional volume/volumemount slices so
  reflect.DeepEqual treats K8s-normalised absent and locally-absent the same

Extend UpdateResource to log the object's namespace and APIManager owner
name as structured fields, enabling the integration test's ReconcileCounter
to attribute each Deployment update to the correct CR instance.

Add ReconcileCounter and verifyNoDeploymentUpdates to the integration test
suite to assert ≤50 total Deployment update calls per APIManager install,
providing a regression test for this class of bug.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@urbanikb urbanikb force-pushed the THREESCALE-14652 branch from 2efbfb9 to 08edbf7 Compare May 8, 2026 05:15
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 8, 2026

Codecov Report

❌ Patch coverage is 86.49351% with 52 lines in your changes missing coverage. Please review.
✅ Project coverage is 44.28%. Comparing base (4963add) to head (08edbf7).
⚠️ Report is 18 commits behind head on master.

Files with missing lines Patch % Lines
pkg/3scale/amp/component/system.go 85.71% 14 Missing ⚠️
pkg/3scale/amp/component/apicast.go 86.58% 11 Missing ⚠️
pkg/3scale/amp/component/zync.go 82.53% 11 Missing ⚠️
pkg/3scale/amp/component/system_searchd.go 67.85% 9 Missing ⚠️
pkg/reconcilers/base_reconciler.go 0.00% 4 Missing ⚠️
controllers/apps/apimanager_controller.go 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1174      +/-   ##
==========================================
+ Coverage   41.84%   44.28%   +2.43%     
==========================================
  Files         203      204       +1     
  Lines       20859    21087     +228     
==========================================
+ Hits         8729     9338     +609     
+ Misses      11350    10947     -403     
- Partials      780      802      +22     
Flag Coverage Δ
unit 44.28% <86.49%> (+2.43%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
apis/apps/v1alpha1 (u) 63.19% <ø> (+4.64%) ⬆️
apis/capabilities/v1alpha1 (u) 3.50% <ø> (ø)
apis/capabilities/v1beta1 (u) 20.21% <ø> (ø)
controllers (i) 12.08% <85.22%> (+2.76%) ⬆️
pkg (u) 63.93% <85.04%> (+2.21%) ⬆️
Files with missing lines Coverage Δ
pkg/3scale/amp/component/backend.go 97.26% <100.00%> (+12.68%) ⬆️
pkg/3scale/amp/component/memcached.go 100.00% <100.00%> (ø)
controllers/apps/apimanager_controller.go 10.21% <0.00%> (ø)
pkg/reconcilers/base_reconciler.go 69.76% <0.00%> (-2.24%) ⬇️
pkg/3scale/amp/component/system_searchd.go 49.65% <67.85%> (+1.47%) ⬆️
pkg/3scale/amp/component/apicast.go 69.45% <86.58%> (+0.95%) ⬆️
pkg/3scale/amp/component/zync.go 74.96% <82.53%> (+0.26%) ⬆️
pkg/3scale/amp/component/system.go 83.12% <85.71%> (+8.43%) ⬆️

... and 8 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 9, 2026

PR needs rebase.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants