diff --git a/pkg/scheduler/api/compatibility/BUILD b/pkg/scheduler/api/compatibility/BUILD index 2442cfceb4f..ad80f18ad43 100644 --- a/pkg/scheduler/api/compatibility/BUILD +++ b/pkg/scheduler/api/compatibility/BUILD @@ -10,6 +10,7 @@ go_test( "//pkg/scheduler/api:go_default_library", "//pkg/scheduler/api/latest:go_default_library", "//pkg/scheduler/apis/config:go_default_library", + "//pkg/scheduler/core:go_default_library", "//pkg/scheduler/factory:go_default_library", "//pkg/scheduler/framework/plugins:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", diff --git a/pkg/scheduler/api/compatibility/compatibility_test.go b/pkg/scheduler/api/compatibility/compatibility_test.go index 902ac57eba2..676792000b6 100644 --- a/pkg/scheduler/api/compatibility/compatibility_test.go +++ b/pkg/scheduler/api/compatibility/compatibility_test.go @@ -18,7 +18,6 @@ package compatibility import ( "fmt" - "reflect" "testing" v1 "k8s.io/api/core/v1" @@ -34,6 +33,7 @@ import ( latestschedulerapi "k8s.io/kubernetes/pkg/scheduler/api/latest" kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config" schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/kubernetes/pkg/scheduler/core" "k8s.io/kubernetes/pkg/scheduler/factory" schedulerframework "k8s.io/kubernetes/pkg/scheduler/framework/plugins" ) @@ -1196,7 +1196,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) { }, }, } - registeredPredicates := sets.NewString(factory.ListRegisteredFitPredicates()...) registeredPriorities := sets.NewString(factory.ListRegisteredPriorityFunctions()...) seenPredicates := sets.NewString() @@ -1210,20 +1209,10 @@ func TestCompatibility_v1_Scheduler(t *testing.T) { t.Errorf("%s: Error decoding: %v", v, err) continue } - for _, predicate := range policy.Predicates { - seenPredicates.Insert(predicate.Name) - } - for _, priority := range policy.Priorities { - seenPriorities.Insert(priority.Name) - } - if !reflect.DeepEqual(policy, tc.ExpectedPolicy) { - t.Errorf("%s: Expected:\n\t%#v\nGot:\n\t%#v", v, tc.ExpectedPolicy, policy) - } policyConfigMap := v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: "scheduler-custom-policy-config"}, Data: map[string]string{schedulerconfig.SchedulerPolicyConfigMapKey: tc.JSON}, } - policyConfigMap.APIVersion = "v1" client := fake.NewSimpleClientset(&policyConfigMap) algorithmSrc := schedulerconfig.SchedulerAlgorithmSource{ Policy: &schedulerconfig.SchedulerPolicySource{ @@ -1235,7 +1224,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) { } informerFactory := informers.NewSharedInformerFactory(client, 0) - if _, err := scheduler.New( + sched, err := scheduler.New( client, informerFactory.Core().V1().Nodes(), informerFactory.Core().V1().Pods(), @@ -1254,10 +1243,50 @@ func TestCompatibility_v1_Scheduler(t *testing.T) { schedulerframework.NewDefaultRegistry(), nil, []kubeschedulerconfig.PluginConfig{}, - ); err != nil { + ) + if err != nil { t.Errorf("%s: Error constructing: %v", v, err) continue } + schedPredicates := sets.NewString() + for p := range sched.Algorithm.Predicates() { + schedPredicates.Insert(p) + } + wantPredicates := sets.NewString() + wantPredicates.Insert("CheckNodeCondition") // mandatory predicate + for _, p := range tc.ExpectedPolicy.Predicates { + wantPredicates.Insert(p.Name) + seenPredicates.Insert(p.Name) + } + if !schedPredicates.Equal(wantPredicates) { + t.Errorf("Expected predicates %v, got %v", wantPredicates, schedPredicates) + } + schedPrioritizers := sets.NewString() + for _, p := range sched.Algorithm.Prioritizers() { + schedPrioritizers.Insert(p.Name) + seenPriorities.Insert(p.Name) + } + wantPrioritizers := sets.NewString() + for _, p := range tc.ExpectedPolicy.Priorities { + wantPrioritizers.Insert(p.Name) + } + if !schedPrioritizers.Equal(wantPrioritizers) { + t.Errorf("Expected prioritizers %v, got %v", wantPrioritizers, schedPrioritizers) + } + schedExtenders := sched.Algorithm.Extenders() + var wantExtenders []*core.HTTPExtender + for _, e := range tc.ExpectedPolicy.ExtenderConfigs { + extender, err := core.NewHTTPExtender(&e) + if err != nil { + t.Errorf("Error transforming extender: %+v", e) + } + wantExtenders = append(wantExtenders, extender.(*core.HTTPExtender)) + } + for i := range schedExtenders { + if !core.Equal(wantExtenders[i], schedExtenders[i].(*core.HTTPExtender)) { + t.Errorf("Got extender #%d %+v, want %+v", i, schedExtenders[i], wantExtenders[i]) + } + } } if !seenPredicates.HasAll(registeredPredicates.List()...) { diff --git a/pkg/scheduler/core/extender.go b/pkg/scheduler/core/extender.go index 0b21d732ffa..8a1b10f51ff 100644 --- a/pkg/scheduler/core/extender.go +++ b/pkg/scheduler/core/extender.go @@ -114,6 +114,36 @@ func NewHTTPExtender(config *schedulerapi.ExtenderConfig) (algorithm.SchedulerEx }, nil } +// Equal is used to check if two extenders are equal +// ignoring the client field, exported for testing +func Equal(e1, e2 *HTTPExtender) bool { + if e1.extenderURL != e2.extenderURL { + return false + } + if e1.preemptVerb != e2.preemptVerb { + return false + } + if e1.prioritizeVerb != e2.prioritizeVerb { + return false + } + if e1.bindVerb != e2.bindVerb { + return false + } + if e1.weight != e2.weight { + return false + } + if e1.nodeCacheCapable != e2.nodeCacheCapable { + return false + } + if !e1.managedResources.Equal(e2.managedResources) { + return false + } + if e1.ignorable != e2.ignorable { + return false + } + return true +} + // Name returns extenderURL to identify the extender. func (h *HTTPExtender) Name() string { return h.extenderURL diff --git a/pkg/scheduler/core/generic_scheduler.go b/pkg/scheduler/core/generic_scheduler.go index fb24bf098a2..71ddd61a1ce 100644 --- a/pkg/scheduler/core/generic_scheduler.go +++ b/pkg/scheduler/core/generic_scheduler.go @@ -144,6 +144,9 @@ type ScheduleAlgorithm interface { // Prioritizers returns a slice of priority config. This is exposed for // testing. Prioritizers() []priorities.PriorityConfig + // Extenders returns a slice of extender config. This is exposed for + // testing. + Extenders() []algorithm.SchedulerExtender } // ScheduleResult represents the result of one pod scheduled. It will contain @@ -280,6 +283,10 @@ func (g *genericScheduler) Predicates() map[string]predicates.FitPredicate { return g.predicates } +func (g *genericScheduler) Extenders() []algorithm.SchedulerExtender { + return g.extenders +} + // selectHost takes a prioritized list of nodes and then picks one // in a reservoir sampling manner from the nodes that had the highest score. func (g *genericScheduler) selectHost(priorityList schedulerapi.HostPriorityList) (string, error) { diff --git a/pkg/scheduler/scheduler_test.go b/pkg/scheduler/scheduler_test.go index e0e296b82f5..b02f8acee86 100644 --- a/pkg/scheduler/scheduler_test.go +++ b/pkg/scheduler/scheduler_test.go @@ -163,6 +163,9 @@ func (es mockScheduler) Predicates() map[string]predicates.FitPredicate { func (es mockScheduler) Prioritizers() []priorities.PriorityConfig { return nil } +func (es mockScheduler) Extenders() []algorithm.SchedulerExtender { + return nil +} func (es mockScheduler) Preempt(pc *framework.PluginContext, pod *v1.Pod, scheduleErr error) (*v1.Node, []*v1.Pod, []*v1.Pod, error) { return nil, nil, nil, nil