From cf7a2cdfff283365c29fa4f9874457c00eee9ac0 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Tue, 11 Aug 2015 15:03:35 -0400 Subject: [PATCH] Re-add ServiceSpreadingPriority priority algorithm --- plugin/pkg/scheduler/algorithm/listers.go | 13 +++ .../defaults/compatibility_test.go | 100 ++++++++++++++++++ .../algorithmprovider/defaults/defaults.go | 16 ++- 3 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 plugin/pkg/scheduler/algorithmprovider/defaults/compatibility_test.go diff --git a/plugin/pkg/scheduler/algorithm/listers.go b/plugin/pkg/scheduler/algorithm/listers.go index f4b6eec1b0..5b7c173a49 100644 --- a/plugin/pkg/scheduler/algorithm/listers.go +++ b/plugin/pkg/scheduler/algorithm/listers.go @@ -100,6 +100,19 @@ type ControllerLister interface { GetPodControllers(*api.Pod) ([]api.ReplicationController, error) } +// EmptyControllerLister implements ControllerLister on []api.ReplicationController returning empty data +type EmptyControllerLister struct{} + +// List returns nil +func (f EmptyControllerLister) List() ([]api.ReplicationController, error) { + return nil, nil +} + +// GetPodControllers returns nil +func (f EmptyControllerLister) GetPodControllers(pod *api.Pod) (controllers []api.ReplicationController, err error) { + return nil, nil +} + // FakeControllerLister implements ControllerLister on []api.ReplicationController for test purposes. type FakeControllerLister []api.ReplicationController diff --git a/plugin/pkg/scheduler/algorithmprovider/defaults/compatibility_test.go b/plugin/pkg/scheduler/algorithmprovider/defaults/compatibility_test.go new file mode 100644 index 0000000000..62918ca184 --- /dev/null +++ b/plugin/pkg/scheduler/algorithmprovider/defaults/compatibility_test.go @@ -0,0 +1,100 @@ +/* +Copyright 2015 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package defaults + +import ( + "reflect" + "testing" + + schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api" + latestschedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api/latest" + "k8s.io/kubernetes/plugin/pkg/scheduler/factory" +) + +func TestCompatibility_v1_Scheduler(t *testing.T) { + // Add serialized versions of scheduler config that exercise available options to ensure compatibility between releases + schedulerFiles := map[string]struct { + JSON string + ExpectedPolicy schedulerapi.Policy + }{ + // Do not change this JSON. A failure indicates backwards compatibility with 1.0 was broken. + "1.0": { + JSON: `{ + "predicates": [ + {"name": "MatchNodeSelector"}, + {"name": "PodFitsResources"}, + {"name": "PodFitsPorts"}, + {"name": "NoDiskConflict"}, + {"name": "TestServiceAffinity", "argument": {"serviceAffinity" : {"labels" : ["region"]}}}, + {"name": "TestLabelsPresence", "argument": {"labelsPresence" : {"labels" : ["foo"], "presence":true}}} + ],"priorities": [ + {"name": "LeastRequestedPriority", "weight": 1}, + {"name": "ServiceSpreadingPriority", "weight": 2}, + {"name": "TestServiceAntiAffinity", "weight": 3, "argument": {"serviceAntiAffinity": {"label": "zone"}}}, + {"name": "TestLabelPreference", "weight": 4, "argument": {"labelPreference": {"label": "bar", "presence":true}}} + ] +}`, + ExpectedPolicy: schedulerapi.Policy{ + Predicates: []schedulerapi.PredicatePolicy{ + {Name: "MatchNodeSelector"}, + {Name: "PodFitsResources"}, + {Name: "PodFitsPorts"}, + {Name: "NoDiskConflict"}, + {Name: "TestServiceAffinity", Argument: &schedulerapi.PredicateArgument{ServiceAffinity: &schedulerapi.ServiceAffinity{Labels: []string{"region"}}}}, + {Name: "TestLabelsPresence", Argument: &schedulerapi.PredicateArgument{LabelsPresence: &schedulerapi.LabelsPresence{Labels: []string{"foo"}, Presence: true}}}, + }, + Priorities: []schedulerapi.PriorityPolicy{ + {Name: "LeastRequestedPriority", Weight: 1}, + {Name: "ServiceSpreadingPriority", Weight: 2}, + {Name: "TestServiceAntiAffinity", Weight: 3, Argument: &schedulerapi.PriorityArgument{ServiceAntiAffinity: &schedulerapi.ServiceAntiAffinity{Label: "zone"}}}, + {Name: "TestLabelPreference", Weight: 4, Argument: &schedulerapi.PriorityArgument{LabelPreference: &schedulerapi.LabelPreference{Label: "bar", Presence: true}}}, + }, + }, + }, + + // Do not change this JSON after 1.1 is tagged. A failure indicates backwards compatibility with 1.1 was broken. + "1.1": { + JSON: `{ + "priorities": [ + {"name": "SelectorSpreadPriority", "weight": 2} + ] + }`, + ExpectedPolicy: schedulerapi.Policy{ + Priorities: []schedulerapi.PriorityPolicy{ + {Name: "SelectorSpreadPriority", Weight: 2}, + }, + }, + }, + } + + for v, tc := range schedulerFiles { + policy := schedulerapi.Policy{} + err := latestschedulerapi.Codec.DecodeInto([]byte(tc.JSON), &policy) + if err != nil { + t.Errorf("%s: Error decoding: %v", v, err) + continue + } + if !reflect.DeepEqual(policy, tc.ExpectedPolicy) { + t.Errorf("%s: Expected:\n\t%#v\nGot:\n\t%#v", v, tc.ExpectedPolicy, policy) + } + _, err = factory.NewConfigFactory(nil, nil).CreateFromConfig(policy) + if err != nil { + t.Errorf("%s: Error constructing: %v", v, err) + continue + } + } +} diff --git a/plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go b/plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go index 30b3300576..753827f6f5 100644 --- a/plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go +++ b/plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go @@ -32,6 +32,20 @@ func init() { // Register the priority function so that its available // but do not include it as part of the default priorities factory.RegisterPriorityFunction("EqualPriority", scheduler.EqualPriority, 1) + + // ServiceSpreadingPriority is a priority config factory that spreads pods by minimizing + // the number of pods (belonging to the same service) on the same node. + // Register the factory so that it's available, but do not include it as part of the default priorities + // Largely replaced by "SelectorSpreadPriority", but registered for backward compatibility with 1.0 + factory.RegisterPriorityConfigFactory( + "ServiceSpreadingPriority", + factory.PriorityConfigFactory{ + Function: func(args factory.PluginFactoryArgs) algorithm.PriorityFunction { + return priorities.NewSelectorSpreadPriority(args.ServiceLister, algorithm.EmptyControllerLister{}) + }, + Weight: 1, + }, + ) } func defaultPredicates() util.StringSet { @@ -65,7 +79,7 @@ func defaultPriorities() util.StringSet { factory.RegisterPriorityFunction("LeastRequestedPriority", priorities.LeastRequestedPriority, 1), // Prioritizes nodes to help achieve balanced resource usage factory.RegisterPriorityFunction("BalancedResourceAllocation", priorities.BalancedResourceAllocation, 1), - // spreads pods by minimizing the number of pods (belonging to the same service) on the same minion. + // spreads pods by minimizing the number of pods (belonging to the same service or replication controller) on the same node. factory.RegisterPriorityConfigFactory( "SelectorSpreadPriority", factory.PriorityConfigFactory{