Skip to content

Commit 6fa2f18

Browse files
Merge pull request #848 from deads2k/fix-status-conditin
OCPBUGS-25484: make it impossible double set conditions in a single loop
2 parents d390563 + 956dca7 commit 6fa2f18

File tree

7 files changed

+138
-85
lines changed

7 files changed

+138
-85
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ require (
1313
github.com/openshift/api v0.0.0-20231218131639-7a5aa77cc72d
1414
github.com/openshift/build-machinery-go v0.0.0-20220913142420-e25cf57ea46d
1515
github.com/openshift/client-go v0.0.0-20231218140158-47f6d749b9d9
16-
github.com/openshift/library-go v0.0.0-20240115112243-470c096a1ca9
16+
github.com/openshift/library-go v0.0.0-20240124134907-4dfbf6bc7b11
1717
github.com/spf13/cobra v1.7.0
1818
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1
1919
gopkg.in/yaml.v2 v2.4.0

go.sum

Lines changed: 2 additions & 34 deletions
Large diffs are not rendered by default.

pkg/console/controllers/oauthclients/oauthclients.go

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ type oauthClientsController struct {
6363
targetNSConfigLister corev1listers.ConfigMapLister
6464
featureGatesLister configv1lister.FeatureGateLister
6565

66-
statusHandler status.StatusHandler
6766
authStatusHandler status.AuthStatusHandler
6867
}
6968

@@ -103,7 +102,6 @@ func NewOAuthClientsController(
103102
targetNSDeploymentsLister: targetNSDeploymentsInformer.Lister(),
104103
featureGatesLister: featureGatesInformer.Lister(),
105104

106-
statusHandler: status.NewStatusHandler(operatorClient),
107105
authStatusHandler: status.NewAuthStatusHandler(authentication, api.OpenShiftConsoleName, api.TargetNamespace, api.OpenShiftConsoleOperator),
108106
}
109107

@@ -128,6 +126,8 @@ func NewOAuthClientsController(
128126
}
129127

130128
func (c *oauthClientsController) sync(ctx context.Context, controllerContext factory.SyncContext) error {
129+
statusHandler := status.NewStatusHandler(c.operatorClient)
130+
131131
if shouldSync, err := c.handleManaged(ctx); err != nil {
132132
return err
133133
} else if !shouldSync {
@@ -176,36 +176,43 @@ func (c *oauthClientsController) sync(ctx context.Context, controllerContext fac
176176
}
177177

178178
clientSecret, secErr := c.syncSecret(ctx, operatorConfig, controllerContext.Recorder())
179-
c.statusHandler.AddConditions(status.HandleProgressingOrDegraded("OAuthClientSecretSync", "FailedApply", secErr))
179+
statusHandler.AddConditions(status.HandleProgressingOrDegraded("OAuthClientSecretSync", "FailedApply", secErr))
180180
if secErr != nil {
181181
syncErr = secErr
182182
break
183183
}
184184

185185
oauthErrReason, oauthErr := c.syncOAuthClient(ctx, clientSecret, consoleURL.String())
186-
c.statusHandler.AddConditions(status.HandleProgressingOrDegraded("OAuthClientSync", oauthErrReason, oauthErr))
186+
statusHandler.AddConditions(status.HandleProgressingOrDegraded("OAuthClientSync", oauthErrReason, oauthErr))
187187
if oauthErr != nil {
188188
syncErr = oauthErr
189189
break
190190
}
191191

192192
case configv1.AuthenticationTypeOIDC:
193-
syncErr = c.syncAuthTypeOIDC(ctx, controllerContext, operatorConfig, authnConfig)
193+
syncErr = c.syncAuthTypeOIDC(ctx, controllerContext, statusHandler, operatorConfig, authnConfig)
194194
}
195195

196196
// AuthStatusHandler manages fields that are behind the CustomNoUpgrade and TechPreviewNoUpgrade featuregate sets
197197
// call Apply() only if they are enabled, otherwise server-side apply will complain
198198
if featureGates.Spec.FeatureSet == configv1.TechPreviewNoUpgrade || featureGates.Spec.FeatureSet == configv1.CustomNoUpgrade {
199199
if err := c.authStatusHandler.Apply(ctx, authnConfig); err != nil {
200-
c.statusHandler.AddConditions(status.HandleProgressingOrDegraded("AuthStatusHandler", "FailedApply", err))
201-
return c.statusHandler.FlushAndReturn(err)
200+
statusHandler.AddConditions(status.HandleProgressingOrDegraded("AuthStatusHandler", "FailedApply", err))
201+
return statusHandler.FlushAndReturn(err)
202202
}
203203
}
204204

205-
return c.statusHandler.FlushAndReturn(syncErr)
205+
return statusHandler.FlushAndReturn(syncErr)
206206
}
207207

208-
func (c *oauthClientsController) syncAuthTypeOIDC(ctx context.Context, controllerContext factory.SyncContext, operatorConfig *operatorv1.Console, authnConfig *configv1.Authentication) error {
208+
func (c *oauthClientsController) syncAuthTypeOIDC(
209+
ctx context.Context,
210+
controllerContext factory.SyncContext,
211+
statusHandler status.StatusHandler,
212+
operatorConfig *operatorv1.Console,
213+
authnConfig *configv1.Authentication,
214+
) error {
215+
209216
clientConfig := utilsub.GetOIDCClientConfig(authnConfig)
210217
if clientConfig == nil {
211218
c.authStatusHandler.WithCurrentOIDCClient("")
@@ -215,8 +222,8 @@ func (c *oauthClientsController) syncAuthTypeOIDC(ctx context.Context, controlle
215222

216223
if len(clientConfig.ClientID) == 0 {
217224
err := fmt.Errorf("no ID set on OIDC client")
218-
c.statusHandler.AddConditions(status.HandleProgressingOrDegraded("OIDCClientConfig", "MissingID", err))
219-
return c.statusHandler.FlushAndReturn(err)
225+
statusHandler.AddConditions(status.HandleProgressingOrDegraded("OIDCClientConfig", "MissingID", err))
226+
return statusHandler.FlushAndReturn(err)
220227
}
221228
c.authStatusHandler.WithCurrentOIDCClient(clientConfig.ClientID)
222229

@@ -236,7 +243,7 @@ func (c *oauthClientsController) syncAuthTypeOIDC(ctx context.Context, controlle
236243
if apierrors.IsNotFound(err) || secretsub.GetSecretString(secret) != expectedClientSecret {
237244
secret, _, err = resourceapply.ApplySecret(ctx, c.secretsClient, controllerContext.Recorder(), secretsub.DefaultSecret(operatorConfig, expectedClientSecret))
238245
if err != nil {
239-
c.statusHandler.AddConditions(status.HandleProgressingOrDegraded("OIDCClientSecretSync", "FailedApply", err))
246+
statusHandler.AddConditions(status.HandleProgressingOrDegraded("OIDCClientSecretSync", "FailedApply", err))
240247
return err
241248
}
242249
}

pkg/console/status/auth_status.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ type AuthStatusHandler struct {
2727
currentClientID string
2828
}
2929

30+
// NewAuthStatusHandler creates a handler for updating the Authentication.config.openshift.io
31+
// status with information about the expected and currently used OIDC client.
32+
// Not thread safe, only use in controllers with a single worker!
3033
func NewAuthStatusHandler(authnClient configv1client.AuthenticationInterface, componentName, componentNamespace, fieldManager string) AuthStatusHandler {
3134
return AuthStatusHandler{
3235
client: authnClient,
@@ -83,6 +86,10 @@ func (c *AuthStatusHandler) WithCurrentOIDCClient(currentClientID string) {
8386
}
8487

8588
func (c *AuthStatusHandler) Apply(ctx context.Context, authnConfig *configv1.Authentication) error {
89+
defer func() {
90+
c.conditionsToApply = map[string]*metav1.Condition{}
91+
}()
92+
8693
applyConfig, err := configv1ac.ExtractAuthenticationStatus(authnConfig, c.fieldManager)
8794
if err != nil {
8895
return err

pkg/console/status/status.go

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,32 +40,44 @@ import (
4040
// Message: error string value is used as message
4141
//
4242
// all degraded suffix conditions will be aggregated into a final "Degraded" status that will be set on the console ClusterOperator
43-
func HandleDegraded(typePrefix string, reason string, err error) v1helpers.UpdateStatusFunc {
43+
func HandleDegraded(typePrefix string, reason string, err error) ConditionUpdate {
4444
conditionType := typePrefix + operatorsv1.OperatorStatusTypeDegraded
4545
condition := handleCondition(conditionType, reason, err)
46-
return v1helpers.UpdateConditionFn(condition)
46+
return ConditionUpdate{
47+
ConditionType: conditionType,
48+
StatusUpdateFn: v1helpers.UpdateConditionFn(condition),
49+
}
4750
}
4851

49-
func HandleProgressing(typePrefix string, reason string, err error) v1helpers.UpdateStatusFunc {
52+
func HandleProgressing(typePrefix string, reason string, err error) ConditionUpdate {
5053
conditionType := typePrefix + operatorsv1.OperatorStatusTypeProgressing
5154
condition := handleCondition(conditionType, reason, err)
52-
return v1helpers.UpdateConditionFn(condition)
55+
return ConditionUpdate{
56+
ConditionType: conditionType,
57+
StatusUpdateFn: v1helpers.UpdateConditionFn(condition),
58+
}
5359
}
5460

55-
func HandleAvailable(typePrefix string, reason string, err error) v1helpers.UpdateStatusFunc {
61+
func HandleAvailable(typePrefix string, reason string, err error) ConditionUpdate {
5662
conditionType := typePrefix + operatorsv1.OperatorStatusTypeAvailable
5763
condition := handleCondition(conditionType, reason, err)
58-
return v1helpers.UpdateConditionFn(condition)
64+
return ConditionUpdate{
65+
ConditionType: conditionType,
66+
StatusUpdateFn: v1helpers.UpdateConditionFn(condition),
67+
}
5968
}
6069

61-
func HandleUpgradable(typePrefix string, reason string, err error) v1helpers.UpdateStatusFunc {
70+
func HandleUpgradable(typePrefix string, reason string, err error) ConditionUpdate {
6271
conditionType := typePrefix + operatorsv1.OperatorStatusTypeUpgradeable
6372
condition := handleCondition(conditionType, reason, err)
64-
return v1helpers.UpdateConditionFn(condition)
73+
return ConditionUpdate{
74+
ConditionType: conditionType,
75+
StatusUpdateFn: v1helpers.UpdateConditionFn(condition),
76+
}
6577
}
6678

67-
func (c *StatusHandler) ResetConditions(conditions []operatorsv1.OperatorCondition) []v1helpers.UpdateStatusFunc {
68-
updateStatusFuncs := []v1helpers.UpdateStatusFunc{}
79+
func (c *StatusHandler) ResetConditions(conditions []operatorsv1.OperatorCondition) []ConditionUpdate {
80+
updateStatusFuncs := []ConditionUpdate{}
6981
for _, condition := range conditions {
7082
klog.V(2).Info("\nresetting condition: ", condition.Type)
7183
if strings.HasSuffix(condition.Type, operatorsv1.OperatorStatusTypeDegraded) {
@@ -101,8 +113,8 @@ func (c *StatusHandler) ResetConditions(conditions []operatorsv1.OperatorConditi
101113
// - Type suffix will be set to Degraded
102114
// TODO: when we eliminate the special case SyncError, this helper can go away.
103115
// When we do that, however, we must make sure to register deprecated conditions with NewRemoveStaleConditions()
104-
func HandleProgressingOrDegraded(typePrefix string, reason string, err error) []v1helpers.UpdateStatusFunc {
105-
updateStatusFuncs := []v1helpers.UpdateStatusFunc{}
116+
func HandleProgressingOrDegraded(typePrefix string, reason string, err error) []ConditionUpdate {
117+
updateStatusFuncs := []ConditionUpdate{}
106118
if errors.IsSyncError(err) {
107119
updateStatusFuncs = append(updateStatusFuncs, HandleDegraded(typePrefix, reason, nil))
108120
updateStatusFuncs = append(updateStatusFuncs, HandleProgressing(typePrefix, reason, err))
@@ -144,22 +156,39 @@ func setConditionValue(conditionType string, err error) operatorsv1.ConditionSta
144156
}
145157

146158
type StatusHandler struct {
147-
client v1helpers.OperatorClient
159+
client v1helpers.OperatorClient
160+
// conditionUpdates are keyed by condition type so that we always choose the latest as authoritative
161+
conditionUpdates map[string]v1helpers.UpdateStatusFunc
162+
148163
statusFuncs []v1helpers.UpdateStatusFunc
149164
}
150165

151-
func (c *StatusHandler) AddCondition(newStatusFunc v1helpers.UpdateStatusFunc) {
152-
c.statusFuncs = append(c.statusFuncs, newStatusFunc)
166+
type ConditionUpdate struct {
167+
ConditionType string
168+
StatusUpdateFn v1helpers.UpdateStatusFunc
153169
}
154170

155-
func (c *StatusHandler) AddConditions(newStatusFuncs []v1helpers.UpdateStatusFunc) {
156-
for _, newStatusFunc := range newStatusFuncs {
157-
c.statusFuncs = append(c.statusFuncs, newStatusFunc)
171+
func (c *StatusHandler) AddCondition(conditionUpdate ConditionUpdate) {
172+
c.conditionUpdates[conditionUpdate.ConditionType] = conditionUpdate.StatusUpdateFn
173+
}
174+
175+
func (c *StatusHandler) AddConditions(conditionUpdates []ConditionUpdate) {
176+
for i := range conditionUpdates {
177+
conditionUpdate := conditionUpdates[i]
178+
c.conditionUpdates[conditionUpdate.ConditionType] = conditionUpdate.StatusUpdateFn
158179
}
159180
}
160181

161182
func (c *StatusHandler) FlushAndReturn(returnErr error) error {
162-
if _, _, updateErr := v1helpers.UpdateStatus(context.TODO(), c.client, c.statusFuncs...); updateErr != nil {
183+
allStatusFns := []v1helpers.UpdateStatusFunc{}
184+
for i := range c.statusFuncs {
185+
allStatusFns = append(allStatusFns, c.statusFuncs[i])
186+
}
187+
for k := range c.conditionUpdates {
188+
allStatusFns = append(allStatusFns, c.conditionUpdates[k])
189+
}
190+
191+
if _, _, updateErr := v1helpers.UpdateStatus(context.TODO(), c.client, allStatusFns...); updateErr != nil {
163192
return updateErr
164193
}
165194
return returnErr
@@ -191,7 +220,8 @@ func (c *StatusHandler) UpdateDeploymentGeneration(actualDeployment *appsv1.Depl
191220

192221
func NewStatusHandler(client v1helpers.OperatorClient) StatusHandler {
193222
return StatusHandler{
194-
client: client,
223+
client: client,
224+
conditionUpdates: map[string]v1helpers.UpdateStatusFunc{},
195225
}
196226
}
197227

vendor/github.com/openshift/library-go/pkg/operator/v1helpers/helpers.go

Lines changed: 58 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)