@@ -45,6 +45,7 @@ import (
45
45
"github.com/openshift/cluster-version-operator/pkg/customsignaturestore"
46
46
cvointernal "github.com/openshift/cluster-version-operator/pkg/cvo/internal"
47
47
"github.com/openshift/cluster-version-operator/pkg/cvo/internal/dynamicclient"
48
+ "github.com/openshift/cluster-version-operator/pkg/featuregates"
48
49
"github.com/openshift/cluster-version-operator/pkg/internal"
49
50
"github.com/openshift/cluster-version-operator/pkg/payload"
50
51
"github.com/openshift/cluster-version-operator/pkg/payload/precondition"
@@ -164,9 +165,7 @@ type Operator struct {
164
165
// via annotation
165
166
exclude string
166
167
167
- // requiredFeatureSet is set the value of featuregates.config.openshift.io|.spec.featureSet. It's a very slow
168
- // moving resource, so it is not re-detected live.
169
- requiredFeatureSet string
168
+ enabledFeatureGates featuregates.CvoGateChecker
170
169
171
170
clusterProfile string
172
171
uid types.UID
@@ -187,7 +186,6 @@ func New(
187
186
client clientset.Interface ,
188
187
kubeClient kubernetes.Interface ,
189
188
exclude string ,
190
- requiredFeatureSet string ,
191
189
clusterProfile string ,
192
190
promqlTarget clusterconditions.PromQLTarget ,
193
191
injectClusterIdIntoPromQL bool ,
@@ -219,10 +217,14 @@ func New(
219
217
upgradeableQueue : workqueue .NewNamedRateLimitingQueue (workqueue .DefaultControllerRateLimiter (), "upgradeable" ),
220
218
221
219
exclude : exclude ,
222
- requiredFeatureSet : requiredFeatureSet ,
223
220
clusterProfile : clusterProfile ,
224
221
conditionRegistry : standard .NewConditionRegistry (promqlTarget ),
225
222
injectClusterIdIntoPromQL : injectClusterIdIntoPromQL ,
223
+
224
+ // Because of OCPBUGS-30080, we can only detect the enabled feature gates after Operator loads the initial payload
225
+ // from disk via LoadInitialPayload. We must not have any gate-checking code until that happens, so we initialize
226
+ // this field with a checker that panics when used.
227
+ enabledFeatureGates : featuregates .PanicOnUsageBeforeInitialization ,
226
228
}
227
229
228
230
if _ , err := cvInformer .Informer ().AddEventHandler (optr .clusterVersionEventHandler ()); err != nil {
@@ -254,10 +256,9 @@ func New(
254
256
return optr , nil
255
257
}
256
258
257
- // InitializeFromPayload waits until a ClusterVersion object exists. It then retrieves the payload contents and verifies the
258
- // initial state, then configures the controller that loads and applies content to the cluster. It returns an error if the
259
- // payload appears to be in error rather than continuing.
260
- func (optr * Operator ) InitializeFromPayload (ctx context.Context , restConfig * rest.Config , burstRestConfig * rest.Config ) error {
259
+ // LoadInitialPayload waits until a ClusterVersion object exists. It then retrieves the payload contents, verifies the
260
+ // initial state and returns it. If the payload is invalid, an error is returned.
261
+ func (optr * Operator ) LoadInitialPayload (ctx context.Context , startingRequiredFeatureSet configv1.FeatureSet , restConfig * rest.Config ) (* payload.Update , error ) {
261
262
262
263
// wait until cluster version object exists
263
264
if err := wait .PollUntilContextCancel (ctx , 3 * time .Second , true , func (ctx context.Context ) (bool , error ) {
@@ -274,24 +275,19 @@ func (optr *Operator) InitializeFromPayload(ctx context.Context, restConfig *res
274
275
}
275
276
return true , nil
276
277
}); err != nil {
277
- return fmt .Errorf ("Error when attempting to get cluster version object: %w" , err )
278
+ return nil , fmt .Errorf ("Error when attempting to get cluster version object: %w" , err )
278
279
}
279
280
280
- update , err := payload .LoadUpdate (optr .defaultPayloadDir (), optr .release .Image , optr .exclude , optr . requiredFeatureSet ,
281
+ update , err := payload .LoadUpdate (optr .defaultPayloadDir (), optr .release .Image , optr .exclude , string ( startingRequiredFeatureSet ) ,
281
282
optr .clusterProfile , capability .GetKnownCapabilities ())
282
283
283
284
if err != nil {
284
- return fmt .Errorf ("the local release contents are invalid - no current version can be determined from disk: %v" , err )
285
+ return nil , fmt .Errorf ("the local release contents are invalid - no current version can be determined from disk: %v" , err )
285
286
}
286
-
287
- optr .release = update .Release
288
- optr .releaseCreated = update .ImageRef .CreationTimestamp .Time
289
- optr .SetArchitecture (update .Architecture )
290
-
291
287
httpClientConstructor := sigstore .NewCachedHTTPClientConstructor (optr .HTTPClient , nil )
292
288
configClient , err := coreclientsetv1 .NewForConfig (restConfig )
293
289
if err != nil {
294
- return fmt .Errorf ("unable to create a configuration client: %v" , err )
290
+ return nil , fmt .Errorf ("unable to create a configuration client: %v" , err )
295
291
}
296
292
297
293
customSignatureStore := & customsignaturestore.Store {
@@ -303,7 +299,7 @@ func (optr *Operator) InitializeFromPayload(ctx context.Context, restConfig *res
303
299
// attempt to load a verifier as defined in the payload
304
300
verifier , signatureStore , err := loadConfigMapVerifierDataFromUpdate (update , httpClientConstructor .HTTPClient , configClient , customSignatureStore )
305
301
if err != nil {
306
- return err
302
+ return nil , err
307
303
}
308
304
if verifier != nil {
309
305
klog .Infof ("Verifying release authenticity: %v" , verifier )
@@ -313,6 +309,16 @@ func (optr *Operator) InitializeFromPayload(ctx context.Context, restConfig *res
313
309
}
314
310
optr .verifier = verifier
315
311
optr .signatureStore = signatureStore
312
+ return update , nil
313
+ }
314
+
315
+ // InitializeFromPayload configures the controller that loads and applies content to the cluster given an initial payload
316
+ // and feature gate data.
317
+ func (optr * Operator ) InitializeFromPayload (update * payload.Update , requiredFeatureSet configv1.FeatureSet , cvoFlags featuregates.CvoGateChecker , restConfig * rest.Config , burstRestConfig * rest.Config ) {
318
+ optr .enabledFeatureGates = cvoFlags
319
+ optr .release = update .Release
320
+ optr .releaseCreated = update .ImageRef .CreationTimestamp .Time
321
+ optr .SetArchitecture (update .Architecture )
316
322
317
323
// after the verifier has been loaded, initialize the sync worker with a payload retriever
318
324
// which will consume the verifier
@@ -328,12 +334,10 @@ func (optr *Operator) InitializeFromPayload(ctx context.Context, restConfig *res
328
334
Cap : time .Second * 15 ,
329
335
},
330
336
optr .exclude ,
331
- optr . requiredFeatureSet ,
337
+ requiredFeatureSet ,
332
338
optr .eventRecorder ,
333
339
optr .clusterProfile ,
334
340
)
335
-
336
- return nil
337
341
}
338
342
339
343
// ownerReferenceModifier sets the owner reference to the current CV resource if no other reference exists. It also resets
0 commit comments