From 548e0da5671d37987ca9db3672141fb4075578c8 Mon Sep 17 00:00:00 2001 From: Abhishek Gupta Date: Thu, 19 Feb 2015 16:18:28 -0800 Subject: [PATCH 1/6] Configuring scheduler via json configuration file --- plugin/cmd/kube-scheduler/app/server.go | 27 +++++ .../algorithmprovider/affinity/affinity.go | 8 +- plugin/pkg/scheduler/api/latest/latest.go | 40 +++++++ plugin/pkg/scheduler/api/register.go | 32 ++++++ plugin/pkg/scheduler/api/types.go | 73 ++++++++++++ plugin/pkg/scheduler/api/v1/register.go | 33 ++++++ plugin/pkg/scheduler/api/v1/types.go | 106 ++++++++++++++++++ plugin/pkg/scheduler/factory/factory.go | 20 ++++ plugin/pkg/scheduler/factory/plugins.go | 87 +++++++++++++- 9 files changed, 421 insertions(+), 5 deletions(-) create mode 100644 plugin/pkg/scheduler/api/latest/latest.go create mode 100644 plugin/pkg/scheduler/api/register.go create mode 100644 plugin/pkg/scheduler/api/types.go create mode 100644 plugin/pkg/scheduler/api/v1/register.go create mode 100644 plugin/pkg/scheduler/api/v1/types.go diff --git a/plugin/cmd/kube-scheduler/app/server.go b/plugin/cmd/kube-scheduler/app/server.go index f65f7100f3d..4e643bf99d4 100644 --- a/plugin/cmd/kube-scheduler/app/server.go +++ b/plugin/cmd/kube-scheduler/app/server.go @@ -18,8 +18,11 @@ limitations under the License. package app import ( + "fmt" + "io/ioutil" "net" "net/http" + "os" "strconv" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" @@ -30,6 +33,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler" _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/algorithmprovider" + schedulerapi "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api" + latestschedulerapi "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api/latest" "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/factory" "github.com/golang/glog" @@ -42,6 +47,7 @@ type SchedulerServer struct { Address util.IP ClientConfig client.Config AlgorithmProvider string + PolicyConfigFile string } // NewSchedulerServer creates a new SchedulerServer with default parameters @@ -60,6 +66,7 @@ func (s *SchedulerServer) AddFlags(fs *pflag.FlagSet) { fs.Var(&s.Address, "address", "The IP address to serve on (set to 0.0.0.0 for all interfaces)") client.BindClientConfigFlags(fs, &s.ClientConfig) fs.StringVar(&s.AlgorithmProvider, "algorithm_provider", s.AlgorithmProvider, "The scheduling algorithm provider to use") + fs.StringVar(&s.PolicyConfigFile, "policy_config_file", s.PolicyConfigFile, "File with scheduler policy configuration") } // Run runs the specified SchedulerServer. This should never exit. @@ -78,6 +85,7 @@ func (s *SchedulerServer) Run(_ []string) error { if err != nil { glog.Fatalf("Failed to create scheduler configuration: %v", err) } + sched := scheduler.New(config) sched.Run() @@ -85,10 +93,29 @@ func (s *SchedulerServer) Run(_ []string) error { } func (s *SchedulerServer) createConfig(configFactory *factory.ConfigFactory) (*scheduler.Config, error) { + var policy schedulerapi.Policy + var configData []byte + + if _, err := os.Stat(s.PolicyConfigFile); err == nil { + configData, err = ioutil.ReadFile(s.PolicyConfigFile) + if err != nil { + return nil, fmt.Errorf("Unable to read policy config: %v", err) + } + //err = json.Unmarshal(configData, &policy) + err = latestschedulerapi.Codec.DecodeInto(configData, &policy) + if err != nil { + return nil, fmt.Errorf("Invalid configuration: %v", err) + } + + return configFactory.CreateFromConfig(policy) + } + + // if the config file isn't provided, use the specified (or default) provider // check of algorithm provider is registered and fail fast _, err := factory.GetAlgorithmProvider(s.AlgorithmProvider) if err != nil { return nil, err } + return configFactory.CreateFromProvider(s.AlgorithmProvider) } diff --git a/plugin/pkg/scheduler/algorithmprovider/affinity/affinity.go b/plugin/pkg/scheduler/algorithmprovider/affinity/affinity.go index ee023355d47..44f2bd26e6b 100644 --- a/plugin/pkg/scheduler/algorithmprovider/affinity/affinity.go +++ b/plugin/pkg/scheduler/algorithmprovider/affinity/affinity.go @@ -37,9 +37,9 @@ func affinityPredicates() util.StringSet { "PodFitsResources", "NoDiskConflict", // Ensures that all pods within the same service are hosted on minions within the same region as defined by the "region" label - factory.RegisterFitPredicate("ServiceAffinity", algorithm.NewServiceAffinityPredicate(factory.PodLister, factory.ServiceLister, factory.MinionLister, []string{"region"})), + factory.RegisterFitPredicate("RegionAffinity", algorithm.NewServiceAffinityPredicate(factory.PodLister, factory.ServiceLister, factory.MinionLister, []string{"region"})), // Fit is defined based on the presence of the "region" label on a minion, regardless of value. - factory.RegisterFitPredicate("NodeLabelPredicate", algorithm.NewNodeLabelPredicate(factory.MinionLister, []string{"region"}, true)), + factory.RegisterFitPredicate("RegionRequired", algorithm.NewNodeLabelPredicate(factory.MinionLister, []string{"region"}, true)), ) } @@ -48,8 +48,8 @@ func affinityPriorities() util.StringSet { "LeastRequestedPriority", "ServiceSpreadingPriority", // spreads pods belonging to the same service across minions in different zones - factory.RegisterPriorityFunction("ZoneSpreadingPriority", algorithm.NewServiceAntiAffinityPriority(factory.ServiceLister, "zone"), 2), + factory.RegisterPriorityFunction("ZoneSpread", algorithm.NewServiceAntiAffinityPriority(factory.ServiceLister, "zone"), 2), // Prioritize nodes based on the presence of the "zone" label on a minion, regardless of value. - factory.RegisterPriorityFunction("NodeLabelPriority", algorithm.NewNodeLabelPriority("zone", true), 1), + factory.RegisterPriorityFunction("ZonePreferred", algorithm.NewNodeLabelPriority("zone", true), 1), ) } diff --git a/plugin/pkg/scheduler/api/latest/latest.go b/plugin/pkg/scheduler/api/latest/latest.go new file mode 100644 index 00000000000..c4559130e41 --- /dev/null +++ b/plugin/pkg/scheduler/api/latest/latest.go @@ -0,0 +1,40 @@ +/* +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 latest + +import ( + "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api/v1" +) + +// Version is the string that represents the current external default version. +const Version = "v1" + +// OldestVersion is the string that represents the oldest server version supported, +// for client code that wants to hardcode the lowest common denominator. +const OldestVersion = "v1" + +// Versions is the list of versions that are recognized in code. The order provided +// may be assumed to be least feature rich to most feature rich, and clients may +// choose to prefer the latter items in the list over the former items when presented +// with a set of versions to choose. +var Versions = []string{"v1"} + +// Codec is the default codec for serializing output that should use +// the latest supported version. Use this Codec when writing to +// disk, a data store that is not dynamically versioned, or in tests. +// This codec can decode any object that Kubernetes is aware of. +var Codec = v1.Codec diff --git a/plugin/pkg/scheduler/api/register.go b/plugin/pkg/scheduler/api/register.go new file mode 100644 index 00000000000..ae3c8ae3d87 --- /dev/null +++ b/plugin/pkg/scheduler/api/register.go @@ -0,0 +1,32 @@ +/* +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 api + +import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" +) + +// Scheme is the default instance of runtime.Scheme to which types in the Kubernetes API are already registered. +var Scheme = runtime.NewScheme() + +func init() { + Scheme.AddKnownTypes("", + &Policy{}, + ) +} + +func (*Policy) IsAnAPIObject() {} diff --git a/plugin/pkg/scheduler/api/types.go b/plugin/pkg/scheduler/api/types.go new file mode 100644 index 00000000000..7453eb199ab --- /dev/null +++ b/plugin/pkg/scheduler/api/types.go @@ -0,0 +1,73 @@ +/* +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 api + +import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" +) + +// Where possible, json tags match the cli argument names. +// Top level config objects and all values required for proper functioning are not "omitempty". Any truly optional piece of config is allowed to be omitted. + +type Policy struct { + api.TypeMeta `json:",inline"` + Predicates []PredicatePolicy `json:"predicates"` + Priorities []PriorityPolicy `json:"priorities"` +} + +type PredicatePolicy struct { + Name string `json:"name"` + Argument *PredicateArgument `json:"argument"` +} + +type PriorityPolicy struct { + Name string `json:"name"` + Weight int `json:"weight"` + Argument *PriorityArgument `json:"argument"` +} + +// PredicateArgument represents the arguments that the different types of predicates take. +// Only one of its members may be specified. +type PredicateArgument struct { + ServiceAffinity *ServiceAffinity `json:"serviceAffinity"` + LabelsPresence *LabelsPresence `json:"labelsPresence"` +} + +// PriorityArgument represents the arguments that the different types of priorities take. +// Only one of its members may be specified. +type PriorityArgument struct { + ServiceAntiAffinity *ServiceAntiAffinity `json:"serviceAntiAffinity"` + LabelPreference *LabelPreference `json:"labelPreference"` +} + +type ServiceAffinity struct { + Labels []string `json:"labels"` +} + +type LabelsPresence struct { + Labels []string `json:"labels"` + Presence bool `json:"presence"` +} + +type ServiceAntiAffinity struct { + Label string `json:"label"` +} + +type LabelPreference struct { + Label string `json:"label"` + Presence bool `json:"presence"` +} diff --git a/plugin/pkg/scheduler/api/v1/register.go b/plugin/pkg/scheduler/api/v1/register.go new file mode 100644 index 00000000000..b6718cff877 --- /dev/null +++ b/plugin/pkg/scheduler/api/v1/register.go @@ -0,0 +1,33 @@ +/* +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 v1 + +import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" + "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api" +) + +// Codec encodes internal objects to the v1 scheme +var Codec = runtime.CodecFor(api.Scheme, "v1") + +func init() { + api.Scheme.AddKnownTypes("v1", + &Policy{}, + ) +} + +func (*Policy) IsAnAPIObject() {} diff --git a/plugin/pkg/scheduler/api/v1/types.go b/plugin/pkg/scheduler/api/v1/types.go new file mode 100644 index 00000000000..bbf5f0b8628 --- /dev/null +++ b/plugin/pkg/scheduler/api/v1/types.go @@ -0,0 +1,106 @@ +/* +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 v1 + +import ( + "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" +) + +// Where possible, json tags match the cli argument names. +// Top level config objects and all values required for proper functioning are not "omitempty". Any truly optional piece of config is allowed to be omitted. + +type Policy struct { + v1beta3.TypeMeta `json:",inline"` + // Predicates holds the information to configure the fit predicate functions + Predicates []PredicatePolicy `json:"predicates"` + // Priorities holds the information to configure the priority functions + Priorities []PriorityPolicy `json:"priorities"` +} + +type PredicatePolicy struct { + // Name is the identifier of the predicate policy + // For a custom predicate, the name can be user-defined + // For the Kubernetes provided predicates, the name is the identifier of the pre-defined predicate + Name string `json:"name"` + // Argument holds the parameters to configure the given predicate + Argument *PredicateArgument `json:"argument"` +} + +type PriorityPolicy struct { + // Name is the identifier of the priority policy + // For a custom priority, the name can be user-defined + // For the Kubernetes provided priority functions, the name is the identifier of the pre-defined priority function + Name string `json:"name"` + // Weight is the numeric multiplier for the minion scores that the priority function generates + Weight int `json:"weight"` + // Argument holds the parameters to configure the given priority function + Argument *PriorityArgument `json:"argument"` +} + +// PredicateArgument represents the arguments that the different types of predicates take +// Only one of its members may be specified +type PredicateArgument struct { + // ServiceAffinity is the predicate that provides affinity for pods belonging to a service + // It uses a label to identify minions that belong to the same "group" + ServiceAffinity *ServiceAffinity `json:"serviceAffinity"` + // LabelsPresence is the predicate that checks whether a particular minion has a certain label + // defined or not, regardless of value + LabelsPresence *LabelsPresence `json:"labelsPresence"` +} + +// PriorityArgument represents the arguments that the different types of priorities take. +// Only one of its members may be specified +type PriorityArgument struct { + // ServiceAntiAffinity is the priority function that ensures a good spread (anti-affinity) for pods belonging to a service + // It uses a label to identify minions that belong to the same "group" + ServiceAntiAffinity *ServiceAntiAffinity `json:"serviceAntiAffinity"` + // LabelPreference is the priority function that checks whether a particular minion has a certain label + // defined or not, regardless of value + LabelPreference *LabelPreference `json:"labelPreference"` +} + +// ServiceAffinity holds the parameters that are used to configure the corresponding predicate +type ServiceAffinity struct { + // Labels is the list of labels that identify minion "groups" + // All of the labels should match for the minion to be considered a fit for hosting the pod + Labels []string `json:"labels"` +} + +// LabelsPresence holds the parameters that are used to configure the corresponding predicate +type LabelsPresence struct { + // Labels is the list of labels that identify minion "groups" + // All of the labels should be either present (or absent) for the minion to be considered a fit for hosting the pod + Labels []string `json:"labels"` + // Presence is the boolean flag that indicates whether the labels should be present or absent from the minion + Presence bool `json:"presence"` +} + +// ServiceAntiAffinity holds the parameters that are used to configure the corresponding priority function +type ServiceAntiAffinity struct { + // Label is used to identify minion "groups" + Label string `json:"label"` +} + +// LabelPreference holds the parameters that are used to configure the corresponding priority function +type LabelPreference struct { + // Label is used to identify minion "groups" + Label string `json:"label"` + // Presence is a boolean flag + // If true, higher priority is given to minions that have the label + // If false, higher priority is given to minions that do not have the label + Presence bool `json:"presence"` +} diff --git a/plugin/pkg/scheduler/factory/factory.go b/plugin/pkg/scheduler/factory/factory.go index e7cb6f12457..9f4c4c6ec95 100644 --- a/plugin/pkg/scheduler/factory/factory.go +++ b/plugin/pkg/scheduler/factory/factory.go @@ -30,6 +30,7 @@ import ( algorithm "github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler" + schedulerapi "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api" "github.com/golang/glog" ) @@ -80,6 +81,25 @@ func (f *ConfigFactory) CreateFromProvider(providerName string) (*scheduler.Conf return f.CreateFromKeys(provider.FitPredicateKeys, provider.PriorityFunctionKeys) } +// CreateFromConfig creates a scheduler from the configuration file +func (f *ConfigFactory) CreateFromConfig(policy schedulerapi.Policy) (*scheduler.Config, error) { + glog.V(2).Infof("creating scheduler from configuration: %v", policy) + + predicateKeys := util.NewStringSet() + for _, predicate := range policy.Predicates { + glog.V(2).Infof("Registering predicate: %s", predicate.Name) + predicateKeys.Insert(RegisterCustomPredicate(predicate)) + } + + priorityKeys := util.NewStringSet() + for _, priority := range policy.Priorities { + glog.V(2).Infof("Registering priority: %s", priority.Name) + priorityKeys.Insert(RegisterCustomPriorityFunction(priority)) + } + + return f.CreateFromKeys(predicateKeys, priorityKeys) +} + // CreateFromKeys creates a scheduler from a set of registered fit predicate keys and priority keys. func (f *ConfigFactory) CreateFromKeys(predicateKeys, priorityKeys util.StringSet) (*scheduler.Config, error) { glog.V(2).Infof("creating scheduler with fit predicates '%v' and priority functions '%v", predicateKeys, priorityKeys) diff --git a/plugin/pkg/scheduler/factory/plugins.go b/plugin/pkg/scheduler/factory/plugins.go index 4ec5c2c028a..a15ae65411b 100644 --- a/plugin/pkg/scheduler/factory/plugins.go +++ b/plugin/pkg/scheduler/factory/plugins.go @@ -23,6 +23,7 @@ import ( algorithm "github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + schedulerapi "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api" "github.com/golang/glog" ) @@ -55,6 +56,33 @@ func RegisterFitPredicate(name string, predicate algorithm.FitPredicate) string return name } +// RegisterCustomPredicate registers a custom fit predicate with the algorithm registry. +// Returns the name, with which the predicate was registered. +func RegisterCustomPredicate(policy schedulerapi.PredicatePolicy) string { + var predicate algorithm.FitPredicate + var ok bool + + validatePredicateOrDie(policy) + + // generate the predicate function, if a custom type is requested + if policy.Argument != nil { + if policy.Argument.ServiceAffinity != nil { + predicate = algorithm.NewServiceAffinityPredicate(PodLister, ServiceLister, MinionLister, policy.Argument.ServiceAffinity.Labels) + } else if policy.Argument.LabelsPresence != nil { + predicate = algorithm.NewNodeLabelPredicate(MinionLister, policy.Argument.LabelsPresence.Labels, policy.Argument.LabelsPresence.Presence) + } + // check to see if a pre-defined predicate is requested + } else if predicate, ok = fitPredicateMap[policy.Name]; ok { + glog.V(2).Infof("Predicate type %s already registered, reusing.", policy.Name) + } + + if predicate == nil { + glog.Fatalf("Invalid configuration: Predicate type not found for %s", policy.Name) + } + + return RegisterFitPredicate(policy.Name, predicate) +} + // IsFitPredicateRegistered check is useful for testing providers. func IsFitPredicateRegistered(name string) bool { schedulerFactoryMutex.Lock() @@ -63,7 +91,7 @@ func IsFitPredicateRegistered(name string) bool { return ok } -// RegisterFitPredicate registers a priority function with the algorithm registry. Returns the name, +// RegisterPriorityFunction registers a priority function with the algorithm registry. Returns the name, // with which the function was registered. func RegisterPriorityFunction(name string, function algorithm.PriorityFunction, weight int) string { schedulerFactoryMutex.Lock() @@ -73,6 +101,32 @@ func RegisterPriorityFunction(name string, function algorithm.PriorityFunction, return name } +// RegisterCustomPriority registers a custom priority function with the algorithm registry. +// Returns the name, with which the priority function was registered. +func RegisterCustomPriorityFunction(policy schedulerapi.PriorityPolicy) string { + var priority algorithm.PriorityFunction + + validatePriorityOrDie(policy) + + // generate the priority function, if a custom priority is requested + if policy.Argument != nil { + if policy.Argument.ServiceAntiAffinity != nil { + priority = algorithm.NewServiceAntiAffinityPriority(ServiceLister, policy.Argument.ServiceAntiAffinity.Label) + } else if policy.Argument.LabelPreference != nil { + priority = algorithm.NewNodeLabelPriority(policy.Argument.LabelPreference.Label, policy.Argument.LabelPreference.Presence) + } + } else if priorityConfig, ok := priorityFunctionMap[policy.Name]; ok { + glog.V(2).Infof("Priority type %s already registered, reusing.", policy.Name) + priority = priorityConfig.Function + } + + if priority == nil { + glog.Fatalf("Invalid configuration: Priority type not found for %s", policy.Name) + } + + return RegisterPriorityFunction(policy.Name, priority, policy.Weight) +} + // IsPriorityFunctionRegistered check is useful for testing providers. func IsPriorityFunctionRegistered(name string) bool { schedulerFactoryMutex.Lock() @@ -91,6 +145,7 @@ func SetPriorityFunctionWeight(name string, weight int) { return } config.Weight = weight + priorityFunctionMap[name] = config } // RegisterAlgorithmProvider registers a new algorithm provider with the algorithm registry. This should @@ -157,3 +212,33 @@ func validateAlgorithmNameOrDie(name string) { glog.Fatalf("algorithm name %v does not match the name validation regexp \"%v\".", name, validName) } } + +func validatePredicateOrDie(predicate schedulerapi.PredicatePolicy) { + if predicate.Argument != nil { + numArgs := 0 + if predicate.Argument.ServiceAffinity != nil { + numArgs++ + } + if predicate.Argument.LabelsPresence != nil { + numArgs++ + } + if numArgs != 1 { + glog.Fatalf("Exactly 1 predicate argument is required") + } + } +} + +func validatePriorityOrDie(priority schedulerapi.PriorityPolicy) { + if priority.Argument != nil { + numArgs := 0 + if priority.Argument.ServiceAntiAffinity != nil { + numArgs++ + } + if priority.Argument.LabelPreference != nil { + numArgs++ + } + if numArgs != 1 { + glog.Fatalf("Exactly 1 priority argument is required") + } + } +} From 3607a16293ec57cfcc7e791ac3fe2448203567b3 Mon Sep 17 00:00:00 2001 From: Abhishek Gupta Date: Thu, 26 Feb 2015 16:40:15 -0800 Subject: [PATCH 2/6] Implementing PR feedback --- plugin/cmd/kube-scheduler/app/server.go | 1 - plugin/pkg/scheduler/api/latest/latest.go | 8 ++- plugin/pkg/scheduler/api/types.go | 66 ++++++++++++++++------- plugin/pkg/scheduler/api/v1/types.go | 49 ++++++++--------- plugin/pkg/scheduler/factory/factory.go | 20 +++---- plugin/pkg/scheduler/factory/plugins.go | 20 +++---- 6 files changed, 94 insertions(+), 70 deletions(-) diff --git a/plugin/cmd/kube-scheduler/app/server.go b/plugin/cmd/kube-scheduler/app/server.go index 4e643bf99d4..e255a256d92 100644 --- a/plugin/cmd/kube-scheduler/app/server.go +++ b/plugin/cmd/kube-scheduler/app/server.go @@ -101,7 +101,6 @@ func (s *SchedulerServer) createConfig(configFactory *factory.ConfigFactory) (*s if err != nil { return nil, fmt.Errorf("Unable to read policy config: %v", err) } - //err = json.Unmarshal(configData, &policy) err = latestschedulerapi.Codec.DecodeInto(configData, &policy) if err != nil { return nil, fmt.Errorf("Invalid configuration: %v", err) diff --git a/plugin/pkg/scheduler/api/latest/latest.go b/plugin/pkg/scheduler/api/latest/latest.go index c4559130e41..b2e544253cd 100644 --- a/plugin/pkg/scheduler/api/latest/latest.go +++ b/plugin/pkg/scheduler/api/latest/latest.go @@ -23,8 +23,7 @@ import ( // Version is the string that represents the current external default version. const Version = "v1" -// OldestVersion is the string that represents the oldest server version supported, -// for client code that wants to hardcode the lowest common denominator. +// OldestVersion is the string that represents the oldest server version supported. const OldestVersion = "v1" // Versions is the list of versions that are recognized in code. The order provided @@ -33,8 +32,7 @@ const OldestVersion = "v1" // with a set of versions to choose. var Versions = []string{"v1"} -// Codec is the default codec for serializing output that should use -// the latest supported version. Use this Codec when writing to -// disk, a data store that is not dynamically versioned, or in tests. +// Codec is the default codec for serializing input that should use +// the latest supported version. Use this Codec when reading from the file. // This codec can decode any object that Kubernetes is aware of. var Codec = v1.Codec diff --git a/plugin/pkg/scheduler/api/types.go b/plugin/pkg/scheduler/api/types.go index 7453eb199ab..a1cac22bad4 100644 --- a/plugin/pkg/scheduler/api/types.go +++ b/plugin/pkg/scheduler/api/types.go @@ -20,54 +20,84 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api" ) -// Where possible, json tags match the cli argument names. -// Top level config objects and all values required for proper functioning are not "omitempty". Any truly optional piece of config is allowed to be omitted. - type Policy struct { api.TypeMeta `json:",inline"` - Predicates []PredicatePolicy `json:"predicates"` - Priorities []PriorityPolicy `json:"priorities"` + // Holds the information to configure the fit predicate functions + Predicates []PredicatePolicy `json:"predicates"` + // Holds the information to configure the priority functions + Priorities []PriorityPolicy `json:"priorities"` } type PredicatePolicy struct { - Name string `json:"name"` + // Identifier of the predicate policy + // For a custom predicate, the name can be user-defined + // For the Kubernetes provided predicates, the name is the identifier of the pre-defined predicate + Name string `json:"name"` + // Holds the parameters to configure the given predicate Argument *PredicateArgument `json:"argument"` } type PriorityPolicy struct { - Name string `json:"name"` - Weight int `json:"weight"` + // Identifier of the priority policy + // For a custom priority, the name can be user-defined + // For the Kubernetes provided priority functions, the name is the identifier of the pre-defined priority function + Name string `json:"name"` + // The numeric multiplier for the minion scores that the priority function generates + Weight int `json:"weight"` + // Holds the parameters to configure the given priority function Argument *PriorityArgument `json:"argument"` } -// PredicateArgument represents the arguments that the different types of predicates take. -// Only one of its members may be specified. +// Represents the arguments that the different types of predicates take +// Only one of its members may be specified type PredicateArgument struct { + // The predicate that provides affinity for pods belonging to a service + // It uses a label to identify minions that belong to the same "group" ServiceAffinity *ServiceAffinity `json:"serviceAffinity"` - LabelsPresence *LabelsPresence `json:"labelsPresence"` + // The predicate that checks whether a particular minion has a certain label + // defined or not, regardless of value + LabelsPresence *LabelsPresence `json:"labelsPresence"` } -// PriorityArgument represents the arguments that the different types of priorities take. -// Only one of its members may be specified. +// Represents the arguments that the different types of priorities take. +// Only one of its members may be specified type PriorityArgument struct { + // The priority function that ensures a good spread (anti-affinity) for pods belonging to a service + // It uses a label to identify minions that belong to the same "group" ServiceAntiAffinity *ServiceAntiAffinity `json:"serviceAntiAffinity"` - LabelPreference *LabelPreference `json:"labelPreference"` + // The priority function that checks whether a particular minion has a certain label + // defined or not, regardless of value + LabelPreference *LabelPreference `json:"labelPreference"` } +// Holds the parameters that are used to configure the corresponding predicate type ServiceAffinity struct { + // The list of labels that identify minion "groups" + // All of the labels should match for the minion to be considered a fit for hosting the pod Labels []string `json:"labels"` } +// Holds the parameters that are used to configure the corresponding predicate type LabelsPresence struct { - Labels []string `json:"labels"` - Presence bool `json:"presence"` + // The list of labels that identify minion "groups" + // All of the labels should be either present (or absent) for the minion to be considered a fit for hosting the pod + Labels []string `json:"labels"` + // The boolean flag that indicates whether the labels should be present or absent from the minion + Presence bool `json:"presence"` } +// Holds the parameters that are used to configure the corresponding priority function type ServiceAntiAffinity struct { + // Used to identify minion "groups" Label string `json:"label"` } +// Holds the parameters that are used to configure the corresponding priority function type LabelPreference struct { - Label string `json:"label"` - Presence bool `json:"presence"` + // Used to identify minion "groups" + Label string `json:"label"` + // This is a boolean flag + // If true, higher priority is given to minions that have the label + // If false, higher priority is given to minions that do not have the label + Presence bool `json:"presence"` } diff --git a/plugin/pkg/scheduler/api/v1/types.go b/plugin/pkg/scheduler/api/v1/types.go index bbf5f0b8628..fefb278ad85 100644 --- a/plugin/pkg/scheduler/api/v1/types.go +++ b/plugin/pkg/scheduler/api/v1/types.go @@ -20,86 +20,83 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3" ) -// Where possible, json tags match the cli argument names. -// Top level config objects and all values required for proper functioning are not "omitempty". Any truly optional piece of config is allowed to be omitted. - type Policy struct { v1beta3.TypeMeta `json:",inline"` - // Predicates holds the information to configure the fit predicate functions + // Holds the information to configure the fit predicate functions Predicates []PredicatePolicy `json:"predicates"` - // Priorities holds the information to configure the priority functions + // Holds the information to configure the priority functions Priorities []PriorityPolicy `json:"priorities"` } type PredicatePolicy struct { - // Name is the identifier of the predicate policy + // Identifier of the predicate policy // For a custom predicate, the name can be user-defined // For the Kubernetes provided predicates, the name is the identifier of the pre-defined predicate Name string `json:"name"` - // Argument holds the parameters to configure the given predicate + // Holds the parameters to configure the given predicate Argument *PredicateArgument `json:"argument"` } type PriorityPolicy struct { - // Name is the identifier of the priority policy + // Identifier of the priority policy // For a custom priority, the name can be user-defined // For the Kubernetes provided priority functions, the name is the identifier of the pre-defined priority function Name string `json:"name"` - // Weight is the numeric multiplier for the minion scores that the priority function generates + // The numeric multiplier for the minion scores that the priority function generates Weight int `json:"weight"` - // Argument holds the parameters to configure the given priority function + // Holds the parameters to configure the given priority function Argument *PriorityArgument `json:"argument"` } -// PredicateArgument represents the arguments that the different types of predicates take +// Represents the arguments that the different types of predicates take // Only one of its members may be specified type PredicateArgument struct { - // ServiceAffinity is the predicate that provides affinity for pods belonging to a service + // The predicate that provides affinity for pods belonging to a service // It uses a label to identify minions that belong to the same "group" ServiceAffinity *ServiceAffinity `json:"serviceAffinity"` - // LabelsPresence is the predicate that checks whether a particular minion has a certain label + // The predicate that checks whether a particular minion has a certain label // defined or not, regardless of value LabelsPresence *LabelsPresence `json:"labelsPresence"` } -// PriorityArgument represents the arguments that the different types of priorities take. +// Represents the arguments that the different types of priorities take. // Only one of its members may be specified type PriorityArgument struct { - // ServiceAntiAffinity is the priority function that ensures a good spread (anti-affinity) for pods belonging to a service + // The priority function that ensures a good spread (anti-affinity) for pods belonging to a service // It uses a label to identify minions that belong to the same "group" ServiceAntiAffinity *ServiceAntiAffinity `json:"serviceAntiAffinity"` - // LabelPreference is the priority function that checks whether a particular minion has a certain label + // The priority function that checks whether a particular minion has a certain label // defined or not, regardless of value LabelPreference *LabelPreference `json:"labelPreference"` } -// ServiceAffinity holds the parameters that are used to configure the corresponding predicate +// Holds the parameters that are used to configure the corresponding predicate type ServiceAffinity struct { - // Labels is the list of labels that identify minion "groups" + // The list of labels that identify minion "groups" // All of the labels should match for the minion to be considered a fit for hosting the pod Labels []string `json:"labels"` } -// LabelsPresence holds the parameters that are used to configure the corresponding predicate +// Holds the parameters that are used to configure the corresponding predicate type LabelsPresence struct { - // Labels is the list of labels that identify minion "groups" + // The list of labels that identify minion "groups" // All of the labels should be either present (or absent) for the minion to be considered a fit for hosting the pod Labels []string `json:"labels"` - // Presence is the boolean flag that indicates whether the labels should be present or absent from the minion + // The boolean flag that indicates whether the labels should be present or absent from the minion Presence bool `json:"presence"` } -// ServiceAntiAffinity holds the parameters that are used to configure the corresponding priority function +// Holds the parameters that are used to configure the corresponding priority function type ServiceAntiAffinity struct { - // Label is used to identify minion "groups" + // Used to identify minion "groups" Label string `json:"label"` } -// LabelPreference holds the parameters that are used to configure the corresponding priority function +// Holds the parameters that are used to configure the corresponding priority function type LabelPreference struct { - // Label is used to identify minion "groups" + // Used to identify minion "groups" Label string `json:"label"` - // Presence is a boolean flag + // This is a boolean flag // If true, higher priority is given to minions that have the label // If false, higher priority is given to minions that do not have the label Presence bool `json:"presence"` diff --git a/plugin/pkg/scheduler/factory/factory.go b/plugin/pkg/scheduler/factory/factory.go index 9f4c4c6ec95..48c84142091 100644 --- a/plugin/pkg/scheduler/factory/factory.go +++ b/plugin/pkg/scheduler/factory/factory.go @@ -54,7 +54,7 @@ type ConfigFactory struct { ServiceLister *cache.StoreToServiceLister } -// NewConfigFactory initializes the factory. +// Initializes the factory. func NewConfigFactory(client *client.Client) *ConfigFactory { return &ConfigFactory{ Client: client, @@ -70,7 +70,7 @@ func (f *ConfigFactory) Create() (*scheduler.Config, error) { return f.CreateFromProvider(DefaultProvider) } -// CreateFromProvider creates a scheduler from the name of a registered algorithm provider. +// Creates a scheduler from the name of a registered algorithm provider. func (f *ConfigFactory) CreateFromProvider(providerName string) (*scheduler.Config, error) { glog.V(2).Infof("creating scheduler from algorithm provider '%v'", providerName) provider, err := GetAlgorithmProvider(providerName) @@ -81,14 +81,14 @@ func (f *ConfigFactory) CreateFromProvider(providerName string) (*scheduler.Conf return f.CreateFromKeys(provider.FitPredicateKeys, provider.PriorityFunctionKeys) } -// CreateFromConfig creates a scheduler from the configuration file +// Creates a scheduler from the configuration file func (f *ConfigFactory) CreateFromConfig(policy schedulerapi.Policy) (*scheduler.Config, error) { glog.V(2).Infof("creating scheduler from configuration: %v", policy) predicateKeys := util.NewStringSet() for _, predicate := range policy.Predicates { glog.V(2).Infof("Registering predicate: %s", predicate.Name) - predicateKeys.Insert(RegisterCustomPredicate(predicate)) + predicateKeys.Insert(RegisterCustomFitPredicate(predicate)) } priorityKeys := util.NewStringSet() @@ -100,7 +100,7 @@ func (f *ConfigFactory) CreateFromConfig(policy schedulerapi.Policy) (*scheduler return f.CreateFromKeys(predicateKeys, priorityKeys) } -// CreateFromKeys creates a scheduler from a set of registered fit predicate keys and priority keys. +// Creates a scheduler from a set of registered fit predicate keys and priority keys. func (f *ConfigFactory) CreateFromKeys(predicateKeys, priorityKeys util.StringSet) (*scheduler.Config, error) { glog.V(2).Infof("creating scheduler with fit predicates '%v' and priority functions '%v", predicateKeys, priorityKeys) predicateFuncs, err := getFitPredicateFunctions(predicateKeys) @@ -160,7 +160,7 @@ func (f *ConfigFactory) CreateFromKeys(predicateKeys, priorityKeys util.StringSe }, nil } -// createUnassignedPodLW returns a cache.ListWatch that finds all pods that need to be +// Returns a cache.ListWatch that finds all pods that need to be // scheduled. func (factory *ConfigFactory) createUnassignedPodLW() *cache.ListWatch { return cache.NewListWatchFromClient(factory.Client, "pods", api.NamespaceAll, labels.Set{"DesiredState.Host": ""}.AsSelector()) @@ -174,7 +174,7 @@ func parseSelectorOrDie(s string) labels.Selector { return selector } -// createAssignedPodLW returns a cache.ListWatch that finds all pods that are +// Returns a cache.ListWatch that finds all pods that are // already scheduled. // TODO: return a ListerWatcher interface instead? func (factory *ConfigFactory) createAssignedPodLW() *cache.ListWatch { @@ -186,7 +186,7 @@ func (factory *ConfigFactory) createMinionLW() *cache.ListWatch { return cache.NewListWatchFromClient(factory.Client, "minions", api.NamespaceAll, parseSelectorOrDie("")) } -// pollMinions lists all minions and filter out unhealthy ones, then returns +// Lists all minions and filter out unhealthy ones, then returns // an enumerator for cache.Poller. func (factory *ConfigFactory) pollMinions() (cache.Enumerator, error) { allNodes := &api.NodeList{} @@ -221,7 +221,7 @@ func (factory *ConfigFactory) pollMinions() (cache.Enumerator, error) { return &nodeEnumerator{nodes}, nil } -// createServiceLW returns a cache.ListWatch that gets all changes to services. +// Returns a cache.ListWatch that gets all changes to services. func (factory *ConfigFactory) createServiceLW() *cache.ListWatch { return cache.NewListWatchFromClient(factory.Client, "services", api.NamespaceAll, parseSelectorOrDie("")) } @@ -251,7 +251,7 @@ func (factory *ConfigFactory) makeDefaultErrorFunc(backoff *podBackoff, podQueue } } -// nodeEnumerator allows a cache.Poller to enumerate items in an api.NodeList +// Allows a cache.Poller to enumerate items in an api.NodeList type nodeEnumerator struct { *api.NodeList } diff --git a/plugin/pkg/scheduler/factory/plugins.go b/plugin/pkg/scheduler/factory/plugins.go index a15ae65411b..031cd31ee25 100644 --- a/plugin/pkg/scheduler/factory/plugins.go +++ b/plugin/pkg/scheduler/factory/plugins.go @@ -46,7 +46,7 @@ type AlgorithmProviderConfig struct { PriorityFunctionKeys util.StringSet } -// RegisterFitPredicate registers a fit predicate with the algorithm registry. Returns the name, +// Registers a fit predicate with the algorithm registry. Returns the name, // with which the predicate was registered. func RegisterFitPredicate(name string, predicate algorithm.FitPredicate) string { schedulerFactoryMutex.Lock() @@ -56,9 +56,9 @@ func RegisterFitPredicate(name string, predicate algorithm.FitPredicate) string return name } -// RegisterCustomPredicate registers a custom fit predicate with the algorithm registry. +// Registers a custom fit predicate with the algorithm registry. // Returns the name, with which the predicate was registered. -func RegisterCustomPredicate(policy schedulerapi.PredicatePolicy) string { +func RegisterCustomFitPredicate(policy schedulerapi.PredicatePolicy) string { var predicate algorithm.FitPredicate var ok bool @@ -83,7 +83,7 @@ func RegisterCustomPredicate(policy schedulerapi.PredicatePolicy) string { return RegisterFitPredicate(policy.Name, predicate) } -// IsFitPredicateRegistered check is useful for testing providers. +// This check is useful for testing providers. func IsFitPredicateRegistered(name string) bool { schedulerFactoryMutex.Lock() defer schedulerFactoryMutex.Unlock() @@ -91,7 +91,7 @@ func IsFitPredicateRegistered(name string) bool { return ok } -// RegisterPriorityFunction registers a priority function with the algorithm registry. Returns the name, +// Registers a priority function with the algorithm registry. Returns the name, // with which the function was registered. func RegisterPriorityFunction(name string, function algorithm.PriorityFunction, weight int) string { schedulerFactoryMutex.Lock() @@ -101,7 +101,7 @@ func RegisterPriorityFunction(name string, function algorithm.PriorityFunction, return name } -// RegisterCustomPriority registers a custom priority function with the algorithm registry. +// Registers a custom priority function with the algorithm registry. // Returns the name, with which the priority function was registered. func RegisterCustomPriorityFunction(policy schedulerapi.PriorityPolicy) string { var priority algorithm.PriorityFunction @@ -127,7 +127,7 @@ func RegisterCustomPriorityFunction(policy schedulerapi.PriorityPolicy) string { return RegisterPriorityFunction(policy.Name, priority, policy.Weight) } -// IsPriorityFunctionRegistered check is useful for testing providers. +// This check is useful for testing providers. func IsPriorityFunctionRegistered(name string) bool { schedulerFactoryMutex.Lock() defer schedulerFactoryMutex.Unlock() @@ -135,7 +135,7 @@ func IsPriorityFunctionRegistered(name string) bool { return ok } -// SetPriorityFunctionWeight sets the weight of an already registered priority function. +// Sets the weight of an already registered priority function. func SetPriorityFunctionWeight(name string, weight int) { schedulerFactoryMutex.Lock() defer schedulerFactoryMutex.Unlock() @@ -148,7 +148,7 @@ func SetPriorityFunctionWeight(name string, weight int) { priorityFunctionMap[name] = config } -// RegisterAlgorithmProvider registers a new algorithm provider with the algorithm registry. This should +// Registers a new algorithm provider with the algorithm registry. This should // be called from the init function in a provider plugin. func RegisterAlgorithmProvider(name string, predicateKeys, priorityKeys util.StringSet) string { schedulerFactoryMutex.Lock() @@ -161,7 +161,7 @@ func RegisterAlgorithmProvider(name string, predicateKeys, priorityKeys util.Str return name } -// GetAlgorithmProvider should not be used to modify providers. It is publicly visible for testing. +// This function should not be used to modify providers. It is publicly visible for testing. func GetAlgorithmProvider(name string) (*AlgorithmProviderConfig, error) { schedulerFactoryMutex.Lock() defer schedulerFactoryMutex.Unlock() From 28fbde0f22dd28729ea9224e1255094c0306e560 Mon Sep 17 00:00:00 2001 From: Abhishek Gupta Date: Thu, 26 Feb 2015 16:42:27 -0800 Subject: [PATCH 3/6] Removing affinity provider --- .../algorithmprovider/affinity/affinity.go | 55 ------------------- .../scheduler/algorithmprovider/plugins.go | 1 - .../algorithmprovider/plugins_test.go | 2 - 3 files changed, 58 deletions(-) delete mode 100644 plugin/pkg/scheduler/algorithmprovider/affinity/affinity.go diff --git a/plugin/pkg/scheduler/algorithmprovider/affinity/affinity.go b/plugin/pkg/scheduler/algorithmprovider/affinity/affinity.go deleted file mode 100644 index 44f2bd26e6b..00000000000 --- a/plugin/pkg/scheduler/algorithmprovider/affinity/affinity.go +++ /dev/null @@ -1,55 +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. -*/ - -// This algorithm provider has predicates and priorities related to affinity/anti-affinity for the scheduler. -package affinity - -import ( - algorithm "github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler" - "github.com/GoogleCloudPlatform/kubernetes/pkg/util" - "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/factory" -) - -const AffinityProvider string = "AffinityProvider" - -func init() { - factory.RegisterAlgorithmProvider(AffinityProvider, affinityPredicates(), affinityPriorities()) -} - -func affinityPredicates() util.StringSet { - return util.NewStringSet( - "HostName", - "MatchNodeSelector", - "PodFitsPorts", - "PodFitsResources", - "NoDiskConflict", - // Ensures that all pods within the same service are hosted on minions within the same region as defined by the "region" label - factory.RegisterFitPredicate("RegionAffinity", algorithm.NewServiceAffinityPredicate(factory.PodLister, factory.ServiceLister, factory.MinionLister, []string{"region"})), - // Fit is defined based on the presence of the "region" label on a minion, regardless of value. - factory.RegisterFitPredicate("RegionRequired", algorithm.NewNodeLabelPredicate(factory.MinionLister, []string{"region"}, true)), - ) -} - -func affinityPriorities() util.StringSet { - return util.NewStringSet( - "LeastRequestedPriority", - "ServiceSpreadingPriority", - // spreads pods belonging to the same service across minions in different zones - factory.RegisterPriorityFunction("ZoneSpread", algorithm.NewServiceAntiAffinityPriority(factory.ServiceLister, "zone"), 2), - // Prioritize nodes based on the presence of the "zone" label on a minion, regardless of value. - factory.RegisterPriorityFunction("ZonePreferred", algorithm.NewNodeLabelPriority("zone", true), 1), - ) -} diff --git a/plugin/pkg/scheduler/algorithmprovider/plugins.go b/plugin/pkg/scheduler/algorithmprovider/plugins.go index ac7123efe26..d534b05c0bf 100644 --- a/plugin/pkg/scheduler/algorithmprovider/plugins.go +++ b/plugin/pkg/scheduler/algorithmprovider/plugins.go @@ -18,6 +18,5 @@ limitations under the License. package algorithmprovider import ( - _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/algorithmprovider/affinity" _ "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/algorithmprovider/defaults" ) diff --git a/plugin/pkg/scheduler/algorithmprovider/plugins_test.go b/plugin/pkg/scheduler/algorithmprovider/plugins_test.go index b70d55fc789..8f7dd3a1ffa 100644 --- a/plugin/pkg/scheduler/algorithmprovider/plugins_test.go +++ b/plugin/pkg/scheduler/algorithmprovider/plugins_test.go @@ -19,14 +19,12 @@ package algorithmprovider import ( "testing" - "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/algorithmprovider/affinity" "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/factory" ) var ( algorithmProviderNames = []string{ factory.DefaultProvider, - affinity.AffinityProvider, } ) From e5d319d611f5fdcf9b4be69a1473ee84121c65b7 Mon Sep 17 00:00:00 2001 From: Abhishek Gupta Date: Thu, 26 Feb 2015 17:32:53 -0800 Subject: [PATCH 4/6] Fixing comment alignment --- plugin/pkg/scheduler/factory/plugins.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/pkg/scheduler/factory/plugins.go b/plugin/pkg/scheduler/factory/plugins.go index 031cd31ee25..e53c24f0b18 100644 --- a/plugin/pkg/scheduler/factory/plugins.go +++ b/plugin/pkg/scheduler/factory/plugins.go @@ -71,8 +71,8 @@ func RegisterCustomFitPredicate(policy schedulerapi.PredicatePolicy) string { } else if policy.Argument.LabelsPresence != nil { predicate = algorithm.NewNodeLabelPredicate(MinionLister, policy.Argument.LabelsPresence.Labels, policy.Argument.LabelsPresence.Presence) } - // check to see if a pre-defined predicate is requested } else if predicate, ok = fitPredicateMap[policy.Name]; ok { + // checking to see if a pre-defined predicate is requested glog.V(2).Infof("Predicate type %s already registered, reusing.", policy.Name) } From a04e600f16bd5e4451a0f846520ca01b909531e3 Mon Sep 17 00:00:00 2001 From: Abhishek Gupta Date: Fri, 27 Feb 2015 12:53:04 -0800 Subject: [PATCH 5/6] Added test cases --- pkg/scheduler/generic_scheduler.go | 7 ++ plugin/pkg/scheduler/api/latest/latest.go | 2 +- plugin/pkg/scheduler/factory/factory_test.go | 73 ++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/pkg/scheduler/generic_scheduler.go b/pkg/scheduler/generic_scheduler.go index 0aa679274ae..7a2542daa0a 100644 --- a/pkg/scheduler/generic_scheduler.go +++ b/pkg/scheduler/generic_scheduler.go @@ -135,6 +135,13 @@ func findNodesThatFit(pod api.Pod, podLister PodLister, predicates map[string]Fi // All scores are finally combined (added) to get the total weighted scores of all minions func prioritizeNodes(pod api.Pod, podLister PodLister, priorityConfigs []PriorityConfig, minionLister MinionLister) (HostPriorityList, error) { result := HostPriorityList{} + + // If no priority configs are provided, then the EqualPriority function is applied + // This is required to generate the priority list in the required format + if len(priorityConfigs) == 0 { + return EqualPriority(pod, podLister, minionLister) + } + combinedScores := map[string]int{} for _, priorityConfig := range priorityConfigs { weight := priorityConfig.Weight diff --git a/plugin/pkg/scheduler/api/latest/latest.go b/plugin/pkg/scheduler/api/latest/latest.go index b2e544253cd..73551248e38 100644 --- a/plugin/pkg/scheduler/api/latest/latest.go +++ b/plugin/pkg/scheduler/api/latest/latest.go @@ -33,6 +33,6 @@ const OldestVersion = "v1" var Versions = []string{"v1"} // Codec is the default codec for serializing input that should use -// the latest supported version. Use this Codec when reading from the file. +// the latest supported version. // This codec can decode any object that Kubernetes is aware of. var Codec = v1.Codec diff --git a/plugin/pkg/scheduler/factory/factory_test.go b/plugin/pkg/scheduler/factory/factory_test.go index f07fe4daf68..c23b8a2b830 100644 --- a/plugin/pkg/scheduler/factory/factory_test.go +++ b/plugin/pkg/scheduler/factory/factory_test.go @@ -30,7 +30,10 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" + algorithm "github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" + schedulerapi "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api" + latestschedulerapi "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler/api/latest" ) func TestCreate(t *testing.T) { @@ -46,6 +49,76 @@ func TestCreate(t *testing.T) { factory.Create() } +func TestCreateFromConfig(t *testing.T) { + var configData []byte + var policy schedulerapi.Policy + + handler := util.FakeHandler{ + StatusCode: 500, + ResponseBody: "", + T: t, + } + server := httptest.NewServer(&handler) + defer server.Close() + client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()}) + factory := NewConfigFactory(client) + + // Register the predicate and priority functions + // These would be registered by the DefaultProvider in regular operation + RegisterFitPredicate("PodFitsPorts", algorithm.PodFitsPorts) + RegisterFitPredicate("PodFitsResources", algorithm.NewResourceFitPredicate(MinionLister)) + RegisterFitPredicate("NoDiskConflict", algorithm.NoDiskConflict) + RegisterFitPredicate("MatchNodeSelector", algorithm.NewSelectorMatchPredicate(MinionLister)) + RegisterFitPredicate("HostName", algorithm.PodFitsHost) + RegisterPriorityFunction("LeastRequestedPriority", algorithm.LeastRequestedPriority, 1) + RegisterPriorityFunction("ServiceSpreadingPriority", algorithm.NewServiceSpreadPriority(ServiceLister), 1) + RegisterPriorityFunction("EqualPriority", algorithm.EqualPriority, 0) + + configData = []byte(`{ + "kind" : "Policy", + "apiVersion" : "v1", + "predicates" : [ + {"name" : "TestZoneAffinity", "argument" : {"serviceAffinity" : {"labels" : ["zone"]}}}, + {"name" : "TestRequireZone", "argument" : {"labelsPresence" : {"labels" : ["zone"], "presence" : true}}}, + {"name" : "PodFitsPorts"}, + {"name" : "MatchNodeSelector"} + ], + "priorities" : [ + {"name" : "RackSpread", "weight" : 2, "argument" : {"serviceAntiAffinity" : {"label" : "rack"}}}, + {"name" : "ServiceSpreadingPriority", "weight" : 1} + ] + }`) + err := latestschedulerapi.Codec.DecodeInto(configData, &policy) + if err != nil { + t.Errorf("Invalid configuration: %v", err) + } + + factory.CreateFromConfig(policy) +} + +func TestCreateFromEmptyConfig(t *testing.T) { + var configData []byte + var policy schedulerapi.Policy + + handler := util.FakeHandler{ + StatusCode: 500, + ResponseBody: "", + T: t, + } + server := httptest.NewServer(&handler) + defer server.Close() + client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()}) + factory := NewConfigFactory(client) + + configData = []byte(`{}`) + err := latestschedulerapi.Codec.DecodeInto(configData, &policy) + if err != nil { + t.Errorf("Invalid configuration: %v", err) + } + + factory.CreateFromConfig(policy) +} + func TestPollMinions(t *testing.T) { table := []struct { minions []api.Node From 5e096fed343b851629ea93d5eaba7a477420b385 Mon Sep 17 00:00:00 2001 From: Abhishek Gupta Date: Mon, 2 Mar 2015 09:59:29 -0800 Subject: [PATCH 6/6] Fixing test case to remove dependency on algorithm provider --- plugin/pkg/scheduler/factory/factory_test.go | 43 +++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/plugin/pkg/scheduler/factory/factory_test.go b/plugin/pkg/scheduler/factory/factory_test.go index c23b8a2b830..9d3eff0a571 100644 --- a/plugin/pkg/scheduler/factory/factory_test.go +++ b/plugin/pkg/scheduler/factory/factory_test.go @@ -49,6 +49,8 @@ func TestCreate(t *testing.T) { factory.Create() } +// Test configures a scheduler from a policies defined in a file +// It combines some configurable predicate/priorities with some pre-defined ones func TestCreateFromConfig(t *testing.T) { var configData []byte var policy schedulerapi.Policy @@ -63,16 +65,11 @@ func TestCreateFromConfig(t *testing.T) { client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()}) factory := NewConfigFactory(client) - // Register the predicate and priority functions - // These would be registered by the DefaultProvider in regular operation - RegisterFitPredicate("PodFitsPorts", algorithm.PodFitsPorts) - RegisterFitPredicate("PodFitsResources", algorithm.NewResourceFitPredicate(MinionLister)) - RegisterFitPredicate("NoDiskConflict", algorithm.NoDiskConflict) - RegisterFitPredicate("MatchNodeSelector", algorithm.NewSelectorMatchPredicate(MinionLister)) - RegisterFitPredicate("HostName", algorithm.PodFitsHost) - RegisterPriorityFunction("LeastRequestedPriority", algorithm.LeastRequestedPriority, 1) - RegisterPriorityFunction("ServiceSpreadingPriority", algorithm.NewServiceSpreadPriority(ServiceLister), 1) - RegisterPriorityFunction("EqualPriority", algorithm.EqualPriority, 0) + // Pre-register some predicate and priority functions + RegisterFitPredicate("PredicateOne", PredicateOne) + RegisterFitPredicate("PredicateTwo", PredicateTwo) + RegisterPriorityFunction("PriorityOne", PriorityOne, 1) + RegisterPriorityFunction("PriorityTwo", PriorityTwo, 1) configData = []byte(`{ "kind" : "Policy", @@ -80,13 +77,13 @@ func TestCreateFromConfig(t *testing.T) { "predicates" : [ {"name" : "TestZoneAffinity", "argument" : {"serviceAffinity" : {"labels" : ["zone"]}}}, {"name" : "TestRequireZone", "argument" : {"labelsPresence" : {"labels" : ["zone"], "presence" : true}}}, - {"name" : "PodFitsPorts"}, - {"name" : "MatchNodeSelector"} + {"name" : "PredicateOne"}, + {"name" : "PredicateTwo"} ], "priorities" : [ - {"name" : "RackSpread", "weight" : 2, "argument" : {"serviceAntiAffinity" : {"label" : "rack"}}}, - {"name" : "ServiceSpreadingPriority", "weight" : 1} - ] + {"name" : "RackSpread", "weight" : 3, "argument" : {"serviceAntiAffinity" : {"label" : "rack"}}}, + {"name" : "PriorityOne", "weight" : 2}, + {"name" : "PriorityTwo", "weight" : 1} ] }`) err := latestschedulerapi.Codec.DecodeInto(configData, &policy) if err != nil { @@ -119,6 +116,22 @@ func TestCreateFromEmptyConfig(t *testing.T) { factory.CreateFromConfig(policy) } +func PredicateOne(pod api.Pod, existingPods []api.Pod, node string) (bool, error) { + return true, nil +} + +func PredicateTwo(pod api.Pod, existingPods []api.Pod, node string) (bool, error) { + return true, nil +} + +func PriorityOne(pod api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) { + return []algorithm.HostPriority{}, nil +} + +func PriorityTwo(pod api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) { + return []algorithm.HostPriority{}, nil +} + func TestPollMinions(t *testing.T) { table := []struct { minions []api.Node