diff --git a/pkg/scheduler/generic_scheduler.go b/pkg/scheduler/generic_scheduler.go index 737a964764c..df6946bf9fc 100644 --- a/pkg/scheduler/generic_scheduler.go +++ b/pkg/scheduler/generic_scheduler.go @@ -100,7 +100,8 @@ func getMinHosts(list HostPriorityList) []string { return result } -func evenPriority(pod api.Pod, podLister PodLister, minionLister MinionLister) (HostPriorityList, error) { +// EqualPriority is a prioritizer function that gives an equal weight of one to all nodes +func EqualPriority(pod api.Pod, podLister PodLister, minionLister MinionLister) (HostPriorityList, error) { nodes, err := minionLister.List() result := []HostPriority{} diff --git a/pkg/scheduler/generic_scheduler_test.go b/pkg/scheduler/generic_scheduler_test.go index 1b9e98e7693..a49b3d3fe26 100644 --- a/pkg/scheduler/generic_scheduler_test.go +++ b/pkg/scheduler/generic_scheduler_test.go @@ -25,6 +25,14 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" ) +func falsePredicate(pod api.Pod, existingPods []api.Pod, node string) (bool, error) { + return false, nil +} + +func truePredicate(pod api.Pod, existingPods []api.Pod, node string) (bool, error) { + return true, nil +} + func matchesPredicate(pod api.Pod, existingPods []api.Pod, node string) (bool, error) { return pod.ID == node, nil } @@ -61,13 +69,13 @@ func TestGenericScheduler(t *testing.T) { }{ { predicates: []FitPredicate{falsePredicate}, - prioritizer: evenPriority, + prioritizer: EqualPriority, nodes: []string{"machine1", "machine2"}, expectsErr: true, }, { predicates: []FitPredicate{truePredicate}, - prioritizer: evenPriority, + prioritizer: EqualPriority, nodes: []string{"machine1", "machine2"}, // Random choice between both, the rand seeded above with zero, chooses "machine2" expectedHost: "machine2", @@ -75,7 +83,7 @@ func TestGenericScheduler(t *testing.T) { { // Fits on a machine where the pod ID matches the machine name predicates: []FitPredicate{matchesPredicate}, - prioritizer: evenPriority, + prioritizer: EqualPriority, nodes: []string{"machine1", "machine2"}, pod: api.Pod{JSONBase: api.JSONBase{ID: "machine2"}}, expectedHost: "machine2", diff --git a/pkg/scheduler/randomfit.go b/pkg/scheduler/predicates.go similarity index 72% rename from pkg/scheduler/randomfit.go rename to pkg/scheduler/predicates.go index 8f30fe172b1..348345b8a23 100644 --- a/pkg/scheduler/randomfit.go +++ b/pkg/scheduler/predicates.go @@ -17,24 +17,11 @@ limitations under the License. package scheduler import ( - "math/rand" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" ) -// NewRandomFitScheduler creates a random fit scheduler with the default set of fit predicates -func NewRandomFitScheduler(podLister PodLister, random *rand.Rand) Scheduler { - return NewRandomFitSchedulerWithPredicates(podLister, random, []FitPredicate{podFitsPorts}) -} - -// NewRandomFitScheduler creates a random fit scheduler with the specified set of fit predicates. -// All predicates must be true for the pod to be considered a fit. -func NewRandomFitSchedulerWithPredicates(podLister PodLister, random *rand.Rand, predicates []FitPredicate) Scheduler { - return NewGenericScheduler(predicates, evenPriority, podLister, random) -} - -func podFitsPorts(pod api.Pod, existingPods []api.Pod, node string) (bool, error) { +func PodFitsPorts(pod api.Pod, existingPods []api.Pod, node string) (bool, error) { for _, scheduledPod := range existingPods { for _, container := range pod.DesiredState.Manifest.Containers { for _, port := range container.Ports { diff --git a/pkg/scheduler/predicates_test.go b/pkg/scheduler/predicates_test.go new file mode 100644 index 00000000000..89539f7d791 --- /dev/null +++ b/pkg/scheduler/predicates_test.go @@ -0,0 +1,80 @@ +/* +Copyright 2014 Google Inc. 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 scheduler + +import ( + "testing" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" +) + +func TestPodFitsPorts(t *testing.T) { + tests := []struct { + pod api.Pod + existingPods []api.Pod + fits bool + test string + }{ + { + pod: api.Pod{}, + existingPods: []api.Pod{}, + fits: true, + test: "nothing running", + }, + { + pod: newPod("m1", 8080), + existingPods: []api.Pod{ + newPod("m1", 9090), + }, + fits: true, + test: "other port", + }, + { + pod: newPod("m1", 8080), + existingPods: []api.Pod{ + newPod("m1", 8080), + }, + fits: false, + test: "same port", + }, + { + pod: newPod("m1", 8000, 8080), + existingPods: []api.Pod{ + newPod("m1", 8080), + }, + fits: false, + test: "second port", + }, + { + pod: newPod("m1", 8000, 8080), + existingPods: []api.Pod{ + newPod("m1", 8001, 8080), + }, + fits: false, + test: "second port", + }, + } + for _, test := range tests { + fits, err := PodFitsPorts(test.pod, test.existingPods, "machine") + if err != nil { + t.Errorf("unexpected error: %v") + } + if test.fits != fits { + t.Errorf("%s: expected %v, saw %v", test.test, test.fits, fits) + } + } +} diff --git a/pkg/scheduler/randomfit_test.go b/pkg/scheduler/randomfit_test.go deleted file mode 100644 index f4c3b908f33..00000000000 --- a/pkg/scheduler/randomfit_test.go +++ /dev/null @@ -1,116 +0,0 @@ -/* -Copyright 2014 Google Inc. 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 scheduler - -import ( - "math/rand" - "testing" - - "github.com/GoogleCloudPlatform/kubernetes/pkg/api" -) - -func TestRandomFitSchedulerNothingScheduled(t *testing.T) { - fakeRegistry := FakePodLister{} - r := rand.New(rand.NewSource(0)) - st := schedulerTester{ - t: t, - scheduler: NewRandomFitScheduler(&fakeRegistry, r), - minionLister: FakeMinionLister{"m1", "m2", "m3"}, - } - st.expectSchedule(api.Pod{}, "m3") -} - -func TestRandomFitSchedulerFirstScheduled(t *testing.T) { - fakeRegistry := FakePodLister{ - newPod("m1", 8080), - } - r := rand.New(rand.NewSource(0)) - st := schedulerTester{ - t: t, - scheduler: NewRandomFitScheduler(fakeRegistry, r), - minionLister: FakeMinionLister{"m1", "m2", "m3"}, - } - st.expectSchedule(newPod("", 8080), "m3") -} - -func TestRandomFitSchedulerFirstScheduledComplicated(t *testing.T) { - fakeRegistry := FakePodLister{ - newPod("m1", 80, 8080), - newPod("m2", 8081, 8082, 8083), - newPod("m3", 80, 443, 8085), - } - r := rand.New(rand.NewSource(0)) - st := schedulerTester{ - t: t, - scheduler: NewRandomFitScheduler(fakeRegistry, r), - minionLister: FakeMinionLister{"m1", "m2", "m3"}, - } - st.expectSchedule(newPod("", 8080, 8081), "m3") -} - -func TestRandomFitSchedulerFirstScheduledImpossible(t *testing.T) { - fakeRegistry := FakePodLister{ - newPod("m1", 8080), - newPod("m2", 8081), - newPod("m3", 8080), - } - r := rand.New(rand.NewSource(0)) - st := schedulerTester{ - t: t, - scheduler: NewRandomFitScheduler(fakeRegistry, r), - minionLister: FakeMinionLister{"m1", "m2", "m3"}, - } - st.expectFailure(newPod("", 8080, 8081)) -} - -func falsePredicate(pod api.Pod, existingPods []api.Pod, node string) (bool, error) { - return false, nil -} - -func truePredicate(pod api.Pod, existingPods []api.Pod, node string) (bool, error) { - return true, nil -} - -func TestRandomFitSchedulerFirstScheduledComplicatedWithMultiplePredicates(t *testing.T) { - fakeRegistry := FakePodLister{ - newPod("m1", 80, 8080), - newPod("m2", 8081, 8082, 8083), - newPod("m3", 80, 443, 8085), - } - r := rand.New(rand.NewSource(0)) - st := schedulerTester{ - t: t, - scheduler: NewRandomFitSchedulerWithPredicates(fakeRegistry, r, []FitPredicate{podFitsPorts, truePredicate}), - minionLister: FakeMinionLister{"m1", "m2", "m3"}, - } - st.expectSchedule(newPod("", 8080, 8081), "m3") -} - -func TestRandomFitSchedulerFailureManyPredicates(t *testing.T) { - fakeRegistry := FakePodLister{ - newPod("m1", 8080), - newPod("m2", 8081), - newPod("m3", 8080), - } - r := rand.New(rand.NewSource(0)) - st := schedulerTester{ - t: t, - scheduler: NewRandomFitSchedulerWithPredicates(fakeRegistry, r, []FitPredicate{truePredicate, falsePredicate}), - minionLister: FakeMinionLister{"m1", "m2", "m3"}, - } - st.expectFailure(newPod("", 8080, 8081)) -} diff --git a/pkg/scheduler/spreading_scheduler.go b/pkg/scheduler/spreading.go similarity index 100% rename from pkg/scheduler/spreading_scheduler.go rename to pkg/scheduler/spreading.go diff --git a/pkg/scheduler/spreading_scheduler_test.go b/pkg/scheduler/spreading_test.go similarity index 100% rename from pkg/scheduler/spreading_scheduler_test.go rename to pkg/scheduler/spreading_test.go diff --git a/plugin/pkg/scheduler/factory/factory.go b/plugin/pkg/scheduler/factory/factory.go index c67aa863785..f3efb03d1a7 100644 --- a/plugin/pkg/scheduler/factory/factory.go +++ b/plugin/pkg/scheduler/factory/factory.go @@ -62,7 +62,11 @@ func (factory *ConfigFactory) Create() *scheduler.Config { } r := rand.New(rand.NewSource(time.Now().UnixNano())) - algo := algorithm.NewRandomFitScheduler( + algo := algorithm.NewGenericScheduler( + // Fit is defined based on the absence of port conflicts. + []algorithm.FitPredicate{algorithm.PodFitsPorts}, + // All nodes where things fit are equally likely (Random) + algorithm.EqualPriority, &storeToPodLister{podCache}, r) return &scheduler.Config{