diff --git a/pkg/descheduler/descheduler.go b/pkg/descheduler/descheduler.go index 95bd3f50f..c3c4d60a2 100644 --- a/pkg/descheduler/descheduler.go +++ b/pkg/descheduler/descheduler.go @@ -552,6 +552,7 @@ func bootstrapDescheduler( rs *options.DeschedulerServer, deschedulerPolicy *api.DeschedulerPolicy, evictionPolicyGroupVersion string, + metricProviderTokenReconciliation tokenReconciliation, sharedInformerFactory, namespacedSharedInformerFactory informers.SharedInformerFactory, eventRecorder events.EventRecorder, ) (*descheduler, error) { @@ -585,6 +586,53 @@ func bootstrapDescheduler( } } + // init is responsible for starting all informer factories, metrics providers + // and other parts that require to start before a first descheduling cycle is run + deschedulerInitFnc := func(ctx context.Context) error { + // In dry run mode, start and sync the fake shared informer factory so it can mirror + // events from the real factory. Reliable propagation depends on both factories being + // fully synced (see WaitForCacheSync calls below), not solely on startup order. + if rs.DryRun { + descheduler.kubeClientSandbox.fakeSharedInformerFactory().Start(ctx.Done()) + descheduler.kubeClientSandbox.fakeSharedInformerFactory().WaitForCacheSync(ctx.Done()) + } + sharedInformerFactory.Start(ctx.Done()) + if metricProviderTokenReconciliation == secretReconciliation { + namespacedSharedInformerFactory.Start(ctx.Done()) + } + + sharedInformerFactory.WaitForCacheSync(ctx.Done()) + if metricProviderTokenReconciliation == secretReconciliation { + namespacedSharedInformerFactory.WaitForCacheSync(ctx.Done()) + } + + descheduler.podEvictor.WaitForEventHandlersSync(ctx) + + if descheduler.metricsCollector != nil { + go func() { + klog.V(2).Infof("Starting metrics collector") + descheduler.metricsCollector.Run(ctx) + klog.V(2).Infof("Stopped metrics collector") + }() + klog.V(2).Infof("Waiting for metrics collector to sync") + if err := wait.PollWithContext(ctx, time.Second, time.Minute, func(context.Context) (done bool, err error) { + return descheduler.metricsCollector.HasSynced(), nil + }); err != nil { + return fmt.Errorf("unable to wait for metrics collector to sync: %v", err) + } + } + + if metricProviderTokenReconciliation == secretReconciliation { + go descheduler.promClientCtrl.runAuthenticationSecretReconciler(ctx) + } + + return nil + } + + if err := deschedulerInitFnc(ctx); err != nil { + return nil, err + } + return descheduler, nil } @@ -622,49 +670,12 @@ func RunDeschedulerStrategies(ctx context.Context, rs *options.DeschedulerServer } } - descheduler, err := bootstrapDescheduler(ctx, rs, deschedulerPolicy, evictionPolicyGroupVersion, sharedInformerFactory, namespacedSharedInformerFactory, eventRecorder) + descheduler, err := bootstrapDescheduler(ctx, rs, deschedulerPolicy, evictionPolicyGroupVersion, metricProviderTokenReconciliation, sharedInformerFactory, namespacedSharedInformerFactory, eventRecorder) if err != nil { span.AddEvent("Failed to bootstrap a descheduler", trace.WithAttributes(attribute.String("err", err.Error()))) return err } - // In dry run mode, start and sync the fake shared informer factory so it can mirror - // events from the real factory. Reliable propagation depends on both factories being - // fully synced (see WaitForCacheSync calls below), not solely on startup order. - if rs.DryRun { - descheduler.kubeClientSandbox.fakeSharedInformerFactory().Start(ctx.Done()) - descheduler.kubeClientSandbox.fakeSharedInformerFactory().WaitForCacheSync(ctx.Done()) - } - sharedInformerFactory.Start(ctx.Done()) - if metricProviderTokenReconciliation == secretReconciliation { - namespacedSharedInformerFactory.Start(ctx.Done()) - } - - sharedInformerFactory.WaitForCacheSync(ctx.Done()) - if metricProviderTokenReconciliation == secretReconciliation { - namespacedSharedInformerFactory.WaitForCacheSync(ctx.Done()) - } - - descheduler.podEvictor.WaitForEventHandlersSync(ctx) - - if descheduler.metricsCollector != nil { - go func() { - klog.V(2).Infof("Starting metrics collector") - descheduler.metricsCollector.Run(ctx) - klog.V(2).Infof("Stopped metrics collector") - }() - klog.V(2).Infof("Waiting for metrics collector to sync") - if err := wait.PollWithContext(ctx, time.Second, time.Minute, func(context.Context) (done bool, err error) { - return descheduler.metricsCollector.HasSynced(), nil - }); err != nil { - return fmt.Errorf("unable to wait for metrics collector to sync: %v", err) - } - } - - if metricProviderTokenReconciliation == secretReconciliation { - go descheduler.promClientCtrl.runAuthenticationSecretReconciler(ctx) - } - wait.NonSlidingUntil(func() { if metricProviderTokenReconciliation == inClusterReconciliation { // Read the sa token and assume it has the sufficient permissions to authenticate diff --git a/pkg/descheduler/descheduler_test.go b/pkg/descheduler/descheduler_test.go index cb0854a11..37d845925 100644 --- a/pkg/descheduler/descheduler_test.go +++ b/pkg/descheduler/descheduler_test.go @@ -220,20 +220,12 @@ func initDescheduler(t *testing.T, ctx context.Context, featureGates featuregate eventBroadcaster, eventRecorder := utils.GetRecorderAndBroadcaster(ctx, client) // Always create descheduler with real client/factory first to register all informers - descheduler, err := bootstrapDescheduler(ctx, rs, internalDeschedulerPolicy, "v1", sharedInformerFactory, nil, eventRecorder) + descheduler, err := bootstrapDescheduler(ctx, rs, internalDeschedulerPolicy, "v1", noReconciliation, sharedInformerFactory, nil, eventRecorder) if err != nil { eventBroadcaster.Shutdown() t.Fatalf("Failed to bootstrap a descheduler: %v", err) } - // Start the real shared informer factory after creating the descheduler - if dryRun { - descheduler.kubeClientSandbox.fakeSharedInformerFactory().Start(ctx.Done()) - descheduler.kubeClientSandbox.fakeSharedInformerFactory().WaitForCacheSync(ctx.Done()) - } - sharedInformerFactory.Start(ctx.Done()) - sharedInformerFactory.WaitForCacheSync(ctx.Done()) - if dryRun { if err := wait.PollUntilContextTimeout(ctx, 100*time.Millisecond, 5*time.Second, true, func(ctx context.Context) (bool, error) { for _, obj := range objects {