k8s.io/kubernetes@v1.29.3/pkg/scheduler/framework/runtime/framework.go (about)

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package runtime
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"reflect"
    23  	"sort"
    24  	"time"
    25  
    26  	v1 "k8s.io/api/core/v1"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/apimachinery/pkg/types"
    29  	"k8s.io/apimachinery/pkg/util/sets"
    30  	"k8s.io/client-go/informers"
    31  	clientset "k8s.io/client-go/kubernetes"
    32  	restclient "k8s.io/client-go/rest"
    33  	"k8s.io/client-go/tools/events"
    34  	"k8s.io/component-helpers/scheduling/corev1"
    35  	"k8s.io/klog/v2"
    36  	"k8s.io/kubernetes/pkg/scheduler/apis/config"
    37  	"k8s.io/kubernetes/pkg/scheduler/framework"
    38  	"k8s.io/kubernetes/pkg/scheduler/framework/parallelize"
    39  	"k8s.io/kubernetes/pkg/scheduler/metrics"
    40  	"k8s.io/kubernetes/pkg/util/slice"
    41  )
    42  
    43  const (
    44  	// Specifies the maximum timeout a permit plugin can return.
    45  	maxTimeout = 15 * time.Minute
    46  )
    47  
    48  // frameworkImpl is the component responsible for initializing and running scheduler
    49  // plugins.
    50  type frameworkImpl struct {
    51  	registry             Registry
    52  	snapshotSharedLister framework.SharedLister
    53  	waitingPods          *waitingPodsMap
    54  	scorePluginWeight    map[string]int
    55  	preEnqueuePlugins    []framework.PreEnqueuePlugin
    56  	enqueueExtensions    []framework.EnqueueExtensions
    57  	queueSortPlugins     []framework.QueueSortPlugin
    58  	preFilterPlugins     []framework.PreFilterPlugin
    59  	filterPlugins        []framework.FilterPlugin
    60  	postFilterPlugins    []framework.PostFilterPlugin
    61  	preScorePlugins      []framework.PreScorePlugin
    62  	scorePlugins         []framework.ScorePlugin
    63  	reservePlugins       []framework.ReservePlugin
    64  	preBindPlugins       []framework.PreBindPlugin
    65  	bindPlugins          []framework.BindPlugin
    66  	postBindPlugins      []framework.PostBindPlugin
    67  	permitPlugins        []framework.PermitPlugin
    68  
    69  	clientSet       clientset.Interface
    70  	kubeConfig      *restclient.Config
    71  	eventRecorder   events.EventRecorder
    72  	informerFactory informers.SharedInformerFactory
    73  	logger          klog.Logger
    74  
    75  	metricsRecorder          *metrics.MetricAsyncRecorder
    76  	profileName              string
    77  	percentageOfNodesToScore *int32
    78  
    79  	extenders []framework.Extender
    80  	framework.PodNominator
    81  
    82  	parallelizer parallelize.Parallelizer
    83  }
    84  
    85  // extensionPoint encapsulates desired and applied set of plugins at a specific extension
    86  // point. This is used to simplify iterating over all extension points supported by the
    87  // frameworkImpl.
    88  type extensionPoint struct {
    89  	// the set of plugins to be configured at this extension point.
    90  	plugins *config.PluginSet
    91  	// a pointer to the slice storing plugins implementations that will run at this
    92  	// extension point.
    93  	slicePtr interface{}
    94  }
    95  
    96  func (f *frameworkImpl) getExtensionPoints(plugins *config.Plugins) []extensionPoint {
    97  	return []extensionPoint{
    98  		{&plugins.PreFilter, &f.preFilterPlugins},
    99  		{&plugins.Filter, &f.filterPlugins},
   100  		{&plugins.PostFilter, &f.postFilterPlugins},
   101  		{&plugins.Reserve, &f.reservePlugins},
   102  		{&plugins.PreScore, &f.preScorePlugins},
   103  		{&plugins.Score, &f.scorePlugins},
   104  		{&plugins.PreBind, &f.preBindPlugins},
   105  		{&plugins.Bind, &f.bindPlugins},
   106  		{&plugins.PostBind, &f.postBindPlugins},
   107  		{&plugins.Permit, &f.permitPlugins},
   108  		{&plugins.PreEnqueue, &f.preEnqueuePlugins},
   109  		{&plugins.QueueSort, &f.queueSortPlugins},
   110  	}
   111  }
   112  
   113  // Extenders returns the registered extenders.
   114  func (f *frameworkImpl) Extenders() []framework.Extender {
   115  	return f.extenders
   116  }
   117  
   118  type frameworkOptions struct {
   119  	componentConfigVersion string
   120  	clientSet              clientset.Interface
   121  	kubeConfig             *restclient.Config
   122  	eventRecorder          events.EventRecorder
   123  	informerFactory        informers.SharedInformerFactory
   124  	snapshotSharedLister   framework.SharedLister
   125  	metricsRecorder        *metrics.MetricAsyncRecorder
   126  	podNominator           framework.PodNominator
   127  	extenders              []framework.Extender
   128  	captureProfile         CaptureProfile
   129  	parallelizer           parallelize.Parallelizer
   130  	logger                 *klog.Logger
   131  }
   132  
   133  // Option for the frameworkImpl.
   134  type Option func(*frameworkOptions)
   135  
   136  // WithComponentConfigVersion sets the component config version to the
   137  // KubeSchedulerConfiguration version used. The string should be the full
   138  // scheme group/version of the external type we converted from (for example
   139  // "kubescheduler.config.k8s.io/v1")
   140  func WithComponentConfigVersion(componentConfigVersion string) Option {
   141  	return func(o *frameworkOptions) {
   142  		o.componentConfigVersion = componentConfigVersion
   143  	}
   144  }
   145  
   146  // WithClientSet sets clientSet for the scheduling frameworkImpl.
   147  func WithClientSet(clientSet clientset.Interface) Option {
   148  	return func(o *frameworkOptions) {
   149  		o.clientSet = clientSet
   150  	}
   151  }
   152  
   153  // WithKubeConfig sets kubeConfig for the scheduling frameworkImpl.
   154  func WithKubeConfig(kubeConfig *restclient.Config) Option {
   155  	return func(o *frameworkOptions) {
   156  		o.kubeConfig = kubeConfig
   157  	}
   158  }
   159  
   160  // WithEventRecorder sets clientSet for the scheduling frameworkImpl.
   161  func WithEventRecorder(recorder events.EventRecorder) Option {
   162  	return func(o *frameworkOptions) {
   163  		o.eventRecorder = recorder
   164  	}
   165  }
   166  
   167  // WithInformerFactory sets informer factory for the scheduling frameworkImpl.
   168  func WithInformerFactory(informerFactory informers.SharedInformerFactory) Option {
   169  	return func(o *frameworkOptions) {
   170  		o.informerFactory = informerFactory
   171  	}
   172  }
   173  
   174  // WithSnapshotSharedLister sets the SharedLister of the snapshot.
   175  func WithSnapshotSharedLister(snapshotSharedLister framework.SharedLister) Option {
   176  	return func(o *frameworkOptions) {
   177  		o.snapshotSharedLister = snapshotSharedLister
   178  	}
   179  }
   180  
   181  // WithPodNominator sets podNominator for the scheduling frameworkImpl.
   182  func WithPodNominator(nominator framework.PodNominator) Option {
   183  	return func(o *frameworkOptions) {
   184  		o.podNominator = nominator
   185  	}
   186  }
   187  
   188  // WithExtenders sets extenders for the scheduling frameworkImpl.
   189  func WithExtenders(extenders []framework.Extender) Option {
   190  	return func(o *frameworkOptions) {
   191  		o.extenders = extenders
   192  	}
   193  }
   194  
   195  // WithParallelism sets parallelism for the scheduling frameworkImpl.
   196  func WithParallelism(parallelism int) Option {
   197  	return func(o *frameworkOptions) {
   198  		o.parallelizer = parallelize.NewParallelizer(parallelism)
   199  	}
   200  }
   201  
   202  // CaptureProfile is a callback to capture a finalized profile.
   203  type CaptureProfile func(config.KubeSchedulerProfile)
   204  
   205  // WithCaptureProfile sets a callback to capture the finalized profile.
   206  func WithCaptureProfile(c CaptureProfile) Option {
   207  	return func(o *frameworkOptions) {
   208  		o.captureProfile = c
   209  	}
   210  }
   211  
   212  // WithMetricsRecorder sets metrics recorder for the scheduling frameworkImpl.
   213  func WithMetricsRecorder(r *metrics.MetricAsyncRecorder) Option {
   214  	return func(o *frameworkOptions) {
   215  		o.metricsRecorder = r
   216  	}
   217  }
   218  
   219  // WithLogger overrides the default logger from k8s.io/klog.
   220  func WithLogger(logger klog.Logger) Option {
   221  	return func(o *frameworkOptions) {
   222  		o.logger = &logger
   223  	}
   224  }
   225  
   226  // defaultFrameworkOptions are applied when no option corresponding to those fields exist.
   227  func defaultFrameworkOptions(stopCh <-chan struct{}) frameworkOptions {
   228  	return frameworkOptions{
   229  		metricsRecorder: metrics.NewMetricsAsyncRecorder(1000, time.Second, stopCh),
   230  		parallelizer:    parallelize.NewParallelizer(parallelize.DefaultParallelism),
   231  	}
   232  }
   233  
   234  var _ framework.Framework = &frameworkImpl{}
   235  
   236  // NewFramework initializes plugins given the configuration and the registry.
   237  func NewFramework(ctx context.Context, r Registry, profile *config.KubeSchedulerProfile, opts ...Option) (framework.Framework, error) {
   238  	options := defaultFrameworkOptions(ctx.Done())
   239  	for _, opt := range opts {
   240  		opt(&options)
   241  	}
   242  
   243  	logger := klog.FromContext(ctx)
   244  	if options.logger != nil {
   245  		logger = *options.logger
   246  	}
   247  
   248  	f := &frameworkImpl{
   249  		registry:             r,
   250  		snapshotSharedLister: options.snapshotSharedLister,
   251  		scorePluginWeight:    make(map[string]int),
   252  		waitingPods:          newWaitingPodsMap(),
   253  		clientSet:            options.clientSet,
   254  		kubeConfig:           options.kubeConfig,
   255  		eventRecorder:        options.eventRecorder,
   256  		informerFactory:      options.informerFactory,
   257  		metricsRecorder:      options.metricsRecorder,
   258  		extenders:            options.extenders,
   259  		PodNominator:         options.podNominator,
   260  		parallelizer:         options.parallelizer,
   261  		logger:               logger,
   262  	}
   263  
   264  	if profile == nil {
   265  		return f, nil
   266  	}
   267  
   268  	f.profileName = profile.SchedulerName
   269  	f.percentageOfNodesToScore = profile.PercentageOfNodesToScore
   270  	if profile.Plugins == nil {
   271  		return f, nil
   272  	}
   273  
   274  	// get needed plugins from config
   275  	pg := f.pluginsNeeded(profile.Plugins)
   276  
   277  	pluginConfig := make(map[string]runtime.Object, len(profile.PluginConfig))
   278  	for i := range profile.PluginConfig {
   279  		name := profile.PluginConfig[i].Name
   280  		if _, ok := pluginConfig[name]; ok {
   281  			return nil, fmt.Errorf("repeated config for plugin %s", name)
   282  		}
   283  		pluginConfig[name] = profile.PluginConfig[i].Args
   284  	}
   285  	outputProfile := config.KubeSchedulerProfile{
   286  		SchedulerName:            f.profileName,
   287  		PercentageOfNodesToScore: f.percentageOfNodesToScore,
   288  		Plugins:                  profile.Plugins,
   289  		PluginConfig:             make([]config.PluginConfig, 0, len(pg)),
   290  	}
   291  
   292  	pluginsMap := make(map[string]framework.Plugin)
   293  	for name, factory := range r {
   294  		// initialize only needed plugins.
   295  		if !pg.Has(name) {
   296  			continue
   297  		}
   298  
   299  		args := pluginConfig[name]
   300  		if args != nil {
   301  			outputProfile.PluginConfig = append(outputProfile.PluginConfig, config.PluginConfig{
   302  				Name: name,
   303  				Args: args,
   304  			})
   305  		}
   306  		p, err := factory(ctx, args, f)
   307  		if err != nil {
   308  			return nil, fmt.Errorf("initializing plugin %q: %w", name, err)
   309  		}
   310  		pluginsMap[name] = p
   311  
   312  		f.fillEnqueueExtensions(p)
   313  	}
   314  
   315  	// initialize plugins per individual extension points
   316  	for _, e := range f.getExtensionPoints(profile.Plugins) {
   317  		if err := updatePluginList(e.slicePtr, *e.plugins, pluginsMap); err != nil {
   318  			return nil, err
   319  		}
   320  	}
   321  
   322  	// initialize multiPoint plugins to their expanded extension points
   323  	if len(profile.Plugins.MultiPoint.Enabled) > 0 {
   324  		if err := f.expandMultiPointPlugins(logger, profile, pluginsMap); err != nil {
   325  			return nil, err
   326  		}
   327  	}
   328  
   329  	if len(f.queueSortPlugins) != 1 {
   330  		return nil, fmt.Errorf("only one queue sort plugin required for profile with scheduler name %q, but got %d", profile.SchedulerName, len(f.queueSortPlugins))
   331  	}
   332  	if len(f.bindPlugins) == 0 {
   333  		return nil, fmt.Errorf("at least one bind plugin is needed for profile with scheduler name %q", profile.SchedulerName)
   334  	}
   335  
   336  	if err := getScoreWeights(f, pluginsMap, append(profile.Plugins.Score.Enabled, profile.Plugins.MultiPoint.Enabled...)); err != nil {
   337  		return nil, err
   338  	}
   339  
   340  	// Verifying the score weights again since Plugin.Name() could return a different
   341  	// value from the one used in the configuration.
   342  	for _, scorePlugin := range f.scorePlugins {
   343  		if f.scorePluginWeight[scorePlugin.Name()] == 0 {
   344  			return nil, fmt.Errorf("score plugin %q is not configured with weight", scorePlugin.Name())
   345  		}
   346  	}
   347  
   348  	if options.captureProfile != nil {
   349  		if len(outputProfile.PluginConfig) != 0 {
   350  			sort.Slice(outputProfile.PluginConfig, func(i, j int) bool {
   351  				return outputProfile.PluginConfig[i].Name < outputProfile.PluginConfig[j].Name
   352  			})
   353  		} else {
   354  			outputProfile.PluginConfig = nil
   355  		}
   356  		options.captureProfile(outputProfile)
   357  	}
   358  
   359  	f.setInstrumentedPlugins()
   360  	return f, nil
   361  }
   362  
   363  // setInstrumentedPlugins initializes instrumented plugins from current plugins that frameworkImpl has.
   364  func (f *frameworkImpl) setInstrumentedPlugins() {
   365  	// Cache metric streams for prefilter and filter plugins.
   366  	for i, pl := range f.preFilterPlugins {
   367  		f.preFilterPlugins[i] = &instrumentedPreFilterPlugin{
   368  			PreFilterPlugin: f.preFilterPlugins[i],
   369  			metric:          metrics.PluginEvaluationTotal.WithLabelValues(pl.Name(), metrics.PreFilter, f.profileName),
   370  		}
   371  	}
   372  	for i, pl := range f.filterPlugins {
   373  		f.filterPlugins[i] = &instrumentedFilterPlugin{
   374  			FilterPlugin: f.filterPlugins[i],
   375  			metric:       metrics.PluginEvaluationTotal.WithLabelValues(pl.Name(), metrics.Filter, f.profileName),
   376  		}
   377  	}
   378  
   379  	// Cache metric streams for prescore and score plugins.
   380  	for i, pl := range f.preScorePlugins {
   381  		f.preScorePlugins[i] = &instrumentedPreScorePlugin{
   382  			PreScorePlugin: f.preScorePlugins[i],
   383  			metric:         metrics.PluginEvaluationTotal.WithLabelValues(pl.Name(), metrics.PreScore, f.profileName),
   384  		}
   385  	}
   386  	for i, pl := range f.scorePlugins {
   387  		f.scorePlugins[i] = &instrumentedScorePlugin{
   388  			ScorePlugin: f.scorePlugins[i],
   389  			metric:      metrics.PluginEvaluationTotal.WithLabelValues(pl.Name(), metrics.Score, f.profileName),
   390  		}
   391  	}
   392  }
   393  
   394  func (f *frameworkImpl) SetPodNominator(n framework.PodNominator) {
   395  	f.PodNominator = n
   396  }
   397  
   398  // getScoreWeights makes sure that, between MultiPoint-Score plugin weights and individual Score
   399  // plugin weights there is not an overflow of MaxTotalScore.
   400  func getScoreWeights(f *frameworkImpl, pluginsMap map[string]framework.Plugin, plugins []config.Plugin) error {
   401  	var totalPriority int64
   402  	scorePlugins := reflect.ValueOf(&f.scorePlugins).Elem()
   403  	pluginType := scorePlugins.Type().Elem()
   404  	for _, e := range plugins {
   405  		pg := pluginsMap[e.Name]
   406  		if !reflect.TypeOf(pg).Implements(pluginType) {
   407  			continue
   408  		}
   409  
   410  		// We append MultiPoint plugins to the list of Score plugins. So if this plugin has already been
   411  		// encountered, let the individual Score weight take precedence.
   412  		if _, ok := f.scorePluginWeight[e.Name]; ok {
   413  			continue
   414  		}
   415  		// a weight of zero is not permitted, plugins can be disabled explicitly
   416  		// when configured.
   417  		f.scorePluginWeight[e.Name] = int(e.Weight)
   418  		if f.scorePluginWeight[e.Name] == 0 {
   419  			f.scorePluginWeight[e.Name] = 1
   420  		}
   421  
   422  		// Checks totalPriority against MaxTotalScore to avoid overflow
   423  		if int64(f.scorePluginWeight[e.Name])*framework.MaxNodeScore > framework.MaxTotalScore-totalPriority {
   424  			return fmt.Errorf("total score of Score plugins could overflow")
   425  		}
   426  		totalPriority += int64(f.scorePluginWeight[e.Name]) * framework.MaxNodeScore
   427  	}
   428  	return nil
   429  }
   430  
   431  type orderedSet struct {
   432  	set         map[string]int
   433  	list        []string
   434  	deletionCnt int
   435  }
   436  
   437  func newOrderedSet() *orderedSet {
   438  	return &orderedSet{set: make(map[string]int)}
   439  }
   440  
   441  func (os *orderedSet) insert(s string) {
   442  	if os.has(s) {
   443  		return
   444  	}
   445  	os.set[s] = len(os.list)
   446  	os.list = append(os.list, s)
   447  }
   448  
   449  func (os *orderedSet) has(s string) bool {
   450  	_, found := os.set[s]
   451  	return found
   452  }
   453  
   454  func (os *orderedSet) delete(s string) {
   455  	if i, found := os.set[s]; found {
   456  		delete(os.set, s)
   457  		os.list = append(os.list[:i-os.deletionCnt], os.list[i+1-os.deletionCnt:]...)
   458  		os.deletionCnt++
   459  	}
   460  }
   461  
   462  func (f *frameworkImpl) expandMultiPointPlugins(logger klog.Logger, profile *config.KubeSchedulerProfile, pluginsMap map[string]framework.Plugin) error {
   463  	// initialize MultiPoint plugins
   464  	for _, e := range f.getExtensionPoints(profile.Plugins) {
   465  		plugins := reflect.ValueOf(e.slicePtr).Elem()
   466  		pluginType := plugins.Type().Elem()
   467  		// build enabledSet of plugins already registered via normal extension points
   468  		// to check double registration
   469  		enabledSet := newOrderedSet()
   470  		for _, plugin := range e.plugins.Enabled {
   471  			enabledSet.insert(plugin.Name)
   472  		}
   473  
   474  		disabledSet := sets.New[string]()
   475  		for _, disabledPlugin := range e.plugins.Disabled {
   476  			disabledSet.Insert(disabledPlugin.Name)
   477  		}
   478  		if disabledSet.Has("*") {
   479  			logger.V(4).Info("Skipped MultiPoint expansion because all plugins are disabled for extension point", "extension", pluginType)
   480  			continue
   481  		}
   482  
   483  		// track plugins enabled via multipoint separately from those enabled by specific extensions,
   484  		// so that we can distinguish between double-registration and explicit overrides
   485  		multiPointEnabled := newOrderedSet()
   486  		overridePlugins := newOrderedSet()
   487  		for _, ep := range profile.Plugins.MultiPoint.Enabled {
   488  			pg, ok := pluginsMap[ep.Name]
   489  			if !ok {
   490  				return fmt.Errorf("%s %q does not exist", pluginType.Name(), ep.Name)
   491  			}
   492  
   493  			// if this plugin doesn't implement the type for the current extension we're trying to expand, skip
   494  			if !reflect.TypeOf(pg).Implements(pluginType) {
   495  				continue
   496  			}
   497  
   498  			// a plugin that's enabled via MultiPoint can still be disabled for specific extension points
   499  			if disabledSet.Has(ep.Name) {
   500  				logger.V(4).Info("Skipped disabled plugin for extension point", "plugin", ep.Name, "extension", pluginType)
   501  				continue
   502  			}
   503  
   504  			// if this plugin has already been enabled by the specific extension point,
   505  			// the user intent is to override the default plugin or make some other explicit setting.
   506  			// Either way, discard the MultiPoint value for this plugin.
   507  			// This maintains expected behavior for overriding default plugins (see https://github.com/kubernetes/kubernetes/pull/99582)
   508  			if enabledSet.has(ep.Name) {
   509  				overridePlugins.insert(ep.Name)
   510  				logger.Info("MultiPoint plugin is explicitly re-configured; overriding", "plugin", ep.Name)
   511  				continue
   512  			}
   513  
   514  			// if this plugin is already registered via MultiPoint, then this is
   515  			// a double registration and an error in the config.
   516  			if multiPointEnabled.has(ep.Name) {
   517  				return fmt.Errorf("plugin %q already registered as %q", ep.Name, pluginType.Name())
   518  			}
   519  
   520  			// we only need to update the multipoint set, since we already have the specific extension set from above
   521  			multiPointEnabled.insert(ep.Name)
   522  		}
   523  
   524  		// Reorder plugins. Here is the expected order:
   525  		// - part 1: overridePlugins. Their order stay intact as how they're specified in regular extension point.
   526  		// - part 2: multiPointEnabled - i.e., plugin defined in multipoint but not in regular extension point.
   527  		// - part 3: other plugins (excluded by part 1 & 2) in regular extension point.
   528  		newPlugins := reflect.New(reflect.TypeOf(e.slicePtr).Elem()).Elem()
   529  		// part 1
   530  		for _, name := range slice.CopyStrings(enabledSet.list) {
   531  			if overridePlugins.has(name) {
   532  				newPlugins = reflect.Append(newPlugins, reflect.ValueOf(pluginsMap[name]))
   533  				enabledSet.delete(name)
   534  			}
   535  		}
   536  		// part 2
   537  		for _, name := range multiPointEnabled.list {
   538  			newPlugins = reflect.Append(newPlugins, reflect.ValueOf(pluginsMap[name]))
   539  		}
   540  		// part 3
   541  		for _, name := range enabledSet.list {
   542  			newPlugins = reflect.Append(newPlugins, reflect.ValueOf(pluginsMap[name]))
   543  		}
   544  		plugins.Set(newPlugins)
   545  	}
   546  	return nil
   547  }
   548  
   549  func shouldHaveEnqueueExtensions(p framework.Plugin) bool {
   550  	switch p.(type) {
   551  	// Only PreEnqueue, PreFilter, Filter, Reserve, and Permit plugins can (should) have EnqueueExtensions.
   552  	// See the comment of EnqueueExtensions for more detailed reason here.
   553  	case framework.PreEnqueuePlugin, framework.PreFilterPlugin, framework.FilterPlugin, framework.ReservePlugin, framework.PermitPlugin:
   554  		return true
   555  	}
   556  	return false
   557  }
   558  
   559  func (f *frameworkImpl) fillEnqueueExtensions(p framework.Plugin) {
   560  	if !shouldHaveEnqueueExtensions(p) {
   561  		// Ignore EnqueueExtensions from plugin which isn't PreEnqueue, PreFilter, Filter, Reserve, and Permit.
   562  		return
   563  	}
   564  
   565  	ext, ok := p.(framework.EnqueueExtensions)
   566  	if !ok {
   567  		// If interface EnqueueExtensions is not implemented, register the default enqueue extensions
   568  		// to the plugin because we don't know which events the plugin is interested in.
   569  		// This is to ensure backward compatibility.
   570  		f.enqueueExtensions = append(f.enqueueExtensions, &defaultEnqueueExtension{pluginName: p.Name()})
   571  		return
   572  	}
   573  
   574  	f.enqueueExtensions = append(f.enqueueExtensions, ext)
   575  }
   576  
   577  // defaultEnqueueExtension is used when a plugin does not implement EnqueueExtensions interface.
   578  type defaultEnqueueExtension struct {
   579  	pluginName string
   580  }
   581  
   582  func (p *defaultEnqueueExtension) Name() string { return p.pluginName }
   583  func (p *defaultEnqueueExtension) EventsToRegister() []framework.ClusterEventWithHint {
   584  	// need to return all specific cluster events with framework.All action instead of wildcard event
   585  	// because the returning values are used to register event handlers.
   586  	// If we return the wildcard here, it won't affect the event handlers registered by the plugin
   587  	// and some events may not be registered in the event handlers.
   588  	return framework.UnrollWildCardResource()
   589  }
   590  
   591  func updatePluginList(pluginList interface{}, pluginSet config.PluginSet, pluginsMap map[string]framework.Plugin) error {
   592  	plugins := reflect.ValueOf(pluginList).Elem()
   593  	pluginType := plugins.Type().Elem()
   594  	set := sets.New[string]()
   595  	for _, ep := range pluginSet.Enabled {
   596  		pg, ok := pluginsMap[ep.Name]
   597  		if !ok {
   598  			return fmt.Errorf("%s %q does not exist", pluginType.Name(), ep.Name)
   599  		}
   600  
   601  		if !reflect.TypeOf(pg).Implements(pluginType) {
   602  			return fmt.Errorf("plugin %q does not extend %s plugin", ep.Name, pluginType.Name())
   603  		}
   604  
   605  		if set.Has(ep.Name) {
   606  			return fmt.Errorf("plugin %q already registered as %q", ep.Name, pluginType.Name())
   607  		}
   608  
   609  		set.Insert(ep.Name)
   610  
   611  		newPlugins := reflect.Append(plugins, reflect.ValueOf(pg))
   612  		plugins.Set(newPlugins)
   613  	}
   614  	return nil
   615  }
   616  
   617  // PreEnqueuePlugins returns the registered preEnqueue plugins.
   618  func (f *frameworkImpl) PreEnqueuePlugins() []framework.PreEnqueuePlugin {
   619  	return f.preEnqueuePlugins
   620  }
   621  
   622  // EnqueueExtensions returns the registered reenqueue plugins.
   623  func (f *frameworkImpl) EnqueueExtensions() []framework.EnqueueExtensions {
   624  	return f.enqueueExtensions
   625  }
   626  
   627  // QueueSortFunc returns the function to sort pods in scheduling queue
   628  func (f *frameworkImpl) QueueSortFunc() framework.LessFunc {
   629  	if f == nil {
   630  		// If frameworkImpl is nil, simply keep their order unchanged.
   631  		// NOTE: this is primarily for tests.
   632  		return func(_, _ *framework.QueuedPodInfo) bool { return false }
   633  	}
   634  
   635  	if len(f.queueSortPlugins) == 0 {
   636  		panic("No QueueSort plugin is registered in the frameworkImpl.")
   637  	}
   638  
   639  	// Only one QueueSort plugin can be enabled.
   640  	return f.queueSortPlugins[0].Less
   641  }
   642  
   643  // RunPreFilterPlugins runs the set of configured PreFilter plugins. It returns
   644  // *Status and its code is set to non-success if any of the plugins returns
   645  // anything but Success/Skip.
   646  // When it returns Skip status, returned PreFilterResult and other fields in status are just ignored,
   647  // and coupled Filter plugin/PreFilterExtensions() will be skipped in this scheduling cycle.
   648  // If a non-success status is returned, then the scheduling cycle is aborted.
   649  func (f *frameworkImpl) RunPreFilterPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod) (_ *framework.PreFilterResult, status *framework.Status) {
   650  	startTime := time.Now()
   651  	skipPlugins := sets.New[string]()
   652  	defer func() {
   653  		state.SkipFilterPlugins = skipPlugins
   654  		metrics.FrameworkExtensionPointDuration.WithLabelValues(metrics.PreFilter, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime))
   655  	}()
   656  	var result *framework.PreFilterResult
   657  	var pluginsWithNodes []string
   658  	logger := klog.FromContext(ctx)
   659  	verboseLogs := logger.V(4).Enabled()
   660  	if verboseLogs {
   661  		logger = klog.LoggerWithName(logger, "PreFilter")
   662  	}
   663  	for _, pl := range f.preFilterPlugins {
   664  		ctx := ctx
   665  		if verboseLogs {
   666  			logger := klog.LoggerWithName(logger, pl.Name())
   667  			ctx = klog.NewContext(ctx, logger)
   668  		}
   669  		r, s := f.runPreFilterPlugin(ctx, pl, state, pod)
   670  		if s.IsSkip() {
   671  			skipPlugins.Insert(pl.Name())
   672  			continue
   673  		}
   674  		if !s.IsSuccess() {
   675  			s.SetPlugin(pl.Name())
   676  			if s.IsRejected() {
   677  				return nil, s
   678  			}
   679  			return nil, framework.AsStatus(fmt.Errorf("running PreFilter plugin %q: %w", pl.Name(), s.AsError())).WithPlugin(pl.Name())
   680  		}
   681  		if !r.AllNodes() {
   682  			pluginsWithNodes = append(pluginsWithNodes, pl.Name())
   683  		}
   684  		result = result.Merge(r)
   685  		if !result.AllNodes() && len(result.NodeNames) == 0 {
   686  			msg := fmt.Sprintf("node(s) didn't satisfy plugin(s) %v simultaneously", pluginsWithNodes)
   687  			if len(pluginsWithNodes) == 1 {
   688  				msg = fmt.Sprintf("node(s) didn't satisfy plugin %v", pluginsWithNodes[0])
   689  			}
   690  			return nil, framework.NewStatus(framework.Unschedulable, msg)
   691  		}
   692  	}
   693  	return result, nil
   694  }
   695  
   696  func (f *frameworkImpl) runPreFilterPlugin(ctx context.Context, pl framework.PreFilterPlugin, state *framework.CycleState, pod *v1.Pod) (*framework.PreFilterResult, *framework.Status) {
   697  	if !state.ShouldRecordPluginMetrics() {
   698  		return pl.PreFilter(ctx, state, pod)
   699  	}
   700  	startTime := time.Now()
   701  	result, status := pl.PreFilter(ctx, state, pod)
   702  	f.metricsRecorder.ObservePluginDurationAsync(metrics.PreFilter, pl.Name(), status.Code().String(), metrics.SinceInSeconds(startTime))
   703  	return result, status
   704  }
   705  
   706  // RunPreFilterExtensionAddPod calls the AddPod interface for the set of configured
   707  // PreFilter plugins. It returns directly if any of the plugins return any
   708  // status other than Success.
   709  func (f *frameworkImpl) RunPreFilterExtensionAddPod(
   710  	ctx context.Context,
   711  	state *framework.CycleState,
   712  	podToSchedule *v1.Pod,
   713  	podInfoToAdd *framework.PodInfo,
   714  	nodeInfo *framework.NodeInfo,
   715  ) (status *framework.Status) {
   716  	logger := klog.FromContext(ctx)
   717  	verboseLogs := logger.V(4).Enabled()
   718  	if verboseLogs {
   719  		logger = klog.LoggerWithName(logger, "PreFilterExtension")
   720  	}
   721  	for _, pl := range f.preFilterPlugins {
   722  		if pl.PreFilterExtensions() == nil || state.SkipFilterPlugins.Has(pl.Name()) {
   723  			continue
   724  		}
   725  		ctx := ctx
   726  		if verboseLogs {
   727  			logger := klog.LoggerWithName(logger, pl.Name())
   728  			ctx = klog.NewContext(ctx, logger)
   729  		}
   730  		status = f.runPreFilterExtensionAddPod(ctx, pl, state, podToSchedule, podInfoToAdd, nodeInfo)
   731  		if !status.IsSuccess() {
   732  			err := status.AsError()
   733  			logger.Error(err, "Plugin failed", "pod", klog.KObj(podToSchedule), "node", klog.KObj(nodeInfo.Node()), "operation", "addPod", "plugin", pl.Name())
   734  			return framework.AsStatus(fmt.Errorf("running AddPod on PreFilter plugin %q: %w", pl.Name(), err))
   735  		}
   736  	}
   737  
   738  	return nil
   739  }
   740  
   741  func (f *frameworkImpl) runPreFilterExtensionAddPod(ctx context.Context, pl framework.PreFilterPlugin, state *framework.CycleState, podToSchedule *v1.Pod, podInfoToAdd *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status {
   742  	if !state.ShouldRecordPluginMetrics() {
   743  		return pl.PreFilterExtensions().AddPod(ctx, state, podToSchedule, podInfoToAdd, nodeInfo)
   744  	}
   745  	startTime := time.Now()
   746  	status := pl.PreFilterExtensions().AddPod(ctx, state, podToSchedule, podInfoToAdd, nodeInfo)
   747  	f.metricsRecorder.ObservePluginDurationAsync(metrics.PreFilterExtensionAddPod, pl.Name(), status.Code().String(), metrics.SinceInSeconds(startTime))
   748  	return status
   749  }
   750  
   751  // RunPreFilterExtensionRemovePod calls the RemovePod interface for the set of configured
   752  // PreFilter plugins. It returns directly if any of the plugins return any
   753  // status other than Success.
   754  func (f *frameworkImpl) RunPreFilterExtensionRemovePod(
   755  	ctx context.Context,
   756  	state *framework.CycleState,
   757  	podToSchedule *v1.Pod,
   758  	podInfoToRemove *framework.PodInfo,
   759  	nodeInfo *framework.NodeInfo,
   760  ) (status *framework.Status) {
   761  	logger := klog.FromContext(ctx)
   762  	verboseLogs := logger.V(4).Enabled()
   763  	if verboseLogs {
   764  		logger = klog.LoggerWithName(logger, "PreFilterExtension")
   765  	}
   766  	for _, pl := range f.preFilterPlugins {
   767  		if pl.PreFilterExtensions() == nil || state.SkipFilterPlugins.Has(pl.Name()) {
   768  			continue
   769  		}
   770  		ctx := ctx
   771  		if verboseLogs {
   772  			logger := klog.LoggerWithName(logger, pl.Name())
   773  			ctx = klog.NewContext(ctx, logger)
   774  		}
   775  		status = f.runPreFilterExtensionRemovePod(ctx, pl, state, podToSchedule, podInfoToRemove, nodeInfo)
   776  		if !status.IsSuccess() {
   777  			err := status.AsError()
   778  			logger.Error(err, "Plugin failed", "node", klog.KObj(nodeInfo.Node()), "operation", "removePod", "plugin", pl.Name(), "pod", klog.KObj(podToSchedule))
   779  			return framework.AsStatus(fmt.Errorf("running RemovePod on PreFilter plugin %q: %w", pl.Name(), err))
   780  		}
   781  	}
   782  
   783  	return nil
   784  }
   785  
   786  func (f *frameworkImpl) runPreFilterExtensionRemovePod(ctx context.Context, pl framework.PreFilterPlugin, state *framework.CycleState, podToSchedule *v1.Pod, podInfoToRemove *framework.PodInfo, nodeInfo *framework.NodeInfo) *framework.Status {
   787  	if !state.ShouldRecordPluginMetrics() {
   788  		return pl.PreFilterExtensions().RemovePod(ctx, state, podToSchedule, podInfoToRemove, nodeInfo)
   789  	}
   790  	startTime := time.Now()
   791  	status := pl.PreFilterExtensions().RemovePod(ctx, state, podToSchedule, podInfoToRemove, nodeInfo)
   792  	f.metricsRecorder.ObservePluginDurationAsync(metrics.PreFilterExtensionRemovePod, pl.Name(), status.Code().String(), metrics.SinceInSeconds(startTime))
   793  	return status
   794  }
   795  
   796  // RunFilterPlugins runs the set of configured Filter plugins for pod on
   797  // the given node. If any of these plugins doesn't return "Success", the
   798  // given node is not suitable for running pod.
   799  // Meanwhile, the failure message and status are set for the given node.
   800  func (f *frameworkImpl) RunFilterPlugins(
   801  	ctx context.Context,
   802  	state *framework.CycleState,
   803  	pod *v1.Pod,
   804  	nodeInfo *framework.NodeInfo,
   805  ) *framework.Status {
   806  	logger := klog.FromContext(ctx)
   807  	verboseLogs := logger.V(4).Enabled()
   808  	if verboseLogs {
   809  		logger = klog.LoggerWithName(logger, "Filter")
   810  	}
   811  
   812  	for _, pl := range f.filterPlugins {
   813  		if state.SkipFilterPlugins.Has(pl.Name()) {
   814  			continue
   815  		}
   816  		ctx := ctx
   817  		if verboseLogs {
   818  			logger := klog.LoggerWithName(logger, pl.Name())
   819  			ctx = klog.NewContext(ctx, logger)
   820  		}
   821  		if status := f.runFilterPlugin(ctx, pl, state, pod, nodeInfo); !status.IsSuccess() {
   822  			if !status.IsRejected() {
   823  				// Filter plugins are not supposed to return any status other than
   824  				// Success or Unschedulable.
   825  				status = framework.AsStatus(fmt.Errorf("running %q filter plugin: %w", pl.Name(), status.AsError()))
   826  			}
   827  			status.SetPlugin(pl.Name())
   828  			return status
   829  		}
   830  	}
   831  
   832  	return nil
   833  }
   834  
   835  func (f *frameworkImpl) runFilterPlugin(ctx context.Context, pl framework.FilterPlugin, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
   836  	if !state.ShouldRecordPluginMetrics() {
   837  		return pl.Filter(ctx, state, pod, nodeInfo)
   838  	}
   839  	startTime := time.Now()
   840  	status := pl.Filter(ctx, state, pod, nodeInfo)
   841  	f.metricsRecorder.ObservePluginDurationAsync(metrics.Filter, pl.Name(), status.Code().String(), metrics.SinceInSeconds(startTime))
   842  	return status
   843  }
   844  
   845  // RunPostFilterPlugins runs the set of configured PostFilter plugins until the first
   846  // Success, Error or UnschedulableAndUnresolvable is met; otherwise continues to execute all plugins.
   847  func (f *frameworkImpl) RunPostFilterPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, filteredNodeStatusMap framework.NodeToStatusMap) (_ *framework.PostFilterResult, status *framework.Status) {
   848  	startTime := time.Now()
   849  	defer func() {
   850  		metrics.FrameworkExtensionPointDuration.WithLabelValues(metrics.PostFilter, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime))
   851  	}()
   852  
   853  	logger := klog.FromContext(ctx)
   854  	verboseLogs := logger.V(4).Enabled()
   855  	if verboseLogs {
   856  		logger = klog.LoggerWithName(logger, "PostFilter")
   857  	}
   858  
   859  	// `result` records the last meaningful(non-noop) PostFilterResult.
   860  	var result *framework.PostFilterResult
   861  	var reasons []string
   862  	var rejectorPlugin string
   863  	for _, pl := range f.postFilterPlugins {
   864  		ctx := ctx
   865  		if verboseLogs {
   866  			logger := klog.LoggerWithName(logger, pl.Name())
   867  			ctx = klog.NewContext(ctx, logger)
   868  		}
   869  		r, s := f.runPostFilterPlugin(ctx, pl, state, pod, filteredNodeStatusMap)
   870  		if s.IsSuccess() {
   871  			return r, s
   872  		} else if s.Code() == framework.UnschedulableAndUnresolvable {
   873  			return r, s.WithPlugin(pl.Name())
   874  		} else if !s.IsRejected() {
   875  			// Any status other than Success, Unschedulable or UnschedulableAndUnresolvable is Error.
   876  			return nil, framework.AsStatus(s.AsError()).WithPlugin(pl.Name())
   877  		} else if r != nil && r.Mode() != framework.ModeNoop {
   878  			result = r
   879  		}
   880  
   881  		reasons = append(reasons, s.Reasons()...)
   882  		// Record the first failed plugin unless we proved that
   883  		// the latter is more relevant.
   884  		if len(rejectorPlugin) == 0 {
   885  			rejectorPlugin = pl.Name()
   886  		}
   887  	}
   888  
   889  	return result, framework.NewStatus(framework.Unschedulable, reasons...).WithPlugin(rejectorPlugin)
   890  }
   891  
   892  func (f *frameworkImpl) runPostFilterPlugin(ctx context.Context, pl framework.PostFilterPlugin, state *framework.CycleState, pod *v1.Pod, filteredNodeStatusMap framework.NodeToStatusMap) (*framework.PostFilterResult, *framework.Status) {
   893  	if !state.ShouldRecordPluginMetrics() {
   894  		return pl.PostFilter(ctx, state, pod, filteredNodeStatusMap)
   895  	}
   896  	startTime := time.Now()
   897  	r, s := pl.PostFilter(ctx, state, pod, filteredNodeStatusMap)
   898  	f.metricsRecorder.ObservePluginDurationAsync(metrics.PostFilter, pl.Name(), s.Code().String(), metrics.SinceInSeconds(startTime))
   899  	return r, s
   900  }
   901  
   902  // RunFilterPluginsWithNominatedPods runs the set of configured filter plugins
   903  // for nominated pod on the given node.
   904  // This function is called from two different places: Schedule and Preempt.
   905  // When it is called from Schedule, we want to test whether the pod is
   906  // schedulable on the node with all the existing pods on the node plus higher
   907  // and equal priority pods nominated to run on the node.
   908  // When it is called from Preempt, we should remove the victims of preemption
   909  // and add the nominated pods. Removal of the victims is done by
   910  // SelectVictimsOnNode(). Preempt removes victims from PreFilter state and
   911  // NodeInfo before calling this function.
   912  func (f *frameworkImpl) RunFilterPluginsWithNominatedPods(ctx context.Context, state *framework.CycleState, pod *v1.Pod, info *framework.NodeInfo) *framework.Status {
   913  	var status *framework.Status
   914  
   915  	podsAdded := false
   916  	// We run filters twice in some cases. If the node has greater or equal priority
   917  	// nominated pods, we run them when those pods are added to PreFilter state and nodeInfo.
   918  	// If all filters succeed in this pass, we run them again when these
   919  	// nominated pods are not added. This second pass is necessary because some
   920  	// filters such as inter-pod affinity may not pass without the nominated pods.
   921  	// If there are no nominated pods for the node or if the first run of the
   922  	// filters fail, we don't run the second pass.
   923  	// We consider only equal or higher priority pods in the first pass, because
   924  	// those are the current "pod" must yield to them and not take a space opened
   925  	// for running them. It is ok if the current "pod" take resources freed for
   926  	// lower priority pods.
   927  	// Requiring that the new pod is schedulable in both circumstances ensures that
   928  	// we are making a conservative decision: filters like resources and inter-pod
   929  	// anti-affinity are more likely to fail when the nominated pods are treated
   930  	// as running, while filters like pod affinity are more likely to fail when
   931  	// the nominated pods are treated as not running. We can't just assume the
   932  	// nominated pods are running because they are not running right now and in fact,
   933  	// they may end up getting scheduled to a different node.
   934  	logger := klog.FromContext(ctx)
   935  	logger = klog.LoggerWithName(logger, "FilterWithNominatedPods")
   936  	ctx = klog.NewContext(ctx, logger)
   937  	for i := 0; i < 2; i++ {
   938  		stateToUse := state
   939  		nodeInfoToUse := info
   940  		if i == 0 {
   941  			var err error
   942  			podsAdded, stateToUse, nodeInfoToUse, err = addNominatedPods(ctx, f, pod, state, info)
   943  			if err != nil {
   944  				return framework.AsStatus(err)
   945  			}
   946  		} else if !podsAdded || !status.IsSuccess() {
   947  			break
   948  		}
   949  
   950  		status = f.RunFilterPlugins(ctx, stateToUse, pod, nodeInfoToUse)
   951  		if !status.IsSuccess() && !status.IsRejected() {
   952  			return status
   953  		}
   954  	}
   955  
   956  	return status
   957  }
   958  
   959  // addNominatedPods adds pods with equal or greater priority which are nominated
   960  // to run on the node. It returns 1) whether any pod was added, 2) augmented cycleState,
   961  // 3) augmented nodeInfo.
   962  func addNominatedPods(ctx context.Context, fh framework.Handle, pod *v1.Pod, state *framework.CycleState, nodeInfo *framework.NodeInfo) (bool, *framework.CycleState, *framework.NodeInfo, error) {
   963  	if fh == nil {
   964  		// This may happen only in tests.
   965  		return false, state, nodeInfo, nil
   966  	}
   967  	nominatedPodInfos := fh.NominatedPodsForNode(nodeInfo.Node().Name)
   968  	if len(nominatedPodInfos) == 0 {
   969  		return false, state, nodeInfo, nil
   970  	}
   971  	nodeInfoOut := nodeInfo.Snapshot()
   972  	stateOut := state.Clone()
   973  	podsAdded := false
   974  	for _, pi := range nominatedPodInfos {
   975  		if corev1.PodPriority(pi.Pod) >= corev1.PodPriority(pod) && pi.Pod.UID != pod.UID {
   976  			nodeInfoOut.AddPodInfo(pi)
   977  			status := fh.RunPreFilterExtensionAddPod(ctx, stateOut, pod, pi, nodeInfoOut)
   978  			if !status.IsSuccess() {
   979  				return false, state, nodeInfo, status.AsError()
   980  			}
   981  			podsAdded = true
   982  		}
   983  	}
   984  	return podsAdded, stateOut, nodeInfoOut, nil
   985  }
   986  
   987  // RunPreScorePlugins runs the set of configured pre-score plugins. If any
   988  // of these plugins returns any status other than Success/Skip, the given pod is rejected.
   989  // When it returns Skip status, other fields in status are just ignored,
   990  // and coupled Score plugin will be skipped in this scheduling cycle.
   991  func (f *frameworkImpl) RunPreScorePlugins(
   992  	ctx context.Context,
   993  	state *framework.CycleState,
   994  	pod *v1.Pod,
   995  	nodes []*v1.Node,
   996  ) (status *framework.Status) {
   997  	startTime := time.Now()
   998  	skipPlugins := sets.New[string]()
   999  	defer func() {
  1000  		state.SkipScorePlugins = skipPlugins
  1001  		metrics.FrameworkExtensionPointDuration.WithLabelValues(metrics.PreScore, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime))
  1002  	}()
  1003  	logger := klog.FromContext(ctx)
  1004  	verboseLogs := logger.V(4).Enabled()
  1005  	if verboseLogs {
  1006  		logger = klog.LoggerWithName(logger, "PreScore")
  1007  	}
  1008  	for _, pl := range f.preScorePlugins {
  1009  		ctx := ctx
  1010  		if verboseLogs {
  1011  			logger := klog.LoggerWithName(logger, pl.Name())
  1012  			ctx = klog.NewContext(ctx, logger)
  1013  		}
  1014  		status = f.runPreScorePlugin(ctx, pl, state, pod, nodes)
  1015  		if status.IsSkip() {
  1016  			skipPlugins.Insert(pl.Name())
  1017  			continue
  1018  		}
  1019  		if !status.IsSuccess() {
  1020  			return framework.AsStatus(fmt.Errorf("running PreScore plugin %q: %w", pl.Name(), status.AsError()))
  1021  		}
  1022  	}
  1023  	return nil
  1024  }
  1025  
  1026  func (f *frameworkImpl) runPreScorePlugin(ctx context.Context, pl framework.PreScorePlugin, state *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status {
  1027  	if !state.ShouldRecordPluginMetrics() {
  1028  		return pl.PreScore(ctx, state, pod, nodes)
  1029  	}
  1030  	startTime := time.Now()
  1031  	status := pl.PreScore(ctx, state, pod, nodes)
  1032  	f.metricsRecorder.ObservePluginDurationAsync(metrics.PreScore, pl.Name(), status.Code().String(), metrics.SinceInSeconds(startTime))
  1033  	return status
  1034  }
  1035  
  1036  // RunScorePlugins runs the set of configured scoring plugins.
  1037  // It returns a list that stores scores from each plugin and total score for each Node.
  1038  // It also returns *Status, which is set to non-success if any of the plugins returns
  1039  // a non-success status.
  1040  func (f *frameworkImpl) RunScorePlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) (ns []framework.NodePluginScores, status *framework.Status) {
  1041  	startTime := time.Now()
  1042  	defer func() {
  1043  		metrics.FrameworkExtensionPointDuration.WithLabelValues(metrics.Score, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime))
  1044  	}()
  1045  	allNodePluginScores := make([]framework.NodePluginScores, len(nodes))
  1046  	numPlugins := len(f.scorePlugins)
  1047  	plugins := make([]framework.ScorePlugin, 0, numPlugins)
  1048  	pluginToNodeScores := make(map[string]framework.NodeScoreList, numPlugins)
  1049  	for _, pl := range f.scorePlugins {
  1050  		if state.SkipScorePlugins.Has(pl.Name()) {
  1051  			continue
  1052  		}
  1053  		plugins = append(plugins, pl)
  1054  		pluginToNodeScores[pl.Name()] = make(framework.NodeScoreList, len(nodes))
  1055  	}
  1056  	ctx, cancel := context.WithCancel(ctx)
  1057  	defer cancel()
  1058  	errCh := parallelize.NewErrorChannel()
  1059  
  1060  	if len(plugins) > 0 {
  1061  		logger := klog.FromContext(ctx)
  1062  		verboseLogs := logger.V(4).Enabled()
  1063  		if verboseLogs {
  1064  			logger = klog.LoggerWithName(logger, "Score")
  1065  		}
  1066  		// Run Score method for each node in parallel.
  1067  		f.Parallelizer().Until(ctx, len(nodes), func(index int) {
  1068  			nodeName := nodes[index].Name
  1069  			logger := logger
  1070  			if verboseLogs {
  1071  				logger = klog.LoggerWithValues(logger, "node", klog.ObjectRef{Name: nodeName})
  1072  			}
  1073  			for _, pl := range plugins {
  1074  				ctx := ctx
  1075  				if verboseLogs {
  1076  					logger := klog.LoggerWithName(logger, pl.Name())
  1077  					ctx = klog.NewContext(ctx, logger)
  1078  				}
  1079  				s, status := f.runScorePlugin(ctx, pl, state, pod, nodeName)
  1080  				if !status.IsSuccess() {
  1081  					err := fmt.Errorf("plugin %q failed with: %w", pl.Name(), status.AsError())
  1082  					errCh.SendErrorWithCancel(err, cancel)
  1083  					return
  1084  				}
  1085  				pluginToNodeScores[pl.Name()][index] = framework.NodeScore{
  1086  					Name:  nodeName,
  1087  					Score: s,
  1088  				}
  1089  			}
  1090  		}, metrics.Score)
  1091  		if err := errCh.ReceiveError(); err != nil {
  1092  			return nil, framework.AsStatus(fmt.Errorf("running Score plugins: %w", err))
  1093  		}
  1094  	}
  1095  
  1096  	// Run NormalizeScore method for each ScorePlugin in parallel.
  1097  	f.Parallelizer().Until(ctx, len(plugins), func(index int) {
  1098  		pl := plugins[index]
  1099  		if pl.ScoreExtensions() == nil {
  1100  			return
  1101  		}
  1102  		nodeScoreList := pluginToNodeScores[pl.Name()]
  1103  		status := f.runScoreExtension(ctx, pl, state, pod, nodeScoreList)
  1104  		if !status.IsSuccess() {
  1105  			err := fmt.Errorf("plugin %q failed with: %w", pl.Name(), status.AsError())
  1106  			errCh.SendErrorWithCancel(err, cancel)
  1107  			return
  1108  		}
  1109  	}, metrics.Score)
  1110  	if err := errCh.ReceiveError(); err != nil {
  1111  		return nil, framework.AsStatus(fmt.Errorf("running Normalize on Score plugins: %w", err))
  1112  	}
  1113  
  1114  	// Apply score weight for each ScorePlugin in parallel,
  1115  	// and then, build allNodePluginScores.
  1116  	f.Parallelizer().Until(ctx, len(nodes), func(index int) {
  1117  		nodePluginScores := framework.NodePluginScores{
  1118  			Name:   nodes[index].Name,
  1119  			Scores: make([]framework.PluginScore, len(plugins)),
  1120  		}
  1121  
  1122  		for i, pl := range plugins {
  1123  			weight := f.scorePluginWeight[pl.Name()]
  1124  			nodeScoreList := pluginToNodeScores[pl.Name()]
  1125  			score := nodeScoreList[index].Score
  1126  
  1127  			if score > framework.MaxNodeScore || score < framework.MinNodeScore {
  1128  				err := fmt.Errorf("plugin %q returns an invalid score %v, it should in the range of [%v, %v] after normalizing", pl.Name(), score, framework.MinNodeScore, framework.MaxNodeScore)
  1129  				errCh.SendErrorWithCancel(err, cancel)
  1130  				return
  1131  			}
  1132  			weightedScore := score * int64(weight)
  1133  			nodePluginScores.Scores[i] = framework.PluginScore{
  1134  				Name:  pl.Name(),
  1135  				Score: weightedScore,
  1136  			}
  1137  			nodePluginScores.TotalScore += weightedScore
  1138  		}
  1139  		allNodePluginScores[index] = nodePluginScores
  1140  	}, metrics.Score)
  1141  	if err := errCh.ReceiveError(); err != nil {
  1142  		return nil, framework.AsStatus(fmt.Errorf("applying score defaultWeights on Score plugins: %w", err))
  1143  	}
  1144  
  1145  	return allNodePluginScores, nil
  1146  }
  1147  
  1148  func (f *frameworkImpl) runScorePlugin(ctx context.Context, pl framework.ScorePlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
  1149  	if !state.ShouldRecordPluginMetrics() {
  1150  		return pl.Score(ctx, state, pod, nodeName)
  1151  	}
  1152  	startTime := time.Now()
  1153  	s, status := pl.Score(ctx, state, pod, nodeName)
  1154  	f.metricsRecorder.ObservePluginDurationAsync(metrics.Score, pl.Name(), status.Code().String(), metrics.SinceInSeconds(startTime))
  1155  	return s, status
  1156  }
  1157  
  1158  func (f *frameworkImpl) runScoreExtension(ctx context.Context, pl framework.ScorePlugin, state *framework.CycleState, pod *v1.Pod, nodeScoreList framework.NodeScoreList) *framework.Status {
  1159  	if !state.ShouldRecordPluginMetrics() {
  1160  		return pl.ScoreExtensions().NormalizeScore(ctx, state, pod, nodeScoreList)
  1161  	}
  1162  	startTime := time.Now()
  1163  	status := pl.ScoreExtensions().NormalizeScore(ctx, state, pod, nodeScoreList)
  1164  	f.metricsRecorder.ObservePluginDurationAsync(metrics.ScoreExtensionNormalize, pl.Name(), status.Code().String(), metrics.SinceInSeconds(startTime))
  1165  	return status
  1166  }
  1167  
  1168  // RunPreBindPlugins runs the set of configured prebind plugins. It returns a
  1169  // failure (bool) if any of the plugins returns an error. It also returns an
  1170  // error containing the rejection message or the error occurred in the plugin.
  1171  func (f *frameworkImpl) RunPreBindPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (status *framework.Status) {
  1172  	startTime := time.Now()
  1173  	defer func() {
  1174  		metrics.FrameworkExtensionPointDuration.WithLabelValues(metrics.PreBind, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime))
  1175  	}()
  1176  	logger := klog.FromContext(ctx)
  1177  	verboseLogs := logger.V(4).Enabled()
  1178  	if verboseLogs {
  1179  		logger = klog.LoggerWithName(logger, "PreBind")
  1180  		logger = klog.LoggerWithValues(logger, "node", klog.ObjectRef{Name: nodeName})
  1181  	}
  1182  	for _, pl := range f.preBindPlugins {
  1183  		ctx := ctx
  1184  		if verboseLogs {
  1185  			logger := klog.LoggerWithName(logger, pl.Name())
  1186  			ctx = klog.NewContext(ctx, logger)
  1187  		}
  1188  		status = f.runPreBindPlugin(ctx, pl, state, pod, nodeName)
  1189  		if !status.IsSuccess() {
  1190  			if status.IsRejected() {
  1191  				logger.V(4).Info("Pod rejected by PreBind plugin", "pod", klog.KObj(pod), "node", nodeName, "plugin", pl.Name(), "status", status.Message())
  1192  				status.SetPlugin(pl.Name())
  1193  				return status
  1194  			}
  1195  			err := status.AsError()
  1196  			logger.Error(err, "Plugin failed", "plugin", pl.Name(), "pod", klog.KObj(pod), "node", nodeName)
  1197  			return framework.AsStatus(fmt.Errorf("running PreBind plugin %q: %w", pl.Name(), err))
  1198  		}
  1199  	}
  1200  	return nil
  1201  }
  1202  
  1203  func (f *frameworkImpl) runPreBindPlugin(ctx context.Context, pl framework.PreBindPlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status {
  1204  	if !state.ShouldRecordPluginMetrics() {
  1205  		return pl.PreBind(ctx, state, pod, nodeName)
  1206  	}
  1207  	startTime := time.Now()
  1208  	status := pl.PreBind(ctx, state, pod, nodeName)
  1209  	f.metricsRecorder.ObservePluginDurationAsync(metrics.PreBind, pl.Name(), status.Code().String(), metrics.SinceInSeconds(startTime))
  1210  	return status
  1211  }
  1212  
  1213  // RunBindPlugins runs the set of configured bind plugins until one returns a non `Skip` status.
  1214  func (f *frameworkImpl) RunBindPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (status *framework.Status) {
  1215  	startTime := time.Now()
  1216  	defer func() {
  1217  		metrics.FrameworkExtensionPointDuration.WithLabelValues(metrics.Bind, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime))
  1218  	}()
  1219  	if len(f.bindPlugins) == 0 {
  1220  		return framework.NewStatus(framework.Skip, "")
  1221  	}
  1222  	logger := klog.FromContext(ctx)
  1223  	verboseLogs := logger.V(4).Enabled()
  1224  	if verboseLogs {
  1225  		logger = klog.LoggerWithName(logger, "Bind")
  1226  	}
  1227  	for _, pl := range f.bindPlugins {
  1228  		ctx := ctx
  1229  		if verboseLogs {
  1230  			logger := klog.LoggerWithName(logger, pl.Name())
  1231  			ctx = klog.NewContext(ctx, logger)
  1232  		}
  1233  		status = f.runBindPlugin(ctx, pl, state, pod, nodeName)
  1234  		if status.IsSkip() {
  1235  			continue
  1236  		}
  1237  		if !status.IsSuccess() {
  1238  			if status.IsRejected() {
  1239  				logger.V(4).Info("Pod rejected by Bind plugin", "pod", klog.KObj(pod), "node", nodeName, "plugin", pl.Name(), "status", status.Message())
  1240  				status.SetPlugin(pl.Name())
  1241  				return status
  1242  			}
  1243  			err := status.AsError()
  1244  			logger.Error(err, "Plugin Failed", "plugin", pl.Name(), "pod", klog.KObj(pod), "node", nodeName)
  1245  			return framework.AsStatus(fmt.Errorf("running Bind plugin %q: %w", pl.Name(), err))
  1246  		}
  1247  		return status
  1248  	}
  1249  	return status
  1250  }
  1251  
  1252  func (f *frameworkImpl) runBindPlugin(ctx context.Context, bp framework.BindPlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status {
  1253  	if !state.ShouldRecordPluginMetrics() {
  1254  		return bp.Bind(ctx, state, pod, nodeName)
  1255  	}
  1256  	startTime := time.Now()
  1257  	status := bp.Bind(ctx, state, pod, nodeName)
  1258  	f.metricsRecorder.ObservePluginDurationAsync(metrics.Bind, bp.Name(), status.Code().String(), metrics.SinceInSeconds(startTime))
  1259  	return status
  1260  }
  1261  
  1262  // RunPostBindPlugins runs the set of configured postbind plugins.
  1263  func (f *frameworkImpl) RunPostBindPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) {
  1264  	startTime := time.Now()
  1265  	defer func() {
  1266  		metrics.FrameworkExtensionPointDuration.WithLabelValues(metrics.PostBind, framework.Success.String(), f.profileName).Observe(metrics.SinceInSeconds(startTime))
  1267  	}()
  1268  	logger := klog.FromContext(ctx)
  1269  	verboseLogs := logger.V(4).Enabled()
  1270  	if verboseLogs {
  1271  		logger = klog.LoggerWithName(logger, "PostBind")
  1272  	}
  1273  	for _, pl := range f.postBindPlugins {
  1274  		ctx := ctx
  1275  		if verboseLogs {
  1276  			logger := klog.LoggerWithName(logger, pl.Name())
  1277  			ctx = klog.NewContext(ctx, logger)
  1278  		}
  1279  		f.runPostBindPlugin(ctx, pl, state, pod, nodeName)
  1280  	}
  1281  }
  1282  
  1283  func (f *frameworkImpl) runPostBindPlugin(ctx context.Context, pl framework.PostBindPlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) {
  1284  	if !state.ShouldRecordPluginMetrics() {
  1285  		pl.PostBind(ctx, state, pod, nodeName)
  1286  		return
  1287  	}
  1288  	startTime := time.Now()
  1289  	pl.PostBind(ctx, state, pod, nodeName)
  1290  	f.metricsRecorder.ObservePluginDurationAsync(metrics.PostBind, pl.Name(), framework.Success.String(), metrics.SinceInSeconds(startTime))
  1291  }
  1292  
  1293  // RunReservePluginsReserve runs the Reserve method in the set of configured
  1294  // reserve plugins. If any of these plugins returns an error, it does not
  1295  // continue running the remaining ones and returns the error. In such a case,
  1296  // the pod will not be scheduled and the caller will be expected to call
  1297  // RunReservePluginsUnreserve.
  1298  func (f *frameworkImpl) RunReservePluginsReserve(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (status *framework.Status) {
  1299  	startTime := time.Now()
  1300  	defer func() {
  1301  		metrics.FrameworkExtensionPointDuration.WithLabelValues(metrics.Reserve, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime))
  1302  	}()
  1303  	logger := klog.FromContext(ctx)
  1304  	verboseLogs := logger.V(4).Enabled()
  1305  	if verboseLogs {
  1306  		logger = klog.LoggerWithName(logger, "Reserve")
  1307  		logger = klog.LoggerWithValues(logger, "node", klog.ObjectRef{Name: nodeName})
  1308  	}
  1309  	for _, pl := range f.reservePlugins {
  1310  		ctx := ctx
  1311  		if verboseLogs {
  1312  			logger := klog.LoggerWithName(logger, pl.Name())
  1313  			ctx = klog.NewContext(ctx, logger)
  1314  		}
  1315  		status = f.runReservePluginReserve(ctx, pl, state, pod, nodeName)
  1316  		if !status.IsSuccess() {
  1317  			if status.IsRejected() {
  1318  				logger.V(4).Info("Pod rejected by plugin", "pod", klog.KObj(pod), "plugin", pl.Name(), "status", status.Message())
  1319  				status.SetPlugin(pl.Name())
  1320  				return status
  1321  			}
  1322  			err := status.AsError()
  1323  			logger.Error(err, "Plugin failed", "plugin", pl.Name(), "pod", klog.KObj(pod))
  1324  			return framework.AsStatus(fmt.Errorf("running Reserve plugin %q: %w", pl.Name(), err))
  1325  		}
  1326  	}
  1327  	return nil
  1328  }
  1329  
  1330  func (f *frameworkImpl) runReservePluginReserve(ctx context.Context, pl framework.ReservePlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status {
  1331  	if !state.ShouldRecordPluginMetrics() {
  1332  		return pl.Reserve(ctx, state, pod, nodeName)
  1333  	}
  1334  	startTime := time.Now()
  1335  	status := pl.Reserve(ctx, state, pod, nodeName)
  1336  	f.metricsRecorder.ObservePluginDurationAsync(metrics.Reserve, pl.Name(), status.Code().String(), metrics.SinceInSeconds(startTime))
  1337  	return status
  1338  }
  1339  
  1340  // RunReservePluginsUnreserve runs the Unreserve method in the set of
  1341  // configured reserve plugins.
  1342  func (f *frameworkImpl) RunReservePluginsUnreserve(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) {
  1343  	startTime := time.Now()
  1344  	defer func() {
  1345  		metrics.FrameworkExtensionPointDuration.WithLabelValues(metrics.Unreserve, framework.Success.String(), f.profileName).Observe(metrics.SinceInSeconds(startTime))
  1346  	}()
  1347  	// Execute the Unreserve operation of each reserve plugin in the
  1348  	// *reverse* order in which the Reserve operation was executed.
  1349  	logger := klog.FromContext(ctx)
  1350  	verboseLogs := logger.V(4).Enabled()
  1351  	if verboseLogs {
  1352  		logger = klog.LoggerWithName(logger, "Unreserve")
  1353  		logger = klog.LoggerWithValues(logger, "node", klog.ObjectRef{Name: nodeName})
  1354  	}
  1355  	for i := len(f.reservePlugins) - 1; i >= 0; i-- {
  1356  		pl := f.reservePlugins[i]
  1357  		ctx := ctx
  1358  		if verboseLogs {
  1359  			logger := klog.LoggerWithName(logger, pl.Name())
  1360  			ctx = klog.NewContext(ctx, logger)
  1361  		}
  1362  		f.runReservePluginUnreserve(ctx, pl, state, pod, nodeName)
  1363  	}
  1364  }
  1365  
  1366  func (f *frameworkImpl) runReservePluginUnreserve(ctx context.Context, pl framework.ReservePlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) {
  1367  	if !state.ShouldRecordPluginMetrics() {
  1368  		pl.Unreserve(ctx, state, pod, nodeName)
  1369  		return
  1370  	}
  1371  	startTime := time.Now()
  1372  	pl.Unreserve(ctx, state, pod, nodeName)
  1373  	f.metricsRecorder.ObservePluginDurationAsync(metrics.Unreserve, pl.Name(), framework.Success.String(), metrics.SinceInSeconds(startTime))
  1374  }
  1375  
  1376  // RunPermitPlugins runs the set of configured permit plugins. If any of these
  1377  // plugins returns a status other than "Success" or "Wait", it does not continue
  1378  // running the remaining plugins and returns an error. Otherwise, if any of the
  1379  // plugins returns "Wait", then this function will create and add waiting pod
  1380  // to a map of currently waiting pods and return status with "Wait" code.
  1381  // Pod will remain waiting pod for the minimum duration returned by the permit plugins.
  1382  func (f *frameworkImpl) RunPermitPlugins(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (status *framework.Status) {
  1383  	startTime := time.Now()
  1384  	defer func() {
  1385  		metrics.FrameworkExtensionPointDuration.WithLabelValues(metrics.Permit, status.Code().String(), f.profileName).Observe(metrics.SinceInSeconds(startTime))
  1386  	}()
  1387  	pluginsWaitTime := make(map[string]time.Duration)
  1388  	statusCode := framework.Success
  1389  	logger := klog.FromContext(ctx)
  1390  	verboseLogs := logger.V(4).Enabled()
  1391  	if verboseLogs {
  1392  		logger = klog.LoggerWithName(logger, "Permit")
  1393  		logger = klog.LoggerWithValues(logger, "node", klog.ObjectRef{Name: nodeName})
  1394  	}
  1395  	for _, pl := range f.permitPlugins {
  1396  		ctx := ctx
  1397  		if verboseLogs {
  1398  			logger := klog.LoggerWithName(logger, pl.Name())
  1399  			ctx = klog.NewContext(ctx, logger)
  1400  		}
  1401  		status, timeout := f.runPermitPlugin(ctx, pl, state, pod, nodeName)
  1402  		if !status.IsSuccess() {
  1403  			if status.IsRejected() {
  1404  				logger.V(4).Info("Pod rejected by plugin", "pod", klog.KObj(pod), "plugin", pl.Name(), "status", status.Message())
  1405  				return status.WithPlugin(pl.Name())
  1406  			}
  1407  			if status.IsWait() {
  1408  				// Not allowed to be greater than maxTimeout.
  1409  				if timeout > maxTimeout {
  1410  					timeout = maxTimeout
  1411  				}
  1412  				pluginsWaitTime[pl.Name()] = timeout
  1413  				statusCode = framework.Wait
  1414  			} else {
  1415  				err := status.AsError()
  1416  				logger.Error(err, "Plugin failed", "plugin", pl.Name(), "pod", klog.KObj(pod))
  1417  				return framework.AsStatus(fmt.Errorf("running Permit plugin %q: %w", pl.Name(), err)).WithPlugin(pl.Name())
  1418  			}
  1419  		}
  1420  	}
  1421  	if statusCode == framework.Wait {
  1422  		waitingPod := newWaitingPod(pod, pluginsWaitTime)
  1423  		f.waitingPods.add(waitingPod)
  1424  		msg := fmt.Sprintf("one or more plugins asked to wait and no plugin rejected pod %q", pod.Name)
  1425  		logger.V(4).Info("One or more plugins asked to wait and no plugin rejected pod", "pod", klog.KObj(pod))
  1426  		return framework.NewStatus(framework.Wait, msg)
  1427  	}
  1428  	return nil
  1429  }
  1430  
  1431  func (f *frameworkImpl) runPermitPlugin(ctx context.Context, pl framework.PermitPlugin, state *framework.CycleState, pod *v1.Pod, nodeName string) (*framework.Status, time.Duration) {
  1432  	if !state.ShouldRecordPluginMetrics() {
  1433  		return pl.Permit(ctx, state, pod, nodeName)
  1434  	}
  1435  	startTime := time.Now()
  1436  	status, timeout := pl.Permit(ctx, state, pod, nodeName)
  1437  	f.metricsRecorder.ObservePluginDurationAsync(metrics.Permit, pl.Name(), status.Code().String(), metrics.SinceInSeconds(startTime))
  1438  	return status, timeout
  1439  }
  1440  
  1441  // WaitOnPermit will block, if the pod is a waiting pod, until the waiting pod is rejected or allowed.
  1442  func (f *frameworkImpl) WaitOnPermit(ctx context.Context, pod *v1.Pod) *framework.Status {
  1443  	waitingPod := f.waitingPods.get(pod.UID)
  1444  	if waitingPod == nil {
  1445  		return nil
  1446  	}
  1447  	defer f.waitingPods.remove(pod.UID)
  1448  
  1449  	logger := klog.FromContext(ctx)
  1450  	logger.V(4).Info("Pod waiting on permit", "pod", klog.KObj(pod))
  1451  
  1452  	startTime := time.Now()
  1453  	s := <-waitingPod.s
  1454  	metrics.PermitWaitDuration.WithLabelValues(s.Code().String()).Observe(metrics.SinceInSeconds(startTime))
  1455  
  1456  	if !s.IsSuccess() {
  1457  		if s.IsRejected() {
  1458  			logger.V(4).Info("Pod rejected while waiting on permit", "pod", klog.KObj(pod), "status", s.Message())
  1459  			return s
  1460  		}
  1461  		err := s.AsError()
  1462  		logger.Error(err, "Failed waiting on permit for pod", "pod", klog.KObj(pod))
  1463  		return framework.AsStatus(fmt.Errorf("waiting on permit for pod: %w", err)).WithPlugin(s.Plugin())
  1464  	}
  1465  	return nil
  1466  }
  1467  
  1468  // SnapshotSharedLister returns the scheduler's SharedLister of the latest NodeInfo
  1469  // snapshot. The snapshot is taken at the beginning of a scheduling cycle and remains
  1470  // unchanged until a pod finishes "Reserve". There is no guarantee that the information
  1471  // remains unchanged after "Reserve".
  1472  func (f *frameworkImpl) SnapshotSharedLister() framework.SharedLister {
  1473  	return f.snapshotSharedLister
  1474  }
  1475  
  1476  // IterateOverWaitingPods acquires a read lock and iterates over the WaitingPods map.
  1477  func (f *frameworkImpl) IterateOverWaitingPods(callback func(framework.WaitingPod)) {
  1478  	f.waitingPods.iterate(callback)
  1479  }
  1480  
  1481  // GetWaitingPod returns a reference to a WaitingPod given its UID.
  1482  func (f *frameworkImpl) GetWaitingPod(uid types.UID) framework.WaitingPod {
  1483  	if wp := f.waitingPods.get(uid); wp != nil {
  1484  		return wp
  1485  	}
  1486  	return nil // Returning nil instead of *waitingPod(nil).
  1487  }
  1488  
  1489  // RejectWaitingPod rejects a WaitingPod given its UID.
  1490  // The returned value indicates if the given pod is waiting or not.
  1491  func (f *frameworkImpl) RejectWaitingPod(uid types.UID) bool {
  1492  	if waitingPod := f.waitingPods.get(uid); waitingPod != nil {
  1493  		waitingPod.Reject("", "removed")
  1494  		return true
  1495  	}
  1496  	return false
  1497  }
  1498  
  1499  // HasFilterPlugins returns true if at least one filter plugin is defined.
  1500  func (f *frameworkImpl) HasFilterPlugins() bool {
  1501  	return len(f.filterPlugins) > 0
  1502  }
  1503  
  1504  // HasPostFilterPlugins returns true if at least one postFilter plugin is defined.
  1505  func (f *frameworkImpl) HasPostFilterPlugins() bool {
  1506  	return len(f.postFilterPlugins) > 0
  1507  }
  1508  
  1509  // HasScorePlugins returns true if at least one score plugin is defined.
  1510  func (f *frameworkImpl) HasScorePlugins() bool {
  1511  	return len(f.scorePlugins) > 0
  1512  }
  1513  
  1514  // ListPlugins returns a map of extension point name to plugin names configured at each extension
  1515  // point. Returns nil if no plugins where configured.
  1516  func (f *frameworkImpl) ListPlugins() *config.Plugins {
  1517  	m := config.Plugins{}
  1518  
  1519  	for _, e := range f.getExtensionPoints(&m) {
  1520  		plugins := reflect.ValueOf(e.slicePtr).Elem()
  1521  		extName := plugins.Type().Elem().Name()
  1522  		var cfgs []config.Plugin
  1523  		for i := 0; i < plugins.Len(); i++ {
  1524  			name := plugins.Index(i).Interface().(framework.Plugin).Name()
  1525  			p := config.Plugin{Name: name}
  1526  			if extName == "ScorePlugin" {
  1527  				// Weights apply only to score plugins.
  1528  				p.Weight = int32(f.scorePluginWeight[name])
  1529  			}
  1530  			cfgs = append(cfgs, p)
  1531  		}
  1532  		if len(cfgs) > 0 {
  1533  			e.plugins.Enabled = cfgs
  1534  		}
  1535  	}
  1536  	return &m
  1537  }
  1538  
  1539  // ClientSet returns a kubernetes clientset.
  1540  func (f *frameworkImpl) ClientSet() clientset.Interface {
  1541  	return f.clientSet
  1542  }
  1543  
  1544  // KubeConfig returns a kubernetes config.
  1545  func (f *frameworkImpl) KubeConfig() *restclient.Config {
  1546  	return f.kubeConfig
  1547  }
  1548  
  1549  // EventRecorder returns an event recorder.
  1550  func (f *frameworkImpl) EventRecorder() events.EventRecorder {
  1551  	return f.eventRecorder
  1552  }
  1553  
  1554  // SharedInformerFactory returns a shared informer factory.
  1555  func (f *frameworkImpl) SharedInformerFactory() informers.SharedInformerFactory {
  1556  	return f.informerFactory
  1557  }
  1558  
  1559  func (f *frameworkImpl) pluginsNeeded(plugins *config.Plugins) sets.Set[string] {
  1560  	pgSet := sets.Set[string]{}
  1561  
  1562  	if plugins == nil {
  1563  		return pgSet
  1564  	}
  1565  
  1566  	find := func(pgs *config.PluginSet) {
  1567  		for _, pg := range pgs.Enabled {
  1568  			pgSet.Insert(pg.Name)
  1569  		}
  1570  	}
  1571  
  1572  	for _, e := range f.getExtensionPoints(plugins) {
  1573  		find(e.plugins)
  1574  	}
  1575  	// Parse MultiPoint separately since they are not returned by f.getExtensionPoints()
  1576  	find(&plugins.MultiPoint)
  1577  
  1578  	return pgSet
  1579  }
  1580  
  1581  // ProfileName returns the profile name associated to this framework.
  1582  func (f *frameworkImpl) ProfileName() string {
  1583  	return f.profileName
  1584  }
  1585  
  1586  // PercentageOfNodesToScore returns percentageOfNodesToScore associated to a profile.
  1587  func (f *frameworkImpl) PercentageOfNodesToScore() *int32 {
  1588  	return f.percentageOfNodesToScore
  1589  }
  1590  
  1591  // Parallelizer returns a parallelizer holding parallelism for scheduler.
  1592  func (f *frameworkImpl) Parallelizer() parallelize.Parallelizer {
  1593  	return f.parallelizer
  1594  }