Skip to content

Commit 9751e8f

Browse files
committed
cvo: determine featureSet and CVO gates early
Extracting config.openshift.io informer factories allows to obtain the `FeatureGate` lister early. We need to start the the config informer factory for that but that is fine, later code can create new informers as long as it calls `Start()` again. Retrieved `FeatureGate` can then be used to read the featureSet enabled in the cluster and also the enabled and disabled CVO feature gates. This is basically identical to what CVO currently does later in `Context.InitializeFromPayload`. For now _that_ code drives the actual CVO behavior, not the values discovered by the early code. The change to switch the CVO behavior from respecting the late code to the early code will follow; this commit just sets the stage for that and allows testing the early informer start.
1 parent 41dd2d0 commit 9751e8f

File tree

1 file changed

+56
-1
lines changed

1 file changed

+56
-1
lines changed

pkg/start/start.go

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,11 @@ func (o *Options) Run(ctx context.Context) error {
189189
return err
190190
}
191191

192-
_ = o.getOpenShiftVersion()
193192
clusterVersionConfigInformerFactory, configInformerFactory := o.prepareConfigInformerFactories(cb)
193+
_, _, err = o.processInitialFeatureGate(ctx, configInformerFactory)
194+
if err != nil {
195+
return fmt.Errorf("error processing feature gates: %w", err)
196+
}
194197

195198
// initialize the controllers and attempt to load the payload information
196199
controllerCtx, err := o.NewControllerContext(cb, clusterVersionConfigInformerFactory, configInformerFactory)
@@ -239,7 +242,59 @@ func (o *Options) getOpenShiftVersion() string {
239242

240243
klog.Infof("Determined OpenShift version for this CVO: %q", releaseMetadata.Version)
241244
return releaseMetadata.Version
245+
}
246+
247+
func (o *Options) processInitialFeatureGate(ctx context.Context, configInformerFactory configinformers.SharedInformerFactory) (configv1.FeatureSet, *featuregates.CvoGates, error) {
248+
featureGates := configInformerFactory.Config().V1().FeatureGates().Lister()
249+
configInformerFactory.Start(ctx.Done())
250+
configInformerFactory.WaitForCacheSync(ctx.Done())
251+
252+
cvoOpenShiftVersion := o.getOpenShiftVersion()
253+
cvoGates := featuregates.DefaultCvoGates(cvoOpenShiftVersion)
254+
255+
var startingFeatureSet configv1.FeatureSet
256+
var clusterFeatureGate *configv1.FeatureGate
257+
258+
// client-go automatically retries some network blip errors on GETs for 30s by default, and we want to
259+
// retry the remaining ones ourselves. If we fail longer than that, the operator won't be able to do work
260+
// anyway. Return the error and crashloop.
261+
//
262+
// We implement the timeout with a context because the timeout in PollImmediateWithContext does not behave
263+
// well when ConditionFunc takes longer time to execute, like here where the GET can be retried by client-go
264+
var lastError error
265+
if err := wait.PollUntilContextTimeout(context.Background(), 2*time.Second, 25*time.Second, true, func(ctx context.Context) (bool, error) {
266+
gate, fgErr := featureGates.Get("cluster")
267+
switch {
268+
case apierrors.IsNotFound(fgErr):
269+
// if we have no featuregates, then the cluster is using the default featureset, which is "".
270+
// This excludes everything that could possibly depend on a different feature set.
271+
startingFeatureSet = ""
272+
klog.Infof("FeatureGate not found in cluster, will assume default feature set %q at startup", startingFeatureSet)
273+
return true, nil
274+
case fgErr != nil:
275+
lastError = fgErr
276+
klog.Warningf("Failed to get FeatureGate from cluster: %v", fgErr)
277+
return false, nil
278+
default:
279+
clusterFeatureGate = gate
280+
startingFeatureSet = gate.Spec.FeatureSet
281+
cvoGates = featuregates.CvoGatesFromFeatureGate(clusterFeatureGate, cvoOpenShiftVersion)
282+
klog.Infof("FeatureGate found in cluster, using its feature set %q at startup", startingFeatureSet)
283+
return true, nil
284+
}
285+
}); err != nil {
286+
if lastError != nil {
287+
return "", nil, lastError
288+
}
289+
return "", nil, err
290+
}
291+
292+
if cvoGates.UnknownVersion() {
293+
klog.Warningf("CVO features for version %s could not be detected from FeatureGate; will use defaults plus special UnknownVersion feature gate", cvoOpenShiftVersion)
294+
}
295+
klog.Infof("CVO features for version %s enabled at startup: %+v", cvoOpenShiftVersion, cvoGates)
242296

297+
return startingFeatureSet, &cvoGates, nil
243298
}
244299

245300
// run launches a number of goroutines to handle manifest application,

0 commit comments

Comments
 (0)