From ee254fc2d08d6a6f910ac5e82931e1af3ad611ad Mon Sep 17 00:00:00 2001 From: Brett Tofel Date: Thu, 28 May 2026 13:49:09 -0400 Subject: [PATCH 1/2] OCPBUGS-86009: Fix dns operator reporting Progressing=True on scale up The cluster-dns-operator was incorrectly reporting Progressing=True during normal cluster scale up events. This was caused by the computeDNSProgressingCondition checking UpdatedNumberScheduled against DesiredNumberScheduled. When a new node is added, DesiredNumberScheduled increases immediately, but UpdatedNumberScheduled lags until the pod is running, causing the operator to appear to be rolling out. This commit introduces an isDaemonSetRollingOut helper, modeled after similar logic in the cluster-ingress-operator. It checks if the DaemonSet Generation matches ObservedGeneration, and checks if UpdatedNumberScheduled is less than CurrentNumberScheduled. If not, the operator is simply scaling and should not report Progressing=True. --- pkg/operator/controller/dns_status.go | 21 +++++++++++++++++++-- pkg/operator/controller/dns_status_test.go | 5 +++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/pkg/operator/controller/dns_status.go b/pkg/operator/controller/dns_status.go index 84033b6f4..a63de52b6 100644 --- a/pkg/operator/controller/dns_status.go +++ b/pkg/operator/controller/dns_status.go @@ -208,7 +208,9 @@ func computeDNSProgressingCondition(oldCondition *operatorv1.OperatorCondition, have := dnsDaemonset.Status.UpdatedNumberScheduled // num of nodes running the updated pod. // It's progressing when have < want. If have >= want, that's okay. if have < want { - messages = append(messages, fmt.Sprintf("Have %d up-to-date DNS pods, want %d.", have, want)) + if isDaemonSetRollingOut(dnsDaemonset) { + messages = append(messages, fmt.Sprintf("Have %d up-to-date DNS pods, want %d.", have, want)) + } } haveSelector := dnsDaemonset.Spec.Template.Spec.NodeSelector @@ -231,7 +233,9 @@ func computeDNSProgressingCondition(oldCondition *operatorv1.OperatorCondition, // It's progressing when have < want. If have >= want, that's okay. if have < want { - messages = append(messages, fmt.Sprintf("Have %d available node-resolver pods, want %d.", have, want)) + if isDaemonSetRollingOut(nodeResolverDaemonset) { + messages = append(messages, fmt.Sprintf("Have %d available node-resolver pods, want %d.", have, want)) + } } } if len(messages) != 0 { @@ -350,3 +354,16 @@ func lastTransitionTimeIsRecent(currTime, prevTime time.Time, toleration time.Du return elapsed <= toleration } } + +// isDaemonSetRollingOut determines if the DaemonSet is currently in a rollout state +// (i.e., actively replacing old pods with new ones or applying a new configuration) +// versus simply stabilizing (e.g., waiting for pods to start after a node reboot or scale up). +func isDaemonSetRollingOut(ds *appsv1.DaemonSet) bool { + if ds.Generation != ds.Status.ObservedGeneration { + return true + } + if ds.Status.UpdatedNumberScheduled < ds.Status.CurrentNumberScheduled { + return true + } + return false +} diff --git a/pkg/operator/controller/dns_status_test.go b/pkg/operator/controller/dns_status_test.go index 579d2f9c4..26e2faa2a 100644 --- a/pkg/operator/controller/dns_status_test.go +++ b/pkg/operator/controller/dns_status_test.go @@ -111,6 +111,7 @@ func TestDNSStatusConditions(t *testing.T) { DesiredNumberScheduled: tc.inputs.desireDNS, NumberAvailable: tc.inputs.availDNS, UpdatedNumberScheduled: tc.inputs.updatedDNS, + CurrentNumberScheduled: tc.inputs.desireDNS, }, } dnsDaemonset.Spec.Template.Spec.NodeSelector = nodeSelectorForDNS(&operatorv1.DNS{}) @@ -132,6 +133,7 @@ func TestDNSStatusConditions(t *testing.T) { DesiredNumberScheduled: tc.inputs.desireNR, NumberAvailable: tc.inputs.availNR, UpdatedNumberScheduled: tc.inputs.updatedNR, + CurrentNumberScheduled: tc.inputs.desireNR, }, } } @@ -240,6 +242,7 @@ func TestComputeDNSDegradedCondition(t *testing.T) { Status: appsv1.DaemonSetStatus{ DesiredNumberScheduled: int32(desired), NumberAvailable: int32(available), + CurrentNumberScheduled: int32(desired), }, } } @@ -471,6 +474,7 @@ func TestComputeDNSProgressingCondition(t *testing.T) { Status: appsv1.DaemonSetStatus{ DesiredNumberScheduled: int32(desired), NumberAvailable: int32(available), + CurrentNumberScheduled: int32(desired), UpdatedNumberScheduled: int32(updated), }, } @@ -638,6 +642,7 @@ func TestSkippingStatusUpdates(t *testing.T) { Status: appsv1.DaemonSetStatus{ DesiredNumberScheduled: int32(desired), NumberAvailable: int32(available), + CurrentNumberScheduled: int32(desired), UpdatedNumberScheduled: int32(updated), }, } From b2ee3f50336631b306659b30908fd26c1b273bd4 Mon Sep 17 00:00:00 2001 From: Brett Tofel Date: Tue, 23 Jun 2026 15:35:36 -0400 Subject: [PATCH 2/2] OCPBUGS-86009: Add regression test for scale-up without rollout Add dedicated regression test cases to TestComputeDNSProgressingCondition to verify that the Progressing condition is False when the DaemonSet is scaling up but not rolling out. This covers the scenario where DesiredNumberScheduled > CurrentNumberScheduled but no active rollout is taking place. --- pkg/operator/controller/dns_status_test.go | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pkg/operator/controller/dns_status_test.go b/pkg/operator/controller/dns_status_test.go index 26e2faa2a..8bab27876 100644 --- a/pkg/operator/controller/dns_status_test.go +++ b/pkg/operator/controller/dns_status_test.go @@ -595,6 +595,32 @@ func TestComputeDNSProgressingCondition(t *testing.T) { tolerations: customTolerations, expected: operatorv1.ConditionTrue, }, + { + name: "DNS daemonset scaling up but not rolling out should not be progressing", + clusterIP: "172.30.0.10", + dnsDaemonset: func() *appsv1.DaemonSet { + ds := makeDaemonSet(6, 5, 5, defaultSelector, defaultTolerations) + ds.Status.CurrentNumberScheduled = 5 + return ds + }(), + nrDaemonset: makeDaemonSet(6, 6, 6, defaultSelector, defaultTolerations), + nodeSelector: defaultSelector, + tolerations: defaultTolerations, + expected: operatorv1.ConditionFalse, + }, + { + name: "node-resolver daemonset scaling up but not rolling out should not be progressing", + clusterIP: "172.30.0.10", + dnsDaemonset: makeDaemonSet(6, 6, 6, defaultSelector, defaultTolerations), + nrDaemonset: func() *appsv1.DaemonSet { + ds := makeDaemonSet(6, 5, 5, defaultSelector, defaultTolerations) + ds.Status.CurrentNumberScheduled = 5 + return ds + }(), + nodeSelector: defaultSelector, + tolerations: defaultTolerations, + expected: operatorv1.ConditionFalse, + }, } for _, tc := range testCases {