From 6120fe9b1129ca10b597df7ae7421396988f3910 Mon Sep 17 00:00:00 2001 From: Abdullah Gharaibeh Date: Fri, 27 Sep 2019 17:07:59 -0400 Subject: [PATCH] Convert predicates/priorities configurations to a framework plugin configs. --- pkg/scheduler/factory/BUILD | 3 + pkg/scheduler/factory/factory.go | 135 ++++++++-- pkg/scheduler/factory/factory_test.go | 254 +++++++++++++++--- .../framework/plugins/default_registry.go | 4 +- .../plugins/default_registry_test.go | 2 +- 5 files changed, 339 insertions(+), 59 deletions(-) diff --git a/pkg/scheduler/factory/BUILD b/pkg/scheduler/factory/BUILD index c0d989727a1..e1d71b79990 100644 --- a/pkg/scheduler/factory/BUILD +++ b/pkg/scheduler/factory/BUILD @@ -18,6 +18,7 @@ go_library( "//pkg/scheduler/api/validation:go_default_library", "//pkg/scheduler/apis/config:go_default_library", "//pkg/scheduler/core:go_default_library", + "//pkg/scheduler/framework/plugins:go_default_library", "//pkg/scheduler/framework/v1alpha1:go_default_library", "//pkg/scheduler/internal/cache:go_default_library", "//pkg/scheduler/internal/cache/debugger:go_default_library", @@ -65,6 +66,7 @@ go_test( "//pkg/scheduler/api/latest:go_default_library", "//pkg/scheduler/apis/config:go_default_library", "//pkg/scheduler/framework/plugins:go_default_library", + "//pkg/scheduler/framework/v1alpha1:go_default_library", "//pkg/scheduler/internal/cache:go_default_library", "//pkg/scheduler/internal/queue:go_default_library", "//pkg/scheduler/nodeinfo:go_default_library", @@ -79,6 +81,7 @@ go_test( "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1/fake:go_default_library", "//staging/src/k8s.io/client-go/testing:go_default_library", "//staging/src/k8s.io/client-go/tools/cache:go_default_library", + "//vendor/github.com/google/go-cmp/cmp:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library", ], ) diff --git a/pkg/scheduler/factory/factory.go b/pkg/scheduler/factory/factory.go index c600f6c0893..a7e7d61db55 100644 --- a/pkg/scheduler/factory/factory.go +++ b/pkg/scheduler/factory/factory.go @@ -54,6 +54,7 @@ import ( "k8s.io/kubernetes/pkg/scheduler/api/validation" "k8s.io/kubernetes/pkg/scheduler/apis/config" "k8s.io/kubernetes/pkg/scheduler/core" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins" framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1" internalcache "k8s.io/kubernetes/pkg/scheduler/internal/cache" cachedebugger "k8s.io/kubernetes/pkg/scheduler/internal/cache/debugger" @@ -122,6 +123,10 @@ type Config struct { // SchedulingQueue holds pods to be scheduled SchedulingQueue internalqueue.SchedulingQueue + + // The final configuration of the framework. + Plugins config.Plugins + PluginConfig []config.PluginConfig } // PodPreemptor has methods needed to delete a pod and to update 'NominatedPod' @@ -189,9 +194,10 @@ type Configurator struct { enableNonPreempting bool // framework configuration arguments. - registry framework.Registry - plugins *config.Plugins - pluginConfig []config.PluginConfig + registry framework.Registry + plugins *config.Plugins + pluginConfig []config.PluginConfig + pluginConfigProducerRegistry *plugins.ConfigProducerRegistry } // ConfigFactoryArgs is a set arguments passed to NewConfigFactory. @@ -216,6 +222,7 @@ type ConfigFactoryArgs struct { Registry framework.Registry Plugins *config.Plugins PluginConfig []config.PluginConfig + PluginConfigProducerRegistry *plugins.ConfigProducerRegistry } // NewConfigFactory initializes the default implementation of a Configurator. To encourage eventual privatization of the struct type, we only @@ -261,6 +268,7 @@ func NewConfigFactory(args *ConfigFactoryArgs) *Configurator { registry: args.Registry, plugins: args.Plugins, pluginConfig: args.PluginConfig, + pluginConfigProducerRegistry: args.PluginConfigProducerRegistry, } // Setup volume binder c.volumeBinder = volumebinder.NewVolumeBinder(args.Client, args.NodeInformer, args.PvcInformer, args.PvInformer, args.StorageClassInformer, time.Duration(args.BindTimeoutSeconds)*time.Second) @@ -375,12 +383,12 @@ func (c *Configurator) CreateFromKeys(predicateKeys, priorityKeys sets.String, e return nil, fmt.Errorf("invalid hardPodAffinitySymmetricWeight: %d, must be in the range 1-100", c.GetHardPodAffinitySymmetricWeight()) } - predicateFuncs, err := c.GetPredicates(predicateKeys) + predicateFuncs, pluginsForPredicates, pluginConfigForPredicates, err := c.getPredicateConfigs(predicateKeys) if err != nil { return nil, err } - priorityConfigs, err := c.getPriorityFunctionConfigs(priorityKeys) + priorityConfigs, pluginsForPriorities, pluginConfigForPriorities, err := c.getPriorityConfigs(priorityKeys) if err != nil { return nil, err } @@ -395,14 +403,25 @@ func (c *Configurator) CreateFromKeys(predicateKeys, priorityKeys sets.String, e return nil, err } - framework, err := framework.NewFramework(c.registry, c.plugins, c.pluginConfig) + // Combine all framework configurations. If this results in any duplication, framework + // instantiation should fail. + var plugins config.Plugins + plugins.Append(pluginsForPredicates) + plugins.Append(pluginsForPriorities) + plugins.Append(c.plugins) + var pluginConfig []config.PluginConfig + pluginConfig = append(pluginConfig, pluginConfigForPredicates...) + pluginConfig = append(pluginConfig, pluginConfigForPriorities...) + pluginConfig = append(pluginConfig, c.pluginConfig...) + + framework, err := framework.NewFramework(c.registry, &plugins, pluginConfig) if err != nil { klog.Fatalf("error initializing the scheduling framework: %v", err) } podQueue := internalqueue.NewSchedulingQueue(c.StopEverything, framework) - // Setup cache debugger + // Setup cache debugger. debugger := cachedebugger.New( c.nodeLister, c.podLister, @@ -449,6 +468,8 @@ func (c *Configurator) CreateFromKeys(predicateKeys, priorityKeys sets.String, e StopEverything: c.StopEverything, VolumeBinder: c.volumeBinder, SchedulingQueue: podQueue, + Plugins: plugins, + PluginConfig: pluginConfig, }, nil } @@ -465,22 +486,43 @@ func getBinderFunc(client clientset.Interface, extenders []algorithm.SchedulerEx } } -func (c *Configurator) getPriorityFunctionConfigs(priorityKeys sets.String) ([]priorities.PriorityConfig, error) { - pluginArgs, err := c.getPluginArgs() +// getPriorityConfigs returns priorities configuration: ones that will run as priorities and ones that will run +// as framework plugins. Specifically, a priority will run as a framework plugin if a plugin config producer was +// registered for that priority. +func (c *Configurator) getPriorityConfigs(priorityKeys sets.String) ([]priorities.PriorityConfig, *config.Plugins, []config.PluginConfig, error) { + algorithmArgs, configProducerArgs := c.getAlgorithmArgs() + + allPriorityConfigs, err := getPriorityFunctionConfigs(priorityKeys, *algorithmArgs) if err != nil { - return nil, err + return nil, nil, nil, err } - return getPriorityFunctionConfigs(priorityKeys, *pluginArgs) + if c.pluginConfigProducerRegistry == nil { + return allPriorityConfigs, nil, nil, nil + } + + var priorityConfigs []priorities.PriorityConfig + var plugins config.Plugins + var pluginConfig []config.PluginConfig + frameworkConfigProducers := c.pluginConfigProducerRegistry.PriorityToConfigProducer + for _, p := range allPriorityConfigs { + if producer, exist := frameworkConfigProducers[p.Name]; exist { + args := *configProducerArgs + args.Weight = int32(p.Weight) + pl, pc := producer(args) + plugins.Append(&pl) + pluginConfig = append(pluginConfig, pc...) + } else { + priorityConfigs = append(priorityConfigs, p) + } + } + return priorityConfigs, &plugins, pluginConfig, nil } func (c *Configurator) getPriorityMetadataProducer() (priorities.PriorityMetadataProducer, error) { - pluginArgs, err := c.getPluginArgs() - if err != nil { - return nil, err - } + algorithmArgs, _ := c.getAlgorithmArgs() - return getPriorityMetadataProducer(*pluginArgs) + return getPriorityMetadataProducer(*algorithmArgs) } // GetPredicateMetadataProducer returns a function to build Predicate Metadata. @@ -489,18 +531,63 @@ func (c *Configurator) GetPredicateMetadataProducer() (predicates.PredicateMetad return getPredicateMetadataProducer() } -// GetPredicates returns the predicate functions. -// It is used by the scheduler and other components, such as k8s.io/autoscaler/cluster-autoscaler. -func (c *Configurator) GetPredicates(predicateKeys sets.String) (map[string]predicates.FitPredicate, error) { - pluginArgs, err := c.getPluginArgs() +// getPredicateConfigs returns predicates configuration: ones that will run as fitPredicates and ones that will run +// as framework plugins. Specifically, a predicate will run as a framework plugin if a plugin config producer was +// registered for that predicate. +// Note that the framework executes plugins according to their order in the Plugins list, and so predicates run as plugins +// are added to the Plugins list according to the order specified in predicates.Ordering(). +func (c *Configurator) getPredicateConfigs(predicateKeys sets.String) (map[string]predicates.FitPredicate, *config.Plugins, []config.PluginConfig, error) { + algorithmArgs, configProducerArgs := c.getAlgorithmArgs() + + allFitPredicates, err := getFitPredicateFunctions(predicateKeys, *algorithmArgs) if err != nil { - return nil, err + return nil, nil, nil, err } - return getFitPredicateFunctions(predicateKeys, *pluginArgs) + if c.pluginConfigProducerRegistry == nil { + return allFitPredicates, nil, nil, nil + } + + asPlugins := sets.NewString() + asFitPredicates := make(map[string]predicates.FitPredicate) + frameworkConfigProducers := c.pluginConfigProducerRegistry.PredicateToConfigProducer + + // First, identify the predicates that will run as actual fit predicates, and ones + // that will run as framework plugins. + for predicateKey := range allFitPredicates { + if _, exist := frameworkConfigProducers[predicateKey]; exist { + asPlugins.Insert(predicateKey) + } else { + asFitPredicates[predicateKey] = allFitPredicates[predicateKey] + } + } + + // Second, create the framework plugin configurations, and place them in the order + // that the corresponding predicates were supposed to run. + var plugins config.Plugins + var pluginConfig []config.PluginConfig + for _, predicateKey := range predicates.Ordering() { + if asPlugins.Has(predicateKey) { + producer := frameworkConfigProducers[predicateKey] + p, pc := producer(*configProducerArgs) + plugins.Append(&p) + pluginConfig = append(pluginConfig, pc...) + asPlugins.Delete(predicateKey) + } + } + + // Third, add the rest in no specific order. + for predicateKey := range asPlugins { + producer := frameworkConfigProducers[predicateKey] + p, pc := producer(*configProducerArgs) + plugins.Append(&p) + pluginConfig = append(pluginConfig, pc...) + } + + return asFitPredicates, &plugins, pluginConfig, nil } -func (c *Configurator) getPluginArgs() (*PluginFactoryArgs, error) { +func (c *Configurator) getAlgorithmArgs() (*PluginFactoryArgs, *plugins.ConfigProducerArgs) { return &PluginFactoryArgs{ PodLister: c.schedulerCache, ServiceLister: c.serviceLister, @@ -516,7 +603,7 @@ func (c *Configurator) getPluginArgs() (*PluginFactoryArgs, error) { StorageClassInfo: &predicates.CachedStorageClassInfo{StorageClassLister: c.storageClassLister}, VolumeBinder: c.volumeBinder, HardPodAffinitySymmetricWeight: c.hardPodAffinitySymmetricWeight, - }, nil + }, &plugins.ConfigProducerArgs{} } type podInformer struct { diff --git a/pkg/scheduler/factory/factory_test.go b/pkg/scheduler/factory/factory_test.go index 87ba842d4ed..a9fb9bfd82a 100644 --- a/pkg/scheduler/factory/factory_test.go +++ b/pkg/scheduler/factory/factory_test.go @@ -20,9 +20,12 @@ import ( "errors" "fmt" "reflect" + "sort" "testing" "time" + "github.com/google/go-cmp/cmp" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -39,8 +42,9 @@ import ( "k8s.io/kubernetes/pkg/scheduler/algorithm/predicates" schedulerapi "k8s.io/kubernetes/pkg/scheduler/api" latestschedulerapi "k8s.io/kubernetes/pkg/scheduler/api/latest" - "k8s.io/kubernetes/pkg/scheduler/apis/config" - plugins "k8s.io/kubernetes/pkg/scheduler/framework/plugins" + config "k8s.io/kubernetes/pkg/scheduler/apis/config" + frameworkplugins "k8s.io/kubernetes/pkg/scheduler/framework/plugins" + framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1" internalcache "k8s.io/kubernetes/pkg/scheduler/internal/cache" internalqueue "k8s.io/kubernetes/pkg/scheduler/internal/queue" schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo" @@ -71,10 +75,10 @@ func TestCreateFromConfig(t *testing.T) { factory := newConfigFactory(client, v1.DefaultHardPodAffinitySymmetricWeight, stopCh) // Pre-register some predicate and priority functions - RegisterFitPredicate("PredicateOne", PredicateOne) - RegisterFitPredicate("PredicateTwo", PredicateTwo) - RegisterPriorityFunction("PriorityOne", PriorityOne, 1) - RegisterPriorityFunction("PriorityTwo", PriorityTwo, 1) + RegisterFitPredicate("PredicateOne", PredicateFunc) + RegisterFitPredicate("PredicateTwo", PredicateFunc) + RegisterPriorityFunction("PriorityOne", PriorityFunc, 1) + RegisterPriorityFunction("PriorityTwo", PriorityFunc, 1) configData = []byte(`{ "kind" : "Policy", @@ -111,10 +115,10 @@ func TestCreateFromConfigWithHardPodAffinitySymmetricWeight(t *testing.T) { factory := newConfigFactory(client, v1.DefaultHardPodAffinitySymmetricWeight, stopCh) // Pre-register some predicate and priority functions - RegisterFitPredicate("PredicateOne", PredicateOne) - RegisterFitPredicate("PredicateTwo", PredicateTwo) - RegisterPriorityFunction("PriorityOne", PriorityOne, 1) - RegisterPriorityFunction("PriorityTwo", PriorityTwo, 1) + RegisterFitPredicate("PredicateOne", PredicateFunc) + RegisterFitPredicate("PredicateTwo", PredicateFunc) + RegisterPriorityFunction("PriorityOne", PriorityFunc, 1) + RegisterPriorityFunction("PriorityTwo", PriorityFunc, 1) configData = []byte(`{ "kind" : "Policy", @@ -168,8 +172,8 @@ func TestCreateFromConfigWithUnspecifiedPredicatesOrPriorities(t *testing.T) { defer close(stopCh) factory := newConfigFactory(client, v1.DefaultHardPodAffinitySymmetricWeight, stopCh) - RegisterFitPredicate("PredicateOne", PredicateOne) - RegisterPriorityFunction("PriorityOne", PriorityOne, 1) + RegisterFitPredicate("PredicateOne", PredicateFunc) + RegisterPriorityFunction("PriorityOne", PriorityFunc, 1) RegisterAlgorithmProvider(DefaultProvider, sets.NewString("PredicateOne"), sets.NewString("PriorityOne")) @@ -182,14 +186,14 @@ func TestCreateFromConfigWithUnspecifiedPredicatesOrPriorities(t *testing.T) { t.Fatalf("Invalid configuration: %v", err) } - config, err := factory.CreateFromConfig(policy) + c, err := factory.CreateFromConfig(policy) if err != nil { t.Fatalf("Failed to create scheduler from configuration: %v", err) } - if _, found := config.Algorithm.Predicates()["PredicateOne"]; !found { + if _, found := c.Algorithm.Predicates()["PredicateOne"]; !found { t.Errorf("Expected predicate PredicateOne from %q", DefaultProvider) } - if len(config.Algorithm.Prioritizers()) != 1 || config.Algorithm.Prioritizers()[0].Name != "PriorityOne" { + if len(c.Algorithm.Prioritizers()) != 1 || c.Algorithm.Prioritizers()[0].Name != "PriorityOne" { t.Errorf("Expected priority PriorityOne from %q", DefaultProvider) } } @@ -203,8 +207,8 @@ func TestCreateFromConfigWithEmptyPredicatesOrPriorities(t *testing.T) { defer close(stopCh) factory := newConfigFactory(client, v1.DefaultHardPodAffinitySymmetricWeight, stopCh) - RegisterFitPredicate("PredicateOne", PredicateOne) - RegisterPriorityFunction("PriorityOne", PriorityOne, 1) + RegisterFitPredicate("PredicateOne", PredicateFunc) + RegisterPriorityFunction("PriorityOne", PriorityFunc, 1) RegisterAlgorithmProvider(DefaultProvider, sets.NewString("PredicateOne"), sets.NewString("PriorityOne")) @@ -219,31 +223,23 @@ func TestCreateFromConfigWithEmptyPredicatesOrPriorities(t *testing.T) { t.Fatalf("Invalid configuration: %v", err) } - config, err := factory.CreateFromConfig(policy) + c, err := factory.CreateFromConfig(policy) if err != nil { t.Fatalf("Failed to create scheduler from configuration: %v", err) } - if len(config.Algorithm.Predicates()) != 0 { + if len(c.Algorithm.Predicates()) != 0 { t.Error("Expected empty predicate sets") } - if len(config.Algorithm.Prioritizers()) != 0 { + if len(c.Algorithm.Prioritizers()) != 0 { t.Error("Expected empty priority sets") } } -func PredicateOne(pod *v1.Pod, meta predicates.PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []predicates.PredicateFailureReason, error) { +func PredicateFunc(pod *v1.Pod, meta predicates.PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []predicates.PredicateFailureReason, error) { return true, nil, nil } -func PredicateTwo(pod *v1.Pod, meta predicates.PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []predicates.PredicateFailureReason, error) { - return true, nil, nil -} - -func PriorityOne(pod *v1.Pod, nodeNameToInfo map[string]*schedulernodeinfo.NodeInfo, nodes []*v1.Node) (schedulerapi.HostPriorityList, error) { - return []schedulerapi.HostPriority{}, nil -} - -func PriorityTwo(pod *v1.Pod, nodeNameToInfo map[string]*schedulernodeinfo.NodeInfo, nodes []*v1.Node) (schedulerapi.HostPriorityList, error) { +func PriorityFunc(pod *v1.Pod, nodeNameToInfo map[string]*schedulernodeinfo.NodeInfo, nodes []*v1.Node) (schedulerapi.HostPriorityList, error) { return []schedulerapi.HostPriority{}, nil } @@ -476,7 +472,9 @@ func TestInvalidFactoryArgs(t *testing.T) { } -func newConfigFactory(client clientset.Interface, hardPodAffinitySymmetricWeight int32, stopCh <-chan struct{}) *Configurator { +func newConfigFactoryWithFrameworkRegistry( + client clientset.Interface, hardPodAffinitySymmetricWeight int32, stopCh <-chan struct{}, + registry framework.Registry, pluginConfigProducerRegistry *frameworkplugins.ConfigProducerRegistry) *Configurator { informerFactory := informers.NewSharedInformerFactory(client, 0) return NewConfigFactory(&ConfigFactoryArgs{ client, @@ -496,12 +494,19 @@ func newConfigFactory(client clientset.Interface, hardPodAffinitySymmetricWeight schedulerapi.DefaultPercentageOfNodesToScore, bindTimeoutSeconds, stopCh, - plugins.NewDefaultRegistry(), + registry, nil, []config.PluginConfig{}, + pluginConfigProducerRegistry, }) } +func newConfigFactory( + client clientset.Interface, hardPodAffinitySymmetricWeight int32, stopCh <-chan struct{}) *Configurator { + return newConfigFactoryWithFrameworkRegistry(client, hardPodAffinitySymmetricWeight, stopCh, + frameworkplugins.NewDefaultRegistry(), frameworkplugins.NewDefaultConfigProducerRegistry()) +} + type fakeExtender struct { isBinder bool interestedPodName string @@ -616,3 +621,188 @@ func testGetBinderFunc(expectedBinderType, podName string, extenders []algorithm t.Errorf("Expected binder %q but got %q", expectedBinderType, binderType) } } + +type TestPlugin struct { + name string +} + +func (t *TestPlugin) Name() string { + return t.name +} + +func (t *TestPlugin) Score(pc *framework.PluginContext, p *v1.Pod, nodeName string) (int, *framework.Status) { + return 1, nil +} + +func (t *TestPlugin) NormalizeScore(pc *framework.PluginContext, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status { + return nil +} + +func (t *TestPlugin) Filter(pc *framework.PluginContext, pod *v1.Pod, nodeInfo *schedulernodeinfo.NodeInfo) *framework.Status { + return nil +} + +// Test configures a scheduler from a policies defined in a file +// It combines some configurable predicate/priorities with some pre-defined ones +func TestCreateWithFrameworkPlugins(t *testing.T) { + var configData []byte + var policy schedulerapi.Policy + + client := fake.NewSimpleClientset() + stopCh := make(chan struct{}) + defer close(stopCh) + + predicateOneName := "PredicateOne" + filterOneName := "FilterOne" + predicateTwoName := "PredicateTwo" + filterTwoName := "FilterTwo" + predicateThreeName := "PredicateThree" + predicateFourName := "PredicateFour" + priorityOneName := "PriorityOne" + scoreOneName := "ScoreOne" + priorityTwoName := "PriorityTwo" + scoreTwoName := "ScoreTwo" + priorityThreeName := "PriorityThree" + + configProducerRegistry := &frameworkplugins.ConfigProducerRegistry{ + PredicateToConfigProducer: make(map[string]frameworkplugins.ConfigProducer), + PriorityToConfigProducer: make(map[string]frameworkplugins.ConfigProducer), + } + configProducerRegistry.RegisterPredicate(predicateOneName, + func(_ frameworkplugins.ConfigProducerArgs) (config.Plugins, []config.PluginConfig) { + return config.Plugins{ + Filter: &config.PluginSet{ + Enabled: []config.Plugin{ + {Name: filterOneName}}}}, nil + }) + + configProducerRegistry.RegisterPredicate(predicateTwoName, + func(_ frameworkplugins.ConfigProducerArgs) (config.Plugins, []config.PluginConfig) { + return config.Plugins{ + Filter: &config.PluginSet{ + Enabled: []config.Plugin{ + {Name: filterTwoName}}}}, nil + }) + + configProducerRegistry.RegisterPriority(priorityOneName, + func(args frameworkplugins.ConfigProducerArgs) (config.Plugins, []config.PluginConfig) { + return config.Plugins{ + Score: &config.PluginSet{ + Enabled: []config.Plugin{ + {Name: scoreOneName, Weight: args.Weight}}}}, nil + }) + + configProducerRegistry.RegisterPriority(priorityTwoName, + func(args frameworkplugins.ConfigProducerArgs) (config.Plugins, []config.PluginConfig) { + return config.Plugins{ + Score: &config.PluginSet{ + Enabled: []config.Plugin{ + {Name: scoreTwoName, Weight: args.Weight}}}}, nil + }) + + registry := framework.Registry{ + filterOneName: func(_ *runtime.Unknown, fh framework.FrameworkHandle) (framework.Plugin, error) { + return &TestPlugin{name: filterOneName}, nil + }, + filterTwoName: func(_ *runtime.Unknown, fh framework.FrameworkHandle) (framework.Plugin, error) { + return &TestPlugin{name: filterTwoName}, nil + }, + scoreOneName: func(_ *runtime.Unknown, fh framework.FrameworkHandle) (framework.Plugin, error) { + return &TestPlugin{name: scoreOneName}, nil + }, + scoreTwoName: func(_ *runtime.Unknown, fh framework.FrameworkHandle) (framework.Plugin, error) { + return &TestPlugin{name: scoreTwoName}, nil + }, + } + + factory := newConfigFactoryWithFrameworkRegistry( + client, v1.DefaultHardPodAffinitySymmetricWeight, stopCh, registry, configProducerRegistry) + + // Pre-register some predicate and priority functions + RegisterMandatoryFitPredicate(predicateOneName, PredicateFunc) + RegisterFitPredicate(predicateTwoName, PredicateFunc) + RegisterFitPredicate(predicateThreeName, PredicateFunc) + RegisterMandatoryFitPredicate(predicateFourName, PredicateFunc) + RegisterPriorityFunction(priorityOneName, PriorityFunc, 1) + RegisterPriorityFunction(priorityTwoName, PriorityFunc, 1) + RegisterPriorityFunction(priorityThreeName, PriorityFunc, 1) + + configData = []byte(`{ + "kind" : "Policy", + "apiVersion" : "v1", + "predicates" : [ + {"name" : "PredicateOne"}, + {"name" : "PredicateTwo"}, + {"name" : "PredicateThree"}, + {"name" : "PredicateThree"} + ], + "priorities" : [ + {"name" : "PriorityOne", "weight" : 2}, + {"name" : "PriorityTwo", "weight" : 1}, + {"name" : "PriorityThree", "weight" : 1} ] + }`) + if err := runtime.DecodeInto(latestschedulerapi.Codec, configData, &policy); err != nil { + t.Errorf("Invalid configuration: %v", err) + } + + c, err := factory.CreateFromConfig(policy) + if err != nil { + t.Fatalf("creating config: %v", err) + } + + gotPredicates := sets.NewString() + for p := range c.Algorithm.Predicates() { + gotPredicates.Insert(p) + } + wantPredicates := sets.NewString( + predicateThreeName, + predicateFourName, + ) + if diff := cmp.Diff(wantPredicates, gotPredicates); diff != "" { + t.Errorf("unexpected predicates diff (-want, +got): %s", diff) + } + + gotPriorities := sets.NewString() + for _, p := range c.Algorithm.Prioritizers() { + gotPriorities.Insert(p.Name) + } + wantPriorities := sets.NewString(priorityThreeName) + if diff := cmp.Diff(wantPriorities, gotPriorities); diff != "" { + t.Errorf("unexpected priorities diff (-want, +got): %s", diff) + } + + // Verify the aggregated configuration. + wantPlugins := config.Plugins{ + QueueSort: &config.PluginSet{}, + PreFilter: &config.PluginSet{}, + Filter: &config.PluginSet{ + Enabled: []config.Plugin{ + {Name: filterOneName}, + {Name: filterTwoName}, + }, + }, + PostFilter: &config.PluginSet{}, + Score: &config.PluginSet{ + Enabled: []config.Plugin{ + {Name: scoreOneName, Weight: 2}, + {Name: scoreTwoName, Weight: 1}, + }, + }, + Reserve: &config.PluginSet{}, + Permit: &config.PluginSet{}, + PreBind: &config.PluginSet{}, + Bind: &config.PluginSet{}, + PostBind: &config.PluginSet{}, + Unreserve: &config.PluginSet{}, + } + + trans := cmp.Transformer("Sort", func(in []config.Plugin) []config.Plugin { + out := append([]config.Plugin(nil), in...) // Copy input to avoid mutating it + sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name }) + return out + }) + + if diff := cmp.Diff(wantPlugins, c.Plugins, trans); diff != "" { + t.Errorf("unexpected plugin configuration (-want, +got): %s", diff) + } +} diff --git a/pkg/scheduler/framework/plugins/default_registry.go b/pkg/scheduler/framework/plugins/default_registry.go index 4c734288fc6..ac91fbe0f02 100644 --- a/pkg/scheduler/framework/plugins/default_registry.go +++ b/pkg/scheduler/framework/plugins/default_registry.go @@ -53,8 +53,8 @@ type ConfigProducerRegistry struct { PriorityToConfigProducer map[string]ConfigProducer } -// NewConfigProducerRegistry creates a new producer registry. -func NewConfigProducerRegistry() *ConfigProducerRegistry { +// NewDefaultConfigProducerRegistry creates a new producer registry. +func NewDefaultConfigProducerRegistry() *ConfigProducerRegistry { return &ConfigProducerRegistry{ PredicateToConfigProducer: make(map[string]ConfigProducer), PriorityToConfigProducer: make(map[string]ConfigProducer), diff --git a/pkg/scheduler/framework/plugins/default_registry_test.go b/pkg/scheduler/framework/plugins/default_registry_test.go index 50e96cd2d40..eaf74362a9c 100644 --- a/pkg/scheduler/framework/plugins/default_registry_test.go +++ b/pkg/scheduler/framework/plugins/default_registry_test.go @@ -53,7 +53,7 @@ func produceConfig(keys []string, producersMap map[string]ConfigProducer, args C } func TestRegisterConfigProducers(t *testing.T) { - registry := NewConfigProducerRegistry() + registry := NewDefaultConfigProducerRegistry() testPredicateName1 := "testPredicate1" testFilterName1 := "testFilter1" registry.RegisterPredicate(testPredicateName1,