Commit efb2bb71 authored by Dan Mace's avatar Dan Mace

Refactor scheduler config API

Refactor the kube-scheduler configuration API, command setup, and server setup according to the guidelines established in #32215 and using the kube-proxy refactor (#34727) as a model of a well factored component adhering to said guidelines. * Config API: clarify meaning and use of algorithm source by replacing modality derived from bools and string emptiness checks with an explicit AlgorithmSource type hierarchy. * Config API: consolidate client connection config with common structs. * Config API: split and simplify healthz/metrics server configuration. * Config API: clarify leader election configuration. * Config API: improve defaulting. * CLI: deprecate all flags except `--config`. * CLI: port all flags to new config API. * CLI: refactor to match kube-proxy Cobra command style. * Server: refactor away configurator.go to clarify application wiring. * Server: refactor to more clearly separate wiring/setup from running. Fixes #52428.
parent 25ca2877
...@@ -17,24 +17,38 @@ limitations under the License. ...@@ -17,24 +17,38 @@ limitations under the License.
package main package main
import ( import (
"flag"
"k8s.io/apiserver/pkg/server/healthz"
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app" "k8s.io/kubernetes/plugin/cmd/kube-scheduler/app"
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/options"
) )
// NewScheduler creates a new hyperkube Server object that includes the // NewScheduler creates a new hyperkube Server object that includes the
// description and flags. // description and flags.
func NewScheduler() *Server { func NewScheduler() *Server {
s := options.NewSchedulerServer() healthz.DefaultHealthz()
command := app.NewSchedulerCommand()
hks := Server{ hks := Server{
name: "scheduler", name: "scheduler",
AlternativeName: "kube-scheduler", AlternativeName: "kube-scheduler",
SimpleUsage: "scheduler", SimpleUsage: "scheduler",
Long: "Implements a Kubernetes scheduler. This will assign pods to kubelets based on capacity and constraints.", Long: command.Long,
Run: func(_ *Server, _ []string, stopCh <-chan struct{}) error {
return app.Run(s)
},
} }
s.AddFlags(hks.Flags())
serverFlags := hks.Flags()
serverFlags.AddFlagSet(command.Flags())
// FIXME this is here because hyperkube does its own flag parsing, and we need
// the command to know about the go flag set. Remove this once hyperkube is
// refactored to use cobra throughout.
command.Flags().AddGoFlagSet(flag.CommandLine)
hks.Run = func(_ *Server, args []string, stopCh <-chan struct{}) error {
command.SetArgs(args)
return command.Execute()
}
return &hks return &hks
} }
...@@ -52,7 +52,7 @@ import ( ...@@ -52,7 +52,7 @@ import (
"k8s.io/kubernetes/pkg/util/initsystem" "k8s.io/kubernetes/pkg/util/initsystem"
versionutil "k8s.io/kubernetes/pkg/util/version" versionutil "k8s.io/kubernetes/pkg/util/version"
kubeadmversion "k8s.io/kubernetes/pkg/version" kubeadmversion "k8s.io/kubernetes/pkg/version"
schoptions "k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/options" schedulerapp "k8s.io/kubernetes/plugin/cmd/kube-scheduler/app"
"k8s.io/kubernetes/test/e2e_node/system" "k8s.io/kubernetes/test/e2e_node/system"
) )
...@@ -409,9 +409,9 @@ func (eac ExtraArgsCheck) Check() (warnings, errors []error) { ...@@ -409,9 +409,9 @@ func (eac ExtraArgsCheck) Check() (warnings, errors []error) {
warnings = append(warnings, argsCheck("kube-controller-manager", eac.ControllerManagerExtraArgs, flags)...) warnings = append(warnings, argsCheck("kube-controller-manager", eac.ControllerManagerExtraArgs, flags)...)
} }
if len(eac.SchedulerExtraArgs) > 0 { if len(eac.SchedulerExtraArgs) > 0 {
command := schedulerapp.NewSchedulerCommand()
flags := pflag.NewFlagSet("", pflag.ContinueOnError) flags := pflag.NewFlagSet("", pflag.ContinueOnError)
s := schoptions.NewSchedulerServer() flags.AddFlagSet(command.Flags())
s.AddFlags(flags)
warnings = append(warnings, argsCheck("kube-scheduler", eac.SchedulerExtraArgs, flags)...) warnings = append(warnings, argsCheck("kube-scheduler", eac.SchedulerExtraArgs, flags)...)
} }
return warnings, nil return warnings, nil
......
...@@ -20,58 +20,107 @@ import ( ...@@ -20,58 +20,107 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
// ClientConnectionConfiguration contains details for constructing a client.
type ClientConnectionConfiguration struct {
// kubeConfigFile is the path to a kubeconfig file.
KubeConfigFile string
// acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the
// default value of 'application/json'. This field will control all connections to the server used by a particular
// client.
AcceptContentTypes string
// contentType is the content type used when sending data to the server from this client.
ContentType string
// cps controls the number of queries per second allowed for this connection.
QPS float32
// burst allows extra queries to accumulate when a client is exceeding its rate.
Burst int
}
// SchedulerPolicyConfigMapKey defines the key of the element in the
// scheduler's policy ConfigMap that contains scheduler's policy config.
const SchedulerPolicyConfigMapKey string = "policy.cfg"
// SchedulerPolicySource configures a means to obtain a scheduler Policy. One
// source field must be specified, and source fields are mutually exclusive.
type SchedulerPolicySource struct {
// File is a file policy source.
File *SchedulerPolicyFileSource
// ConfigMap is a config map policy source.
ConfigMap *SchedulerPolicyConfigMapSource
}
// SchedulerPolicyFileSource is a policy serialized to disk and accessed via
// path.
type SchedulerPolicyFileSource struct {
// Path is the location of a serialized policy.
Path string
}
// SchedulerPolicyConfigMapSource is a policy serialized into a config map value
// under the SchedulerPolicyConfigMapKey key.
type SchedulerPolicyConfigMapSource struct {
// Namespace is the namespace of the policy config map.
Namespace string
// Name is the name of hte policy config map.
Name string
}
// SchedulerAlgorithmSource is the source of a scheduler algorithm. One source
// field must be specified, and source fields are mutually exclusive.
type SchedulerAlgorithmSource struct {
// Policy is a policy based algorithm source.
Policy *SchedulerPolicySource
// Provider is the name of a scheduling algorithm provider to use.
Provider *string
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type KubeSchedulerConfiguration struct { type KubeSchedulerConfiguration struct {
metav1.TypeMeta metav1.TypeMeta
// port is the port that the scheduler's http service runs on.
Port int32
// address is the IP address to serve on.
Address string
// algorithmProvider is the scheduling algorithm provider to use.
AlgorithmProvider string
// policyConfigFile is the filepath to the scheduler policy configuration.
PolicyConfigFile string
// enableProfiling enables profiling via web interface.
EnableProfiling bool
// enableContentionProfiling enables lock contention profiling, if enableProfiling is true.
EnableContentionProfiling bool
// contentType is contentType of requests sent to apiserver.
ContentType string
// kubeAPIQPS is the QPS to use while talking with kubernetes apiserver.
KubeAPIQPS float32
// kubeAPIBurst is the QPS burst to use while talking with kubernetes apiserver.
KubeAPIBurst int32
// schedulerName is name of the scheduler, used to select which pods // schedulerName is name of the scheduler, used to select which pods
// will be processed by this scheduler, based on pod's "spec.SchedulerName". // will be processed by this scheduler, based on pod's "spec.SchedulerName".
SchedulerName string SchedulerName string
// AlgorithmSource specifies the scheduler algorithm source.
AlgorithmSource SchedulerAlgorithmSource
// RequiredDuringScheduling affinity is not symmetric, but there is an implicit PreferredDuringScheduling affinity rule // RequiredDuringScheduling affinity is not symmetric, but there is an implicit PreferredDuringScheduling affinity rule
// corresponding to every RequiredDuringScheduling affinity rule. // corresponding to every RequiredDuringScheduling affinity rule.
// HardPodAffinitySymmetricWeight represents the weight of implicit PreferredDuringScheduling affinity rule, in the range 0-100. // HardPodAffinitySymmetricWeight represents the weight of implicit PreferredDuringScheduling affinity rule, in the range 0-100.
HardPodAffinitySymmetricWeight int HardPodAffinitySymmetricWeight int
// LeaderElection defines the configuration of leader election client.
LeaderElection KubeSchedulerLeaderElectionConfiguration
// ClientConnection specifies the kubeconfig file and client connection
// settings for the proxy server to use when communicating with the apiserver.
ClientConnection ClientConnectionConfiguration
// HealthzBindAddress is the IP address and port for the health check server to serve on,
// defaulting to 0.0.0.0:10251
HealthzBindAddress string
// MetricsBindAddress is the IP address and port for the metrics server to
// serve on, defaulting to 0.0.0.0:10251.
MetricsBindAddress string
// EnableProfiling enables profiling via web interface on /debug/pprof
// handler. Profiling handlers will be handled by metrics server.
EnableProfiling bool
// EnableContentionProfiling enables lock contention profiling, if
// EnableProfiling is true.
EnableContentionProfiling bool
// Indicate the "all topologies" set for empty topologyKey when it's used for PreferredDuringScheduling pod anti-affinity. // Indicate the "all topologies" set for empty topologyKey when it's used for PreferredDuringScheduling pod anti-affinity.
// DEPRECATED: This is no longer used. // DEPRECATED: This is no longer used.
FailureDomains string FailureDomains string
// leaderElection defines the configuration of leader election client. }
LeaderElection LeaderElectionConfiguration
// KubeSchedulerLeaderElectionConfiguration expands LeaderElectionConfiguration
// to include scheduler specific configuration.
type KubeSchedulerLeaderElectionConfiguration struct {
LeaderElectionConfiguration
// LockObjectNamespace defines the namespace of the lock object // LockObjectNamespace defines the namespace of the lock object
LockObjectNamespace string LockObjectNamespace string
// LockObjectName defines the lock object name // LockObjectName defines the lock object name
LockObjectName string LockObjectName string
// PolicyConfigMapName is the name of the ConfigMap object that specifies
// the scheduler's policy config. If UseLegacyPolicyConfig is true, scheduler
// uses PolicyConfigFile. If UseLegacyPolicyConfig is false and
// PolicyConfigMapName is not empty, the ConfigMap object with this name must
// exist in PolicyConfigMapNamespace before scheduler initialization.
PolicyConfigMapName string
// PolicyConfigMapNamespace is the namespace where the above policy config map
// is located. If none is provided default system namespace ("kube-system")
// will be used.
PolicyConfigMapNamespace string
// UseLegacyPolicyConfig tells the scheduler to ignore Policy ConfigMap and
// to use PolicyConfigFile if available.
UseLegacyPolicyConfig bool
} }
// LeaderElectionConfiguration defines the configuration of leader election // LeaderElectionConfiguration defines the configuration of leader election
......
...@@ -17,6 +17,8 @@ limitations under the License. ...@@ -17,6 +17,8 @@ limitations under the License.
package v1alpha1 package v1alpha1
import ( import (
"net"
"strconv"
"time" "time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
...@@ -31,41 +33,63 @@ func addDefaultingFuncs(scheme *kruntime.Scheme) error { ...@@ -31,41 +33,63 @@ func addDefaultingFuncs(scheme *kruntime.Scheme) error {
} }
func SetDefaults_KubeSchedulerConfiguration(obj *KubeSchedulerConfiguration) { func SetDefaults_KubeSchedulerConfiguration(obj *KubeSchedulerConfiguration) {
if obj.Port == 0 { if len(obj.SchedulerName) == 0 {
obj.Port = ports.SchedulerPort obj.SchedulerName = api.DefaultSchedulerName
} }
if obj.Address == "" {
obj.Address = "0.0.0.0" if obj.HardPodAffinitySymmetricWeight == 0 {
obj.HardPodAffinitySymmetricWeight = api.DefaultHardPodAffinitySymmetricWeight
} }
if obj.AlgorithmProvider == "" {
obj.AlgorithmProvider = "DefaultProvider" if obj.AlgorithmSource.Policy == nil &&
(obj.AlgorithmSource.Provider == nil || len(*obj.AlgorithmSource.Provider) == 0) {
val := SchedulerDefaultProviderName
obj.AlgorithmSource.Provider = &val
} }
if obj.ContentType == "" {
obj.ContentType = "application/vnd.kubernetes.protobuf" if policy := obj.AlgorithmSource.Policy; policy != nil {
if policy.ConfigMap != nil && len(policy.ConfigMap.Namespace) == 0 {
obj.AlgorithmSource.Policy.ConfigMap.Namespace = api.NamespaceSystem
} }
if obj.KubeAPIQPS == 0 {
obj.KubeAPIQPS = 50.0
} }
if obj.KubeAPIBurst == 0 {
obj.KubeAPIBurst = 100 if host, port, err := net.SplitHostPort(obj.HealthzBindAddress); err == nil {
if len(host) == 0 {
host = "0.0.0.0"
} }
if obj.SchedulerName == "" { obj.HealthzBindAddress = net.JoinHostPort(host, port)
obj.SchedulerName = api.DefaultSchedulerName } else {
obj.HealthzBindAddress = net.JoinHostPort("0.0.0.0", strconv.Itoa(ports.SchedulerPort))
} }
if obj.HardPodAffinitySymmetricWeight == 0 {
obj.HardPodAffinitySymmetricWeight = api.DefaultHardPodAffinitySymmetricWeight if host, port, err := net.SplitHostPort(obj.MetricsBindAddress); err == nil {
if len(host) == 0 {
host = "0.0.0.0"
} }
if obj.FailureDomains == "" { obj.MetricsBindAddress = net.JoinHostPort(host, port)
obj.FailureDomains = kubeletapis.DefaultFailureDomains } else {
obj.MetricsBindAddress = net.JoinHostPort("0.0.0.0", strconv.Itoa(ports.SchedulerPort))
} }
if obj.LockObjectNamespace == "" {
obj.LockObjectNamespace = SchedulerDefaultLockObjectNamespace if len(obj.ClientConnection.ContentType) == 0 {
obj.ClientConnection.ContentType = "application/vnd.kubernetes.protobuf"
} }
if obj.LockObjectName == "" { if obj.ClientConnection.QPS == 0.0 {
obj.LockObjectName = SchedulerDefaultLockObjectName obj.ClientConnection.QPS = 50.0
} }
if obj.PolicyConfigMapNamespace == "" { if obj.ClientConnection.Burst == 0 {
obj.PolicyConfigMapNamespace = api.NamespaceSystem obj.ClientConnection.Burst = 100
}
if len(obj.LeaderElection.LockObjectNamespace) == 0 {
obj.LeaderElection.LockObjectNamespace = SchedulerDefaultLockObjectNamespace
}
if len(obj.LeaderElection.LockObjectName) == 0 {
obj.LeaderElection.LockObjectName = SchedulerDefaultLockObjectName
}
if len(obj.FailureDomains) == 0 {
obj.FailureDomains = kubeletapis.DefaultFailureDomains
} }
} }
......
...@@ -20,57 +20,92 @@ import ( ...@@ -20,57 +20,92 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
// ClientConnectionConfiguration contains details for constructing a client.
type ClientConnectionConfiguration struct {
// kubeConfigFile is the path to a kubeconfig file.
KubeConfigFile string `json:"kubeconfig"`
// acceptContentTypes defines the Accept header sent by clients when connecting to a server, overriding the
// default value of 'application/json'. This field will control all connections to the server used by a particular
// client.
AcceptContentTypes string `json:"acceptContentTypes"`
// contentType is the content type used when sending data to the server from this client.
ContentType string `json:"contentType"`
// cps controls the number of queries per second allowed for this connection.
QPS float32 `json:"qps"`
// burst allows extra queries to accumulate when a client is exceeding its rate.
Burst int `json:"burst"`
}
// SchedulerPolicySource configures a means to obtain a scheduler Policy. One
// source field must be specified, and source fields are mutually exclusive.
type SchedulerPolicySource struct {
// File is a file policy source.
File *SchedulerPolicyFileSource `json:"file,omitempty"`
// ConfigMap is a config map policy source.
ConfigMap *SchedulerPolicyConfigMapSource `json:"configMap,omitempty"`
}
// SchedulerPolicyFileSource is a policy serialized to disk and accessed via
// path.
type SchedulerPolicyFileSource struct {
// Path is the location of a serialized policy.
Path string `json:"path"`
}
// SchedulerPolicyConfigMapSource is a policy serialized into a config map value
// under the SchedulerPolicyConfigMapKey key.
type SchedulerPolicyConfigMapSource struct {
// Namespace is the namespace of the policy config map.
Namespace string `json:"namespace"`
// Name is the name of hte policy config map.
Name string `json:"name"`
}
// SchedulerAlgorithmSource is the source of a scheduler algorithm. One source
// field must be specified, and source fields are mutually exclusive.
type SchedulerAlgorithmSource struct {
// Policy is a policy based algorithm source.
Policy *SchedulerPolicySource `json:"policy,omitempty"`
// Provider is the name of a scheduling algorithm provider to use.
Provider *string `json:"provider,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type KubeSchedulerConfiguration struct { type KubeSchedulerConfiguration struct {
metav1.TypeMeta `json:",inline"` metav1.TypeMeta `json:",inline"`
// port is the port that the scheduler's http service runs on. // SchedulerName is name of the scheduler, used to select which pods
Port int `json:"port"`
// address is the IP address to serve on.
Address string `json:"address"`
// algorithmProvider is the scheduling algorithm provider to use.
AlgorithmProvider string `json:"algorithmProvider"`
// policyConfigFile is the filepath to the scheduler policy configuration.
PolicyConfigFile string `json:"policyConfigFile"`
// enableProfiling enables profiling via web interface.
EnableProfiling *bool `json:"enableProfiling"`
// enableContentionProfiling enables lock contention profiling, if enableProfiling is true.
EnableContentionProfiling bool `json:"enableContentionProfiling"`
// contentType is contentType of requests sent to apiserver.
ContentType string `json:"contentType"`
// kubeAPIQPS is the QPS to use while talking with kubernetes apiserver.
KubeAPIQPS float32 `json:"kubeAPIQPS"`
// kubeAPIBurst is the QPS burst to use while talking with kubernetes apiserver.
KubeAPIBurst int `json:"kubeAPIBurst"`
// schedulerName is name of the scheduler, used to select which pods
// will be processed by this scheduler, based on pod's "spec.SchedulerName". // will be processed by this scheduler, based on pod's "spec.SchedulerName".
SchedulerName string `json:"schedulerName"` SchedulerName string `json:"schedulerName"`
// AlgorithmSource specifies the scheduler algorithm source.
AlgorithmSource SchedulerAlgorithmSource `json:"algorithmSource"`
// RequiredDuringScheduling affinity is not symmetric, but there is an implicit PreferredDuringScheduling affinity rule // RequiredDuringScheduling affinity is not symmetric, but there is an implicit PreferredDuringScheduling affinity rule
// corresponding to every RequiredDuringScheduling affinity rule. // corresponding to every RequiredDuringScheduling affinity rule.
// HardPodAffinitySymmetricWeight represents the weight of implicit PreferredDuringScheduling affinity rule, in the range 0-100. // HardPodAffinitySymmetricWeight represents the weight of implicit PreferredDuringScheduling affinity rule, in the range 0-100.
HardPodAffinitySymmetricWeight int `json:"hardPodAffinitySymmetricWeight"` HardPodAffinitySymmetricWeight int `json:"hardPodAffinitySymmetricWeight"`
// LeaderElection defines the configuration of leader election client.
LeaderElection KubeSchedulerLeaderElectionConfiguration `json:"leaderElection"`
// ClientConnection specifies the kubeconfig file and client connection
// settings for the proxy server to use when communicating with the apiserver.
ClientConnection ClientConnectionConfiguration `json:"clientConnection"`
// HealthzBindAddress is the IP address and port for the health check server to serve on,
// defaulting to 0.0.0.0:10251
HealthzBindAddress string `json:"healthzBindAddress"`
// MetricsBindAddress is the IP address and port for the metrics server to
// serve on, defaulting to 0.0.0.0:10251.
MetricsBindAddress string `json:"metricsBindAddress"`
// EnableProfiling enables profiling via web interface on /debug/pprof
// handler. Profiling handlers will be handled by metrics server.
EnableProfiling bool `json:"enableProfiling"`
// EnableContentionProfiling enables lock contention profiling, if
// EnableProfiling is true.
EnableContentionProfiling bool `json:"enableContentionProfiling"`
// Indicate the "all topologies" set for empty topologyKey when it's used for PreferredDuringScheduling pod anti-affinity. // Indicate the "all topologies" set for empty topologyKey when it's used for PreferredDuringScheduling pod anti-affinity.
FailureDomains string `json:"failureDomains"` FailureDomains string `json:"failureDomains"`
// leaderElection defines the configuration of leader election client.
LeaderElection LeaderElectionConfiguration `json:"leaderElection"`
// LockObjectNamespace defines the namespace of the lock object
LockObjectNamespace string `json:"lockObjectNamespace"`
// LockObjectName defines the lock object name
LockObjectName string `json:"lockObjectName"`
// PolicyConfigMapName is the name of the ConfigMap object that specifies
// the scheduler's policy config. If UseLegacyPolicyConfig is true, scheduler
// uses PolicyConfigFile. If UseLegacyPolicyConfig is false and
// PolicyConfigMapName is not empty, the ConfigMap object with this name must
// exist in PolicyConfigMapNamespace before scheduler initialization.
PolicyConfigMapName string `json:"policyConfigMapName"`
// PolicyConfigMapNamespace is the namespace where the above policy config map
// is located. If none is provided default system namespace ("kube-system")
// will be used.
PolicyConfigMapNamespace string `json:"policyConfigMapNamespace"`
// UseLegacyPolicyConfig tells the scheduler to ignore Policy ConfigMap and
// to use PolicyConfigFile if available.
UseLegacyPolicyConfig bool `json:"useLegacyPolicyConfig"`
} }
// LeaderElectionConfiguration defines the configuration of leader election // LeaderElectionConfiguration defines the configuration of leader election
...@@ -101,10 +136,22 @@ type LeaderElectionConfiguration struct { ...@@ -101,10 +136,22 @@ type LeaderElectionConfiguration struct {
ResourceLock string `json:"resourceLock"` ResourceLock string `json:"resourceLock"`
} }
// KubeSchedulerLeaderElectionConfiguration expands LeaderElectionConfiguration
// to include scheduler specific configuration.
type KubeSchedulerLeaderElectionConfiguration struct {
LeaderElectionConfiguration `json:",inline"`
// LockObjectNamespace defines the namespace of the lock object
LockObjectNamespace string `json:"lockObjectNamespace"`
// LockObjectName defines the lock object name
LockObjectName string `json:"lockObjectName"`
}
const ( const (
// "kube-system" is the default scheduler lock object namespace // "kube-system" is the default scheduler lock object namespace
SchedulerDefaultLockObjectNamespace string = "kube-system" SchedulerDefaultLockObjectNamespace string = "kube-system"
// "kube-scheduler" is the default scheduler lock object name // "kube-scheduler" is the default scheduler lock object name
SchedulerDefaultLockObjectName = "kube-scheduler" SchedulerDefaultLockObjectName = "kube-scheduler"
SchedulerDefaultProviderName = "DefaultProvider"
) )
...@@ -37,6 +37,10 @@ func init() { ...@@ -37,6 +37,10 @@ func init() {
func RegisterDeepCopies(scheme *runtime.Scheme) error { func RegisterDeepCopies(scheme *runtime.Scheme) error {
return scheme.AddGeneratedDeepCopyFuncs( return scheme.AddGeneratedDeepCopyFuncs(
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error { conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*ClientConnectionConfiguration).DeepCopyInto(out.(*ClientConnectionConfiguration))
return nil
}, InType: reflect.TypeOf(&ClientConnectionConfiguration{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*GroupResource).DeepCopyInto(out.(*GroupResource)) in.(*GroupResource).DeepCopyInto(out.(*GroupResource))
return nil return nil
}, InType: reflect.TypeOf(&GroupResource{})}, }, InType: reflect.TypeOf(&GroupResource{})},
...@@ -53,6 +57,10 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error { ...@@ -53,6 +57,10 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
return nil return nil
}, InType: reflect.TypeOf(&KubeSchedulerConfiguration{})}, }, InType: reflect.TypeOf(&KubeSchedulerConfiguration{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error { conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*KubeSchedulerLeaderElectionConfiguration).DeepCopyInto(out.(*KubeSchedulerLeaderElectionConfiguration))
return nil
}, InType: reflect.TypeOf(&KubeSchedulerLeaderElectionConfiguration{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*LeaderElectionConfiguration).DeepCopyInto(out.(*LeaderElectionConfiguration)) in.(*LeaderElectionConfiguration).DeepCopyInto(out.(*LeaderElectionConfiguration))
return nil return nil
}, InType: reflect.TypeOf(&LeaderElectionConfiguration{})}, }, InType: reflect.TypeOf(&LeaderElectionConfiguration{})},
...@@ -65,6 +73,22 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error { ...@@ -65,6 +73,22 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
return nil return nil
}, InType: reflect.TypeOf(&PortRangeVar{})}, }, InType: reflect.TypeOf(&PortRangeVar{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error { conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*SchedulerAlgorithmSource).DeepCopyInto(out.(*SchedulerAlgorithmSource))
return nil
}, InType: reflect.TypeOf(&SchedulerAlgorithmSource{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*SchedulerPolicyConfigMapSource).DeepCopyInto(out.(*SchedulerPolicyConfigMapSource))
return nil
}, InType: reflect.TypeOf(&SchedulerPolicyConfigMapSource{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*SchedulerPolicyFileSource).DeepCopyInto(out.(*SchedulerPolicyFileSource))
return nil
}, InType: reflect.TypeOf(&SchedulerPolicyFileSource{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*SchedulerPolicySource).DeepCopyInto(out.(*SchedulerPolicySource))
return nil
}, InType: reflect.TypeOf(&SchedulerPolicySource{})},
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
in.(*VolumeConfiguration).DeepCopyInto(out.(*VolumeConfiguration)) in.(*VolumeConfiguration).DeepCopyInto(out.(*VolumeConfiguration))
return nil return nil
}, InType: reflect.TypeOf(&VolumeConfiguration{})}, }, InType: reflect.TypeOf(&VolumeConfiguration{})},
...@@ -72,6 +96,22 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error { ...@@ -72,6 +96,22 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClientConnectionConfiguration) DeepCopyInto(out *ClientConnectionConfiguration) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClientConnectionConfiguration.
func (in *ClientConnectionConfiguration) DeepCopy() *ClientConnectionConfiguration {
if in == nil {
return nil
}
out := new(ClientConnectionConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GroupResource) DeepCopyInto(out *GroupResource) { func (in *GroupResource) DeepCopyInto(out *GroupResource) {
*out = *in *out = *in
return return
...@@ -172,7 +212,9 @@ func (in *KubeControllerManagerConfiguration) DeepCopyObject() runtime.Object { ...@@ -172,7 +212,9 @@ func (in *KubeControllerManagerConfiguration) DeepCopyObject() runtime.Object {
func (in *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerConfiguration) { func (in *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerConfiguration) {
*out = *in *out = *in
out.TypeMeta = in.TypeMeta out.TypeMeta = in.TypeMeta
in.AlgorithmSource.DeepCopyInto(&out.AlgorithmSource)
out.LeaderElection = in.LeaderElection out.LeaderElection = in.LeaderElection
out.ClientConnection = in.ClientConnection
return return
} }
...@@ -196,6 +238,23 @@ func (in *KubeSchedulerConfiguration) DeepCopyObject() runtime.Object { ...@@ -196,6 +238,23 @@ func (in *KubeSchedulerConfiguration) DeepCopyObject() runtime.Object {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeSchedulerLeaderElectionConfiguration) DeepCopyInto(out *KubeSchedulerLeaderElectionConfiguration) {
*out = *in
out.LeaderElectionConfiguration = in.LeaderElectionConfiguration
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerLeaderElectionConfiguration.
func (in *KubeSchedulerLeaderElectionConfiguration) DeepCopy() *KubeSchedulerLeaderElectionConfiguration {
if in == nil {
return nil
}
out := new(KubeSchedulerLeaderElectionConfiguration)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) { func (in *LeaderElectionConfiguration) DeepCopyInto(out *LeaderElectionConfiguration) {
*out = *in *out = *in
out.LeaseDuration = in.LeaseDuration out.LeaseDuration = in.LeaseDuration
...@@ -256,6 +315,106 @@ func (in *PortRangeVar) DeepCopy() *PortRangeVar { ...@@ -256,6 +315,106 @@ func (in *PortRangeVar) DeepCopy() *PortRangeVar {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SchedulerAlgorithmSource) DeepCopyInto(out *SchedulerAlgorithmSource) {
*out = *in
if in.Policy != nil {
in, out := &in.Policy, &out.Policy
if *in == nil {
*out = nil
} else {
*out = new(SchedulerPolicySource)
(*in).DeepCopyInto(*out)
}
}
if in.Provider != nil {
in, out := &in.Provider, &out.Provider
if *in == nil {
*out = nil
} else {
*out = new(string)
**out = **in
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchedulerAlgorithmSource.
func (in *SchedulerAlgorithmSource) DeepCopy() *SchedulerAlgorithmSource {
if in == nil {
return nil
}
out := new(SchedulerAlgorithmSource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SchedulerPolicyConfigMapSource) DeepCopyInto(out *SchedulerPolicyConfigMapSource) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchedulerPolicyConfigMapSource.
func (in *SchedulerPolicyConfigMapSource) DeepCopy() *SchedulerPolicyConfigMapSource {
if in == nil {
return nil
}
out := new(SchedulerPolicyConfigMapSource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SchedulerPolicyFileSource) DeepCopyInto(out *SchedulerPolicyFileSource) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchedulerPolicyFileSource.
func (in *SchedulerPolicyFileSource) DeepCopy() *SchedulerPolicyFileSource {
if in == nil {
return nil
}
out := new(SchedulerPolicyFileSource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SchedulerPolicySource) DeepCopyInto(out *SchedulerPolicySource) {
*out = *in
if in.File != nil {
in, out := &in.File, &out.File
if *in == nil {
*out = nil
} else {
*out = new(SchedulerPolicyFileSource)
**out = **in
}
}
if in.ConfigMap != nil {
in, out := &in.ConfigMap, &out.ConfigMap
if *in == nil {
*out = nil
} else {
*out = new(SchedulerPolicyConfigMapSource)
**out = **in
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchedulerPolicySource.
func (in *SchedulerPolicySource) DeepCopy() *SchedulerPolicySource {
if in == nil {
return nil
}
out := new(SchedulerPolicySource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VolumeConfiguration) DeepCopyInto(out *VolumeConfiguration) { func (in *VolumeConfiguration) DeepCopyInto(out *VolumeConfiguration) {
*out = *in *out = *in
out.PersistentVolumeRecyclerConfiguration = in.PersistentVolumeRecyclerConfiguration out.PersistentVolumeRecyclerConfiguration = in.PersistentVolumeRecyclerConfiguration
......
/*
Copyright 2017 The Kubernetes Authors.
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 app
import (
"fmt"
"io/ioutil"
"os"
appsinformers "k8s.io/client-go/informers/apps/v1beta1"
coreinformers "k8s.io/client-go/informers/core/v1"
extensionsinformers "k8s.io/client-go/informers/extensions/v1beta1"
policyinformers "k8s.io/client-go/informers/policy/v1beta1"
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/options"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
utilfeature "k8s.io/apiserver/pkg/util/feature"
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
clientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/record"
"k8s.io/api/core/v1"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/plugin/pkg/scheduler"
_ "k8s.io/kubernetes/plugin/pkg/scheduler/algorithmprovider"
schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api"
latestschedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api/latest"
"k8s.io/kubernetes/plugin/pkg/scheduler/factory"
"github.com/golang/glog"
)
func createRecorder(kubecli *clientset.Clientset, s *options.SchedulerServer) record.EventRecorder {
eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartLogging(glog.Infof)
eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: v1core.New(kubecli.CoreV1().RESTClient()).Events("")})
return eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: s.SchedulerName})
}
func createClients(s *options.SchedulerServer) (*clientset.Clientset, *clientset.Clientset, error) {
kubeconfig, err := clientcmd.BuildConfigFromFlags(s.Master, s.Kubeconfig)
if err != nil {
return nil, nil, fmt.Errorf("unable to build config from flags: %v", err)
}
kubeconfig.ContentType = s.ContentType
// Override kubeconfig qps/burst settings from flags
kubeconfig.QPS = s.KubeAPIQPS
kubeconfig.Burst = int(s.KubeAPIBurst)
kubeClient, err := clientset.NewForConfig(restclient.AddUserAgent(kubeconfig, "scheduler"))
if err != nil {
glog.Fatalf("Invalid API configuration: %v", err)
}
leaderElectionClient := clientset.NewForConfigOrDie(restclient.AddUserAgent(kubeconfig, "leader-election"))
return kubeClient, leaderElectionClient, nil
}
// CreateScheduler encapsulates the entire creation of a runnable scheduler.
func CreateScheduler(
s *options.SchedulerServer,
kubecli clientset.Interface,
nodeInformer coreinformers.NodeInformer,
podInformer coreinformers.PodInformer,
pvInformer coreinformers.PersistentVolumeInformer,
pvcInformer coreinformers.PersistentVolumeClaimInformer,
replicationControllerInformer coreinformers.ReplicationControllerInformer,
replicaSetInformer extensionsinformers.ReplicaSetInformer,
statefulSetInformer appsinformers.StatefulSetInformer,
serviceInformer coreinformers.ServiceInformer,
pdbInformer policyinformers.PodDisruptionBudgetInformer,
recorder record.EventRecorder,
) (*scheduler.Scheduler, error) {
configurator := factory.NewConfigFactory(
s.SchedulerName,
kubecli,
nodeInformer,
podInformer,
pvInformer,
pvcInformer,
replicationControllerInformer,
replicaSetInformer,
statefulSetInformer,
serviceInformer,
pdbInformer,
s.HardPodAffinitySymmetricWeight,
utilfeature.DefaultFeatureGate.Enabled(features.EnableEquivalenceClassCache),
)
// Rebuild the configurator with a default Create(...) method.
configurator = &schedulerConfigurator{
configurator,
s.PolicyConfigFile,
s.AlgorithmProvider,
s.PolicyConfigMapName,
s.PolicyConfigMapNamespace,
s.UseLegacyPolicyConfig,
}
return scheduler.NewFromConfigurator(configurator, func(cfg *scheduler.Config) {
cfg.Recorder = recorder
})
}
// schedulerConfigurator is an interface wrapper that provides a way to create
// a scheduler from a user provided config file or ConfigMap object.
type schedulerConfigurator struct {
scheduler.Configurator
policyFile string
algorithmProvider string
policyConfigMap string
policyConfigMapNamespace string
useLegacyPolicyConfig bool
}
// getSchedulerPolicyConfig finds and decodes scheduler's policy config. If no
// such policy is found, it returns nil, nil.
func (sc schedulerConfigurator) getSchedulerPolicyConfig() (*schedulerapi.Policy, error) {
var configData []byte
var policyConfigMapFound bool
var policy schedulerapi.Policy
// If not in legacy mode, try to find policy ConfigMap.
if !sc.useLegacyPolicyConfig && len(sc.policyConfigMap) != 0 {
namespace := sc.policyConfigMapNamespace
policyConfigMap, err := sc.GetClient().CoreV1().ConfigMaps(namespace).Get(sc.policyConfigMap, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("Error getting scheduler policy ConfigMap: %v.", err)
}
if policyConfigMap != nil {
var configString string
configString, policyConfigMapFound = policyConfigMap.Data[options.SchedulerPolicyConfigMapKey]
if !policyConfigMapFound {
return nil, fmt.Errorf("No element with key = '%v' is found in the ConfigMap 'Data'.", options.SchedulerPolicyConfigMapKey)
}
glog.V(5).Infof("Scheduler policy ConfigMap: %v", configString)
configData = []byte(configString)
}
}
// If we are in legacy mode or ConfigMap name is empty, try to use policy
// config file.
if !policyConfigMapFound {
if _, err := os.Stat(sc.policyFile); err != nil {
// No config file is found.
return nil, nil
}
var err error
configData, err = ioutil.ReadFile(sc.policyFile)
if err != nil {
return nil, fmt.Errorf("unable to read policy config: %v", err)
}
}
if err := runtime.DecodeInto(latestschedulerapi.Codec, configData, &policy); err != nil {
return nil, fmt.Errorf("invalid configuration: %v", err)
}
return &policy, nil
}
// Create implements the interface for the Configurator, hence it is exported
// even though the struct is not.
func (sc schedulerConfigurator) Create() (*scheduler.Config, error) {
policy, err := sc.getSchedulerPolicyConfig()
if err != nil {
return nil, err
}
// If no policy is found, create scheduler from algorithm provider.
if policy == nil {
if sc.Configurator != nil {
return sc.Configurator.CreateFromProvider(sc.algorithmProvider)
}
return nil, fmt.Errorf("Configurator was nil")
}
return sc.CreateFromConfig(*policy)
}
/*
Copyright 2017 The Kubernetes Authors.
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 app
import (
"testing"
)
func TestSchedulerConfiguratorFailure(t *testing.T) {
sc := &schedulerConfigurator{
// policyfile and algorithm are intentionally undefined.
}
_, err := sc.Create()
if err == nil {
t.Fatalf("Expected error message when creating with incomplete configurator.")
}
}
/*
Copyright 2014 The Kubernetes Authors.
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 options provides the scheduler flags
package options
import (
"fmt"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/componentconfig"
"k8s.io/kubernetes/pkg/apis/componentconfig/v1alpha1"
"k8s.io/kubernetes/pkg/client/leaderelectionconfig"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
"k8s.io/kubernetes/plugin/pkg/scheduler/factory"
// add the kubernetes feature gates
_ "k8s.io/kubernetes/pkg/features"
// install the componentconfig api so we get its defaulting and conversion functions
_ "k8s.io/kubernetes/pkg/apis/componentconfig/install"
"github.com/spf13/pflag"
)
// SchedulerPolicyConfigMapKey defines the key of the element in the
// scheduler's policy ConfigMap that contains scheduler's policy config.
const SchedulerPolicyConfigMapKey string = "policy.cfg"
// SchedulerServer has all the context and params needed to run a Scheduler
type SchedulerServer struct {
componentconfig.KubeSchedulerConfiguration
// Master is the address of the Kubernetes API server (overrides any
// value in kubeconfig).
Master string
// Kubeconfig is Path to kubeconfig file with authorization and master
// location information.
Kubeconfig string
// Dynamic configuration for scheduler features.
}
// NewSchedulerServer creates a new SchedulerServer with default parameters
func NewSchedulerServer() *SchedulerServer {
versioned := &v1alpha1.KubeSchedulerConfiguration{}
legacyscheme.Scheme.Default(versioned)
cfg := componentconfig.KubeSchedulerConfiguration{}
legacyscheme.Scheme.Convert(versioned, &cfg, nil)
cfg.LeaderElection.LeaderElect = true
s := SchedulerServer{
KubeSchedulerConfiguration: cfg,
}
return &s
}
// AddFlags adds flags for a specific SchedulerServer to the specified FlagSet
func (s *SchedulerServer) AddFlags(fs *pflag.FlagSet) {
fs.Int32Var(&s.Port, "port", s.Port, "The port that the scheduler's http service runs on")
fs.StringVar(&s.Address, "address", s.Address, "The IP address to serve on (set to 0.0.0.0 for all interfaces)")
fs.StringVar(&s.AlgorithmProvider, "algorithm-provider", s.AlgorithmProvider, "The scheduling algorithm provider to use, one of: "+factory.ListAlgorithmProviders())
fs.StringVar(&s.PolicyConfigFile, "policy-config-file", s.PolicyConfigFile, "File with scheduler policy configuration. This file is used if policy ConfigMap is not provided or --use-legacy-policy-config==true")
usage := fmt.Sprintf("Name of the ConfigMap object that contains scheduler's policy configuration. It must exist in the system namespace before scheduler initialization if --use-legacy-policy-config==false. The config must be provided as the value of an element in 'Data' map with the key='%v'", SchedulerPolicyConfigMapKey)
fs.StringVar(&s.PolicyConfigMapName, "policy-configmap", s.PolicyConfigMapName, usage)
fs.StringVar(&s.PolicyConfigMapNamespace, "policy-configmap-namespace", s.PolicyConfigMapNamespace, "The namespace where policy ConfigMap is located. The system namespace will be used if this is not provided or is empty.")
fs.BoolVar(&s.UseLegacyPolicyConfig, "use-legacy-policy-config", false, "When set to true, scheduler will ignore policy ConfigMap and uses policy config file")
fs.BoolVar(&s.EnableProfiling, "profiling", true, "Enable profiling via web interface host:port/debug/pprof/")
fs.BoolVar(&s.EnableContentionProfiling, "contention-profiling", false, "Enable lock contention profiling, if profiling is enabled")
fs.StringVar(&s.Master, "master", s.Master, "The address of the Kubernetes API server (overrides any value in kubeconfig)")
fs.StringVar(&s.Kubeconfig, "kubeconfig", s.Kubeconfig, "Path to kubeconfig file with authorization and master location information.")
fs.StringVar(&s.ContentType, "kube-api-content-type", s.ContentType, "Content type of requests sent to apiserver.")
fs.Float32Var(&s.KubeAPIQPS, "kube-api-qps", s.KubeAPIQPS, "QPS to use while talking with kubernetes apiserver")
fs.Int32Var(&s.KubeAPIBurst, "kube-api-burst", s.KubeAPIBurst, "Burst to use while talking with kubernetes apiserver")
fs.StringVar(&s.SchedulerName, "scheduler-name", s.SchedulerName, "Name of the scheduler, used to select which pods will be processed by this scheduler, based on pod's \"spec.SchedulerName\".")
fs.StringVar(&s.LockObjectNamespace, "lock-object-namespace", s.LockObjectNamespace, "Define the namespace of the lock object.")
fs.StringVar(&s.LockObjectName, "lock-object-name", s.LockObjectName, "Define the name of the lock object.")
fs.IntVar(&s.HardPodAffinitySymmetricWeight, "hard-pod-affinity-symmetric-weight", api.DefaultHardPodAffinitySymmetricWeight,
"RequiredDuringScheduling affinity is not symmetric, but there is an implicit PreferredDuringScheduling affinity rule corresponding "+
"to every RequiredDuringScheduling affinity rule. --hard-pod-affinity-symmetric-weight represents the weight of implicit PreferredDuringScheduling affinity rule.")
fs.MarkDeprecated("hard-pod-affinity-symmetric-weight", "This option was moved to the policy configuration file")
fs.StringVar(&s.FailureDomains, "failure-domains", kubeletapis.DefaultFailureDomains, "Indicate the \"all topologies\" set for an empty topologyKey when it's used for PreferredDuringScheduling pod anti-affinity.")
fs.MarkDeprecated("failure-domains", "Doesn't have any effect. Will be removed in future version.")
leaderelectionconfig.BindFlags(&s.LeaderElection, fs)
utilfeature.DefaultFeatureGate.AddFlag(fs)
}
/*
Copyright 2017 The Kubernetes Authors.
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 options
import (
"reflect"
"testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/kubernetes/pkg/apis/componentconfig"
"github.com/spf13/pflag"
)
func TestAddFlags(t *testing.T) {
f := pflag.NewFlagSet("addflagstest", pflag.ContinueOnError)
s := NewSchedulerServer()
s.AddFlags(f)
args := []string{
"--address=192.168.4.20",
"--algorithm-provider=FooProvider",
"--contention-profiling=true",
"--failure-domains=kubernetes.io/hostname",
"--hard-pod-affinity-symmetric-weight=0",
"--kube-api-burst=80",
"--kube-api-content-type=application/vnd.kubernetes.protobuf",
"--kube-api-qps=40.0",
"--kubeconfig=/foo/bar/kubeconfig",
"--leader-elect=true",
"--leader-elect-lease-duration=20s",
"--leader-elect-renew-deadline=15s",
"--leader-elect-resource-lock=endpoints",
"--leader-elect-retry-period=3s",
"--lock-object-name=test-lock-object-name",
"--lock-object-namespace=test-lock-object-ns",
"--master=192.168.4.20",
"--policy-config-file=/foo/bar/policyconfig",
"--policy-configmap=test-policy-configmap",
"--policy-configmap-namespace=test-policy-configmap-ns",
"--port=10000",
"--profiling=false",
"--scheduler-name=test-scheduler-name",
"--use-legacy-policy-config=true",
}
f.Parse(args)
expected := &SchedulerServer{
KubeSchedulerConfiguration: componentconfig.KubeSchedulerConfiguration{
Port: 10000,
Address: "192.168.4.20",
AlgorithmProvider: "FooProvider",
PolicyConfigFile: "/foo/bar/policyconfig",
EnableContentionProfiling: true,
EnableProfiling: false,
ContentType: "application/vnd.kubernetes.protobuf",
KubeAPIQPS: 40.0,
KubeAPIBurst: 80,
SchedulerName: "test-scheduler-name",
LeaderElection: componentconfig.LeaderElectionConfiguration{
ResourceLock: "endpoints",
LeaderElect: true,
LeaseDuration: metav1.Duration{Duration: 20 * time.Second},
RenewDeadline: metav1.Duration{Duration: 15 * time.Second},
RetryPeriod: metav1.Duration{Duration: 3 * time.Second},
},
LockObjectNamespace: "test-lock-object-ns",
LockObjectName: "test-lock-object-name",
PolicyConfigMapName: "test-policy-configmap",
PolicyConfigMapNamespace: "test-policy-configmap-ns",
UseLegacyPolicyConfig: true,
HardPodAffinitySymmetricWeight: 0,
FailureDomains: "kubernetes.io/hostname",
},
Kubeconfig: "/foo/bar/kubeconfig",
Master: "192.168.4.20",
}
if !reflect.DeepEqual(expected, s) {
t.Errorf("Got different run options than expected.\nDifference detected on:\n%s", diff.ObjectReflectDiff(expected, s))
}
}
...@@ -17,27 +17,31 @@ limitations under the License. ...@@ -17,27 +17,31 @@ limitations under the License.
package main package main
import ( import (
"k8s.io/apiserver/pkg/util/flag" goflag "flag"
"k8s.io/apiserver/pkg/util/logs" "os"
"k8s.io/kubernetes/pkg/version/verflag"
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app"
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/options"
"github.com/golang/glog"
"github.com/spf13/pflag" "github.com/spf13/pflag"
utilflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/apiserver/pkg/util/logs"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app"
) )
func main() { func main() {
s := options.NewSchedulerServer() command := app.NewSchedulerCommand()
s.AddFlags(pflag.CommandLine)
// TODO: once we switch everything over to Cobra commands, we can go back to calling
flag.InitFlags() // utilflag.InitFlags() (by removing its pflag.Parse() call). For now, we have to set the
// normalize func and add the go flag set by hand.
pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc)
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
// utilflag.InitFlags()
logs.InitLogs() logs.InitLogs()
defer logs.FlushLogs() defer logs.FlushLogs()
verflag.PrintAndExitIfRequested() if err := command.Execute(); err != nil {
os.Exit(1)
if err := app.Run(s); err != nil {
glog.Fatalf("scheduler app failed to run: %v", err)
} }
} }
...@@ -151,6 +151,14 @@ func NewFromConfigurator(c Configurator, modifiers ...func(c *Config)) (*Schedul ...@@ -151,6 +151,14 @@ func NewFromConfigurator(c Configurator, modifiers ...func(c *Config)) (*Schedul
return s, nil return s, nil
} }
// NewFromConfig returns a new scheduler using the provided Config.
func NewFromConfig(config *Config) *Scheduler {
metrics.Register()
return &Scheduler{
config: config,
}
}
// Run begins watching and scheduling. It waits for cache to be synced, then starts a goroutine and returns immediately. // Run begins watching and scheduling. It waits for cache to be synced, then starts a goroutine and returns immediately.
func (sched *Scheduler) Run() { func (sched *Scheduler) Run() {
if !sched.config.WaitForCacheSync() { if !sched.config.WaitForCacheSync() {
......
...@@ -43,9 +43,9 @@ import ( ...@@ -43,9 +43,9 @@ import (
"k8s.io/client-go/tools/record" "k8s.io/client-go/tools/record"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/apis/componentconfig"
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app" schedulerapp "k8s.io/kubernetes/plugin/cmd/kube-scheduler/app"
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/options"
"k8s.io/kubernetes/plugin/pkg/scheduler" "k8s.io/kubernetes/plugin/pkg/scheduler"
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm" "k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
_ "k8s.io/kubernetes/plugin/pkg/scheduler/algorithmprovider" _ "k8s.io/kubernetes/plugin/pkg/scheduler/algorithmprovider"
...@@ -107,7 +107,7 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) { ...@@ -107,7 +107,7 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
policyConfigMap := v1.ConfigMap{ policyConfigMap := v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: configPolicyName}, ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceSystem, Name: configPolicyName},
Data: map[string]string{ Data: map[string]string{
options.SchedulerPolicyConfigMapKey: `{ componentconfig.SchedulerPolicyConfigMapKey: `{
"kind" : "Policy", "kind" : "Policy",
"apiVersion" : "v1", "apiVersion" : "v1",
"predicates" : [ "predicates" : [
...@@ -127,29 +127,34 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) { ...@@ -127,29 +127,34 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
eventBroadcaster := record.NewBroadcaster() eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartRecordingToSink(&clientv1core.EventSinkImpl{Interface: clientv1core.New(clientSet.CoreV1().RESTClient()).Events("")}) eventBroadcaster.StartRecordingToSink(&clientv1core.EventSinkImpl{Interface: clientv1core.New(clientSet.CoreV1().RESTClient()).Events("")})
ss := options.NewSchedulerServer()
ss.HardPodAffinitySymmetricWeight = v1.DefaultHardPodAffinitySymmetricWeight ss := &schedulerapp.SchedulerServer{
ss.PolicyConfigMapName = configPolicyName SchedulerName: v1.DefaultSchedulerName,
sched, err := app.CreateScheduler(ss, clientSet, AlgorithmSource: componentconfig.SchedulerAlgorithmSource{
informerFactory.Core().V1().Nodes(), Policy: &componentconfig.SchedulerPolicySource{
informerFactory.Core().V1().Pods(), ConfigMap: &componentconfig.SchedulerPolicyConfigMapSource{
informerFactory.Core().V1().PersistentVolumes(), Namespace: policyConfigMap.Namespace,
informerFactory.Core().V1().PersistentVolumeClaims(), Name: policyConfigMap.Name,
informerFactory.Core().V1().ReplicationControllers(), },
informerFactory.Extensions().V1beta1().ReplicaSets(), },
informerFactory.Apps().V1beta1().StatefulSets(), },
informerFactory.Core().V1().Services(), HardPodAffinitySymmetricWeight: v1.DefaultHardPodAffinitySymmetricWeight,
informerFactory.Policy().V1beta1().PodDisruptionBudgets(), Client: clientSet,
eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: v1.DefaultSchedulerName}), InformerFactory: informerFactory,
) PodInformer: factory.NewPodInformer(clientSet, 0, v1.DefaultSchedulerName),
EventClient: clientSet.CoreV1(),
Recorder: eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: v1.DefaultSchedulerName}),
Broadcaster: eventBroadcaster,
}
config, err := ss.SchedulerConfig()
if err != nil { if err != nil {
t.Fatalf("Error creating scheduler: %v", err) t.Fatalf("couldn't make scheduler config: %v", err)
} }
defer close(sched.Config().StopEverything)
// Verify that the config is applied correctly. // Verify that the config is applied correctly.
schedPredicates := sched.Config().Algorithm.Predicates() schedPredicates := config.Algorithm.Predicates()
schedPrioritizers := sched.Config().Algorithm.Prioritizers() schedPrioritizers := config.Algorithm.Prioritizers()
// Includes one mandatory predicates. // Includes one mandatory predicates.
if len(schedPredicates) != 3 || len(schedPrioritizers) != 2 { if len(schedPredicates) != 3 || len(schedPrioritizers) != 2 {
t.Errorf("Unexpected number of predicates or priority functions. Number of predicates: %v, number of prioritizers: %v", len(schedPredicates), len(schedPrioritizers)) t.Errorf("Unexpected number of predicates or priority functions. Number of predicates: %v, number of prioritizers: %v", len(schedPredicates), len(schedPrioritizers))
...@@ -180,83 +185,31 @@ func TestSchedulerCreationFromNonExistentConfigMap(t *testing.T) { ...@@ -180,83 +185,31 @@ func TestSchedulerCreationFromNonExistentConfigMap(t *testing.T) {
eventBroadcaster := record.NewBroadcaster() eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartRecordingToSink(&clientv1core.EventSinkImpl{Interface: clientv1core.New(clientSet.CoreV1().RESTClient()).Events("")}) eventBroadcaster.StartRecordingToSink(&clientv1core.EventSinkImpl{Interface: clientv1core.New(clientSet.CoreV1().RESTClient()).Events("")})
ss := options.NewSchedulerServer() ss := &schedulerapp.SchedulerServer{
ss.PolicyConfigMapName = "non-existent-config" SchedulerName: v1.DefaultSchedulerName,
AlgorithmSource: componentconfig.SchedulerAlgorithmSource{
_, err := app.CreateScheduler(ss, clientSet, Policy: &componentconfig.SchedulerPolicySource{
informerFactory.Core().V1().Nodes(), ConfigMap: &componentconfig.SchedulerPolicyConfigMapSource{
informerFactory.Core().V1().Pods(), Namespace: "non-existent-config",
informerFactory.Core().V1().PersistentVolumes(), Name: "non-existent-config",
informerFactory.Core().V1().PersistentVolumeClaims(), },
informerFactory.Core().V1().ReplicationControllers(), },
informerFactory.Extensions().V1beta1().ReplicaSets(), },
informerFactory.Apps().V1beta1().StatefulSets(), HardPodAffinitySymmetricWeight: v1.DefaultHardPodAffinitySymmetricWeight,
informerFactory.Core().V1().Services(), Client: clientSet,
informerFactory.Policy().V1beta1().PodDisruptionBudgets(), InformerFactory: informerFactory,
eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: v1.DefaultSchedulerName}), PodInformer: factory.NewPodInformer(clientSet, 0, v1.DefaultSchedulerName),
) EventClient: clientSet.CoreV1(),
Recorder: eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: v1.DefaultSchedulerName}),
Broadcaster: eventBroadcaster,
}
_, err := ss.SchedulerConfig()
if err == nil { if err == nil {
t.Fatalf("Creation of scheduler didn't fail while the policy ConfigMap didn't exist.") t.Fatalf("Creation of scheduler didn't fail while the policy ConfigMap didn't exist.")
} }
} }
// TestSchedulerCreationInLegacyMode ensures that creation of the scheduler
// works fine when legacy mode is enabled.
func TestSchedulerCreationInLegacyMode(t *testing.T) {
_, s, closeFn := framework.RunAMaster(nil)
defer closeFn()
ns := framework.CreateTestingNamespace("configmap", s, t)
defer framework.DeleteTestingNamespace(ns, s, t)
clientSet := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Groups[v1.GroupName].GroupVersion()}})
defer clientSet.CoreV1().Nodes().DeleteCollection(nil, metav1.ListOptions{})
informerFactory := informers.NewSharedInformerFactory(clientSet, 0)
eventBroadcaster := record.NewBroadcaster()
eventBroadcaster.StartRecordingToSink(&clientv1core.EventSinkImpl{Interface: clientv1core.New(clientSet.CoreV1().RESTClient()).Events("")})
ss := options.NewSchedulerServer()
ss.HardPodAffinitySymmetricWeight = v1.DefaultHardPodAffinitySymmetricWeight
ss.PolicyConfigMapName = "non-existent-configmap"
ss.UseLegacyPolicyConfig = true
sched, err := app.CreateScheduler(ss, clientSet,
informerFactory.Core().V1().Nodes(),
informerFactory.Core().V1().Pods(),
informerFactory.Core().V1().PersistentVolumes(),
informerFactory.Core().V1().PersistentVolumeClaims(),
informerFactory.Core().V1().ReplicationControllers(),
informerFactory.Extensions().V1beta1().ReplicaSets(),
informerFactory.Apps().V1beta1().StatefulSets(),
informerFactory.Core().V1().Services(),
informerFactory.Policy().V1beta1().PodDisruptionBudgets(),
eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: v1.DefaultSchedulerName}),
)
if err != nil {
t.Fatalf("Creation of scheduler in legacy mode failed: %v", err)
}
informerFactory.Start(sched.Config().StopEverything)
defer close(sched.Config().StopEverything)
sched.Run()
_, err = createNode(clientSet, "test-node", nil)
if err != nil {
t.Fatalf("Failed to create node: %v", err)
}
pod, err := createPausePodWithResource(clientSet, "test-pod", "configmap", nil)
if err != nil {
t.Fatalf("Failed to create pod: %v", err)
}
err = waitForPodToSchedule(clientSet, pod)
if err != nil {
t.Errorf("Failed to schedule a pod: %v", err)
} else {
t.Logf("Pod got scheduled on a node.")
}
}
func TestUnschedulableNodes(t *testing.T) { func TestUnschedulableNodes(t *testing.T) {
context := initTest(t, "unschedulable-nodes") context := initTest(t, "unschedulable-nodes")
defer cleanupTest(t, context) defer cleanupTest(t, context)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment