Scheduler can recieve its policy configuration from a ConfigMap
This commit is contained in:
@@ -26,6 +26,7 @@ import (
|
||||
extensionsinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/externalversions/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/plugin/cmd/kube-scheduler/app/options"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
|
||||
@@ -71,8 +72,8 @@ func createClient(s *options.SchedulerServer) (*clientset.Clientset, error) {
|
||||
return cli, nil
|
||||
}
|
||||
|
||||
// createScheduler encapsulates the entire creation of a runnable scheduler.
|
||||
func createScheduler(
|
||||
// CreateScheduler encapsulates the entire creation of a runnable scheduler.
|
||||
func CreateScheduler(
|
||||
s *options.SchedulerServer,
|
||||
kubecli *clientset.Clientset,
|
||||
nodeInformer coreinformers.NodeInformer,
|
||||
@@ -101,38 +102,88 @@ func createScheduler(
|
||||
configurator = &schedulerConfigurator{
|
||||
configurator,
|
||||
s.PolicyConfigFile,
|
||||
s.AlgorithmProvider}
|
||||
s.AlgorithmProvider,
|
||||
s.PolicyConfigMapName,
|
||||
s.UseLegacyPolicyConfig,
|
||||
}
|
||||
|
||||
return scheduler.NewFromConfigurator(configurator, func(cfg *scheduler.Config) {
|
||||
cfg.Recorder = recorder
|
||||
})
|
||||
}
|
||||
|
||||
// schedulerConfigurator is an interface wrapper that provides default Configuration creation based on user
|
||||
// provided config file.
|
||||
// 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
|
||||
policyFile string
|
||||
algorithmProvider string
|
||||
policyConfigMap string
|
||||
useLegacyPolicyConfig bool
|
||||
}
|
||||
|
||||
// Create implements the interface for the Configurator, hence it is exported even through the struct is not.
|
||||
// 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 {
|
||||
policyConfigMap, err := sc.GetClient().CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(sc.policyConfigMap, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error getting scheduler policy ConfigMap: %v.", err)
|
||||
}
|
||||
if policyConfigMap != nil {
|
||||
// We expect the first element in the Data member of the ConfigMap to
|
||||
// contain the policy config.
|
||||
if len(policyConfigMap.Data) != 1 {
|
||||
return nil, fmt.Errorf("ConfigMap %v has %v entries in its 'Data'. It must have only one.", sc.policyConfigMap, len(policyConfigMap.Data))
|
||||
}
|
||||
policyConfigMapFound = true
|
||||
// This loop should iterate only once, as we have already checked the length of Data.
|
||||
for _, val := range policyConfigMap.Data {
|
||||
glog.V(5).Infof("Scheduler policy ConfigMap: %v", val)
|
||||
configData = []byte(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there 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 through the struct is not.
|
||||
func (sc schedulerConfigurator) Create() (*scheduler.Config, error) {
|
||||
if _, err := os.Stat(sc.policyFile); err != nil {
|
||||
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")
|
||||
}
|
||||
|
||||
// policy file is valid, try to create a configuration from it.
|
||||
var policy schedulerapi.Policy
|
||||
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 sc.CreateFromConfig(policy)
|
||||
return sc.CreateFromConfig(*policy)
|
||||
}
|
||||
|
@@ -63,7 +63,9 @@ 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")
|
||||
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 scheduler is using legacy policy config.")
|
||||
fs.StringVar(&s.PolicyConfigMapName, "policy-configmap", s.PolicyConfigMapName, "Name of the ConfigMap object that contains scheduler's policy configuration. It must exist in the system namespace before scheduler initialization if scheduler is not using legacy policy config.")
|
||||
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)")
|
||||
@@ -80,6 +82,5 @@ func (s *SchedulerServer) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVar(&s.FailureDomains, "failure-domains", api.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.")
|
||||
leaderelection.BindFlags(&s.LeaderElection, fs)
|
||||
|
||||
utilfeature.DefaultFeatureGate.AddFlag(fs)
|
||||
}
|
||||
|
@@ -73,7 +73,7 @@ func Run(s *options.SchedulerServer) error {
|
||||
|
||||
informerFactory := informers.NewSharedInformerFactory(kubecli, 0)
|
||||
|
||||
sched, err := createScheduler(
|
||||
sched, err := CreateScheduler(
|
||||
s,
|
||||
kubecli,
|
||||
informerFactory.Core().V1().Nodes(),
|
||||
|
Reference in New Issue
Block a user