From 6d29fcb31aed26b2f677d11723358c52a2effe16 Mon Sep 17 00:00:00 2001 From: Scott Dodson Date: Thu, 20 Nov 2025 15:07:29 -0500 Subject: [PATCH 1/2] feat(status): Add availableInertia support to StatusSyncer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the ability to configure inertia for Available conditions in the StatusSyncer, following the same pattern as degradedInertia. Without this change, Available conditions flip to False immediately upon any error, regardless of how brief the error is. This causes false positives in CI and confuses admins during upgrades when transient errors (like "malformed header: missing HTTP content-type") that last only 1 second trigger Available=False. Changes: - Add availableInertia field to StatusSyncer struct - Add WithAvailableInertia() method to configure inertia - Use availableInertia in Sync() when setting OperatorAvailable condition 🤖 Generated with Claude Code via /jira:solve OCPBUGS-23746 Co-Authored-By: Claude --- pkg/operator/status/status_controller.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/operator/status/status_controller.go b/pkg/operator/status/status_controller.go index de348e797d..d53da28dac 100644 --- a/pkg/operator/status/status_controller.go +++ b/pkg/operator/status/status_controller.go @@ -52,6 +52,7 @@ type StatusSyncer struct { controllerFactory *factory.Factory recorder events.Recorder degradedInertia Inertia + availableInertia Inertia removeUnusedVersions bool } @@ -123,6 +124,14 @@ func (c *StatusSyncer) WithDegradedInertia(inertia Inertia) *StatusSyncer { return &output } +// WithAvailableInertia returns a copy of the StatusSyncer with the +// requested inertia function for available conditions. +func (c *StatusSyncer) WithAvailableInertia(inertia Inertia) *StatusSyncer { + output := *c + output.availableInertia = inertia + return &output +} + // WithVersionRemoval returns a copy of the StatusSyncer that will // remove versions that are missing in VersionGetter from the status. func (c *StatusSyncer) WithVersionRemoval() *StatusSyncer { @@ -217,7 +226,7 @@ func (c StatusSyncer) Sync(ctx context.Context, syncCtx factory.SyncContext) err configv1helpers.SetStatusCondition(&clusterOperatorObj.Status.Conditions, UnionClusterCondition(configv1.OperatorDegraded, operatorv1.ConditionFalse, c.degradedInertia, currentDetailedStatus.Conditions...), c.clock) configv1helpers.SetStatusCondition(&clusterOperatorObj.Status.Conditions, UnionClusterCondition(configv1.OperatorProgressing, operatorv1.ConditionFalse, nil, currentDetailedStatus.Conditions...), c.clock) - configv1helpers.SetStatusCondition(&clusterOperatorObj.Status.Conditions, UnionClusterCondition(configv1.OperatorAvailable, operatorv1.ConditionTrue, nil, currentDetailedStatus.Conditions...), c.clock) + configv1helpers.SetStatusCondition(&clusterOperatorObj.Status.Conditions, UnionClusterCondition(configv1.OperatorAvailable, operatorv1.ConditionTrue, c.availableInertia, currentDetailedStatus.Conditions...), c.clock) configv1helpers.SetStatusCondition(&clusterOperatorObj.Status.Conditions, UnionClusterCondition(configv1.OperatorUpgradeable, operatorv1.ConditionTrue, nil, currentDetailedStatus.Conditions...), c.clock) configv1helpers.SetStatusCondition(&clusterOperatorObj.Status.Conditions, UnionClusterCondition(configv1.EvaluationConditionsDetected, operatorv1.ConditionFalse, nil, currentDetailedStatus.Conditions...), c.clock) From d99e4c2f8c2a014e9c084e3046583dff10ca052e Mon Sep 17 00:00:00 2001 From: Scott Dodson Date: Thu, 20 Nov 2025 15:09:17 -0500 Subject: [PATCH 2/2] feat(apiserver): Add helper for APIServicesAvailable inertia MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add WithStatusControllerAPIServicesAvailableInertia helper function to configure a 5-second inertia for APIServicesAvailable conditions. This prevents brief transient errors (like missing HTTP content-type headers) from causing Available=False in the ClusterOperator status. The 5-second duration is chosen to: - Tolerate brief network hiccups and transient errors (JIRA shows 1s errors) - Still catch real issues quickly (much shorter than 2-minute degraded inertia) - Reduce false positives in CI during upgrades Usage example for operators using APIServices: statusControllerOptions = append(statusControllerOptions, apiservercontrollerset.WithStatusControllerAPIServicesAvailableInertia()) 🤖 Generated with Claude Code via /jira:solve OCPBUGS-23746 Co-Authored-By: Claude --- .../controllerset/apiservercontrollerset.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pkg/operator/apiserver/controllerset/apiservercontrollerset.go b/pkg/operator/apiserver/controllerset/apiservercontrollerset.go index 29e741febe..249dfc2162 100644 --- a/pkg/operator/apiserver/controllerset/apiservercontrollerset.go +++ b/pkg/operator/apiserver/controllerset/apiservercontrollerset.go @@ -170,6 +170,22 @@ func WithStatusControllerPdbCompatibleHighInertia(workloadConditionsPrefix strin } } +// WithStatusControllerAPIServicesAvailableInertia sets inertia for APIServicesAvailable +// conditions to prevent brief transient errors from causing Available=False. +// This is useful for handling temporary network issues or brief missing HTTP headers +// that self-resolve within seconds. +func WithStatusControllerAPIServicesAvailableInertia() func(s *status.StatusSyncer) *status.StatusSyncer { + return func(s *status.StatusSyncer) *status.StatusSyncer { + return s.WithAvailableInertia(status.MustNewInertia( + 0, // default: no inertia for other conditions + status.InertiaCondition{ + ConditionTypeMatcher: regexp.MustCompile("^APIServicesAvailable$"), + Duration: 5 * time.Second, // tolerate brief transient errors + }).Inertia, + ) + } +} + func (cs *APIServerControllerSet) WithoutClusterOperatorStatusController() *APIServerControllerSet { cs.clusterOperatorStatusController.controller = nil cs.clusterOperatorStatusController.emptyAllowed = true