mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
Move scheduler plugin set and configuration defaulting to component config
This commit is contained in:
parent
21ee533508
commit
265ef1741f
@ -42,10 +42,10 @@ func (o *DeprecatedOptions) AddFlags(fs *pflag.FlagSet, cfg *kubeschedulerconfig
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.StringVar(&o.PolicyConfigFile, "policy-config-file", o.PolicyConfigFile, "DEPRECATED: file with scheduler policy configuration. This file is used if policy ConfigMap is not provided or --use-legacy-policy-config=true. Note: The scheduler will fail if this is combined with Plugin configs")
|
fs.StringVar(&o.PolicyConfigFile, "policy-config-file", o.PolicyConfigFile, "DEPRECATED: file with scheduler policy configuration. This file is used if policy ConfigMap is not provided or --use-legacy-policy-config=true. Note: The predicates/priorities defined in this file will take precedence over any profiles define in ComponentConfig.")
|
||||||
usage := fmt.Sprintf("DEPRECATED: 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'. Note: The scheduler will fail if this is combined with Plugin configs", kubeschedulerconfig.SchedulerPolicyConfigMapKey)
|
usage := fmt.Sprintf("DEPRECATED: 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'. Note: The predicates/priorities defined in this file will take precedence over any profiles define in ComponentConfig.", kubeschedulerconfig.SchedulerPolicyConfigMapKey)
|
||||||
fs.StringVar(&o.PolicyConfigMapName, "policy-configmap", o.PolicyConfigMapName, usage)
|
fs.StringVar(&o.PolicyConfigMapName, "policy-configmap", o.PolicyConfigMapName, usage)
|
||||||
fs.StringVar(&o.PolicyConfigMapNamespace, "policy-configmap-namespace", o.PolicyConfigMapNamespace, "DEPRECATED: the namespace where policy ConfigMap is located. The kube-system namespace will be used if this is not provided or is empty. Note: The scheduler will fail if this is combined with Plugin configs")
|
fs.StringVar(&o.PolicyConfigMapNamespace, "policy-configmap-namespace", o.PolicyConfigMapNamespace, "DEPRECATED: the namespace where policy ConfigMap is located. The kube-system namespace will be used if this is not provided or is empty. Note: The predicates/priorities defined in this file will take precedence over any profiles define in ComponentConfig.")
|
||||||
fs.BoolVar(&o.UseLegacyPolicyConfig, "use-legacy-policy-config", o.UseLegacyPolicyConfig, "DEPRECATED: when set to true, scheduler will ignore policy ConfigMap and uses policy config file. Note: The scheduler will fail if this is combined with Plugin configs")
|
fs.BoolVar(&o.UseLegacyPolicyConfig, "use-legacy-policy-config", o.UseLegacyPolicyConfig, "DEPRECATED: when set to true, scheduler will ignore policy ConfigMap and uses policy config file. Note: The scheduler will fail if this is combined with Plugin configs")
|
||||||
|
|
||||||
fs.BoolVar(&cfg.EnableProfiling, "profiling", cfg.EnableProfiling, "DEPRECATED: enable profiling via web interface host:port/debug/pprof/. This parameter is ignored if a config file is specified in --config.")
|
fs.BoolVar(&cfg.EnableProfiling, "profiling", cfg.EnableProfiling, "DEPRECATED: enable profiling via web interface host:port/debug/pprof/. This parameter is ignored if a config file is specified in --config.")
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/uuid"
|
"k8s.io/apimachinery/pkg/util/uuid"
|
||||||
apiserveroptions "k8s.io/apiserver/pkg/server/options"
|
apiserveroptions "k8s.io/apiserver/pkg/server/options"
|
||||||
@ -175,8 +176,8 @@ func (o *Options) ApplyTo(c *schedulerappconfig.Config) error {
|
|||||||
if len(o.ConfigFile) == 0 {
|
if len(o.ConfigFile) == 0 {
|
||||||
c.ComponentConfig = o.ComponentConfig
|
c.ComponentConfig = o.ComponentConfig
|
||||||
|
|
||||||
// apply deprecated flags if no config file is loaded (this is the old behaviour).
|
|
||||||
o.Deprecated.ApplyTo(c)
|
o.Deprecated.ApplyTo(c)
|
||||||
|
|
||||||
if err := o.CombinedInsecureServing.ApplyTo(c, &c.ComponentConfig); err != nil {
|
if err := o.CombinedInsecureServing.ApplyTo(c, &c.ComponentConfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -194,18 +195,18 @@ func (o *Options) ApplyTo(c *schedulerappconfig.Config) error {
|
|||||||
// apply any deprecated Policy flags, if applicable
|
// apply any deprecated Policy flags, if applicable
|
||||||
o.Deprecated.ApplyTo(c)
|
o.Deprecated.ApplyTo(c)
|
||||||
|
|
||||||
// if the user has set CC profiles and is trying to use a Policy config, error out
|
|
||||||
// these configs are no longer merged and they should not be used simultaneously
|
|
||||||
if !emptySchedulerProfileConfig(c.ComponentConfig.Profiles) && c.LegacyPolicySource != nil {
|
|
||||||
return fmt.Errorf("cannot set a Plugin config and Policy config")
|
|
||||||
}
|
|
||||||
|
|
||||||
// use the loaded config file only, with the exception of --address and --port.
|
// use the loaded config file only, with the exception of --address and --port.
|
||||||
if err := o.CombinedInsecureServing.ApplyToFromLoadedConfig(c, &c.ComponentConfig); err != nil {
|
if err := o.CombinedInsecureServing.ApplyToFromLoadedConfig(c, &c.ComponentConfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the user is using the legacy policy config, clear the profiles, they will be set
|
||||||
|
// on scheduler instantiation based on the configurations in the policy file.
|
||||||
|
if c.LegacyPolicySource != nil {
|
||||||
|
c.ComponentConfig.Profiles = nil
|
||||||
|
}
|
||||||
|
|
||||||
if err := o.SecureServing.ApplyTo(&c.SecureServing, &c.LoopbackClientConfig); err != nil {
|
if err := o.SecureServing.ApplyTo(&c.SecureServing, &c.LoopbackClientConfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -222,15 +223,6 @@ func (o *Options) ApplyTo(c *schedulerappconfig.Config) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// emptySchedulerProfileConfig returns true if the list of profiles passed to it contains only
|
|
||||||
// the "default-scheduler" profile with no plugins or pluginconfigs registered
|
|
||||||
// (this is the default empty profile initialized by defaults.go)
|
|
||||||
func emptySchedulerProfileConfig(profiles []kubeschedulerconfig.KubeSchedulerProfile) bool {
|
|
||||||
return len(profiles) == 1 &&
|
|
||||||
len(profiles[0].PluginConfig) == 0 &&
|
|
||||||
profiles[0].Plugins == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate validates all the required options.
|
// Validate validates all the required options.
|
||||||
func (o *Options) Validate() []error {
|
func (o *Options) Validate() []error {
|
||||||
var errs []error
|
var errs []error
|
||||||
@ -280,7 +272,11 @@ func (o *Options) Config() (*schedulerappconfig.Config, error) {
|
|||||||
var leaderElectionConfig *leaderelection.LeaderElectionConfig
|
var leaderElectionConfig *leaderelection.LeaderElectionConfig
|
||||||
if c.ComponentConfig.LeaderElection.LeaderElect {
|
if c.ComponentConfig.LeaderElection.LeaderElect {
|
||||||
// Use the scheduler name in the first profile to record leader election.
|
// Use the scheduler name in the first profile to record leader election.
|
||||||
coreRecorder := c.EventBroadcaster.DeprecatedNewLegacyRecorder(c.ComponentConfig.Profiles[0].SchedulerName)
|
schedulerName := corev1.DefaultSchedulerName
|
||||||
|
if len(c.ComponentConfig.Profiles) != 0 {
|
||||||
|
schedulerName = c.ComponentConfig.Profiles[0].SchedulerName
|
||||||
|
}
|
||||||
|
coreRecorder := c.EventBroadcaster.DeprecatedNewLegacyRecorder(schedulerName)
|
||||||
leaderElectionConfig, err = makeLeaderElectionConfig(c.ComponentConfig.LeaderElection, kubeConfig, coreRecorder)
|
leaderElectionConfig, err = makeLeaderElectionConfig(c.ComponentConfig.LeaderElection, kubeConfig, coreRecorder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -34,26 +34,15 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
apiserveroptions "k8s.io/apiserver/pkg/server/options"
|
apiserveroptions "k8s.io/apiserver/pkg/server/options"
|
||||||
componentbaseconfig "k8s.io/component-base/config"
|
componentbaseconfig "k8s.io/component-base/config"
|
||||||
"k8s.io/component-base/config/v1alpha1"
|
|
||||||
"k8s.io/component-base/logs"
|
"k8s.io/component-base/logs"
|
||||||
"k8s.io/kube-scheduler/config/v1beta1"
|
"k8s.io/kube-scheduler/config/v1beta1"
|
||||||
"k8s.io/kube-scheduler/config/v1beta2"
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"
|
configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/apis/config/testing/defaults"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newV1beta1DefaultComponentConfig() (*kubeschedulerconfig.KubeSchedulerConfiguration, error) {
|
|
||||||
versionedCfg := v1beta1.KubeSchedulerConfiguration{}
|
|
||||||
versionedCfg.DebuggingConfiguration = *v1alpha1.NewRecommendedDebuggingConfiguration()
|
|
||||||
|
|
||||||
scheme.Scheme.Default(&versionedCfg)
|
|
||||||
cfg := kubeschedulerconfig.KubeSchedulerConfiguration{}
|
|
||||||
if err := scheme.Scheme.Convert(&versionedCfg, &cfg, nil); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &cfg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSchedulerOptions(t *testing.T) {
|
func TestSchedulerOptions(t *testing.T) {
|
||||||
// temp dir
|
// temp dir
|
||||||
tmpDir, err := ioutil.TempDir("", "scheduler-options")
|
tmpDir, err := ioutil.TempDir("", "scheduler-options")
|
||||||
@ -224,12 +213,12 @@ profiles:
|
|||||||
- name: foo
|
- name: foo
|
||||||
- name: bar
|
- name: bar
|
||||||
disabled:
|
disabled:
|
||||||
- name: baz
|
- name: VolumeBinding
|
||||||
preBind:
|
preBind:
|
||||||
enabled:
|
enabled:
|
||||||
- name: foo
|
- name: foo
|
||||||
disabled:
|
disabled:
|
||||||
- name: baz
|
- name: VolumeBinding
|
||||||
pluginConfig:
|
pluginConfig:
|
||||||
- name: InterPodAffinity
|
- name: InterPodAffinity
|
||||||
args:
|
args:
|
||||||
@ -255,12 +244,12 @@ profiles:
|
|||||||
- name: foo
|
- name: foo
|
||||||
- name: bar
|
- name: bar
|
||||||
disabled:
|
disabled:
|
||||||
- name: baz
|
- name: VolumeBinding
|
||||||
preBind:
|
preBind:
|
||||||
enabled:
|
enabled:
|
||||||
- name: foo
|
- name: foo
|
||||||
disabled:
|
disabled:
|
||||||
- name: baz
|
- name: VolumeBinding
|
||||||
pluginConfig:
|
pluginConfig:
|
||||||
- name: ServiceAffinity
|
- name: ServiceAffinity
|
||||||
args:
|
args:
|
||||||
@ -286,11 +275,14 @@ profiles:
|
|||||||
reserve:
|
reserve:
|
||||||
enabled:
|
enabled:
|
||||||
- name: foo
|
- name: foo
|
||||||
|
- name: VolumeBinding
|
||||||
|
disabled:
|
||||||
|
- name: VolumeBinding
|
||||||
- schedulerName: "bar-profile"
|
- schedulerName: "bar-profile"
|
||||||
plugins:
|
plugins:
|
||||||
preBind:
|
preBind:
|
||||||
disabled:
|
disabled:
|
||||||
- name: baz
|
- name: VolumeBinding
|
||||||
pluginConfig:
|
pluginConfig:
|
||||||
- name: foo
|
- name: foo
|
||||||
`, configKubeconfig)), os.FileMode(0600)); err != nil {
|
`, configKubeconfig)), os.FileMode(0600)); err != nil {
|
||||||
@ -310,11 +302,14 @@ profiles:
|
|||||||
reserve:
|
reserve:
|
||||||
enabled:
|
enabled:
|
||||||
- name: foo
|
- name: foo
|
||||||
|
- name: VolumeBinding
|
||||||
|
disabled:
|
||||||
|
- name: VolumeBinding
|
||||||
- schedulerName: "bar-profile"
|
- schedulerName: "bar-profile"
|
||||||
plugins:
|
plugins:
|
||||||
preBind:
|
preBind:
|
||||||
disabled:
|
disabled:
|
||||||
- name: baz
|
- name: VolumeBinding
|
||||||
pluginConfig:
|
pluginConfig:
|
||||||
- name: foo
|
- name: foo
|
||||||
`, configKubeconfig)), os.FileMode(0600)); err != nil {
|
`, configKubeconfig)), os.FileMode(0600)); err != nil {
|
||||||
@ -409,7 +404,11 @@ profiles:
|
|||||||
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
|
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
|
||||||
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
|
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
|
||||||
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
|
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
|
||||||
{SchedulerName: "default-scheduler"},
|
{
|
||||||
|
SchedulerName: "default-scheduler",
|
||||||
|
Plugins: defaults.PluginsV1beta2,
|
||||||
|
PluginConfig: defaults.PluginConfigs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -418,10 +417,7 @@ profiles:
|
|||||||
options: &Options{
|
options: &Options{
|
||||||
ConfigFile: v1beta1VersionConfig,
|
ConfigFile: v1beta1VersionConfig,
|
||||||
ComponentConfig: func() kubeschedulerconfig.KubeSchedulerConfiguration {
|
ComponentConfig: func() kubeschedulerconfig.KubeSchedulerConfiguration {
|
||||||
cfg, err := newV1beta1DefaultComponentConfig()
|
cfg := configtesting.V1beta1ToInternalWithDefaults(t, v1beta1.KubeSchedulerConfiguration{})
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
return *cfg
|
return *cfg
|
||||||
}(),
|
}(),
|
||||||
SecureServing: (&apiserveroptions.SecureServingOptions{
|
SecureServing: (&apiserveroptions.SecureServingOptions{
|
||||||
@ -481,7 +477,11 @@ profiles:
|
|||||||
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
|
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
|
||||||
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
|
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
|
||||||
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
|
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
|
||||||
{SchedulerName: "default-scheduler"},
|
{
|
||||||
|
SchedulerName: "default-scheduler",
|
||||||
|
Plugins: defaults.PluginsV1beta1,
|
||||||
|
PluginConfig: defaults.PluginConfigs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -581,7 +581,11 @@ profiles:
|
|||||||
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
|
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
|
||||||
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
|
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
|
||||||
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
|
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
|
||||||
{SchedulerName: "default-scheduler"},
|
{
|
||||||
|
SchedulerName: "default-scheduler",
|
||||||
|
Plugins: defaults.PluginsV1beta2,
|
||||||
|
PluginConfig: defaults.PluginConfigs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -649,7 +653,11 @@ profiles:
|
|||||||
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
|
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
|
||||||
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
|
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
|
||||||
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
|
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
|
||||||
{SchedulerName: "default-scheduler"},
|
{
|
||||||
|
SchedulerName: "default-scheduler",
|
||||||
|
Plugins: defaults.PluginsV1beta2,
|
||||||
|
PluginConfig: defaults.PluginConfigs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedUsername: "none, http",
|
expectedUsername: "none, http",
|
||||||
@ -694,23 +702,24 @@ profiles:
|
|||||||
{
|
{
|
||||||
SchedulerName: "default-scheduler",
|
SchedulerName: "default-scheduler",
|
||||||
Plugins: &kubeschedulerconfig.Plugins{
|
Plugins: &kubeschedulerconfig.Plugins{
|
||||||
|
QueueSort: defaults.PluginsV1beta2.QueueSort,
|
||||||
|
PreFilter: defaults.PluginsV1beta2.PreFilter,
|
||||||
|
Filter: defaults.PluginsV1beta2.Filter,
|
||||||
|
PostFilter: defaults.PluginsV1beta2.PostFilter,
|
||||||
|
PreScore: defaults.PluginsV1beta2.PreScore,
|
||||||
|
Score: defaults.PluginsV1beta2.Score,
|
||||||
Reserve: kubeschedulerconfig.PluginSet{
|
Reserve: kubeschedulerconfig.PluginSet{
|
||||||
Enabled: []kubeschedulerconfig.Plugin{
|
Enabled: []kubeschedulerconfig.Plugin{
|
||||||
{Name: "foo"},
|
{Name: "foo"},
|
||||||
{Name: "bar"},
|
{Name: "bar"},
|
||||||
},
|
},
|
||||||
Disabled: []kubeschedulerconfig.Plugin{
|
|
||||||
{Name: "baz"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
PreBind: kubeschedulerconfig.PluginSet{
|
PreBind: kubeschedulerconfig.PluginSet{
|
||||||
Enabled: []kubeschedulerconfig.Plugin{
|
Enabled: []kubeschedulerconfig.Plugin{
|
||||||
{Name: "foo"},
|
{Name: "foo"},
|
||||||
},
|
},
|
||||||
Disabled: []kubeschedulerconfig.Plugin{
|
|
||||||
{Name: "baz"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
Bind: defaults.PluginsV1beta2.Bind,
|
||||||
},
|
},
|
||||||
PluginConfig: []kubeschedulerconfig.PluginConfig{
|
PluginConfig: []kubeschedulerconfig.PluginConfig{
|
||||||
{
|
{
|
||||||
@ -726,6 +735,39 @@ profiles:
|
|||||||
ContentType: "application/json",
|
ContentType: "application/json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "DefaultPreemption",
|
||||||
|
Args: &kubeschedulerconfig.DefaultPreemptionArgs{
|
||||||
|
MinCandidateNodesPercentage: 10,
|
||||||
|
MinCandidateNodesAbsolute: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeAffinity",
|
||||||
|
Args: &kubeschedulerconfig.NodeAffinityArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesFit",
|
||||||
|
Args: &kubeschedulerconfig.NodeResourcesFitArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesLeastAllocated",
|
||||||
|
Args: &kubeschedulerconfig.NodeResourcesLeastAllocatedArgs{
|
||||||
|
Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PodTopologySpread",
|
||||||
|
Args: &kubeschedulerconfig.PodTopologySpreadArgs{
|
||||||
|
DefaultingType: kubeschedulerconfig.SystemDefaulting,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: &kubeschedulerconfig.VolumeBindingArgs{
|
||||||
|
BindTimeoutSeconds: 600,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -771,23 +813,24 @@ profiles:
|
|||||||
{
|
{
|
||||||
SchedulerName: "default-scheduler",
|
SchedulerName: "default-scheduler",
|
||||||
Plugins: &kubeschedulerconfig.Plugins{
|
Plugins: &kubeschedulerconfig.Plugins{
|
||||||
|
QueueSort: defaults.PluginsV1beta1.QueueSort,
|
||||||
|
PreFilter: defaults.PluginsV1beta1.PreFilter,
|
||||||
|
Filter: defaults.PluginsV1beta1.Filter,
|
||||||
|
PostFilter: defaults.PluginsV1beta1.PostFilter,
|
||||||
|
PreScore: defaults.PluginsV1beta1.PreScore,
|
||||||
|
Score: defaults.PluginsV1beta1.Score,
|
||||||
Reserve: kubeschedulerconfig.PluginSet{
|
Reserve: kubeschedulerconfig.PluginSet{
|
||||||
Enabled: []kubeschedulerconfig.Plugin{
|
Enabled: []kubeschedulerconfig.Plugin{
|
||||||
{Name: "foo"},
|
{Name: "foo"},
|
||||||
{Name: "bar"},
|
{Name: "bar"},
|
||||||
},
|
},
|
||||||
Disabled: []kubeschedulerconfig.Plugin{
|
|
||||||
{Name: "baz"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
PreBind: kubeschedulerconfig.PluginSet{
|
PreBind: kubeschedulerconfig.PluginSet{
|
||||||
Enabled: []kubeschedulerconfig.Plugin{
|
Enabled: []kubeschedulerconfig.Plugin{
|
||||||
{Name: "foo"},
|
{Name: "foo"},
|
||||||
},
|
},
|
||||||
Disabled: []kubeschedulerconfig.Plugin{
|
|
||||||
{Name: "baz"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
Bind: defaults.PluginsV1beta1.Bind,
|
||||||
},
|
},
|
||||||
PluginConfig: []kubeschedulerconfig.PluginConfig{
|
PluginConfig: []kubeschedulerconfig.PluginConfig{
|
||||||
{
|
{
|
||||||
@ -804,6 +847,45 @@ profiles:
|
|||||||
ContentType: "application/json",
|
ContentType: "application/json",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "DefaultPreemption",
|
||||||
|
Args: &kubeschedulerconfig.DefaultPreemptionArgs{
|
||||||
|
MinCandidateNodesPercentage: 10,
|
||||||
|
MinCandidateNodesAbsolute: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "InterPodAffinity",
|
||||||
|
Args: &kubeschedulerconfig.InterPodAffinityArgs{
|
||||||
|
HardPodAffinityWeight: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeAffinity",
|
||||||
|
Args: &kubeschedulerconfig.NodeAffinityArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesFit",
|
||||||
|
Args: &kubeschedulerconfig.NodeResourcesFitArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesLeastAllocated",
|
||||||
|
Args: &kubeschedulerconfig.NodeResourcesLeastAllocatedArgs{
|
||||||
|
Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PodTopologySpread",
|
||||||
|
Args: &kubeschedulerconfig.PodTopologySpreadArgs{
|
||||||
|
DefaultingType: kubeschedulerconfig.SystemDefaulting,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: &kubeschedulerconfig.VolumeBindingArgs{
|
||||||
|
BindTimeoutSeconds: 600,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -849,26 +931,78 @@ profiles:
|
|||||||
{
|
{
|
||||||
SchedulerName: "foo-profile",
|
SchedulerName: "foo-profile",
|
||||||
Plugins: &kubeschedulerconfig.Plugins{
|
Plugins: &kubeschedulerconfig.Plugins{
|
||||||
|
QueueSort: defaults.PluginsV1beta2.QueueSort,
|
||||||
|
PreFilter: defaults.PluginsV1beta2.PreFilter,
|
||||||
|
Filter: defaults.PluginsV1beta2.Filter,
|
||||||
|
PostFilter: defaults.PluginsV1beta2.PostFilter,
|
||||||
|
PreScore: defaults.PluginsV1beta2.PreScore,
|
||||||
|
Score: defaults.PluginsV1beta2.Score,
|
||||||
|
Bind: defaults.PluginsV1beta2.Bind,
|
||||||
|
PreBind: defaults.PluginsV1beta2.PreBind,
|
||||||
Reserve: kubeschedulerconfig.PluginSet{
|
Reserve: kubeschedulerconfig.PluginSet{
|
||||||
Enabled: []kubeschedulerconfig.Plugin{
|
Enabled: []kubeschedulerconfig.Plugin{
|
||||||
{Name: "foo"},
|
{Name: "foo"},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
PluginConfig: defaults.PluginConfigs,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
SchedulerName: "bar-profile",
|
SchedulerName: "bar-profile",
|
||||||
Plugins: &kubeschedulerconfig.Plugins{
|
Plugins: &kubeschedulerconfig.Plugins{
|
||||||
PreBind: kubeschedulerconfig.PluginSet{
|
QueueSort: defaults.PluginsV1beta2.QueueSort,
|
||||||
Disabled: []kubeschedulerconfig.Plugin{
|
PreFilter: defaults.PluginsV1beta2.PreFilter,
|
||||||
{Name: "baz"},
|
Filter: defaults.PluginsV1beta2.Filter,
|
||||||
},
|
PostFilter: defaults.PluginsV1beta2.PostFilter,
|
||||||
},
|
PreScore: defaults.PluginsV1beta2.PreScore,
|
||||||
|
Score: defaults.PluginsV1beta2.Score,
|
||||||
|
Bind: defaults.PluginsV1beta2.Bind,
|
||||||
|
Reserve: defaults.PluginsV1beta2.Reserve,
|
||||||
},
|
},
|
||||||
PluginConfig: []kubeschedulerconfig.PluginConfig{
|
PluginConfig: []kubeschedulerconfig.PluginConfig{
|
||||||
{
|
{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "DefaultPreemption",
|
||||||
|
Args: &kubeschedulerconfig.DefaultPreemptionArgs{
|
||||||
|
MinCandidateNodesPercentage: 10,
|
||||||
|
MinCandidateNodesAbsolute: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "InterPodAffinity",
|
||||||
|
Args: &kubeschedulerconfig.InterPodAffinityArgs{
|
||||||
|
HardPodAffinityWeight: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeAffinity",
|
||||||
|
Args: &kubeschedulerconfig.NodeAffinityArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesFit",
|
||||||
|
Args: &kubeschedulerconfig.NodeResourcesFitArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesLeastAllocated",
|
||||||
|
Args: &kubeschedulerconfig.NodeResourcesLeastAllocatedArgs{
|
||||||
|
Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PodTopologySpread",
|
||||||
|
Args: &kubeschedulerconfig.PodTopologySpreadArgs{
|
||||||
|
DefaultingType: kubeschedulerconfig.SystemDefaulting,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: &kubeschedulerconfig.VolumeBindingArgs{
|
||||||
|
BindTimeoutSeconds: 600,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -914,38 +1048,83 @@ profiles:
|
|||||||
{
|
{
|
||||||
SchedulerName: "foo-profile",
|
SchedulerName: "foo-profile",
|
||||||
Plugins: &kubeschedulerconfig.Plugins{
|
Plugins: &kubeschedulerconfig.Plugins{
|
||||||
|
QueueSort: defaults.PluginsV1beta1.QueueSort,
|
||||||
|
PreFilter: defaults.PluginsV1beta1.PreFilter,
|
||||||
|
Filter: defaults.PluginsV1beta1.Filter,
|
||||||
|
PostFilter: defaults.PluginsV1beta1.PostFilter,
|
||||||
|
PreScore: defaults.PluginsV1beta1.PreScore,
|
||||||
|
Score: defaults.PluginsV1beta1.Score,
|
||||||
|
Bind: defaults.PluginsV1beta1.Bind,
|
||||||
|
PreBind: defaults.PluginsV1beta1.PreBind,
|
||||||
Reserve: kubeschedulerconfig.PluginSet{
|
Reserve: kubeschedulerconfig.PluginSet{
|
||||||
Enabled: []kubeschedulerconfig.Plugin{
|
Enabled: []kubeschedulerconfig.Plugin{
|
||||||
{Name: "foo"},
|
{Name: "foo"},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
PluginConfig: defaults.PluginConfigs,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
SchedulerName: "bar-profile",
|
SchedulerName: "bar-profile",
|
||||||
Plugins: &kubeschedulerconfig.Plugins{
|
Plugins: &kubeschedulerconfig.Plugins{
|
||||||
PreBind: kubeschedulerconfig.PluginSet{
|
QueueSort: defaults.PluginsV1beta1.QueueSort,
|
||||||
Disabled: []kubeschedulerconfig.Plugin{
|
PreFilter: defaults.PluginsV1beta1.PreFilter,
|
||||||
{Name: "baz"},
|
Filter: defaults.PluginsV1beta1.Filter,
|
||||||
},
|
PostFilter: defaults.PluginsV1beta1.PostFilter,
|
||||||
},
|
PreScore: defaults.PluginsV1beta1.PreScore,
|
||||||
|
Score: defaults.PluginsV1beta1.Score,
|
||||||
|
Bind: defaults.PluginsV1beta1.Bind,
|
||||||
|
Reserve: defaults.PluginsV1beta1.Reserve,
|
||||||
},
|
},
|
||||||
PluginConfig: []kubeschedulerconfig.PluginConfig{
|
PluginConfig: []kubeschedulerconfig.PluginConfig{
|
||||||
{
|
{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "DefaultPreemption",
|
||||||
|
Args: &kubeschedulerconfig.DefaultPreemptionArgs{
|
||||||
|
MinCandidateNodesPercentage: 10,
|
||||||
|
MinCandidateNodesAbsolute: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "InterPodAffinity",
|
||||||
|
Args: &kubeschedulerconfig.InterPodAffinityArgs{
|
||||||
|
HardPodAffinityWeight: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeAffinity",
|
||||||
|
Args: &kubeschedulerconfig.NodeAffinityArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesFit",
|
||||||
|
Args: &kubeschedulerconfig.NodeResourcesFitArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesLeastAllocated",
|
||||||
|
Args: &kubeschedulerconfig.NodeResourcesLeastAllocatedArgs{
|
||||||
|
Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PodTopologySpread",
|
||||||
|
Args: &kubeschedulerconfig.PodTopologySpreadArgs{
|
||||||
|
DefaultingType: kubeschedulerconfig.SystemDefaulting,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: &kubeschedulerconfig.VolumeBindingArgs{
|
||||||
|
BindTimeoutSeconds: 600,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "no config",
|
|
||||||
options: &Options{
|
|
||||||
Logs: logs.NewOptions(),
|
|
||||||
},
|
|
||||||
expectedError: "no configuration has been provided",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "Attempting to set Component Config Profiles and Policy config",
|
name: "Attempting to set Component Config Profiles and Policy config",
|
||||||
options: &Options{
|
options: &Options{
|
||||||
@ -953,8 +1132,46 @@ profiles:
|
|||||||
Deprecated: &DeprecatedOptions{
|
Deprecated: &DeprecatedOptions{
|
||||||
PolicyConfigMapName: "bar",
|
PolicyConfigMapName: "bar",
|
||||||
},
|
},
|
||||||
|
Logs: logs.NewOptions(),
|
||||||
},
|
},
|
||||||
expectedError: "cannot set a Plugin config and Policy config",
|
expectedUsername: "config",
|
||||||
|
expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: v1beta2.SchemeGroupVersion.String(),
|
||||||
|
},
|
||||||
|
Parallelism: 16,
|
||||||
|
HealthzBindAddress: "0.0.0.0:10251",
|
||||||
|
MetricsBindAddress: "0.0.0.0:10251",
|
||||||
|
DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{
|
||||||
|
EnableProfiling: true,
|
||||||
|
EnableContentionProfiling: true,
|
||||||
|
},
|
||||||
|
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
|
||||||
|
LeaderElect: true,
|
||||||
|
LeaseDuration: metav1.Duration{Duration: 15 * time.Second},
|
||||||
|
RenewDeadline: metav1.Duration{Duration: 10 * time.Second},
|
||||||
|
RetryPeriod: metav1.Duration{Duration: 2 * time.Second},
|
||||||
|
ResourceLock: "leases",
|
||||||
|
ResourceNamespace: "kube-system",
|
||||||
|
ResourceName: "kube-scheduler",
|
||||||
|
},
|
||||||
|
ClientConnection: componentbaseconfig.ClientConnectionConfiguration{
|
||||||
|
Kubeconfig: configKubeconfig,
|
||||||
|
QPS: 50,
|
||||||
|
Burst: 100,
|
||||||
|
ContentType: "application/vnd.kubernetes.protobuf",
|
||||||
|
},
|
||||||
|
PercentageOfNodesToScore: defaultPercentageOfNodesToScore,
|
||||||
|
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
|
||||||
|
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no config",
|
||||||
|
options: &Options{
|
||||||
|
Logs: logs.NewOptions(),
|
||||||
|
},
|
||||||
|
expectedError: "no configuration has been provided",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "unknown field",
|
name: "unknown field",
|
||||||
|
@ -30,7 +30,8 @@ import (
|
|||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"k8s.io/kubernetes/cmd/kube-scheduler/app/options"
|
"k8s.io/kubernetes/cmd/kube-scheduler/app/options"
|
||||||
kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/apis/config/testing/defaults"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSetup(t *testing.T) {
|
func TestSetup(t *testing.T) {
|
||||||
@ -151,143 +152,81 @@ profiles:
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultPlugins := map[string][]kubeschedulerconfig.Plugin{
|
|
||||||
"QueueSortPlugin": {
|
|
||||||
{Name: "PrioritySort"},
|
|
||||||
},
|
|
||||||
"PreFilterPlugin": {
|
|
||||||
{Name: "NodeResourcesFit"},
|
|
||||||
{Name: "NodePorts"},
|
|
||||||
{Name: "PodTopologySpread"},
|
|
||||||
{Name: "InterPodAffinity"},
|
|
||||||
{Name: "VolumeBinding"},
|
|
||||||
{Name: "NodeAffinity"},
|
|
||||||
},
|
|
||||||
"FilterPlugin": {
|
|
||||||
{Name: "NodeUnschedulable"},
|
|
||||||
{Name: "NodeName"},
|
|
||||||
{Name: "TaintToleration"},
|
|
||||||
{Name: "NodeAffinity"},
|
|
||||||
{Name: "NodePorts"},
|
|
||||||
{Name: "NodeResourcesFit"},
|
|
||||||
{Name: "VolumeRestrictions"},
|
|
||||||
{Name: "EBSLimits"},
|
|
||||||
{Name: "GCEPDLimits"},
|
|
||||||
{Name: "NodeVolumeLimits"},
|
|
||||||
{Name: "AzureDiskLimits"},
|
|
||||||
{Name: "VolumeBinding"},
|
|
||||||
{Name: "VolumeZone"},
|
|
||||||
{Name: "PodTopologySpread"},
|
|
||||||
{Name: "InterPodAffinity"},
|
|
||||||
},
|
|
||||||
"PostFilterPlugin": {
|
|
||||||
{Name: "DefaultPreemption"},
|
|
||||||
},
|
|
||||||
"PreScorePlugin": {
|
|
||||||
{Name: "InterPodAffinity"},
|
|
||||||
{Name: "PodTopologySpread"},
|
|
||||||
{Name: "TaintToleration"},
|
|
||||||
{Name: "NodeAffinity"},
|
|
||||||
},
|
|
||||||
"ScorePlugin": {
|
|
||||||
{Name: "NodeResourcesBalancedAllocation", Weight: 1},
|
|
||||||
{Name: "ImageLocality", Weight: 1},
|
|
||||||
{Name: "InterPodAffinity", Weight: 1},
|
|
||||||
{Name: "NodeResourcesLeastAllocated", Weight: 1},
|
|
||||||
{Name: "NodeAffinity", Weight: 1},
|
|
||||||
{Name: "NodePreferAvoidPods", Weight: 10000},
|
|
||||||
{Name: "PodTopologySpread", Weight: 2},
|
|
||||||
{Name: "TaintToleration", Weight: 1},
|
|
||||||
},
|
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
|
||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
name string
|
name string
|
||||||
flags []string
|
flags []string
|
||||||
wantPlugins map[string]map[string][]kubeschedulerconfig.Plugin
|
wantPlugins map[string]*config.Plugins
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "default config",
|
name: "default config",
|
||||||
flags: []string{
|
flags: []string{
|
||||||
"--kubeconfig", configKubeconfig,
|
"--kubeconfig", configKubeconfig,
|
||||||
},
|
},
|
||||||
wantPlugins: map[string]map[string][]kubeschedulerconfig.Plugin{
|
wantPlugins: map[string]*config.Plugins{
|
||||||
"default-scheduler": defaultPlugins,
|
"default-scheduler": defaults.PluginsV1beta2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "plugin config with single profile",
|
name: "component configuration",
|
||||||
flags: []string{
|
flags: []string{
|
||||||
"--config", pluginConfigFile,
|
"--config", pluginConfigFile,
|
||||||
"--kubeconfig", configKubeconfig,
|
"--kubeconfig", configKubeconfig,
|
||||||
},
|
},
|
||||||
wantPlugins: map[string]map[string][]kubeschedulerconfig.Plugin{
|
wantPlugins: map[string]*config.Plugins{
|
||||||
"default-scheduler": {
|
"default-scheduler": {
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
Bind: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultBinder"}}},
|
||||||
"FilterPlugin": {{Name: "NodeResourcesFit"}, {Name: "NodePorts"}},
|
Filter: config.PluginSet{
|
||||||
"PreFilterPlugin": {{Name: "NodeResourcesFit"}, {Name: "NodePorts"}},
|
Enabled: []config.Plugin{
|
||||||
"PostFilterPlugin": {{Name: "DefaultPreemption"}},
|
{Name: "NodeResourcesFit"},
|
||||||
"PreScorePlugin": {{Name: "InterPodAffinity"}, {Name: "TaintToleration"}},
|
{Name: "NodePorts"},
|
||||||
"QueueSortPlugin": {{Name: "PrioritySort"}},
|
},
|
||||||
"ScorePlugin": {{Name: "InterPodAffinity", Weight: 1}, {Name: "TaintToleration", Weight: 1}},
|
},
|
||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
PreFilter: config.PluginSet{
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
Enabled: []config.Plugin{
|
||||||
|
{Name: "NodeResourcesFit"},
|
||||||
|
{Name: "NodePorts"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultPreemption"}}},
|
||||||
|
PreScore: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: "InterPodAffinity"},
|
||||||
|
{Name: "TaintToleration"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
QueueSort: config.PluginSet{Enabled: []config.Plugin{{Name: "PrioritySort"}}},
|
||||||
|
Score: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: "InterPodAffinity", Weight: 1},
|
||||||
|
{Name: "TaintToleration", Weight: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Reserve: config.PluginSet{Enabled: []config.Plugin{{Name: "VolumeBinding"}}},
|
||||||
|
PreBind: config.PluginSet{Enabled: []config.Plugin{{Name: "VolumeBinding"}}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "plugin config with multiple profiles",
|
|
||||||
flags: []string{
|
|
||||||
"--config", multiProfilesConfig,
|
|
||||||
"--kubeconfig", configKubeconfig,
|
|
||||||
},
|
|
||||||
wantPlugins: map[string]map[string][]kubeschedulerconfig.Plugin{
|
|
||||||
"profile-default-plugins": defaultPlugins,
|
|
||||||
"profile-disable-all-filter-and-score-plugins": {
|
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
|
||||||
"QueueSortPlugin": {{Name: "PrioritySort"}},
|
|
||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "default algorithm provider",
|
|
||||||
flags: []string{
|
|
||||||
"--kubeconfig", configKubeconfig,
|
|
||||||
},
|
|
||||||
wantPlugins: map[string]map[string][]kubeschedulerconfig.Plugin{
|
|
||||||
"default-scheduler": defaultPlugins,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "policy config file",
|
name: "policy config file",
|
||||||
flags: []string{
|
flags: []string{
|
||||||
"--kubeconfig", configKubeconfig,
|
"--kubeconfig", configKubeconfig,
|
||||||
"--policy-config-file", policyConfigFile,
|
"--policy-config-file", policyConfigFile,
|
||||||
},
|
},
|
||||||
wantPlugins: map[string]map[string][]kubeschedulerconfig.Plugin{
|
wantPlugins: map[string]*config.Plugins{
|
||||||
"default-scheduler": {
|
"default-scheduler": {
|
||||||
"QueueSortPlugin": {{Name: "PrioritySort"}},
|
QueueSort: config.PluginSet{Enabled: []config.Plugin{{Name: "PrioritySort"}}},
|
||||||
"PreFilterPlugin": {
|
PreFilter: config.PluginSet{Enabled: []config.Plugin{{Name: "InterPodAffinity"}}},
|
||||||
{Name: "InterPodAffinity"},
|
Filter: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: "NodeUnschedulable"},
|
||||||
|
{Name: "TaintToleration"},
|
||||||
|
{Name: "InterPodAffinity"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"FilterPlugin": {
|
PostFilter: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultPreemption"}}},
|
||||||
{Name: "NodeUnschedulable"},
|
PreScore: config.PluginSet{Enabled: []config.Plugin{{Name: "InterPodAffinity"}}},
|
||||||
{Name: "TaintToleration"},
|
Score: config.PluginSet{Enabled: []config.Plugin{{Name: "InterPodAffinity", Weight: 2}}},
|
||||||
{Name: "InterPodAffinity"},
|
Bind: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultBinder"}}},
|
||||||
},
|
|
||||||
"PostFilterPlugin": {{Name: "DefaultPreemption"}},
|
|
||||||
"PreScorePlugin": {
|
|
||||||
{Name: "InterPodAffinity"},
|
|
||||||
},
|
|
||||||
"ScorePlugin": {
|
|
||||||
{Name: "InterPodAffinity", Weight: 2},
|
|
||||||
},
|
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -332,7 +271,7 @@ profiles:
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gotPlugins := make(map[string]map[string][]kubeschedulerconfig.Plugin)
|
gotPlugins := make(map[string]*config.Plugins)
|
||||||
for n, p := range sched.Profiles {
|
for n, p := range sched.Profiles {
|
||||||
gotPlugins[n] = p.ListPlugins()
|
gotPlugins[n] = p.ListPlugins()
|
||||||
}
|
}
|
||||||
|
@ -1,144 +0,0 @@
|
|||||||
/*
|
|
||||||
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 algorithmprovider
|
|
||||||
|
|
||||||
import (
|
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/klog/v2"
|
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodepreferavoidpods"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeunschedulable"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/selectorspread"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumerestrictions"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumezone"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetDefaultConfig() *schedulerapi.Plugins {
|
|
||||||
plugins := &schedulerapi.Plugins{
|
|
||||||
QueueSort: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: queuesort.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PreFilter: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: noderesources.FitName},
|
|
||||||
{Name: nodeports.Name},
|
|
||||||
{Name: podtopologyspread.Name},
|
|
||||||
{Name: interpodaffinity.Name},
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
{Name: nodeaffinity.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Filter: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: nodeunschedulable.Name},
|
|
||||||
{Name: nodename.Name},
|
|
||||||
{Name: tainttoleration.Name},
|
|
||||||
{Name: nodeaffinity.Name},
|
|
||||||
{Name: nodeports.Name},
|
|
||||||
{Name: noderesources.FitName},
|
|
||||||
{Name: volumerestrictions.Name},
|
|
||||||
{Name: nodevolumelimits.EBSName},
|
|
||||||
{Name: nodevolumelimits.GCEPDName},
|
|
||||||
{Name: nodevolumelimits.CSIName},
|
|
||||||
{Name: nodevolumelimits.AzureDiskName},
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
{Name: volumezone.Name},
|
|
||||||
{Name: podtopologyspread.Name},
|
|
||||||
{Name: interpodaffinity.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PostFilter: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: defaultpreemption.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PreScore: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: interpodaffinity.Name},
|
|
||||||
{Name: podtopologyspread.Name},
|
|
||||||
{Name: tainttoleration.Name},
|
|
||||||
{Name: nodeaffinity.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Score: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: noderesources.BalancedAllocationName, Weight: 1},
|
|
||||||
{Name: imagelocality.Name, Weight: 1},
|
|
||||||
{Name: interpodaffinity.Name, Weight: 1},
|
|
||||||
{Name: noderesources.LeastAllocatedName, Weight: 1},
|
|
||||||
{Name: nodeaffinity.Name, Weight: 1},
|
|
||||||
{Name: nodepreferavoidpods.Name, Weight: 10000},
|
|
||||||
// Weight is doubled because:
|
|
||||||
// - This is a score coming from user preference.
|
|
||||||
// - It makes its signal comparable to NodeResourcesLeastAllocated.
|
|
||||||
{Name: podtopologyspread.Name, Weight: 2},
|
|
||||||
{Name: tainttoleration.Name, Weight: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Reserve: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PreBind: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Bind: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: defaultbinder.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
applyFeatureGates(plugins)
|
|
||||||
|
|
||||||
return plugins
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyFeatureGates(config *schedulerapi.Plugins) {
|
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority) {
|
|
||||||
config.Score.Enabled = append(config.Score.Enabled, schedulerapi.Plugin{Name: volumebinding.Name, Weight: 1})
|
|
||||||
}
|
|
||||||
|
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.DefaultPodTopologySpread) {
|
|
||||||
// When feature is enabled, the default spreading is done by
|
|
||||||
// PodTopologySpread plugin, which is enabled by default.
|
|
||||||
klog.Infof("Registering SelectorSpread plugin")
|
|
||||||
s := schedulerapi.Plugin{Name: selectorspread.Name}
|
|
||||||
config.PreScore.Enabled = append(config.PreScore.Enabled, s)
|
|
||||||
s.Weight = 1
|
|
||||||
config.Score.Enabled = append(config.Score.Enabled, s)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,232 +0,0 @@
|
|||||||
/*
|
|
||||||
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 algorithmprovider
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/component-base/featuregate"
|
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodepreferavoidpods"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeunschedulable"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodevolumelimits"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/selectorspread"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumerestrictions"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumezone"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestApplyFeatureGates(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
features map[featuregate.Feature]bool
|
|
||||||
wantConfig *schedulerapi.Plugins
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Feature gates disabled",
|
|
||||||
wantConfig: &schedulerapi.Plugins{
|
|
||||||
QueueSort: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: queuesort.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PreFilter: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: noderesources.FitName},
|
|
||||||
{Name: nodeports.Name},
|
|
||||||
{Name: podtopologyspread.Name},
|
|
||||||
{Name: interpodaffinity.Name},
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
{Name: nodeaffinity.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Filter: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: nodeunschedulable.Name},
|
|
||||||
{Name: nodename.Name},
|
|
||||||
{Name: tainttoleration.Name},
|
|
||||||
{Name: nodeaffinity.Name},
|
|
||||||
{Name: nodeports.Name},
|
|
||||||
{Name: noderesources.FitName},
|
|
||||||
{Name: volumerestrictions.Name},
|
|
||||||
{Name: nodevolumelimits.EBSName},
|
|
||||||
{Name: nodevolumelimits.GCEPDName},
|
|
||||||
{Name: nodevolumelimits.CSIName},
|
|
||||||
{Name: nodevolumelimits.AzureDiskName},
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
{Name: volumezone.Name},
|
|
||||||
{Name: podtopologyspread.Name},
|
|
||||||
{Name: interpodaffinity.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PostFilter: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: defaultpreemption.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PreScore: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: interpodaffinity.Name},
|
|
||||||
{Name: podtopologyspread.Name},
|
|
||||||
{Name: tainttoleration.Name},
|
|
||||||
{Name: nodeaffinity.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Score: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: noderesources.BalancedAllocationName, Weight: 1},
|
|
||||||
{Name: imagelocality.Name, Weight: 1},
|
|
||||||
{Name: interpodaffinity.Name, Weight: 1},
|
|
||||||
{Name: noderesources.LeastAllocatedName, Weight: 1},
|
|
||||||
{Name: nodeaffinity.Name, Weight: 1},
|
|
||||||
{Name: nodepreferavoidpods.Name, Weight: 10000},
|
|
||||||
{Name: podtopologyspread.Name, Weight: 2},
|
|
||||||
{Name: tainttoleration.Name, Weight: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Reserve: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PreBind: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Bind: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: defaultbinder.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "DefaultPodTopologySpread disabled",
|
|
||||||
features: map[featuregate.Feature]bool{
|
|
||||||
features.DefaultPodTopologySpread: false,
|
|
||||||
},
|
|
||||||
wantConfig: &schedulerapi.Plugins{
|
|
||||||
QueueSort: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: queuesort.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PreFilter: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: noderesources.FitName},
|
|
||||||
{Name: nodeports.Name},
|
|
||||||
{Name: podtopologyspread.Name},
|
|
||||||
{Name: interpodaffinity.Name},
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
{Name: nodeaffinity.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Filter: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: nodeunschedulable.Name},
|
|
||||||
{Name: nodename.Name},
|
|
||||||
{Name: tainttoleration.Name},
|
|
||||||
{Name: nodeaffinity.Name},
|
|
||||||
{Name: nodeports.Name},
|
|
||||||
{Name: noderesources.FitName},
|
|
||||||
{Name: volumerestrictions.Name},
|
|
||||||
{Name: nodevolumelimits.EBSName},
|
|
||||||
{Name: nodevolumelimits.GCEPDName},
|
|
||||||
{Name: nodevolumelimits.CSIName},
|
|
||||||
{Name: nodevolumelimits.AzureDiskName},
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
{Name: volumezone.Name},
|
|
||||||
{Name: podtopologyspread.Name},
|
|
||||||
{Name: interpodaffinity.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PostFilter: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: defaultpreemption.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PreScore: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: interpodaffinity.Name},
|
|
||||||
{Name: podtopologyspread.Name},
|
|
||||||
{Name: tainttoleration.Name},
|
|
||||||
{Name: nodeaffinity.Name},
|
|
||||||
{Name: selectorspread.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Score: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: noderesources.BalancedAllocationName, Weight: 1},
|
|
||||||
{Name: imagelocality.Name, Weight: 1},
|
|
||||||
{Name: interpodaffinity.Name, Weight: 1},
|
|
||||||
{Name: noderesources.LeastAllocatedName, Weight: 1},
|
|
||||||
{Name: nodeaffinity.Name, Weight: 1},
|
|
||||||
{Name: nodepreferavoidpods.Name, Weight: 10000},
|
|
||||||
{Name: podtopologyspread.Name, Weight: 2},
|
|
||||||
{Name: tainttoleration.Name, Weight: 1},
|
|
||||||
{Name: selectorspread.Name, Weight: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Reserve: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PreBind: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Bind: schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: defaultbinder.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
t.Run(test.name, func(t *testing.T) {
|
|
||||||
for k, v := range test.features {
|
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, k, v)()
|
|
||||||
}
|
|
||||||
|
|
||||||
gotConfig := GetDefaultConfig()
|
|
||||||
|
|
||||||
if diff := cmp.Diff(test.wantConfig, gotConfig); diff != "" {
|
|
||||||
t.Errorf("unexpected config diff (-want, +got): %s", diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -27,6 +27,7 @@ import (
|
|||||||
"k8s.io/kube-scheduler/config/v1beta1"
|
"k8s.io/kube-scheduler/config/v1beta1"
|
||||||
"k8s.io/kube-scheduler/config/v1beta2"
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/apis/config/testing/defaults"
|
||||||
"k8s.io/utils/pointer"
|
"k8s.io/utils/pointer"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
@ -102,6 +103,7 @@ profiles:
|
|||||||
wantProfiles: []config.KubeSchedulerProfile{
|
wantProfiles: []config.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
SchedulerName: "default-scheduler",
|
SchedulerName: "default-scheduler",
|
||||||
|
Plugins: defaults.PluginsV1beta1,
|
||||||
PluginConfig: []config.PluginConfig{
|
PluginConfig: []config.PluginConfig{
|
||||||
{
|
{
|
||||||
Name: "DefaultPreemption",
|
Name: "DefaultPreemption",
|
||||||
@ -199,12 +201,13 @@ profiles:
|
|||||||
wantProfiles: []config.KubeSchedulerProfile{
|
wantProfiles: []config.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
SchedulerName: "default-scheduler",
|
SchedulerName: "default-scheduler",
|
||||||
PluginConfig: []config.PluginConfig{
|
Plugins: defaults.PluginsV1beta1,
|
||||||
|
PluginConfig: append([]config.PluginConfig{
|
||||||
{
|
{
|
||||||
Name: "NodeLabel",
|
Name: "NodeLabel",
|
||||||
Args: &config.NodeLabelArgs{PresentLabels: []string{"bars"}},
|
Args: &config.NodeLabelArgs{PresentLabels: []string{"bars"}},
|
||||||
},
|
},
|
||||||
},
|
}, defaults.PluginConfigs...),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -269,7 +272,8 @@ profiles:
|
|||||||
wantProfiles: []config.KubeSchedulerProfile{
|
wantProfiles: []config.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
SchedulerName: "default-scheduler",
|
SchedulerName: "default-scheduler",
|
||||||
PluginConfig: []config.PluginConfig{
|
Plugins: defaults.PluginsV1beta1,
|
||||||
|
PluginConfig: append([]config.PluginConfig{
|
||||||
{
|
{
|
||||||
Name: "OutOfTreePlugin",
|
Name: "OutOfTreePlugin",
|
||||||
Args: &runtime.Unknown{
|
Args: &runtime.Unknown{
|
||||||
@ -277,7 +281,7 @@ profiles:
|
|||||||
Raw: []byte(`{"foo":"bar"}`),
|
Raw: []byte(`{"foo":"bar"}`),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}, defaults.PluginConfigs...),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -307,6 +311,7 @@ profiles:
|
|||||||
wantProfiles: []config.KubeSchedulerProfile{
|
wantProfiles: []config.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
SchedulerName: "default-scheduler",
|
SchedulerName: "default-scheduler",
|
||||||
|
Plugins: defaults.PluginsV1beta1,
|
||||||
PluginConfig: []config.PluginConfig{
|
PluginConfig: []config.PluginConfig{
|
||||||
{
|
{
|
||||||
Name: "DefaultPreemption",
|
Name: "DefaultPreemption",
|
||||||
@ -411,6 +416,7 @@ profiles:
|
|||||||
wantProfiles: []config.KubeSchedulerProfile{
|
wantProfiles: []config.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
SchedulerName: "default-scheduler",
|
SchedulerName: "default-scheduler",
|
||||||
|
Plugins: defaults.PluginsV1beta2,
|
||||||
PluginConfig: []config.PluginConfig{
|
PluginConfig: []config.PluginConfig{
|
||||||
{
|
{
|
||||||
Name: "DefaultPreemption",
|
Name: "DefaultPreemption",
|
||||||
@ -498,11 +504,44 @@ profiles:
|
|||||||
wantProfiles: []config.KubeSchedulerProfile{
|
wantProfiles: []config.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
SchedulerName: "default-scheduler",
|
SchedulerName: "default-scheduler",
|
||||||
|
Plugins: defaults.PluginsV1beta2,
|
||||||
PluginConfig: []config.PluginConfig{
|
PluginConfig: []config.PluginConfig{
|
||||||
{
|
{
|
||||||
Name: "DefaultPreemption",
|
Name: "DefaultPreemption",
|
||||||
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 100},
|
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 100},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "InterPodAffinity",
|
||||||
|
Args: &config.InterPodAffinityArgs{
|
||||||
|
HardPodAffinityWeight: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeAffinity",
|
||||||
|
Args: &config.NodeAffinityArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesFit",
|
||||||
|
Args: &config.NodeResourcesFitArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesLeastAllocated",
|
||||||
|
Args: &config.NodeResourcesLeastAllocatedArgs{
|
||||||
|
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PodTopologySpread",
|
||||||
|
Args: &config.PodTopologySpreadArgs{
|
||||||
|
DefaultingType: config.SystemDefaulting,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: &config.VolumeBindingArgs{
|
||||||
|
BindTimeoutSeconds: 600,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -568,7 +607,8 @@ profiles:
|
|||||||
wantProfiles: []config.KubeSchedulerProfile{
|
wantProfiles: []config.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
SchedulerName: "default-scheduler",
|
SchedulerName: "default-scheduler",
|
||||||
PluginConfig: []config.PluginConfig{
|
Plugins: defaults.PluginsV1beta2,
|
||||||
|
PluginConfig: append([]config.PluginConfig{
|
||||||
{
|
{
|
||||||
Name: "OutOfTreePlugin",
|
Name: "OutOfTreePlugin",
|
||||||
Args: &runtime.Unknown{
|
Args: &runtime.Unknown{
|
||||||
@ -576,7 +616,7 @@ profiles:
|
|||||||
Raw: []byte(`{"foo":"bar"}`),
|
Raw: []byte(`{"foo":"bar"}`),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}, defaults.PluginConfigs...),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -606,6 +646,7 @@ profiles:
|
|||||||
wantProfiles: []config.KubeSchedulerProfile{
|
wantProfiles: []config.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
SchedulerName: "default-scheduler",
|
SchedulerName: "default-scheduler",
|
||||||
|
Plugins: defaults.PluginsV1beta2,
|
||||||
PluginConfig: []config.PluginConfig{
|
PluginConfig: []config.PluginConfig{
|
||||||
{
|
{
|
||||||
Name: "DefaultPreemption",
|
Name: "DefaultPreemption",
|
||||||
|
File diff suppressed because it is too large
Load Diff
51
pkg/scheduler/apis/config/testing/config.go
Normal file
51
pkg/scheduler/apis/config/testing/config.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2021 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 testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/component-base/config/v1alpha1"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta1"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"
|
||||||
|
)
|
||||||
|
|
||||||
|
// V1beta1ToInternalWithDefaults creates a v1beta1 default configuration.
|
||||||
|
func V1beta1ToInternalWithDefaults(t *testing.T, versionedCfg v1beta1.KubeSchedulerConfiguration) *config.KubeSchedulerConfiguration {
|
||||||
|
versionedCfg.DebuggingConfiguration = *v1alpha1.NewRecommendedDebuggingConfiguration()
|
||||||
|
|
||||||
|
scheme.Scheme.Default(&versionedCfg)
|
||||||
|
cfg := config.KubeSchedulerConfiguration{}
|
||||||
|
if err := scheme.Scheme.Convert(&versionedCfg, &cfg, nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return &cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// V1beta2ToInternalWithDefaults creates a v1beta2 default configuration.
|
||||||
|
func V1beta2ToInternalWithDefaults(t *testing.T, versionedCfg v1beta2.KubeSchedulerConfiguration) *config.KubeSchedulerConfiguration {
|
||||||
|
versionedCfg.DebuggingConfiguration = *v1alpha1.NewRecommendedDebuggingConfiguration()
|
||||||
|
|
||||||
|
scheme.Scheme.Default(&versionedCfg)
|
||||||
|
cfg := config.KubeSchedulerConfiguration{}
|
||||||
|
if err := scheme.Scheme.Convert(&versionedCfg, &cfg, nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return &cfg
|
||||||
|
}
|
227
pkg/scheduler/apis/config/testing/defaults/defaults.go
Normal file
227
pkg/scheduler/apis/config/testing/defaults/defaults.go
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2021 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 defaults
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PluginsV1beta1 default set of v1beta1 plugins.
|
||||||
|
var PluginsV1beta1 = &config.Plugins{
|
||||||
|
QueueSort: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.PrioritySort},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Filter: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.NodeUnschedulable},
|
||||||
|
{Name: names.NodeName},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.VolumeRestrictions},
|
||||||
|
{Name: names.EBSLimits},
|
||||||
|
{Name: names.GCEPDLimits},
|
||||||
|
{Name: names.NodeVolumeLimits},
|
||||||
|
{Name: names.AzureDiskLimits},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.VolumeZone},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.DefaultPreemption},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreScore: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.NodeResourcesBalancedAllocation, Weight: 1},
|
||||||
|
{Name: names.ImageLocality, Weight: 1},
|
||||||
|
{Name: names.InterPodAffinity, Weight: 1},
|
||||||
|
{Name: names.NodeResourcesLeastAllocated, Weight: 1},
|
||||||
|
{Name: names.NodeAffinity, Weight: 1},
|
||||||
|
{Name: names.NodePreferAvoidPods, Weight: 10000},
|
||||||
|
// Weight is doubled because:
|
||||||
|
// - This is a score coming from user preference.
|
||||||
|
// - It makes its signal comparable to NodeResourcesLeastAllocated.
|
||||||
|
{Name: names.PodTopologySpread, Weight: 2},
|
||||||
|
{Name: names.TaintToleration, Weight: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Reserve: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreBind: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bind: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.DefaultBinder},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginsV1beta2 default set of v1beta2 plugins.
|
||||||
|
var PluginsV1beta2 = &config.Plugins{
|
||||||
|
QueueSort: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.PrioritySort},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Filter: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.NodeUnschedulable},
|
||||||
|
{Name: names.NodeName},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.VolumeRestrictions},
|
||||||
|
{Name: names.EBSLimits},
|
||||||
|
{Name: names.GCEPDLimits},
|
||||||
|
{Name: names.NodeVolumeLimits},
|
||||||
|
{Name: names.AzureDiskLimits},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.VolumeZone},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.DefaultPreemption},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreScore: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.NodeResourcesBalancedAllocation, Weight: 1},
|
||||||
|
{Name: names.ImageLocality, Weight: 1},
|
||||||
|
{Name: names.InterPodAffinity, Weight: 1},
|
||||||
|
{Name: names.NodeResourcesLeastAllocated, Weight: 1},
|
||||||
|
{Name: names.NodeAffinity, Weight: 1},
|
||||||
|
// Weight is doubled because:
|
||||||
|
// - This is a score coming from user preference.
|
||||||
|
// - It makes its signal comparable to NodeResourcesLeastAllocated.
|
||||||
|
{Name: names.PodTopologySpread, Weight: 2},
|
||||||
|
{Name: names.TaintToleration, Weight: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Reserve: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreBind: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bind: config.PluginSet{
|
||||||
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.DefaultBinder},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginConfigs default plugin configurations. This could get versioned, but since
|
||||||
|
// all available versions produce the same defaults, we just have one for now.
|
||||||
|
var PluginConfigs = []config.PluginConfig{
|
||||||
|
{
|
||||||
|
Name: "DefaultPreemption",
|
||||||
|
Args: &config.DefaultPreemptionArgs{
|
||||||
|
MinCandidateNodesPercentage: 10,
|
||||||
|
MinCandidateNodesAbsolute: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "InterPodAffinity",
|
||||||
|
Args: &config.InterPodAffinityArgs{
|
||||||
|
HardPodAffinityWeight: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeAffinity",
|
||||||
|
Args: &config.NodeAffinityArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesFit",
|
||||||
|
Args: &config.NodeResourcesFitArgs{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesLeastAllocated",
|
||||||
|
Args: &config.NodeResourcesLeastAllocatedArgs{
|
||||||
|
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PodTopologySpread",
|
||||||
|
Args: &config.PodTopologySpreadArgs{
|
||||||
|
DefaultingType: config.SystemDefaulting,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: &config.VolumeBindingArgs{
|
||||||
|
BindTimeoutSeconds: 600,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
@ -243,69 +243,31 @@ const (
|
|||||||
MaxWeight = MaxTotalScore / MaxCustomPriorityScore
|
MaxWeight = MaxTotalScore / MaxCustomPriorityScore
|
||||||
)
|
)
|
||||||
|
|
||||||
func appendPluginSet(dst PluginSet, src PluginSet) PluginSet {
|
// Names returns the list of enabled plugin names.
|
||||||
dst.Enabled = append(dst.Enabled, src.Enabled...)
|
func (p *Plugins) Names() []string {
|
||||||
dst.Disabled = append(dst.Disabled, src.Disabled...)
|
if p == nil {
|
||||||
return dst
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
// Append appends src Plugins to current Plugins. If a PluginSet is nil, it will
|
|
||||||
// be created.
|
|
||||||
func (p *Plugins) Append(src *Plugins) {
|
|
||||||
if p == nil || src == nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
p.QueueSort = appendPluginSet(p.QueueSort, src.QueueSort)
|
extensions := []PluginSet{
|
||||||
p.PreFilter = appendPluginSet(p.PreFilter, src.PreFilter)
|
p.PreFilter,
|
||||||
p.Filter = appendPluginSet(p.Filter, src.Filter)
|
p.Filter,
|
||||||
p.PostFilter = appendPluginSet(p.PostFilter, src.PostFilter)
|
p.PostFilter,
|
||||||
p.PreScore = appendPluginSet(p.PreScore, src.PreScore)
|
p.Reserve,
|
||||||
p.Score = appendPluginSet(p.Score, src.Score)
|
p.PreScore,
|
||||||
p.Reserve = appendPluginSet(p.Reserve, src.Reserve)
|
p.Score,
|
||||||
p.Permit = appendPluginSet(p.Permit, src.Permit)
|
p.PreBind,
|
||||||
p.PreBind = appendPluginSet(p.PreBind, src.PreBind)
|
p.Bind,
|
||||||
p.Bind = appendPluginSet(p.Bind, src.Bind)
|
p.PostBind,
|
||||||
p.PostBind = appendPluginSet(p.PostBind, src.PostBind)
|
p.Permit,
|
||||||
}
|
p.QueueSort,
|
||||||
|
|
||||||
// Apply merges the plugin configuration from custom plugins, handling disabled sets.
|
|
||||||
func (p *Plugins) Apply(customPlugins *Plugins) {
|
|
||||||
if customPlugins == nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
n := sets.NewString()
|
||||||
p.QueueSort = mergePluginSets(p.QueueSort, customPlugins.QueueSort)
|
for _, e := range extensions {
|
||||||
p.PreFilter = mergePluginSets(p.PreFilter, customPlugins.PreFilter)
|
for _, pg := range e.Enabled {
|
||||||
p.Filter = mergePluginSets(p.Filter, customPlugins.Filter)
|
n.Insert(pg.Name)
|
||||||
p.PostFilter = mergePluginSets(p.PostFilter, customPlugins.PostFilter)
|
|
||||||
p.PreScore = mergePluginSets(p.PreScore, customPlugins.PreScore)
|
|
||||||
p.Score = mergePluginSets(p.Score, customPlugins.Score)
|
|
||||||
p.Reserve = mergePluginSets(p.Reserve, customPlugins.Reserve)
|
|
||||||
p.Permit = mergePluginSets(p.Permit, customPlugins.Permit)
|
|
||||||
p.PreBind = mergePluginSets(p.PreBind, customPlugins.PreBind)
|
|
||||||
p.Bind = mergePluginSets(p.Bind, customPlugins.Bind)
|
|
||||||
p.PostBind = mergePluginSets(p.PostBind, customPlugins.PostBind)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mergePluginSets(defaultPluginSet, customPluginSet PluginSet) PluginSet {
|
|
||||||
disabledPlugins := sets.NewString()
|
|
||||||
for _, disabledPlugin := range customPluginSet.Disabled {
|
|
||||||
disabledPlugins.Insert(disabledPlugin.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
var enabledPlugins []Plugin
|
|
||||||
if !disabledPlugins.Has("*") {
|
|
||||||
for _, defaultEnabledPlugin := range defaultPluginSet.Enabled {
|
|
||||||
if disabledPlugins.Has(defaultEnabledPlugin.Name) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
enabledPlugins = append(enabledPlugins, defaultEnabledPlugin)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return n.List()
|
||||||
enabledPlugins = append(enabledPlugins, customPluginSet.Enabled...)
|
|
||||||
return PluginSet{Enabled: enabledPlugins}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extender holds the parameters used to communicate with the extender. If a verb is unspecified/empty,
|
// Extender holds the parameters used to communicate with the extender. If a verb is unspecified/empty,
|
||||||
|
@ -22,210 +22,40 @@ import (
|
|||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPluginsAppend(t *testing.T) {
|
func TestPluginsNames(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
customPlugins *Plugins
|
plugins *Plugins
|
||||||
defaultPlugins *Plugins
|
want []string
|
||||||
expectedPlugins *Plugins
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "AppendPlugin",
|
name: "empty",
|
||||||
customPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "CustomPlugin"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
{Name: "CustomPlugin"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "AppendNilPlugin",
|
name: "with duplicates",
|
||||||
customPlugins: nil,
|
plugins: &Plugins{
|
||||||
defaultPlugins: &Plugins{},
|
Filter: PluginSet{
|
||||||
expectedPlugins: &Plugins{},
|
Enabled: []Plugin{
|
||||||
|
{Name: "CustomFilter"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: PluginSet{
|
||||||
|
Enabled: []Plugin{
|
||||||
|
{Name: "CustomFilter"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: PluginSet{
|
||||||
|
Enabled: []Plugin{
|
||||||
|
{Name: "CustomScore"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: []string{"CustomFilter", "CustomScore"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
test.defaultPlugins.Append(test.customPlugins)
|
if d := cmp.Diff(test.want, test.plugins.Names()); d != "" {
|
||||||
if d := cmp.Diff(test.expectedPlugins, test.defaultPlugins); d != "" {
|
|
||||||
t.Fatalf("plugins mismatch (-want +got):\n%s", d)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPluginsApply(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
customPlugins *Plugins
|
|
||||||
defaultPlugins *Plugins
|
|
||||||
expectedPlugins *Plugins
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "AppendCustomPlugin",
|
|
||||||
customPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "CustomPlugin"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
{Name: "CustomPlugin"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "InsertAfterDefaultPlugins2",
|
|
||||||
customPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "CustomPlugin"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
Disabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "CustomPlugin"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "InsertBeforeAllPlugins",
|
|
||||||
customPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "CustomPlugin"},
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
Disabled: []Plugin{
|
|
||||||
{Name: "*"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "CustomPlugin"},
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ReorderDefaultPlugins",
|
|
||||||
customPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
},
|
|
||||||
Disabled: []Plugin{
|
|
||||||
{Name: "*"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ApplyNilCustomPlugin",
|
|
||||||
customPlugins: nil,
|
|
||||||
defaultPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedPlugins: &Plugins{
|
|
||||||
Filter: PluginSet{
|
|
||||||
Enabled: []Plugin{
|
|
||||||
{Name: "DefaultPlugin1"},
|
|
||||||
{Name: "DefaultPlugin2"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
t.Run(test.name, func(t *testing.T) {
|
|
||||||
test.defaultPlugins.Apply(test.customPlugins)
|
|
||||||
if d := cmp.Diff(test.expectedPlugins, test.defaultPlugins); d != "" {
|
|
||||||
t.Fatalf("plugins mismatch (-want +got):\n%s", d)
|
t.Fatalf("plugins mismatch (-want +got):\n%s", d)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -149,20 +149,20 @@ func Convert_v1beta1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfigura
|
|||||||
func convertToInternalPluginConfigArgs(out *config.KubeSchedulerConfiguration) error {
|
func convertToInternalPluginConfigArgs(out *config.KubeSchedulerConfiguration) error {
|
||||||
scheme := getPluginArgConversionScheme()
|
scheme := getPluginArgConversionScheme()
|
||||||
for i := range out.Profiles {
|
for i := range out.Profiles {
|
||||||
for j := range out.Profiles[i].PluginConfig {
|
prof := &out.Profiles[i]
|
||||||
args := out.Profiles[i].PluginConfig[j].Args
|
for j := range prof.PluginConfig {
|
||||||
|
args := prof.PluginConfig[j].Args
|
||||||
if args == nil {
|
if args == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, isUnknown := args.(*runtime.Unknown); isUnknown {
|
if _, isUnknown := args.(*runtime.Unknown); isUnknown {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
scheme.Default(args)
|
|
||||||
internalArgs, err := scheme.ConvertToVersion(args, config.SchemeGroupVersion)
|
internalArgs, err := scheme.ConvertToVersion(args, config.SchemeGroupVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("converting .Profiles[%d].PluginConfig[%d].Args into internal type: %w", i, j, err)
|
return fmt.Errorf("converting .Profiles[%d].PluginConfig[%d].Args into internal type: %w", i, j, err)
|
||||||
}
|
}
|
||||||
out.Profiles[i].PluginConfig[j].Args = internalArgs
|
prof.PluginConfig[j].Args = internalArgs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
179
pkg/scheduler/apis/config/v1beta1/default_plugins.go
Normal file
179
pkg/scheduler/apis/config/v1beta1/default_plugins.go
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2021 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 v1beta1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta1"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getDefaultPlugins returns the default set of plugins.
|
||||||
|
func getDefaultPlugins() *v1beta1.Plugins {
|
||||||
|
plugins := &v1beta1.Plugins{
|
||||||
|
QueueSort: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.PrioritySort},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeUnschedulable},
|
||||||
|
{Name: names.NodeName},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.VolumeRestrictions},
|
||||||
|
{Name: names.EBSLimits},
|
||||||
|
{Name: names.GCEPDLimits},
|
||||||
|
{Name: names.NodeVolumeLimits},
|
||||||
|
{Name: names.AzureDiskLimits},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.VolumeZone},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.DefaultPreemption},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreScore: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodePreferAvoidPods, Weight: pointer.Int32Ptr(10000)},
|
||||||
|
// Weight is doubled because:
|
||||||
|
// - This is a score coming from user preference.
|
||||||
|
// - It makes its signal comparable to NodeResourcesLeastAllocated.
|
||||||
|
{Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)},
|
||||||
|
{Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Reserve: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreBind: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bind: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.DefaultBinder},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
applyFeatureGates(plugins)
|
||||||
|
|
||||||
|
return plugins
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyFeatureGates(config *v1beta1.Plugins) {
|
||||||
|
if utilfeature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority) {
|
||||||
|
config.Score.Enabled = append(config.Score.Enabled, v1beta1.Plugin{Name: names.VolumeBinding, Weight: pointer.Int32Ptr(1)})
|
||||||
|
}
|
||||||
|
|
||||||
|
if !utilfeature.DefaultFeatureGate.Enabled(features.DefaultPodTopologySpread) {
|
||||||
|
// When feature is enabled, the default spreading is done by
|
||||||
|
// PodTopologySpread plugin, which is enabled by default.
|
||||||
|
klog.InfoS("Registering SelectorSpread plugin")
|
||||||
|
s := v1beta1.Plugin{Name: names.SelectorSpread}
|
||||||
|
config.PreScore.Enabled = append(config.PreScore.Enabled, s)
|
||||||
|
s.Weight = pointer.Int32Ptr(1)
|
||||||
|
config.Score.Enabled = append(config.Score.Enabled, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergePlugins merges the custom set into the given default one, handling disabled sets.
|
||||||
|
func mergePlugins(defaultPlugins, customPlugins *v1beta1.Plugins) *v1beta1.Plugins {
|
||||||
|
if customPlugins == nil {
|
||||||
|
return defaultPlugins
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultPlugins.QueueSort = mergePluginSet(defaultPlugins.QueueSort, customPlugins.QueueSort)
|
||||||
|
defaultPlugins.PreFilter = mergePluginSet(defaultPlugins.PreFilter, customPlugins.PreFilter)
|
||||||
|
defaultPlugins.Filter = mergePluginSet(defaultPlugins.Filter, customPlugins.Filter)
|
||||||
|
defaultPlugins.PostFilter = mergePluginSet(defaultPlugins.PostFilter, customPlugins.PostFilter)
|
||||||
|
defaultPlugins.PreScore = mergePluginSet(defaultPlugins.PreScore, customPlugins.PreScore)
|
||||||
|
defaultPlugins.Score = mergePluginSet(defaultPlugins.Score, customPlugins.Score)
|
||||||
|
defaultPlugins.Reserve = mergePluginSet(defaultPlugins.Reserve, customPlugins.Reserve)
|
||||||
|
defaultPlugins.Permit = mergePluginSet(defaultPlugins.Permit, customPlugins.Permit)
|
||||||
|
defaultPlugins.PreBind = mergePluginSet(defaultPlugins.PreBind, customPlugins.PreBind)
|
||||||
|
defaultPlugins.Bind = mergePluginSet(defaultPlugins.Bind, customPlugins.Bind)
|
||||||
|
defaultPlugins.PostBind = mergePluginSet(defaultPlugins.PostBind, customPlugins.PostBind)
|
||||||
|
return defaultPlugins
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergePluginSet(defaultPluginSet, customPluginSet *v1beta1.PluginSet) *v1beta1.PluginSet {
|
||||||
|
disabledPlugins := sets.NewString()
|
||||||
|
if customPluginSet != nil {
|
||||||
|
for _, disabledPlugin := range customPluginSet.Disabled {
|
||||||
|
disabledPlugins.Insert(disabledPlugin.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var enabledPlugins []v1beta1.Plugin
|
||||||
|
if defaultPluginSet != nil && !disabledPlugins.Has("*") {
|
||||||
|
for _, defaultEnabledPlugin := range defaultPluginSet.Enabled {
|
||||||
|
if disabledPlugins.Has(defaultEnabledPlugin.Name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
enabledPlugins = append(enabledPlugins, defaultEnabledPlugin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if customPluginSet != nil {
|
||||||
|
enabledPlugins = append(enabledPlugins, customPluginSet.Enabled...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(enabledPlugins) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &v1beta1.PluginSet{Enabled: enabledPlugins}
|
||||||
|
}
|
374
pkg/scheduler/apis/config/v1beta1/default_plugins_test.go
Normal file
374
pkg/scheduler/apis/config/v1beta1/default_plugins_test.go
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
/*
|
||||||
|
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 v1beta1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"k8s.io/apiserver/pkg/util/feature"
|
||||||
|
"k8s.io/component-base/featuregate"
|
||||||
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta1"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestApplyFeatureGates(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
features map[featuregate.Feature]bool
|
||||||
|
wantConfig *v1beta1.Plugins
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Feature gates disabled",
|
||||||
|
wantConfig: &v1beta1.Plugins{
|
||||||
|
QueueSort: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.PrioritySort},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeUnschedulable},
|
||||||
|
{Name: names.NodeName},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.VolumeRestrictions},
|
||||||
|
{Name: names.EBSLimits},
|
||||||
|
{Name: names.GCEPDLimits},
|
||||||
|
{Name: names.NodeVolumeLimits},
|
||||||
|
{Name: names.AzureDiskLimits},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.VolumeZone},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.DefaultPreemption},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreScore: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodePreferAvoidPods, Weight: pointer.Int32Ptr(10000)},
|
||||||
|
{Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)},
|
||||||
|
{Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Reserve: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreBind: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bind: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.DefaultBinder},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DefaultPodTopologySpread disabled",
|
||||||
|
features: map[featuregate.Feature]bool{
|
||||||
|
features.DefaultPodTopologySpread: false,
|
||||||
|
},
|
||||||
|
wantConfig: &v1beta1.Plugins{
|
||||||
|
QueueSort: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.PrioritySort},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeUnschedulable},
|
||||||
|
{Name: names.NodeName},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.VolumeRestrictions},
|
||||||
|
{Name: names.EBSLimits},
|
||||||
|
{Name: names.GCEPDLimits},
|
||||||
|
{Name: names.NodeVolumeLimits},
|
||||||
|
{Name: names.AzureDiskLimits},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.VolumeZone},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.DefaultPreemption},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreScore: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.SelectorSpread},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodePreferAvoidPods, Weight: pointer.Int32Ptr(10000)},
|
||||||
|
{Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)},
|
||||||
|
{Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.SelectorSpread, Weight: pointer.Int32Ptr(1)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Reserve: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreBind: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bind: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.DefaultBinder},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
for k, v := range test.features {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, k, v)()
|
||||||
|
}
|
||||||
|
|
||||||
|
gotConfig := getDefaultPlugins()
|
||||||
|
if diff := cmp.Diff(test.wantConfig, gotConfig); diff != "" {
|
||||||
|
t.Errorf("unexpected config diff (-want, +got): %s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergePlugins(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
customPlugins *v1beta1.Plugins
|
||||||
|
defaultPlugins *v1beta1.Plugins
|
||||||
|
expectedPlugins *v1beta1.Plugins
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "AppendCustomPlugin",
|
||||||
|
customPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "InsertAfterDefaultPlugins2",
|
||||||
|
customPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
Disabled: []v1beta1.Plugin{
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "InsertBeforeAllPlugins",
|
||||||
|
customPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
Disabled: []v1beta1.Plugin{
|
||||||
|
{Name: "*"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ReorderDefaultPlugins",
|
||||||
|
customPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
},
|
||||||
|
Disabled: []v1beta1.Plugin{
|
||||||
|
{Name: "*"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ApplyNilCustomPlugin",
|
||||||
|
customPlugins: nil,
|
||||||
|
defaultPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedPlugins: &v1beta1.Plugins{
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
test.defaultPlugins = mergePlugins(test.defaultPlugins, test.customPlugins)
|
||||||
|
if d := cmp.Diff(test.expectedPlugins, test.defaultPlugins); d != "" {
|
||||||
|
t.Fatalf("plugins mismatch (-want +got):\n%s", d)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apiserver/pkg/util/feature"
|
"k8s.io/apiserver/pkg/util/feature"
|
||||||
componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1"
|
componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1"
|
||||||
"k8s.io/kube-scheduler/config/v1beta1"
|
"k8s.io/kube-scheduler/config/v1beta1"
|
||||||
@ -39,9 +40,72 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
|||||||
return RegisterDefaults(scheme)
|
return RegisterDefaults(scheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pluginsNames(p *v1beta1.Plugins) []string {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
extensions := []*v1beta1.PluginSet{
|
||||||
|
p.PreFilter,
|
||||||
|
p.Filter,
|
||||||
|
p.PostFilter,
|
||||||
|
p.Reserve,
|
||||||
|
p.PreScore,
|
||||||
|
p.Score,
|
||||||
|
p.PreBind,
|
||||||
|
p.Bind,
|
||||||
|
p.PostBind,
|
||||||
|
p.Permit,
|
||||||
|
p.QueueSort,
|
||||||
|
}
|
||||||
|
n := sets.NewString()
|
||||||
|
for _, e := range extensions {
|
||||||
|
if e != nil {
|
||||||
|
for _, pg := range e.Enabled {
|
||||||
|
n.Insert(pg.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n.List()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setDefaults_KubeSchedulerProfile(prof *v1beta1.KubeSchedulerProfile) {
|
||||||
|
// Set default plugins.
|
||||||
|
prof.Plugins = mergePlugins(getDefaultPlugins(), prof.Plugins)
|
||||||
|
|
||||||
|
// Set default plugin configs.
|
||||||
|
scheme := getPluginArgConversionScheme()
|
||||||
|
existingConfigs := sets.NewString()
|
||||||
|
for j := range prof.PluginConfig {
|
||||||
|
existingConfigs.Insert(prof.PluginConfig[j].Name)
|
||||||
|
args := prof.PluginConfig[j].Args.Object
|
||||||
|
if _, isUnknown := args.(*runtime.Unknown); isUnknown {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
scheme.Default(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append default configs for plugins that didn't have one explicitly set.
|
||||||
|
for _, name := range pluginsNames(prof.Plugins) {
|
||||||
|
if existingConfigs.Has(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gvk := v1beta1.SchemeGroupVersion.WithKind(name + "Args")
|
||||||
|
args, err := scheme.New(gvk)
|
||||||
|
if err != nil {
|
||||||
|
// This plugin is out-of-tree or doesn't require configuration.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
scheme.Default(args)
|
||||||
|
args.GetObjectKind().SetGroupVersionKind(gvk)
|
||||||
|
prof.PluginConfig = append(prof.PluginConfig, v1beta1.PluginConfig{
|
||||||
|
Name: name,
|
||||||
|
Args: runtime.RawExtension{Object: args},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaults_KubeSchedulerConfiguration sets additional defaults
|
// SetDefaults_KubeSchedulerConfiguration sets additional defaults
|
||||||
func SetDefaults_KubeSchedulerConfiguration(obj *v1beta1.KubeSchedulerConfiguration) {
|
func SetDefaults_KubeSchedulerConfiguration(obj *v1beta1.KubeSchedulerConfiguration) {
|
||||||
|
|
||||||
if obj.Parallelism == nil {
|
if obj.Parallelism == nil {
|
||||||
obj.Parallelism = pointer.Int32Ptr(16)
|
obj.Parallelism = pointer.Int32Ptr(16)
|
||||||
}
|
}
|
||||||
@ -55,6 +119,12 @@ func SetDefaults_KubeSchedulerConfiguration(obj *v1beta1.KubeSchedulerConfigurat
|
|||||||
obj.Profiles[0].SchedulerName = pointer.StringPtr(corev1.DefaultSchedulerName)
|
obj.Profiles[0].SchedulerName = pointer.StringPtr(corev1.DefaultSchedulerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the default set of plugins and apply the configuration.
|
||||||
|
for i := range obj.Profiles {
|
||||||
|
prof := &obj.Profiles[i]
|
||||||
|
setDefaults_KubeSchedulerProfile(prof)
|
||||||
|
}
|
||||||
|
|
||||||
// For Healthz and Metrics bind addresses, we want to check:
|
// For Healthz and Metrics bind addresses, we want to check:
|
||||||
// 1. If the value is nil, default to 0.0.0.0 and default scheduler port
|
// 1. If the value is nil, default to 0.0.0.0 and default scheduler port
|
||||||
// 2. If there is a value set, attempt to split it. If it's just a port (ie, ":1234"), default to 0.0.0.0 with that port
|
// 2. If there is a value set, attempt to split it. If it's just a port (ie, ":1234"), default to 0.0.0.0 with that port
|
||||||
|
@ -31,9 +31,84 @@ import (
|
|||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
"k8s.io/kube-scheduler/config/v1beta1"
|
"k8s.io/kube-scheduler/config/v1beta1"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
|
||||||
"k8s.io/utils/pointer"
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var pluginConfigs = []v1beta1.PluginConfig{
|
||||||
|
{
|
||||||
|
Name: "DefaultPreemption",
|
||||||
|
Args: runtime.RawExtension{
|
||||||
|
Object: &v1beta1.DefaultPreemptionArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "DefaultPreemptionArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
MinCandidateNodesPercentage: pointer.Int32Ptr(10),
|
||||||
|
MinCandidateNodesAbsolute: pointer.Int32Ptr(100),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "InterPodAffinity",
|
||||||
|
Args: runtime.RawExtension{
|
||||||
|
Object: &v1beta1.InterPodAffinityArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "InterPodAffinityArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
HardPodAffinityWeight: pointer.Int32Ptr(1),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeAffinity",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta1.NodeAffinityArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeAffinityArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesFit",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta1.NodeResourcesFitArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeResourcesFitArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesLeastAllocated",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta1.NodeResourcesLeastAllocatedArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeResourcesLeastAllocatedArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
Resources: []v1beta1.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PodTopologySpread",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta1.PodTopologySpreadArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "PodTopologySpreadArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
DefaultingType: v1beta1.SystemDefaulting,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta1.VolumeBindingArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "VolumeBindingArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
BindTimeoutSeconds: pointer.Int64Ptr(600),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func TestSchedulerDefaults(t *testing.T) {
|
func TestSchedulerDefaults(t *testing.T) {
|
||||||
enable := true
|
enable := true
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -70,20 +145,18 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
||||||
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
||||||
Profiles: []v1beta1.KubeSchedulerProfile{
|
Profiles: []v1beta1.KubeSchedulerProfile{
|
||||||
{SchedulerName: pointer.StringPtr("default-scheduler")},
|
{
|
||||||
|
SchedulerName: pointer.StringPtr("default-scheduler"),
|
||||||
|
Plugins: getDefaultPlugins(),
|
||||||
|
PluginConfig: pluginConfigs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no scheduler name",
|
name: "no scheduler name",
|
||||||
config: &v1beta1.KubeSchedulerConfiguration{
|
config: &v1beta1.KubeSchedulerConfiguration{
|
||||||
Profiles: []v1beta1.KubeSchedulerProfile{
|
Profiles: []v1beta1.KubeSchedulerProfile{{}},
|
||||||
{
|
|
||||||
PluginConfig: []v1beta1.PluginConfig{
|
|
||||||
{Name: "FooPlugin"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
expected: &v1beta1.KubeSchedulerConfiguration{
|
expected: &v1beta1.KubeSchedulerConfiguration{
|
||||||
Parallelism: pointer.Int32Ptr(16),
|
Parallelism: pointer.Int32Ptr(16),
|
||||||
@ -113,9 +186,8 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
Profiles: []v1beta1.KubeSchedulerProfile{
|
Profiles: []v1beta1.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
SchedulerName: pointer.StringPtr("default-scheduler"),
|
SchedulerName: pointer.StringPtr("default-scheduler"),
|
||||||
PluginConfig: []v1beta1.PluginConfig{
|
Plugins: getDefaultPlugins(),
|
||||||
{Name: "FooPlugin"},
|
PluginConfig: pluginConfigs,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -169,19 +241,162 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
||||||
Profiles: []v1beta1.KubeSchedulerProfile{
|
Profiles: []v1beta1.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
|
Plugins: getDefaultPlugins(),
|
||||||
PluginConfig: []v1beta1.PluginConfig{
|
PluginConfig: []v1beta1.PluginConfig{
|
||||||
{Name: "FooPlugin"},
|
{Name: "FooPlugin"},
|
||||||
|
{
|
||||||
|
Name: "DefaultPreemption",
|
||||||
|
Args: runtime.RawExtension{
|
||||||
|
Object: &v1beta1.DefaultPreemptionArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "DefaultPreemptionArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
MinCandidateNodesPercentage: pointer.Int32Ptr(10),
|
||||||
|
MinCandidateNodesAbsolute: pointer.Int32Ptr(100),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "InterPodAffinity",
|
||||||
|
Args: runtime.RawExtension{
|
||||||
|
Object: &v1beta1.InterPodAffinityArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "InterPodAffinityArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
HardPodAffinityWeight: pointer.Int32Ptr(1),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeAffinity",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta1.NodeAffinityArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeAffinityArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesFit",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta1.NodeResourcesFitArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeResourcesFitArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesLeastAllocated",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta1.NodeResourcesLeastAllocatedArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeResourcesLeastAllocatedArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
Resources: []v1beta1.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PodTopologySpread",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta1.PodTopologySpreadArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "PodTopologySpreadArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
DefaultingType: v1beta1.SystemDefaulting,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta1.VolumeBindingArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "VolumeBindingArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta1",
|
||||||
|
},
|
||||||
|
BindTimeoutSeconds: pointer.Int64Ptr(600),
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
SchedulerName: pointer.StringPtr("custom-scheduler"),
|
SchedulerName: pointer.StringPtr("custom-scheduler"),
|
||||||
Plugins: &v1beta1.Plugins{
|
Plugins: &v1beta1.Plugins{
|
||||||
|
QueueSort: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.PrioritySort},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeUnschedulable},
|
||||||
|
{Name: names.NodeName},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.VolumeRestrictions},
|
||||||
|
{Name: names.EBSLimits},
|
||||||
|
{Name: names.GCEPDLimits},
|
||||||
|
{Name: names.NodeVolumeLimits},
|
||||||
|
{Name: names.AzureDiskLimits},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.VolumeZone},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.DefaultPreemption},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreScore: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodePreferAvoidPods, Weight: pointer.Int32Ptr(10000)},
|
||||||
|
{Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)},
|
||||||
|
{Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Reserve: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreBind: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
Bind: &v1beta1.PluginSet{
|
Bind: &v1beta1.PluginSet{
|
||||||
Enabled: []v1beta1.Plugin{
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: names.DefaultBinder},
|
||||||
{Name: "BarPlugin"},
|
{Name: "BarPlugin"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
PluginConfig: pluginConfigs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -219,7 +434,11 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
||||||
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
||||||
Profiles: []v1beta1.KubeSchedulerProfile{
|
Profiles: []v1beta1.KubeSchedulerProfile{
|
||||||
{SchedulerName: pointer.StringPtr("default-scheduler")},
|
{
|
||||||
|
SchedulerName: pointer.StringPtr("default-scheduler"),
|
||||||
|
Plugins: getDefaultPlugins(),
|
||||||
|
PluginConfig: pluginConfigs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -255,7 +474,11 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
||||||
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
||||||
Profiles: []v1beta1.KubeSchedulerProfile{
|
Profiles: []v1beta1.KubeSchedulerProfile{
|
||||||
{SchedulerName: pointer.StringPtr("default-scheduler")},
|
{
|
||||||
|
SchedulerName: pointer.StringPtr("default-scheduler"),
|
||||||
|
Plugins: getDefaultPlugins(),
|
||||||
|
PluginConfig: pluginConfigs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -290,7 +513,11 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
||||||
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
||||||
Profiles: []v1beta1.KubeSchedulerProfile{
|
Profiles: []v1beta1.KubeSchedulerProfile{
|
||||||
{SchedulerName: pointer.StringPtr("default-scheduler")},
|
{
|
||||||
|
SchedulerName: pointer.StringPtr("default-scheduler"),
|
||||||
|
Plugins: getDefaultPlugins(),
|
||||||
|
PluginConfig: pluginConfigs,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -35,7 +35,7 @@ var (
|
|||||||
initPluginArgConversionScheme sync.Once
|
initPluginArgConversionScheme sync.Once
|
||||||
)
|
)
|
||||||
|
|
||||||
func getPluginArgConversionScheme() *runtime.Scheme {
|
func GetPluginArgConversionScheme() *runtime.Scheme {
|
||||||
initPluginArgConversionScheme.Do(func() {
|
initPluginArgConversionScheme.Do(func() {
|
||||||
// set up the scheme used for plugin arg conversion
|
// set up the scheme used for plugin arg conversion
|
||||||
pluginArgConversionScheme = runtime.NewScheme()
|
pluginArgConversionScheme = runtime.NewScheme()
|
||||||
@ -55,22 +55,22 @@ func Convert_v1beta2_KubeSchedulerConfiguration_To_config_KubeSchedulerConfigura
|
|||||||
// convertToInternalPluginConfigArgs converts PluginConfig#Args into internal
|
// convertToInternalPluginConfigArgs converts PluginConfig#Args into internal
|
||||||
// types using a scheme, after applying defaults.
|
// types using a scheme, after applying defaults.
|
||||||
func convertToInternalPluginConfigArgs(out *config.KubeSchedulerConfiguration) error {
|
func convertToInternalPluginConfigArgs(out *config.KubeSchedulerConfiguration) error {
|
||||||
scheme := getPluginArgConversionScheme()
|
scheme := GetPluginArgConversionScheme()
|
||||||
for i := range out.Profiles {
|
for i := range out.Profiles {
|
||||||
for j := range out.Profiles[i].PluginConfig {
|
prof := &out.Profiles[i]
|
||||||
args := out.Profiles[i].PluginConfig[j].Args
|
for j := range prof.PluginConfig {
|
||||||
|
args := prof.PluginConfig[j].Args
|
||||||
if args == nil {
|
if args == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, isUnknown := args.(*runtime.Unknown); isUnknown {
|
if _, isUnknown := args.(*runtime.Unknown); isUnknown {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
scheme.Default(args)
|
|
||||||
internalArgs, err := scheme.ConvertToVersion(args, config.SchemeGroupVersion)
|
internalArgs, err := scheme.ConvertToVersion(args, config.SchemeGroupVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("converting .Profiles[%d].PluginConfig[%d].Args into internal type: %w", i, j, err)
|
return fmt.Errorf("converting .Profiles[%d].PluginConfig[%d].Args into internal type: %w", i, j, err)
|
||||||
}
|
}
|
||||||
out.Profiles[i].PluginConfig[j].Args = internalArgs
|
prof.PluginConfig[j].Args = internalArgs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -86,7 +86,7 @@ func Convert_config_KubeSchedulerConfiguration_To_v1beta2_KubeSchedulerConfigura
|
|||||||
// convertToExternalPluginConfigArgs converts PluginConfig#Args into
|
// convertToExternalPluginConfigArgs converts PluginConfig#Args into
|
||||||
// external (versioned) types using a scheme.
|
// external (versioned) types using a scheme.
|
||||||
func convertToExternalPluginConfigArgs(out *v1beta2.KubeSchedulerConfiguration) error {
|
func convertToExternalPluginConfigArgs(out *v1beta2.KubeSchedulerConfiguration) error {
|
||||||
scheme := getPluginArgConversionScheme()
|
scheme := GetPluginArgConversionScheme()
|
||||||
for i := range out.Profiles {
|
for i := range out.Profiles {
|
||||||
for j := range out.Profiles[i].PluginConfig {
|
for j := range out.Profiles[i].PluginConfig {
|
||||||
args := out.Profiles[i].PluginConfig[j].Args
|
args := out.Profiles[i].PluginConfig[j].Args
|
||||||
|
169
pkg/scheduler/apis/config/v1beta2/default_plugins.go
Normal file
169
pkg/scheduler/apis/config/v1beta2/default_plugins.go
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2021 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 v1beta2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getDefaultPlugins returns the default set of plugins.
|
||||||
|
func getDefaultPlugins() *v1beta2.Plugins {
|
||||||
|
plugins := &v1beta2.Plugins{
|
||||||
|
QueueSort: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.PrioritySort},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeUnschedulable},
|
||||||
|
{Name: names.NodeName},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.VolumeRestrictions},
|
||||||
|
{Name: names.EBSLimits},
|
||||||
|
{Name: names.GCEPDLimits},
|
||||||
|
{Name: names.NodeVolumeLimits},
|
||||||
|
{Name: names.AzureDiskLimits},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.VolumeZone},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.DefaultPreemption},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreScore: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
// Weight is doubled because:
|
||||||
|
// - This is a score coming from user preference.
|
||||||
|
// - It makes its signal comparable to NodeResourcesLeastAllocated.
|
||||||
|
{Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)},
|
||||||
|
{Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Reserve: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreBind: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bind: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.DefaultBinder},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
applyFeatureGates(plugins)
|
||||||
|
|
||||||
|
return plugins
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyFeatureGates(config *v1beta2.Plugins) {
|
||||||
|
if utilfeature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority) {
|
||||||
|
config.Score.Enabled = append(config.Score.Enabled, v1beta2.Plugin{Name: names.VolumeBinding, Weight: pointer.Int32Ptr(1)})
|
||||||
|
}
|
||||||
|
|
||||||
|
if !utilfeature.DefaultFeatureGate.Enabled(features.DefaultPodTopologySpread) {
|
||||||
|
// When feature is enabled, the default spreading is done by
|
||||||
|
// PodTopologySpread plugin, which is enabled by default.
|
||||||
|
klog.InfoS("Registering SelectorSpread plugin")
|
||||||
|
s := v1beta2.Plugin{Name: names.SelectorSpread}
|
||||||
|
config.PreScore.Enabled = append(config.PreScore.Enabled, s)
|
||||||
|
s.Weight = pointer.Int32Ptr(1)
|
||||||
|
config.Score.Enabled = append(config.Score.Enabled, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergePlugins merges the custom set into the given default one, handling disabled sets.
|
||||||
|
func mergePlugins(defaultPlugins, customPlugins *v1beta2.Plugins) *v1beta2.Plugins {
|
||||||
|
if customPlugins == nil {
|
||||||
|
return defaultPlugins
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultPlugins.QueueSort = mergePluginSet(defaultPlugins.QueueSort, customPlugins.QueueSort)
|
||||||
|
defaultPlugins.PreFilter = mergePluginSet(defaultPlugins.PreFilter, customPlugins.PreFilter)
|
||||||
|
defaultPlugins.Filter = mergePluginSet(defaultPlugins.Filter, customPlugins.Filter)
|
||||||
|
defaultPlugins.PostFilter = mergePluginSet(defaultPlugins.PostFilter, customPlugins.PostFilter)
|
||||||
|
defaultPlugins.PreScore = mergePluginSet(defaultPlugins.PreScore, customPlugins.PreScore)
|
||||||
|
defaultPlugins.Score = mergePluginSet(defaultPlugins.Score, customPlugins.Score)
|
||||||
|
defaultPlugins.Reserve = mergePluginSet(defaultPlugins.Reserve, customPlugins.Reserve)
|
||||||
|
defaultPlugins.Permit = mergePluginSet(defaultPlugins.Permit, customPlugins.Permit)
|
||||||
|
defaultPlugins.PreBind = mergePluginSet(defaultPlugins.PreBind, customPlugins.PreBind)
|
||||||
|
defaultPlugins.Bind = mergePluginSet(defaultPlugins.Bind, customPlugins.Bind)
|
||||||
|
defaultPlugins.PostBind = mergePluginSet(defaultPlugins.PostBind, customPlugins.PostBind)
|
||||||
|
return defaultPlugins
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergePluginSet(defaultPluginSet, customPluginSet v1beta2.PluginSet) v1beta2.PluginSet {
|
||||||
|
disabledPlugins := sets.NewString()
|
||||||
|
for _, disabledPlugin := range customPluginSet.Disabled {
|
||||||
|
disabledPlugins.Insert(disabledPlugin.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
var enabledPlugins []v1beta2.Plugin
|
||||||
|
if !disabledPlugins.Has("*") {
|
||||||
|
for _, defaultEnabledPlugin := range defaultPluginSet.Enabled {
|
||||||
|
if disabledPlugins.Has(defaultEnabledPlugin.Name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
enabledPlugins = append(enabledPlugins, defaultEnabledPlugin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enabledPlugins = append(enabledPlugins, customPluginSet.Enabled...)
|
||||||
|
return v1beta2.PluginSet{Enabled: enabledPlugins}
|
||||||
|
}
|
372
pkg/scheduler/apis/config/v1beta2/default_plugins_test.go
Normal file
372
pkg/scheduler/apis/config/v1beta2/default_plugins_test.go
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
/*
|
||||||
|
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 v1beta2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"k8s.io/apiserver/pkg/util/feature"
|
||||||
|
"k8s.io/component-base/featuregate"
|
||||||
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestApplyFeatureGates(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
features map[featuregate.Feature]bool
|
||||||
|
wantConfig *v1beta2.Plugins
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Feature gates disabled",
|
||||||
|
wantConfig: &v1beta2.Plugins{
|
||||||
|
QueueSort: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.PrioritySort},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeUnschedulable},
|
||||||
|
{Name: names.NodeName},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.VolumeRestrictions},
|
||||||
|
{Name: names.EBSLimits},
|
||||||
|
{Name: names.GCEPDLimits},
|
||||||
|
{Name: names.NodeVolumeLimits},
|
||||||
|
{Name: names.AzureDiskLimits},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.VolumeZone},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.DefaultPreemption},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreScore: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)},
|
||||||
|
{Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Reserve: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreBind: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bind: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.DefaultBinder},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DefaultPodTopologySpread disabled",
|
||||||
|
features: map[featuregate.Feature]bool{
|
||||||
|
features.DefaultPodTopologySpread: false,
|
||||||
|
},
|
||||||
|
wantConfig: &v1beta2.Plugins{
|
||||||
|
QueueSort: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.PrioritySort},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeUnschedulable},
|
||||||
|
{Name: names.NodeName},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.VolumeRestrictions},
|
||||||
|
{Name: names.EBSLimits},
|
||||||
|
{Name: names.GCEPDLimits},
|
||||||
|
{Name: names.NodeVolumeLimits},
|
||||||
|
{Name: names.AzureDiskLimits},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.VolumeZone},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.DefaultPreemption},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreScore: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.SelectorSpread},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)},
|
||||||
|
{Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.SelectorSpread, Weight: pointer.Int32Ptr(1)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Reserve: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreBind: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Bind: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.DefaultBinder},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
for k, v := range test.features {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, k, v)()
|
||||||
|
}
|
||||||
|
|
||||||
|
gotConfig := getDefaultPlugins()
|
||||||
|
if diff := cmp.Diff(test.wantConfig, gotConfig); diff != "" {
|
||||||
|
t.Errorf("unexpected config diff (-want, +got): %s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergePlugins(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
customPlugins *v1beta2.Plugins
|
||||||
|
defaultPlugins *v1beta2.Plugins
|
||||||
|
expectedPlugins *v1beta2.Plugins
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "AppendCustomPlugin",
|
||||||
|
customPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "InsertAfterDefaultPlugins2",
|
||||||
|
customPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
Disabled: []v1beta2.Plugin{
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "InsertBeforeAllPlugins",
|
||||||
|
customPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
Disabled: []v1beta2.Plugin{
|
||||||
|
{Name: "*"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "CustomPlugin"},
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ReorderDefaultPlugins",
|
||||||
|
customPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
},
|
||||||
|
Disabled: []v1beta2.Plugin{
|
||||||
|
{Name: "*"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ApplyNilCustomPlugin",
|
||||||
|
customPlugins: nil,
|
||||||
|
defaultPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedPlugins: &v1beta2.Plugins{
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "DefaultPlugin1"},
|
||||||
|
{Name: "DefaultPlugin2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
test.defaultPlugins = mergePlugins(test.defaultPlugins, test.customPlugins)
|
||||||
|
if d := cmp.Diff(test.expectedPlugins, test.defaultPlugins); d != "" {
|
||||||
|
t.Fatalf("plugins mismatch (-want +got):\n%s", d)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ import (
|
|||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apiserver/pkg/util/feature"
|
"k8s.io/apiserver/pkg/util/feature"
|
||||||
componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1"
|
componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1"
|
||||||
"k8s.io/kube-scheduler/config/v1beta2"
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
@ -40,9 +41,70 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error {
|
|||||||
return RegisterDefaults(scheme)
|
return RegisterDefaults(scheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pluginsNames(p *v1beta2.Plugins) []string {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
extensions := []v1beta2.PluginSet{
|
||||||
|
p.PreFilter,
|
||||||
|
p.Filter,
|
||||||
|
p.PostFilter,
|
||||||
|
p.Reserve,
|
||||||
|
p.PreScore,
|
||||||
|
p.Score,
|
||||||
|
p.PreBind,
|
||||||
|
p.Bind,
|
||||||
|
p.PostBind,
|
||||||
|
p.Permit,
|
||||||
|
p.QueueSort,
|
||||||
|
}
|
||||||
|
n := sets.NewString()
|
||||||
|
for _, e := range extensions {
|
||||||
|
for _, pg := range e.Enabled {
|
||||||
|
n.Insert(pg.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n.List()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setDefaults_KubeSchedulerProfile(prof *v1beta2.KubeSchedulerProfile) {
|
||||||
|
// Set default plugins.
|
||||||
|
prof.Plugins = mergePlugins(getDefaultPlugins(), prof.Plugins)
|
||||||
|
|
||||||
|
// Set default plugin configs.
|
||||||
|
scheme := GetPluginArgConversionScheme()
|
||||||
|
existingConfigs := sets.NewString()
|
||||||
|
for j := range prof.PluginConfig {
|
||||||
|
existingConfigs.Insert(prof.PluginConfig[j].Name)
|
||||||
|
args := prof.PluginConfig[j].Args.Object
|
||||||
|
if _, isUnknown := args.(*runtime.Unknown); isUnknown {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
scheme.Default(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append default configs for plugins that didn't have one explicitly set.
|
||||||
|
for _, name := range pluginsNames(prof.Plugins) {
|
||||||
|
if existingConfigs.Has(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gvk := v1beta2.SchemeGroupVersion.WithKind(name + "Args")
|
||||||
|
args, err := scheme.New(gvk)
|
||||||
|
if err != nil {
|
||||||
|
// This plugin is out-of-tree or doesn't require configuration.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
scheme.Default(args)
|
||||||
|
args.GetObjectKind().SetGroupVersionKind(gvk)
|
||||||
|
prof.PluginConfig = append(prof.PluginConfig, v1beta2.PluginConfig{
|
||||||
|
Name: name,
|
||||||
|
Args: runtime.RawExtension{Object: args},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaults_KubeSchedulerConfiguration sets additional defaults
|
// SetDefaults_KubeSchedulerConfiguration sets additional defaults
|
||||||
func SetDefaults_KubeSchedulerConfiguration(obj *v1beta2.KubeSchedulerConfiguration) {
|
func SetDefaults_KubeSchedulerConfiguration(obj *v1beta2.KubeSchedulerConfiguration) {
|
||||||
|
|
||||||
if obj.Parallelism == nil {
|
if obj.Parallelism == nil {
|
||||||
obj.Parallelism = pointer.Int32Ptr(16)
|
obj.Parallelism = pointer.Int32Ptr(16)
|
||||||
}
|
}
|
||||||
@ -56,6 +118,12 @@ func SetDefaults_KubeSchedulerConfiguration(obj *v1beta2.KubeSchedulerConfigurat
|
|||||||
obj.Profiles[0].SchedulerName = pointer.StringPtr(v1.DefaultSchedulerName)
|
obj.Profiles[0].SchedulerName = pointer.StringPtr(v1.DefaultSchedulerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the default set of plugins and apply the configuration.
|
||||||
|
for i := range obj.Profiles {
|
||||||
|
prof := &obj.Profiles[i]
|
||||||
|
setDefaults_KubeSchedulerProfile(prof)
|
||||||
|
}
|
||||||
|
|
||||||
// For Healthz and Metrics bind addresses, we want to check:
|
// For Healthz and Metrics bind addresses, we want to check:
|
||||||
// 1. If the value is nil, default to 0.0.0.0 and default scheduler port
|
// 1. If the value is nil, default to 0.0.0.0 and default scheduler port
|
||||||
// 2. If there is a value set, attempt to split it. If it's just a port (ie, ":1234"), default to 0.0.0.0 with that port
|
// 2. If there is a value set, attempt to split it. If it's just a port (ie, ":1234"), default to 0.0.0.0 with that port
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@ -31,9 +32,84 @@ import (
|
|||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
"k8s.io/kube-scheduler/config/v1beta2"
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
|
||||||
"k8s.io/utils/pointer"
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var pluginConfigs = []v1beta2.PluginConfig{
|
||||||
|
{
|
||||||
|
Name: "DefaultPreemption",
|
||||||
|
Args: runtime.RawExtension{
|
||||||
|
Object: &v1beta2.DefaultPreemptionArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "DefaultPreemptionArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
MinCandidateNodesPercentage: pointer.Int32Ptr(10),
|
||||||
|
MinCandidateNodesAbsolute: pointer.Int32Ptr(100),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "InterPodAffinity",
|
||||||
|
Args: runtime.RawExtension{
|
||||||
|
Object: &v1beta2.InterPodAffinityArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "InterPodAffinityArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
HardPodAffinityWeight: pointer.Int32Ptr(1),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeAffinity",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta2.NodeAffinityArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeAffinityArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesFit",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta2.NodeResourcesFitArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeResourcesFitArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesLeastAllocated",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta2.NodeResourcesLeastAllocatedArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeResourcesLeastAllocatedArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
Resources: []v1beta2.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PodTopologySpread",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta2.PodTopologySpreadArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "PodTopologySpreadArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
DefaultingType: v1beta2.SystemDefaulting,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta2.VolumeBindingArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "VolumeBindingArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
BindTimeoutSeconds: pointer.Int64Ptr(600),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func TestSchedulerDefaults(t *testing.T) {
|
func TestSchedulerDefaults(t *testing.T) {
|
||||||
enable := true
|
enable := true
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -70,20 +146,18 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
||||||
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
||||||
Profiles: []v1beta2.KubeSchedulerProfile{
|
Profiles: []v1beta2.KubeSchedulerProfile{
|
||||||
{SchedulerName: pointer.StringPtr("default-scheduler")},
|
{
|
||||||
|
Plugins: getDefaultPlugins(),
|
||||||
|
PluginConfig: pluginConfigs,
|
||||||
|
SchedulerName: pointer.StringPtr("default-scheduler"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no scheduler name",
|
name: "no scheduler name",
|
||||||
config: &v1beta2.KubeSchedulerConfiguration{
|
config: &v1beta2.KubeSchedulerConfiguration{
|
||||||
Profiles: []v1beta2.KubeSchedulerProfile{
|
Profiles: []v1beta2.KubeSchedulerProfile{{}},
|
||||||
{
|
|
||||||
PluginConfig: []v1beta2.PluginConfig{
|
|
||||||
{Name: "FooPlugin"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
expected: &v1beta2.KubeSchedulerConfiguration{
|
expected: &v1beta2.KubeSchedulerConfiguration{
|
||||||
Parallelism: pointer.Int32Ptr(16),
|
Parallelism: pointer.Int32Ptr(16),
|
||||||
@ -113,10 +187,8 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
Profiles: []v1beta2.KubeSchedulerProfile{
|
Profiles: []v1beta2.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
SchedulerName: pointer.StringPtr("default-scheduler"),
|
SchedulerName: pointer.StringPtr("default-scheduler"),
|
||||||
PluginConfig: []v1beta2.PluginConfig{
|
Plugins: getDefaultPlugins(),
|
||||||
{Name: "FooPlugin"},
|
PluginConfig: pluginConfigs},
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -137,6 +209,9 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
Enabled: []v1beta2.Plugin{
|
Enabled: []v1beta2.Plugin{
|
||||||
{Name: "BarPlugin"},
|
{Name: "BarPlugin"},
|
||||||
},
|
},
|
||||||
|
Disabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.DefaultBinder},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -169,19 +244,160 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
||||||
Profiles: []v1beta2.KubeSchedulerProfile{
|
Profiles: []v1beta2.KubeSchedulerProfile{
|
||||||
{
|
{
|
||||||
|
Plugins: getDefaultPlugins(),
|
||||||
PluginConfig: []v1beta2.PluginConfig{
|
PluginConfig: []v1beta2.PluginConfig{
|
||||||
{Name: "FooPlugin"},
|
{Name: "FooPlugin"},
|
||||||
|
{
|
||||||
|
Name: "DefaultPreemption",
|
||||||
|
Args: runtime.RawExtension{
|
||||||
|
Object: &v1beta2.DefaultPreemptionArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "DefaultPreemptionArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
MinCandidateNodesPercentage: pointer.Int32Ptr(10),
|
||||||
|
MinCandidateNodesAbsolute: pointer.Int32Ptr(100),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "InterPodAffinity",
|
||||||
|
Args: runtime.RawExtension{
|
||||||
|
Object: &v1beta2.InterPodAffinityArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "InterPodAffinityArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
HardPodAffinityWeight: pointer.Int32Ptr(1),
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeAffinity",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta2.NodeAffinityArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeAffinityArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesFit",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta2.NodeResourcesFitArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeResourcesFitArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NodeResourcesLeastAllocated",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta2.NodeResourcesLeastAllocatedArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "NodeResourcesLeastAllocatedArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
Resources: []v1beta2.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PodTopologySpread",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta2.PodTopologySpreadArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "PodTopologySpreadArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
DefaultingType: v1beta2.SystemDefaulting,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: runtime.RawExtension{Object: &v1beta2.VolumeBindingArgs{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
Kind: "VolumeBindingArgs",
|
||||||
|
APIVersion: "kubescheduler.config.k8s.io/v1beta2",
|
||||||
|
},
|
||||||
|
BindTimeoutSeconds: pointer.Int64Ptr(600),
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
SchedulerName: pointer.StringPtr("custom-scheduler"),
|
SchedulerName: pointer.StringPtr("custom-scheduler"),
|
||||||
Plugins: &v1beta2.Plugins{
|
Plugins: &v1beta2.Plugins{
|
||||||
|
QueueSort: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.PrioritySort},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Filter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeUnschedulable},
|
||||||
|
{Name: names.NodeName},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
{Name: names.NodePorts},
|
||||||
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.VolumeRestrictions},
|
||||||
|
{Name: names.EBSLimits},
|
||||||
|
{Name: names.GCEPDLimits},
|
||||||
|
{Name: names.NodeVolumeLimits},
|
||||||
|
{Name: names.AzureDiskLimits},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
{Name: names.VolumeZone},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.DefaultPreemption},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreScore: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.InterPodAffinity},
|
||||||
|
{Name: names.PodTopologySpread},
|
||||||
|
{Name: names.TaintToleration},
|
||||||
|
{Name: names.NodeAffinity},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.ImageLocality, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.InterPodAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeResourcesLeastAllocated, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.NodeAffinity, Weight: pointer.Int32Ptr(1)},
|
||||||
|
{Name: names.PodTopologySpread, Weight: pointer.Int32Ptr(2)},
|
||||||
|
{Name: names.TaintToleration, Weight: pointer.Int32Ptr(1)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Reserve: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreBind: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
|
},
|
||||||
|
},
|
||||||
Bind: v1beta2.PluginSet{
|
Bind: v1beta2.PluginSet{
|
||||||
Enabled: []v1beta2.Plugin{
|
Enabled: []v1beta2.Plugin{
|
||||||
{Name: "BarPlugin"},
|
{Name: "BarPlugin"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
PluginConfig: pluginConfigs,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -219,7 +435,11 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
||||||
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
||||||
Profiles: []v1beta2.KubeSchedulerProfile{
|
Profiles: []v1beta2.KubeSchedulerProfile{
|
||||||
{SchedulerName: pointer.StringPtr("default-scheduler")},
|
{
|
||||||
|
Plugins: getDefaultPlugins(),
|
||||||
|
PluginConfig: pluginConfigs,
|
||||||
|
SchedulerName: pointer.StringPtr("default-scheduler"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -255,7 +475,11 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
||||||
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
||||||
Profiles: []v1beta2.KubeSchedulerProfile{
|
Profiles: []v1beta2.KubeSchedulerProfile{
|
||||||
{SchedulerName: pointer.StringPtr("default-scheduler")},
|
{
|
||||||
|
Plugins: getDefaultPlugins(),
|
||||||
|
PluginConfig: pluginConfigs,
|
||||||
|
SchedulerName: pointer.StringPtr("default-scheduler"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -291,7 +515,11 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
||||||
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
||||||
Profiles: []v1beta2.KubeSchedulerProfile{
|
Profiles: []v1beta2.KubeSchedulerProfile{
|
||||||
{SchedulerName: pointer.StringPtr("default-scheduler")},
|
{
|
||||||
|
Plugins: getDefaultPlugins(),
|
||||||
|
PluginConfig: pluginConfigs,
|
||||||
|
SchedulerName: pointer.StringPtr("default-scheduler"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -326,7 +554,11 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
|
||||||
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
|
||||||
Profiles: []v1beta2.KubeSchedulerProfile{
|
Profiles: []v1beta2.KubeSchedulerProfile{
|
||||||
{SchedulerName: pointer.StringPtr("default-scheduler")},
|
{
|
||||||
|
Plugins: getDefaultPlugins(),
|
||||||
|
PluginConfig: pluginConfigs,
|
||||||
|
SchedulerName: pointer.StringPtr("default-scheduler"),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -33,8 +33,8 @@ import (
|
|||||||
corelisters "k8s.io/client-go/listers/core/v1"
|
corelisters "k8s.io/client-go/listers/core/v1"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/algorithmprovider"
|
|
||||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
|
"k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/core"
|
"k8s.io/kubernetes/pkg/scheduler/core"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework"
|
"k8s.io/kubernetes/pkg/scheduler/framework"
|
||||||
@ -120,20 +120,30 @@ func (c *Configurator) create() (*Scheduler, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If there are any extended resources found from the Extenders, append them to the pluginConfig for each profile.
|
// If there are any extended resources found from the Extenders, append them to the pluginConfig for each profile.
|
||||||
// This should only have an effect on ComponentConfig v1beta1, where it is possible to configure Extenders and
|
// This should only have an effect on ComponentConfig, where it is possible to configure Extenders and
|
||||||
// plugin args (and in which case the extender ignored resources take precedence).
|
// plugin args (and in which case the extender ignored resources take precedence).
|
||||||
// For earlier versions, using both policy and custom plugin config is disallowed, so this should be the only
|
// For earlier versions, using both policy and custom plugin config is disallowed, so this should be the only
|
||||||
// plugin config for this plugin.
|
// plugin config for this plugin.
|
||||||
if len(ignoredExtendedResources) > 0 {
|
if len(ignoredExtendedResources) > 0 {
|
||||||
for i := range c.profiles {
|
for i := range c.profiles {
|
||||||
prof := &c.profiles[i]
|
prof := &c.profiles[i]
|
||||||
pc := schedulerapi.PluginConfig{
|
var found = false
|
||||||
Name: noderesources.FitName,
|
for k := range prof.PluginConfig {
|
||||||
Args: &schedulerapi.NodeResourcesFitArgs{
|
if prof.PluginConfig[k].Name == noderesources.FitName {
|
||||||
IgnoredResources: ignoredExtendedResources,
|
// Update the existing args
|
||||||
},
|
pc := &prof.PluginConfig[k]
|
||||||
|
args, ok := pc.Args.(*schedulerapi.NodeResourcesFitArgs)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("want args to be of type NodeResourcesFitArgs, got %T", pc.Args)
|
||||||
|
}
|
||||||
|
args.IgnoredResources = ignoredExtendedResources
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("can't find NodeResourcesFitArgs in plugin config")
|
||||||
}
|
}
|
||||||
prof.PluginConfig = append(prof.PluginConfig, pc)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,21 +205,7 @@ func (c *Configurator) create() (*Scheduler, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createFromConfig creates a scheduler from ComonentConfig profiles.
|
// createFromPolicy creates a scheduler from the legacy policy file.
|
||||||
func (c *Configurator) createFromConfig() (*Scheduler, error) {
|
|
||||||
defaultPlugins := algorithmprovider.GetDefaultConfig()
|
|
||||||
|
|
||||||
for i := range c.profiles {
|
|
||||||
prof := &c.profiles[i]
|
|
||||||
plugins := &schedulerapi.Plugins{}
|
|
||||||
plugins.Append(defaultPlugins)
|
|
||||||
plugins.Apply(prof.Plugins)
|
|
||||||
prof.Plugins = plugins
|
|
||||||
}
|
|
||||||
return c.create()
|
|
||||||
}
|
|
||||||
|
|
||||||
// createFromPolicy creates a scheduler from the legacy policy file
|
|
||||||
func (c *Configurator) createFromPolicy(policy schedulerapi.Policy) (*Scheduler, error) {
|
func (c *Configurator) createFromPolicy(policy schedulerapi.Policy) (*Scheduler, error) {
|
||||||
lr := frameworkplugins.NewLegacyRegistry()
|
lr := frameworkplugins.NewLegacyRegistry()
|
||||||
args := &frameworkplugins.ConfigProducerArgs{}
|
args := &frameworkplugins.ConfigProducerArgs{}
|
||||||
@ -221,6 +217,12 @@ func (c *Configurator) createFromPolicy(policy schedulerapi.Policy) (*Scheduler,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If profiles is already set, it means the user is using both CC and policy config, error out
|
||||||
|
// since these configs are no longer merged and they should not be used simultaneously.
|
||||||
|
if c.profiles != nil {
|
||||||
|
return nil, fmt.Errorf("profiles and policy config both set, this should not happen")
|
||||||
|
}
|
||||||
|
|
||||||
predicateKeys := sets.NewString()
|
predicateKeys := sets.NewString()
|
||||||
if policy.Predicates == nil {
|
if policy.Predicates == nil {
|
||||||
predicateKeys = lr.DefaultPredicates
|
predicateKeys = lr.DefaultPredicates
|
||||||
@ -297,17 +299,59 @@ func (c *Configurator) createFromPolicy(policy schedulerapi.Policy) (*Scheduler,
|
|||||||
if pluginConfig, err = dedupPluginConfigs(pluginConfig); err != nil {
|
if pluginConfig, err = dedupPluginConfigs(pluginConfig); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for i := range c.profiles {
|
|
||||||
prof := &c.profiles[i]
|
c.profiles = []schedulerapi.KubeSchedulerProfile{
|
||||||
// Plugins and PluginConfig are empty when using Policy; overriding.
|
{
|
||||||
prof.Plugins = &schedulerapi.Plugins{}
|
SchedulerName: v1.DefaultSchedulerName,
|
||||||
prof.Plugins.Append(&plugins)
|
Plugins: &plugins,
|
||||||
prof.PluginConfig = pluginConfig
|
PluginConfig: pluginConfig,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := defaultPluginConfigArgs(&c.profiles[0]); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.create()
|
return c.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func defaultPluginConfigArgs(prof *schedulerapi.KubeSchedulerProfile) error {
|
||||||
|
scheme := v1beta2.GetPluginArgConversionScheme()
|
||||||
|
existingConfigs := sets.NewString()
|
||||||
|
for j := range prof.PluginConfig {
|
||||||
|
existingConfigs.Insert(prof.PluginConfig[j].Name)
|
||||||
|
// For existing plugin configs, we don't apply any defaulting, the assumption
|
||||||
|
// is that the legacy registry does it already.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append default configs for plugins that didn't have one explicitly set.
|
||||||
|
for _, name := range prof.Plugins.Names() {
|
||||||
|
if existingConfigs.Has(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gvk := v1beta2.SchemeGroupVersion.WithKind(name + "Args")
|
||||||
|
args, err := scheme.New(gvk)
|
||||||
|
if err != nil {
|
||||||
|
if runtime.IsNotRegisteredError(err) {
|
||||||
|
// This plugin is out-of-tree or doesn't require configuration.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
scheme.Default(args)
|
||||||
|
internalArgs, err := scheme.ConvertToVersion(args, schedulerapi.SchemeGroupVersion)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("converting %q into internal type: %w", gvk.Kind, err)
|
||||||
|
}
|
||||||
|
prof.PluginConfig = append(prof.PluginConfig, schedulerapi.PluginConfig{
|
||||||
|
Name: name,
|
||||||
|
Args: internalArgs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// dedupPluginConfigs removes duplicates from pluginConfig, ensuring that,
|
// dedupPluginConfigs removes duplicates from pluginConfig, ensuring that,
|
||||||
// if a plugin name is repeated, the arguments are the same.
|
// if a plugin name is repeated, the arguments are the same.
|
||||||
func dedupPluginConfigs(pc []schedulerapi.PluginConfig) ([]schedulerapi.PluginConfig, error) {
|
func dedupPluginConfigs(pc []schedulerapi.PluginConfig) ([]schedulerapi.PluginConfig, error) {
|
||||||
|
@ -64,7 +64,7 @@ func TestCreate(t *testing.T) {
|
|||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
defer close(stopCh)
|
defer close(stopCh)
|
||||||
factory := newConfigFactory(client, stopCh)
|
factory := newConfigFactory(client, stopCh)
|
||||||
if _, err := factory.createFromConfig(); err != nil {
|
if _, err := factory.create(); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -402,6 +402,7 @@ func TestCreateFromConfig(t *testing.T) {
|
|||||||
informerFactory,
|
informerFactory,
|
||||||
recorderFactory,
|
recorderFactory,
|
||||||
make(chan struct{}),
|
make(chan struct{}),
|
||||||
|
WithProfiles([]schedulerapi.KubeSchedulerProfile(nil)...),
|
||||||
WithLegacyPolicySource(createPolicySource(tc.configData, client)),
|
WithLegacyPolicySource(createPolicySource(tc.configData, client)),
|
||||||
WithBuildFrameworkCapturer(func(p schedulerapi.KubeSchedulerProfile) {
|
WithBuildFrameworkCapturer(func(p schedulerapi.KubeSchedulerProfile) {
|
||||||
if p.SchedulerName != v1.DefaultSchedulerName {
|
if p.SchedulerName != v1.DefaultSchedulerName {
|
||||||
@ -641,7 +642,13 @@ func newConfigFactoryWithFrameworkRegistry(
|
|||||||
StopEverything: stopCh,
|
StopEverything: stopCh,
|
||||||
registry: registry,
|
registry: registry,
|
||||||
profiles: []schedulerapi.KubeSchedulerProfile{
|
profiles: []schedulerapi.KubeSchedulerProfile{
|
||||||
{SchedulerName: testSchedulerName},
|
{
|
||||||
|
SchedulerName: testSchedulerName,
|
||||||
|
Plugins: &schedulerapi.Plugins{
|
||||||
|
QueueSort: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "PrioritySort"}}},
|
||||||
|
Bind: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "DefaultBinder"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
recorderFactory: recorderFactory,
|
recorderFactory: recorderFactory,
|
||||||
nodeInfoSnapshot: snapshot,
|
nodeInfoSnapshot: snapshot,
|
||||||
|
@ -525,7 +525,7 @@ type Framework interface {
|
|||||||
HasScorePlugins() bool
|
HasScorePlugins() bool
|
||||||
|
|
||||||
// ListPlugins returns a map of extension point name to list of configured Plugins.
|
// ListPlugins returns a map of extension point name to list of configured Plugins.
|
||||||
ListPlugins() map[string][]config.Plugin
|
ListPlugins() *config.Plugins
|
||||||
|
|
||||||
// ProfileName returns the profile name associated to this framework.
|
// ProfileName returns the profile name associated to this framework.
|
||||||
ProfileName() string
|
ProfileName() string
|
||||||
|
@ -25,7 +25,6 @@ import (
|
|||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
@ -34,10 +33,7 @@ import (
|
|||||||
"k8s.io/client-go/tools/events"
|
"k8s.io/client-go/tools/events"
|
||||||
"k8s.io/component-helpers/scheduling/corev1"
|
"k8s.io/component-helpers/scheduling/corev1"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
"k8s.io/kube-scheduler/config/v1beta1"
|
|
||||||
"k8s.io/kube-scheduler/config/v1beta2"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework"
|
"k8s.io/kubernetes/pkg/scheduler/framework"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/internal/parallelize"
|
"k8s.io/kubernetes/pkg/scheduler/internal/parallelize"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/metrics"
|
"k8s.io/kubernetes/pkg/scheduler/metrics"
|
||||||
@ -72,8 +68,6 @@ var allClusterEvents = []framework.ClusterEvent{
|
|||||||
{Resource: framework.StorageClass, ActionType: framework.All},
|
{Resource: framework.StorageClass, ActionType: framework.All},
|
||||||
}
|
}
|
||||||
|
|
||||||
var configDecoder = scheme.Codecs.UniversalDecoder()
|
|
||||||
|
|
||||||
// frameworkImpl is the component responsible for initializing and running scheduler
|
// frameworkImpl is the component responsible for initializing and running scheduler
|
||||||
// plugins.
|
// plugins.
|
||||||
type frameworkImpl struct {
|
type frameworkImpl struct {
|
||||||
@ -116,7 +110,7 @@ type frameworkImpl struct {
|
|||||||
// frameworkImpl.
|
// frameworkImpl.
|
||||||
type extensionPoint struct {
|
type extensionPoint struct {
|
||||||
// the set of plugins to be configured at this extension point.
|
// the set of plugins to be configured at this extension point.
|
||||||
plugins config.PluginSet
|
plugins *config.PluginSet
|
||||||
// a pointer to the slice storing plugins implementations that will run at this
|
// a pointer to the slice storing plugins implementations that will run at this
|
||||||
// extension point.
|
// extension point.
|
||||||
slicePtr interface{}
|
slicePtr interface{}
|
||||||
@ -124,17 +118,17 @@ type extensionPoint struct {
|
|||||||
|
|
||||||
func (f *frameworkImpl) getExtensionPoints(plugins *config.Plugins) []extensionPoint {
|
func (f *frameworkImpl) getExtensionPoints(plugins *config.Plugins) []extensionPoint {
|
||||||
return []extensionPoint{
|
return []extensionPoint{
|
||||||
{plugins.PreFilter, &f.preFilterPlugins},
|
{&plugins.PreFilter, &f.preFilterPlugins},
|
||||||
{plugins.Filter, &f.filterPlugins},
|
{&plugins.Filter, &f.filterPlugins},
|
||||||
{plugins.PostFilter, &f.postFilterPlugins},
|
{&plugins.PostFilter, &f.postFilterPlugins},
|
||||||
{plugins.Reserve, &f.reservePlugins},
|
{&plugins.Reserve, &f.reservePlugins},
|
||||||
{plugins.PreScore, &f.preScorePlugins},
|
{&plugins.PreScore, &f.preScorePlugins},
|
||||||
{plugins.Score, &f.scorePlugins},
|
{&plugins.Score, &f.scorePlugins},
|
||||||
{plugins.PreBind, &f.preBindPlugins},
|
{&plugins.PreBind, &f.preBindPlugins},
|
||||||
{plugins.Bind, &f.bindPlugins},
|
{&plugins.Bind, &f.bindPlugins},
|
||||||
{plugins.PostBind, &f.postBindPlugins},
|
{&plugins.PostBind, &f.postBindPlugins},
|
||||||
{plugins.Permit, &f.permitPlugins},
|
{&plugins.Permit, &f.permitPlugins},
|
||||||
{plugins.QueueSort, &f.queueSortPlugins},
|
{&plugins.QueueSort, &f.queueSortPlugins},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,10 +329,7 @@ func NewFramework(r Registry, profile *config.KubeSchedulerProfile, opts ...Opti
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
args, err := getPluginArgsOrDefault(options.componentConfigVersion, pluginConfig, name)
|
args := pluginConfig[name]
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("getting args for Plugin %q: %w", name, err)
|
|
||||||
}
|
|
||||||
if args != nil {
|
if args != nil {
|
||||||
outputProfile.PluginConfig = append(outputProfile.PluginConfig, config.PluginConfig{
|
outputProfile.PluginConfig = append(outputProfile.PluginConfig, config.PluginConfig{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -356,7 +347,7 @@ func NewFramework(r Registry, profile *config.KubeSchedulerProfile, opts ...Opti
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range f.getExtensionPoints(profile.Plugins) {
|
for _, e := range f.getExtensionPoints(profile.Plugins) {
|
||||||
if err := updatePluginList(e.slicePtr, e.plugins, pluginsMap); err != nil {
|
if err := updatePluginList(e.slicePtr, *e.plugins, pluginsMap); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -424,34 +415,6 @@ func registerClusterEvents(name string, eventToPlugins map[framework.ClusterEven
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPluginArgsOrDefault returns a configuration provided by the user or builds
|
|
||||||
// a default from the scheme. Returns `nil, nil` if the plugin does not have a
|
|
||||||
// defined arg types, such as in-tree plugins that don't require configuration
|
|
||||||
// or out-of-tree plugins.
|
|
||||||
func getPluginArgsOrDefault(componentConfigVersion string, pluginConfig map[string]runtime.Object, name string) (runtime.Object, error) {
|
|
||||||
res, ok := pluginConfig[name]
|
|
||||||
if ok {
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
// Use defaults from latest config API version.
|
|
||||||
var gvk schema.GroupVersionKind
|
|
||||||
switch componentConfigVersion {
|
|
||||||
case v1beta1.SchemeGroupVersion.String():
|
|
||||||
gvk = v1beta1.SchemeGroupVersion.WithKind(name + "Args")
|
|
||||||
case v1beta2.SchemeGroupVersion.String():
|
|
||||||
gvk = v1beta2.SchemeGroupVersion.WithKind(name + "Args")
|
|
||||||
default:
|
|
||||||
// default to v1beta2 (latest API)
|
|
||||||
gvk = v1beta2.SchemeGroupVersion.WithKind(name + "Args")
|
|
||||||
}
|
|
||||||
obj, _, err := configDecoder.Decode(nil, &gvk, nil)
|
|
||||||
if runtime.IsNotRegisteredError(err) {
|
|
||||||
// This plugin is out-of-tree or doesn't require configuration.
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return obj, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func updatePluginList(pluginList interface{}, pluginSet config.PluginSet, pluginsMap map[string]framework.Plugin) error {
|
func updatePluginList(pluginList interface{}, pluginSet config.PluginSet, pluginsMap map[string]framework.Plugin) error {
|
||||||
plugins := reflect.ValueOf(pluginList).Elem()
|
plugins := reflect.ValueOf(pluginList).Elem()
|
||||||
pluginType := plugins.Type().Elem()
|
pluginType := plugins.Type().Elem()
|
||||||
@ -1153,10 +1116,10 @@ func (f *frameworkImpl) HasScorePlugins() bool {
|
|||||||
|
|
||||||
// ListPlugins returns a map of extension point name to plugin names configured at each extension
|
// ListPlugins returns a map of extension point name to plugin names configured at each extension
|
||||||
// point. Returns nil if no plugins where configured.
|
// point. Returns nil if no plugins where configured.
|
||||||
func (f *frameworkImpl) ListPlugins() map[string][]config.Plugin {
|
func (f *frameworkImpl) ListPlugins() *config.Plugins {
|
||||||
m := make(map[string][]config.Plugin)
|
m := config.Plugins{}
|
||||||
|
|
||||||
for _, e := range f.getExtensionPoints(&config.Plugins{}) {
|
for _, e := range f.getExtensionPoints(&m) {
|
||||||
plugins := reflect.ValueOf(e.slicePtr).Elem()
|
plugins := reflect.ValueOf(e.slicePtr).Elem()
|
||||||
extName := plugins.Type().Elem().Name()
|
extName := plugins.Type().Elem().Name()
|
||||||
var cfgs []config.Plugin
|
var cfgs []config.Plugin
|
||||||
@ -1170,13 +1133,10 @@ func (f *frameworkImpl) ListPlugins() map[string][]config.Plugin {
|
|||||||
cfgs = append(cfgs, p)
|
cfgs = append(cfgs, p)
|
||||||
}
|
}
|
||||||
if len(cfgs) > 0 {
|
if len(cfgs) > 0 {
|
||||||
m[extName] = cfgs
|
e.plugins.Enabled = cfgs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(m) > 0 {
|
return &m
|
||||||
return m
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientSet returns a kubernetes clientset.
|
// ClientSet returns a kubernetes clientset.
|
||||||
@ -1206,7 +1166,7 @@ func (f *frameworkImpl) pluginsNeeded(plugins *config.Plugins) map[string]config
|
|||||||
return pgMap
|
return pgMap
|
||||||
}
|
}
|
||||||
|
|
||||||
find := func(pgs config.PluginSet) {
|
find := func(pgs *config.PluginSet) {
|
||||||
for _, pg := range pgs.Enabled {
|
for _, pg := range pgs.Enabled {
|
||||||
pgMap[pg.Name] = pg
|
pgMap[pg.Name] = pg
|
||||||
}
|
}
|
||||||
|
@ -378,23 +378,13 @@ func newFrameworkWithQueueSortAndBind(r Registry, profile config.KubeSchedulerPr
|
|||||||
if _, ok := r[bindPlugin]; !ok {
|
if _, ok := r[bindPlugin]; !ok {
|
||||||
r[bindPlugin] = newBindPlugin
|
r[bindPlugin] = newBindPlugin
|
||||||
}
|
}
|
||||||
plugins := &config.Plugins{}
|
|
||||||
plugins.Append(profile.Plugins)
|
if len(profile.Plugins.QueueSort.Enabled) == 0 {
|
||||||
if len(plugins.QueueSort.Enabled) == 0 {
|
profile.Plugins.QueueSort.Enabled = append(profile.Plugins.QueueSort.Enabled, config.Plugin{Name: queueSortPlugin})
|
||||||
plugins.Append(&config.Plugins{
|
|
||||||
QueueSort: config.PluginSet{
|
|
||||||
Enabled: []config.Plugin{{Name: queueSortPlugin}},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if len(plugins.Bind.Enabled) == 0 {
|
if len(profile.Plugins.Bind.Enabled) == 0 {
|
||||||
plugins.Append(&config.Plugins{
|
profile.Plugins.Bind.Enabled = append(profile.Plugins.Bind.Enabled, config.Plugin{Name: bindPlugin})
|
||||||
Bind: config.PluginSet{
|
|
||||||
Enabled: []config.Plugin{{Name: bindPlugin}},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
profile.Plugins = plugins
|
|
||||||
return NewFramework(r, &profile, opts...)
|
return NewFramework(r, &profile, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,160 +490,6 @@ func TestNewFrameworkErrors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func recordingPluginFactory(name string, result map[string]runtime.Object) PluginFactory {
|
|
||||||
return func(args runtime.Object, f framework.Handle) (framework.Plugin, error) {
|
|
||||||
result[name] = args
|
|
||||||
return &TestPlugin{
|
|
||||||
name: name,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewFrameworkPluginDefaults(t *testing.T) {
|
|
||||||
// In-tree plugins that use args.
|
|
||||||
pluginsWithArgs := []string{
|
|
||||||
"InterPodAffinity",
|
|
||||||
"NodeLabel",
|
|
||||||
"NodeResourcesFit",
|
|
||||||
"NodeResourcesLeastAllocated",
|
|
||||||
"NodeResourcesMostAllocated",
|
|
||||||
"PodTopologySpread",
|
|
||||||
"RequestedToCapacityRatio",
|
|
||||||
"VolumeBinding",
|
|
||||||
}
|
|
||||||
plugins := config.Plugins{}
|
|
||||||
// Use all plugins in Filter.
|
|
||||||
// NOTE: This does not mean those plugins implemented `Filter` interfaces.
|
|
||||||
// `TestPlugin` is created in this test to fake the behavior for test purpose.
|
|
||||||
for _, name := range pluginsWithArgs {
|
|
||||||
plugins.Filter.Enabled = append(plugins.Filter.Enabled, config.Plugin{Name: name})
|
|
||||||
}
|
|
||||||
// Set required extension points.
|
|
||||||
onePlugin := config.PluginSet{
|
|
||||||
Enabled: []config.Plugin{{Name: pluginsWithArgs[0]}},
|
|
||||||
}
|
|
||||||
plugins.QueueSort = onePlugin
|
|
||||||
plugins.Bind = onePlugin
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
pluginCfg []config.PluginConfig
|
|
||||||
wantCfg map[string]runtime.Object
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "empty plugin config",
|
|
||||||
wantCfg: map[string]runtime.Object{
|
|
||||||
"InterPodAffinity": &config.InterPodAffinityArgs{
|
|
||||||
HardPodAffinityWeight: 1,
|
|
||||||
},
|
|
||||||
"NodeLabel": nil,
|
|
||||||
"NodeResourcesFit": &config.NodeResourcesFitArgs{},
|
|
||||||
"NodeResourcesLeastAllocated": &config.NodeResourcesLeastAllocatedArgs{
|
|
||||||
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
|
||||||
},
|
|
||||||
"NodeResourcesMostAllocated": &config.NodeResourcesMostAllocatedArgs{
|
|
||||||
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
|
||||||
},
|
|
||||||
"RequestedToCapacityRatio": &config.RequestedToCapacityRatioArgs{
|
|
||||||
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
|
|
||||||
},
|
|
||||||
"PodTopologySpread": &config.PodTopologySpreadArgs{
|
|
||||||
DefaultingType: config.SystemDefaulting,
|
|
||||||
},
|
|
||||||
"VolumeBinding": &config.VolumeBindingArgs{
|
|
||||||
BindTimeoutSeconds: 600,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "some overridden plugin config",
|
|
||||||
pluginCfg: []config.PluginConfig{
|
|
||||||
{
|
|
||||||
Name: "InterPodAffinity",
|
|
||||||
Args: &config.InterPodAffinityArgs{
|
|
||||||
HardPodAffinityWeight: 3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "NodeResourcesFit",
|
|
||||||
Args: &config.NodeResourcesFitArgs{
|
|
||||||
IgnoredResources: []string{"example.com/foo"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "NodeResourcesLeastAllocated",
|
|
||||||
Args: &config.NodeResourcesLeastAllocatedArgs{
|
|
||||||
Resources: []config.ResourceSpec{{Name: "resource", Weight: 4}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "NodeResourcesMostAllocated",
|
|
||||||
Args: &config.NodeResourcesMostAllocatedArgs{
|
|
||||||
Resources: []config.ResourceSpec{{Name: "resource", Weight: 3}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "RequestedToCapacityRatio",
|
|
||||||
Args: &config.RequestedToCapacityRatioArgs{
|
|
||||||
Resources: []config.ResourceSpec{{Name: "resource", Weight: 2}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "VolumeBinding",
|
|
||||||
Args: &config.VolumeBindingArgs{
|
|
||||||
BindTimeoutSeconds: 300,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantCfg: map[string]runtime.Object{
|
|
||||||
"InterPodAffinity": &config.InterPodAffinityArgs{
|
|
||||||
HardPodAffinityWeight: 3,
|
|
||||||
},
|
|
||||||
"NodeLabel": nil,
|
|
||||||
"NodeResourcesFit": &config.NodeResourcesFitArgs{
|
|
||||||
IgnoredResources: []string{"example.com/foo"},
|
|
||||||
},
|
|
||||||
"NodeResourcesLeastAllocated": &config.NodeResourcesLeastAllocatedArgs{
|
|
||||||
Resources: []config.ResourceSpec{{Name: "resource", Weight: 4}},
|
|
||||||
},
|
|
||||||
"NodeResourcesMostAllocated": &config.NodeResourcesMostAllocatedArgs{
|
|
||||||
Resources: []config.ResourceSpec{{Name: "resource", Weight: 3}},
|
|
||||||
},
|
|
||||||
"PodTopologySpread": &config.PodTopologySpreadArgs{
|
|
||||||
DefaultingType: config.SystemDefaulting,
|
|
||||||
},
|
|
||||||
"RequestedToCapacityRatio": &config.RequestedToCapacityRatioArgs{
|
|
||||||
Resources: []config.ResourceSpec{{Name: "resource", Weight: 2}},
|
|
||||||
},
|
|
||||||
"VolumeBinding": &config.VolumeBindingArgs{
|
|
||||||
BindTimeoutSeconds: 300,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
// result will hold plugin args passed to factories.
|
|
||||||
result := make(map[string]runtime.Object)
|
|
||||||
registry := make(Registry, len(pluginsWithArgs))
|
|
||||||
for _, name := range pluginsWithArgs {
|
|
||||||
registry[name] = recordingPluginFactory(name, result)
|
|
||||||
}
|
|
||||||
profile := &config.KubeSchedulerProfile{
|
|
||||||
Plugins: &plugins,
|
|
||||||
PluginConfig: tt.pluginCfg,
|
|
||||||
}
|
|
||||||
_, err := NewFramework(registry, profile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if diff := cmp.Diff(tt.wantCfg, result); diff != "" {
|
|
||||||
t.Errorf("unexpected plugin args (-want,+got):\n%s", diff)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fakeNoopPlugin doesn't implement interface framework.EnqueueExtensions.
|
// fakeNoopPlugin doesn't implement interface framework.EnqueueExtensions.
|
||||||
type fakeNoopPlugin struct{}
|
type fakeNoopPlugin struct{}
|
||||||
|
|
||||||
@ -2335,54 +2171,25 @@ func TestListPlugins(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
plugins *config.Plugins
|
plugins *config.Plugins
|
||||||
// pluginSetCount include queue sort plugin and bind plugin.
|
want *config.Plugins
|
||||||
pluginSetCount int
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Add empty plugin",
|
name: "Add empty plugin",
|
||||||
plugins: &config.Plugins{},
|
plugins: &config.Plugins{},
|
||||||
pluginSetCount: 2,
|
want: &config.Plugins{
|
||||||
|
QueueSort: config.PluginSet{Enabled: []config.Plugin{{Name: queueSortPlugin}}},
|
||||||
|
Bind: config.PluginSet{Enabled: []config.Plugin{{Name: bindPlugin}}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Add multiple plugins",
|
name: "Add multiple plugins",
|
||||||
plugins: &config.Plugins{
|
plugins: &config.Plugins{
|
||||||
Score: config.PluginSet{Enabled: []config.Plugin{{Name: scorePlugin1}, {Name: scoreWithNormalizePlugin1}}},
|
Score: config.PluginSet{Enabled: []config.Plugin{{Name: scorePlugin1, Weight: 3}, {Name: scoreWithNormalizePlugin1}}},
|
||||||
},
|
},
|
||||||
pluginSetCount: 3,
|
want: &config.Plugins{
|
||||||
},
|
QueueSort: config.PluginSet{Enabled: []config.Plugin{{Name: queueSortPlugin}}},
|
||||||
}
|
Bind: config.PluginSet{Enabled: []config.Plugin{{Name: bindPlugin}}},
|
||||||
|
Score: config.PluginSet{Enabled: []config.Plugin{{Name: scorePlugin1, Weight: 3}, {Name: scoreWithNormalizePlugin1, Weight: 1}}},
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
profile := config.KubeSchedulerProfile{Plugins: tt.plugins}
|
|
||||||
f, err := newFrameworkWithQueueSortAndBind(registry, profile)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create framework for testing: %v", err)
|
|
||||||
}
|
|
||||||
plugins := f.ListPlugins()
|
|
||||||
if len(plugins) != tt.pluginSetCount {
|
|
||||||
t.Fatalf("Unexpected pluginSet count: %v", len(plugins))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewFrameworkPluginWeights(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
plugins *config.Plugins
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Extend multiple extension points by same plugin",
|
|
||||||
plugins: &config.Plugins{
|
|
||||||
Score: config.PluginSet{Enabled: []config.Plugin{{Name: testPlugin, Weight: 3}}},
|
|
||||||
PostBind: config.PluginSet{Enabled: []config.Plugin{{Name: testPlugin, Weight: 6}}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Add multiple score plugins",
|
|
||||||
plugins: &config.Plugins{
|
|
||||||
Score: config.PluginSet{Enabled: []config.Plugin{{Name: testPlugin, Weight: 3}, {Name: scorePlugin1, Weight: 6}}},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -2394,14 +2201,9 @@ func TestNewFrameworkPluginWeights(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create framework for testing: %v", err)
|
t.Fatalf("Failed to create framework for testing: %v", err)
|
||||||
}
|
}
|
||||||
|
got := f.ListPlugins()
|
||||||
plugins := f.ListPlugins()
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
||||||
if len(plugins["ScorePlugin"]) != len(tt.plugins.Score.Enabled) {
|
t.Errorf("unexpected plugins (-want,+got):\n%s", diff)
|
||||||
t.Fatalf("Expect %d ScorePlugin, got %d from: %v", len(tt.plugins.Score.Enabled), len(plugins["ScorePlugin"]), plugins["ScorePlugin"])
|
|
||||||
}
|
|
||||||
|
|
||||||
if diff := cmp.Diff(tt.plugins.Score.Enabled, plugins["ScorePlugin"]); diff != "" {
|
|
||||||
t.Errorf("unexpected plugin weights (-want,+got):\n%s", diff)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,10 @@ import (
|
|||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"
|
"k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/core"
|
"k8s.io/kubernetes/pkg/scheduler/core"
|
||||||
@ -108,6 +110,7 @@ type schedulerOptions struct {
|
|||||||
extenders []schedulerapi.Extender
|
extenders []schedulerapi.Extender
|
||||||
frameworkCapturer FrameworkCapturer
|
frameworkCapturer FrameworkCapturer
|
||||||
parallelism int32
|
parallelism int32
|
||||||
|
applyDefaultProfile bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option configures a Scheduler
|
// Option configures a Scheduler
|
||||||
@ -135,6 +138,7 @@ func WithKubeConfig(cfg *restclient.Config) Option {
|
|||||||
func WithProfiles(p ...schedulerapi.KubeSchedulerProfile) Option {
|
func WithProfiles(p ...schedulerapi.KubeSchedulerProfile) Option {
|
||||||
return func(o *schedulerOptions) {
|
return func(o *schedulerOptions) {
|
||||||
o.profiles = p
|
o.profiles = p
|
||||||
|
o.applyDefaultProfile = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +149,7 @@ func WithParallelism(threads int32) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithPolicySource sets legacy policy config file source.
|
// WithLegacyPolicySource sets legacy policy config file source.
|
||||||
func WithLegacyPolicySource(source *schedulerapi.SchedulerPolicySource) Option {
|
func WithLegacyPolicySource(source *schedulerapi.SchedulerPolicySource) Option {
|
||||||
return func(o *schedulerOptions) {
|
return func(o *schedulerOptions) {
|
||||||
o.legacyPolicySource = source
|
o.legacyPolicySource = source
|
||||||
@ -199,14 +203,15 @@ func WithBuildFrameworkCapturer(fc FrameworkCapturer) Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var defaultSchedulerOptions = schedulerOptions{
|
var defaultSchedulerOptions = schedulerOptions{
|
||||||
profiles: []schedulerapi.KubeSchedulerProfile{
|
|
||||||
// Profiles' default plugins are set from the algorithm provider.
|
|
||||||
{SchedulerName: v1.DefaultSchedulerName},
|
|
||||||
},
|
|
||||||
percentageOfNodesToScore: schedulerapi.DefaultPercentageOfNodesToScore,
|
percentageOfNodesToScore: schedulerapi.DefaultPercentageOfNodesToScore,
|
||||||
podInitialBackoffSeconds: int64(internalqueue.DefaultPodInitialBackoffDuration.Seconds()),
|
podInitialBackoffSeconds: int64(internalqueue.DefaultPodInitialBackoffDuration.Seconds()),
|
||||||
podMaxBackoffSeconds: int64(internalqueue.DefaultPodMaxBackoffDuration.Seconds()),
|
podMaxBackoffSeconds: int64(internalqueue.DefaultPodMaxBackoffDuration.Seconds()),
|
||||||
parallelism: int32(parallelize.DefaultParallelism),
|
parallelism: int32(parallelize.DefaultParallelism),
|
||||||
|
// Ideally we would statically set the default profile here, but we can't because
|
||||||
|
// creating the default profile may require testing feature gates, which may get
|
||||||
|
// set dynamically in tests. Therefore, we delay creating it until New is actually
|
||||||
|
// invoked.
|
||||||
|
applyDefaultProfile: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a Scheduler
|
// New returns a Scheduler
|
||||||
@ -226,6 +231,15 @@ func New(client clientset.Interface,
|
|||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.applyDefaultProfile {
|
||||||
|
var versionedCfg v1beta2.KubeSchedulerConfiguration
|
||||||
|
scheme.Scheme.Default(&versionedCfg)
|
||||||
|
cfg := config.KubeSchedulerConfiguration{}
|
||||||
|
if err := scheme.Scheme.Convert(&versionedCfg, &cfg, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options.profiles = cfg.Profiles
|
||||||
|
}
|
||||||
schedulerCache := internalcache.New(30*time.Second, stopEverything)
|
schedulerCache := internalcache.New(30*time.Second, stopEverything)
|
||||||
|
|
||||||
registry := frameworkplugins.NewInTreeRegistry()
|
registry := frameworkplugins.NewInTreeRegistry()
|
||||||
@ -260,12 +274,12 @@ func New(client clientset.Interface,
|
|||||||
|
|
||||||
var sched *Scheduler
|
var sched *Scheduler
|
||||||
if options.legacyPolicySource == nil {
|
if options.legacyPolicySource == nil {
|
||||||
sc, err := configurator.createFromConfig()
|
// Create the config from component config
|
||||||
|
sc, err := configurator.create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("couldn't create scheduler: %v", err)
|
return nil, fmt.Errorf("couldn't create scheduler: %v", err)
|
||||||
}
|
}
|
||||||
sched = sc
|
sched = sc
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Create the config from a user specified policy source.
|
// Create the config from a user specified policy source.
|
||||||
policy := &schedulerapi.Policy{}
|
policy := &schedulerapi.Policy{}
|
||||||
|
@ -132,35 +132,83 @@ func TestSchedulerCreation(t *testing.T) {
|
|||||||
wantProfiles []string
|
wantProfiles []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "default scheduler",
|
name: "valid out-of-tree registry",
|
||||||
|
opts: []Option{
|
||||||
|
WithFrameworkOutOfTreeRegistry(validRegistry),
|
||||||
|
WithProfiles(
|
||||||
|
schedulerapi.KubeSchedulerProfile{
|
||||||
|
SchedulerName: "default-scheduler",
|
||||||
|
Plugins: &schedulerapi.Plugins{
|
||||||
|
QueueSort: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "PrioritySort"}}},
|
||||||
|
Bind: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "DefaultBinder"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)},
|
||||||
wantProfiles: []string{"default-scheduler"},
|
wantProfiles: []string{"default-scheduler"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "valid out-of-tree registry",
|
name: "repeated plugin name in out-of-tree plugin",
|
||||||
opts: []Option{WithFrameworkOutOfTreeRegistry(validRegistry)},
|
opts: []Option{
|
||||||
wantProfiles: []string{"default-scheduler"},
|
WithFrameworkOutOfTreeRegistry(invalidRegistry),
|
||||||
},
|
WithProfiles(
|
||||||
{
|
schedulerapi.KubeSchedulerProfile{
|
||||||
name: "repeated plugin name in out-of-tree plugin",
|
SchedulerName: "default-scheduler",
|
||||||
opts: []Option{WithFrameworkOutOfTreeRegistry(invalidRegistry)},
|
Plugins: &schedulerapi.Plugins{
|
||||||
|
QueueSort: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "PrioritySort"}}},
|
||||||
|
Bind: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "DefaultBinder"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)},
|
||||||
wantProfiles: []string{"default-scheduler"},
|
wantProfiles: []string{"default-scheduler"},
|
||||||
wantErr: "a plugin named DefaultBinder already exists",
|
wantErr: "a plugin named DefaultBinder already exists",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple profiles",
|
name: "multiple profiles",
|
||||||
opts: []Option{WithProfiles(
|
opts: []Option{
|
||||||
schedulerapi.KubeSchedulerProfile{SchedulerName: "foo"},
|
WithProfiles(
|
||||||
schedulerapi.KubeSchedulerProfile{SchedulerName: "bar"},
|
schedulerapi.KubeSchedulerProfile{
|
||||||
)},
|
SchedulerName: "foo",
|
||||||
|
Plugins: &schedulerapi.Plugins{
|
||||||
|
QueueSort: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "PrioritySort"}}},
|
||||||
|
Bind: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "DefaultBinder"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
schedulerapi.KubeSchedulerProfile{
|
||||||
|
SchedulerName: "bar",
|
||||||
|
Plugins: &schedulerapi.Plugins{
|
||||||
|
QueueSort: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "PrioritySort"}}},
|
||||||
|
Bind: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "DefaultBinder"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)},
|
||||||
wantProfiles: []string{"bar", "foo"},
|
wantProfiles: []string{"bar", "foo"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Repeated profiles",
|
name: "Repeated profiles",
|
||||||
opts: []Option{WithProfiles(
|
opts: []Option{
|
||||||
schedulerapi.KubeSchedulerProfile{SchedulerName: "foo"},
|
WithProfiles(
|
||||||
schedulerapi.KubeSchedulerProfile{SchedulerName: "bar"},
|
schedulerapi.KubeSchedulerProfile{
|
||||||
schedulerapi.KubeSchedulerProfile{SchedulerName: "foo"},
|
SchedulerName: "foo",
|
||||||
)},
|
Plugins: &schedulerapi.Plugins{
|
||||||
|
QueueSort: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "PrioritySort"}}},
|
||||||
|
Bind: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "DefaultBinder"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
schedulerapi.KubeSchedulerProfile{
|
||||||
|
SchedulerName: "bar",
|
||||||
|
Plugins: &schedulerapi.Plugins{
|
||||||
|
QueueSort: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "PrioritySort"}}},
|
||||||
|
Bind: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "DefaultBinder"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
schedulerapi.KubeSchedulerProfile{
|
||||||
|
SchedulerName: "foo",
|
||||||
|
Plugins: &schedulerapi.Plugins{
|
||||||
|
QueueSort: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "PrioritySort"}}},
|
||||||
|
Bind: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "DefaultBinder"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)},
|
||||||
wantErr: "duplicate profile with scheduler name \"foo\"",
|
wantErr: "duplicate profile with scheduler name \"foo\"",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -463,12 +511,13 @@ func TestSchedulerMultipleProfilesScheduling(t *testing.T) {
|
|||||||
WithProfiles(
|
WithProfiles(
|
||||||
schedulerapi.KubeSchedulerProfile{SchedulerName: "match-machine2",
|
schedulerapi.KubeSchedulerProfile{SchedulerName: "match-machine2",
|
||||||
Plugins: &schedulerapi.Plugins{
|
Plugins: &schedulerapi.Plugins{
|
||||||
Filter: schedulerapi.PluginSet{
|
Filter: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "FakeNodeSelector"}}},
|
||||||
Enabled: []schedulerapi.Plugin{{Name: "FakeNodeSelector"}},
|
QueueSort: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "PrioritySort"}}},
|
||||||
Disabled: []schedulerapi.Plugin{{Name: "*"}},
|
Bind: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "DefaultBinder"}}},
|
||||||
}},
|
},
|
||||||
PluginConfig: []schedulerapi.PluginConfig{
|
PluginConfig: []schedulerapi.PluginConfig{
|
||||||
{Name: "FakeNodeSelector",
|
{
|
||||||
|
Name: "FakeNodeSelector",
|
||||||
Args: &runtime.Unknown{Raw: []byte(`{"nodeName":"machine2"}`)},
|
Args: &runtime.Unknown{Raw: []byte(`{"nodeName":"machine2"}`)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -476,12 +525,13 @@ func TestSchedulerMultipleProfilesScheduling(t *testing.T) {
|
|||||||
schedulerapi.KubeSchedulerProfile{
|
schedulerapi.KubeSchedulerProfile{
|
||||||
SchedulerName: "match-machine3",
|
SchedulerName: "match-machine3",
|
||||||
Plugins: &schedulerapi.Plugins{
|
Plugins: &schedulerapi.Plugins{
|
||||||
Filter: schedulerapi.PluginSet{
|
Filter: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "FakeNodeSelector"}}},
|
||||||
Enabled: []schedulerapi.Plugin{{Name: "FakeNodeSelector"}},
|
QueueSort: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "PrioritySort"}}},
|
||||||
Disabled: []schedulerapi.Plugin{{Name: "*"}},
|
Bind: schedulerapi.PluginSet{Enabled: []schedulerapi.Plugin{{Name: "DefaultBinder"}}},
|
||||||
}},
|
},
|
||||||
PluginConfig: []schedulerapi.PluginConfig{
|
PluginConfig: []schedulerapi.PluginConfig{
|
||||||
{Name: "FakeNodeSelector",
|
{
|
||||||
|
Name: "FakeNodeSelector",
|
||||||
Args: &runtime.Unknown{Raw: []byte(`{"nodeName":"machine3"}`)},
|
Args: &runtime.Unknown{Raw: []byte(`{"nodeName":"machine3"}`)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -17,28 +17,32 @@ limitations under the License.
|
|||||||
package testing
|
package testing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework"
|
"k8s.io/kubernetes/pkg/scheduler/framework"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/runtime"
|
"k8s.io/kubernetes/pkg/scheduler/framework/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var configDecoder = scheme.Codecs.UniversalDecoder()
|
||||||
|
|
||||||
// NewFramework creates a Framework from the register functions and options.
|
// NewFramework creates a Framework from the register functions and options.
|
||||||
func NewFramework(fns []RegisterPluginFunc, profileName string, opts ...runtime.Option) (framework.Framework, error) {
|
func NewFramework(fns []RegisterPluginFunc, profileName string, opts ...runtime.Option) (framework.Framework, error) {
|
||||||
registry := runtime.Registry{}
|
registry := runtime.Registry{}
|
||||||
plugins := &schedulerapi.Plugins{}
|
|
||||||
for _, f := range fns {
|
|
||||||
f(®istry, plugins)
|
|
||||||
}
|
|
||||||
profile := &schedulerapi.KubeSchedulerProfile{
|
profile := &schedulerapi.KubeSchedulerProfile{
|
||||||
SchedulerName: profileName,
|
SchedulerName: profileName,
|
||||||
Plugins: plugins,
|
Plugins: &schedulerapi.Plugins{},
|
||||||
|
}
|
||||||
|
for _, f := range fns {
|
||||||
|
f(®istry, profile)
|
||||||
}
|
}
|
||||||
return runtime.NewFramework(registry, profile, opts...)
|
return runtime.NewFramework(registry, profile, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterPluginFunc is a function signature used in method RegisterFilterPlugin()
|
// RegisterPluginFunc is a function signature used in method RegisterFilterPlugin()
|
||||||
// to register a Filter Plugin to a given registry.
|
// to register a Filter Plugin to a given registry.
|
||||||
type RegisterPluginFunc func(reg *runtime.Registry, plugins *schedulerapi.Plugins)
|
type RegisterPluginFunc func(reg *runtime.Registry, profile *schedulerapi.KubeSchedulerProfile)
|
||||||
|
|
||||||
// RegisterQueueSortPlugin returns a function to register a QueueSort Plugin to a given registry.
|
// RegisterQueueSortPlugin returns a function to register a QueueSort Plugin to a given registry.
|
||||||
func RegisterQueueSortPlugin(pluginName string, pluginNewFunc runtime.PluginFactory) RegisterPluginFunc {
|
func RegisterQueueSortPlugin(pluginName string, pluginNewFunc runtime.PluginFactory) RegisterPluginFunc {
|
||||||
@ -92,15 +96,24 @@ func RegisterPluginAsExtensions(pluginName string, pluginNewFunc runtime.PluginF
|
|||||||
|
|
||||||
// RegisterPluginAsExtensionsWithWeight returns a function to register a Plugin as given extensionPoints with weight to a given registry.
|
// RegisterPluginAsExtensionsWithWeight returns a function to register a Plugin as given extensionPoints with weight to a given registry.
|
||||||
func RegisterPluginAsExtensionsWithWeight(pluginName string, weight int32, pluginNewFunc runtime.PluginFactory, extensions ...string) RegisterPluginFunc {
|
func RegisterPluginAsExtensionsWithWeight(pluginName string, weight int32, pluginNewFunc runtime.PluginFactory, extensions ...string) RegisterPluginFunc {
|
||||||
return func(reg *runtime.Registry, plugins *schedulerapi.Plugins) {
|
return func(reg *runtime.Registry, profile *schedulerapi.KubeSchedulerProfile) {
|
||||||
reg.Register(pluginName, pluginNewFunc)
|
reg.Register(pluginName, pluginNewFunc)
|
||||||
for _, extension := range extensions {
|
for _, extension := range extensions {
|
||||||
ps := getPluginSetByExtension(plugins, extension)
|
ps := getPluginSetByExtension(profile.Plugins, extension)
|
||||||
if ps == nil {
|
if ps == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ps.Enabled = append(ps.Enabled, schedulerapi.Plugin{Name: pluginName, Weight: weight})
|
ps.Enabled = append(ps.Enabled, schedulerapi.Plugin{Name: pluginName, Weight: weight})
|
||||||
}
|
}
|
||||||
|
// Use defaults from latest config API version.
|
||||||
|
var gvk schema.GroupVersionKind
|
||||||
|
gvk = v1beta2.SchemeGroupVersion.WithKind(pluginName + "Args")
|
||||||
|
if args, _, err := configDecoder.Decode(nil, &gvk, nil); err == nil {
|
||||||
|
profile.PluginConfig = append(profile.PluginConfig, schedulerapi.PluginConfig{
|
||||||
|
Name: pluginName,
|
||||||
|
Args: args,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
extenderv1 "k8s.io/kube-scheduler/extender/v1"
|
extenderv1 "k8s.io/kube-scheduler/extender/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/scheduler"
|
||||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
testutils "k8s.io/kubernetes/test/integration/util"
|
testutils "k8s.io/kubernetes/test/integration/util"
|
||||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||||
@ -350,7 +351,8 @@ func TestSchedulerExtender(t *testing.T) {
|
|||||||
}
|
}
|
||||||
policy.APIVersion = "v1"
|
policy.APIVersion = "v1"
|
||||||
|
|
||||||
testCtx = testutils.InitTestScheduler(t, testCtx, &policy)
|
testCtx = testutils.InitTestSchedulerWithOptions(t, testCtx, &policy,
|
||||||
|
scheduler.WithProfiles([]schedulerapi.KubeSchedulerProfile(nil)...))
|
||||||
testutils.SyncInformerFactory(testCtx)
|
testutils.SyncInformerFactory(testCtx)
|
||||||
go testCtx.Scheduler.Run(testCtx.Ctx)
|
go testCtx.Scheduler.Run(testCtx.Ctx)
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
defer testutils.CleanupTest(t, testCtx)
|
||||||
|
@ -30,13 +30,16 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
"k8s.io/kubernetes/pkg/scheduler"
|
"k8s.io/kubernetes/pkg/scheduler"
|
||||||
schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
|
configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework"
|
"k8s.io/kubernetes/pkg/scheduler/framework"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
|
||||||
frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
|
frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
|
||||||
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
||||||
testutils "k8s.io/kubernetes/test/integration/util"
|
testutils "k8s.io/kubernetes/test/integration/util"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PreFilterPlugin struct {
|
type PreFilterPlugin struct {
|
||||||
@ -510,20 +513,22 @@ func TestPreFilterPlugin(t *testing.T) {
|
|||||||
registry := frameworkruntime.Registry{prefilterPluginName: newPlugin(preFilterPlugin)}
|
registry := frameworkruntime.Registry{prefilterPluginName: newPlugin(preFilterPlugin)}
|
||||||
|
|
||||||
// Setup initial prefilter plugin for testing.
|
// Setup initial prefilter plugin for testing.
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
PreFilter: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
PreFilter: v1beta2.PluginSet{
|
||||||
{Name: prefilterPluginName},
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: prefilterPluginName},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}
|
})
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "prefilter-plugin", nil), 2,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "prefilter-plugin", nil), 2,
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
defer testutils.CleanupTest(t, testCtx)
|
||||||
|
|
||||||
@ -653,43 +658,44 @@ func TestPostFilterPlugin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup plugins for testing.
|
// Setup plugins for testing.
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
Filter: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
Filter: v1beta2.PluginSet{
|
||||||
{Name: filterPluginName},
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: filterPluginName},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Score: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: scorePluginName},
|
||||||
|
},
|
||||||
|
// disable default in-tree Score plugins
|
||||||
|
// to make it easy to control configured ScorePlugins failure
|
||||||
|
Disabled: []v1beta2.Plugin{
|
||||||
|
{Name: "*"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostFilter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: postfilterPluginName},
|
||||||
|
},
|
||||||
|
// Need to disable default in-tree PostFilter plugins, as they will
|
||||||
|
// call RunFilterPlugins and hence impact the "numFilterCalled".
|
||||||
|
Disabled: []v1beta2.Plugin{
|
||||||
|
{Name: "*"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Score: schedulerconfig.PluginSet{
|
}}})
|
||||||
Enabled: []schedulerconfig.Plugin{
|
|
||||||
{Name: scorePluginName},
|
|
||||||
},
|
|
||||||
// disable default in-tree Score plugins
|
|
||||||
// to make it easy to control configured ScorePlugins failure
|
|
||||||
Disabled: []schedulerconfig.Plugin{
|
|
||||||
{Name: "*"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PostFilter: schedulerconfig.PluginSet{
|
|
||||||
Enabled: []schedulerconfig.Plugin{
|
|
||||||
{Name: postfilterPluginName},
|
|
||||||
},
|
|
||||||
// Need to disable default in-tree PostFilter plugins, as they will
|
|
||||||
// call RunFilterPlugins and hence impact the "numFilterCalled".
|
|
||||||
Disabled: []schedulerconfig.Plugin{
|
|
||||||
{Name: "*"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(
|
testCtx := initTestSchedulerForFrameworkTest(
|
||||||
t,
|
t,
|
||||||
testutils.InitTestMaster(t, fmt.Sprintf("postfilter%v-", i), nil),
|
testutils.InitTestMaster(t, fmt.Sprintf("postfilter%v-", i), nil),
|
||||||
int(tt.numNodes),
|
int(tt.numNodes),
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry),
|
scheduler.WithFrameworkOutOfTreeRegistry(registry),
|
||||||
)
|
)
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
defer testutils.CleanupTest(t, testCtx)
|
||||||
@ -740,19 +746,21 @@ func TestScorePlugin(t *testing.T) {
|
|||||||
scorePluginName: newPlugin(scorePlugin),
|
scorePluginName: newPlugin(scorePlugin),
|
||||||
}
|
}
|
||||||
|
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
Score: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
Score: v1beta2.PluginSet{
|
||||||
{Name: scorePluginName},
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: scorePluginName},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}
|
})
|
||||||
|
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "score-plugin", nil), 10,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "score-plugin", nil), 10,
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
defer testutils.CleanupTest(t, testCtx)
|
||||||
|
|
||||||
@ -816,18 +824,21 @@ func TestNormalizeScorePlugin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup initial score plugin for testing.
|
// Setup initial score plugin for testing.
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
Score: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
Score: v1beta2.PluginSet{
|
||||||
{Name: scoreWithNormalizePluginName},
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: scoreWithNormalizePluginName},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}
|
})
|
||||||
|
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "score-plugin", nil), 10,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "score-plugin", nil), 10,
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
||||||
|
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
defer testutils.CleanupTest(t, testCtx)
|
||||||
@ -860,22 +871,22 @@ func TestReservePluginReserve(t *testing.T) {
|
|||||||
registry := frameworkruntime.Registry{reservePluginName: newPlugin(reservePlugin)}
|
registry := frameworkruntime.Registry{reservePluginName: newPlugin(reservePlugin)}
|
||||||
|
|
||||||
// Setup initial reserve plugin for testing.
|
// Setup initial reserve plugin for testing.
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
Reserve: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
Reserve: v1beta2.PluginSet{
|
||||||
{
|
Enabled: []v1beta2.Plugin{
|
||||||
Name: reservePluginName,
|
{Name: reservePluginName},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}
|
})
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "reserve-plugin-reserve", nil), 2,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "reserve-plugin-reserve", nil), 2,
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
defer testutils.CleanupTest(t, testCtx)
|
||||||
|
|
||||||
@ -931,22 +942,22 @@ func TestPrebindPlugin(t *testing.T) {
|
|||||||
registry := frameworkruntime.Registry{preBindPluginName: newPlugin(preBindPlugin)}
|
registry := frameworkruntime.Registry{preBindPluginName: newPlugin(preBindPlugin)}
|
||||||
|
|
||||||
// Setup initial prebind plugin for testing.
|
// Setup initial prebind plugin for testing.
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
PreBind: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
PreBind: v1beta2.PluginSet{
|
||||||
{
|
Enabled: []v1beta2.Plugin{
|
||||||
Name: preBindPluginName,
|
{Name: preBindPluginName},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}
|
})
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "prebind-plugin", nil), 2,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "prebind-plugin", nil), 2,
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
defer testutils.CleanupTest(t, testCtx)
|
||||||
|
|
||||||
@ -1006,124 +1017,124 @@ func TestPrebindPlugin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestUnreserveReservePlugin tests invocation of the Unreserve operation in
|
// // TestUnreserveReservePlugin tests invocation of the Unreserve operation in
|
||||||
// reserve plugins through failures in execution points such as pre-bind. Also
|
// // reserve plugins through failures in execution points such as pre-bind. Also
|
||||||
// tests that the order of invocation of Unreserve operation is executed in the
|
// // tests that the order of invocation of Unreserve operation is executed in the
|
||||||
// reverse order of invocation of the Reserve operation.
|
// // reverse order of invocation of the Reserve operation.
|
||||||
func TestReservePluginUnreserve(t *testing.T) {
|
// func TestReservePluginUnreserve(t *testing.T) {
|
||||||
tests := []struct {
|
// tests := []struct {
|
||||||
name string
|
// name string
|
||||||
failReserve bool
|
// failReserve bool
|
||||||
failReserveIndex int
|
// failReserveIndex int
|
||||||
failPreBind bool
|
// failPreBind bool
|
||||||
}{
|
// }{
|
||||||
{
|
// {
|
||||||
name: "fail reserve",
|
// name: "fail reserve",
|
||||||
failReserve: true,
|
// failReserve: true,
|
||||||
failReserveIndex: 1,
|
// failReserveIndex: 1,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "fail preBind",
|
// name: "fail preBind",
|
||||||
failPreBind: true,
|
// failPreBind: true,
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "pass everything",
|
// name: "pass everything",
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
|
|
||||||
for _, test := range tests {
|
// for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
// t.Run(test.name, func(t *testing.T) {
|
||||||
numReservePlugins := 3
|
// numReservePlugins := 3
|
||||||
pluginInvokeEventChan := make(chan pluginInvokeEvent, numReservePlugins)
|
// pluginInvokeEventChan := make(chan pluginInvokeEvent, numReservePlugins)
|
||||||
|
|
||||||
preBindPlugin := &PreBindPlugin{
|
// preBindPlugin := &PreBindPlugin{
|
||||||
failPreBind: true,
|
// failPreBind: true,
|
||||||
}
|
// }
|
||||||
var reservePlugins []*ReservePlugin
|
// var reservePlugins []*ReservePlugin
|
||||||
for i := 0; i < numReservePlugins; i++ {
|
// for i := 0; i < numReservePlugins; i++ {
|
||||||
reservePlugins = append(reservePlugins, &ReservePlugin{
|
// reservePlugins = append(reservePlugins, &ReservePlugin{
|
||||||
name: fmt.Sprintf("%s-%d", reservePluginName, i),
|
// name: fmt.Sprintf("%s-%d", reservePluginName, i),
|
||||||
pluginInvokeEventChan: pluginInvokeEventChan,
|
// pluginInvokeEventChan: pluginInvokeEventChan,
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
registry := frameworkruntime.Registry{
|
// registry := frameworkruntime.Registry{
|
||||||
// TODO(#92229): test more failure points that would trigger Unreserve in
|
// // TODO(#92229): test more failure points that would trigger Unreserve in
|
||||||
// reserve plugins than just one pre-bind plugin.
|
// // reserve plugins than just one pre-bind plugin.
|
||||||
preBindPluginName: newPlugin(preBindPlugin),
|
// preBindPluginName: newPlugin(preBindPlugin),
|
||||||
}
|
// }
|
||||||
for _, pl := range reservePlugins {
|
// for _, pl := range reservePlugins {
|
||||||
registry[pl.Name()] = newPlugin(pl)
|
// registry[pl.Name()] = newPlugin(pl)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Setup initial reserve and prebind plugin for testing.
|
// // Setup initial reserve and prebind plugin for testing.
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
// prof := schedulerconfig.KubeSchedulerProfile{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
// SchedulerName: v1.DefaultSchedulerName,
|
||||||
Plugins: &schedulerconfig.Plugins{
|
// Plugins: &schedulerconfig.Plugins{
|
||||||
Reserve: schedulerconfig.PluginSet{
|
// Reserve: schedulerconfig.PluginSet{
|
||||||
// filled by looping over reservePlugins
|
// // filled by looping over reservePlugins
|
||||||
},
|
// },
|
||||||
PreBind: schedulerconfig.PluginSet{
|
// PreBind: schedulerconfig.PluginSet{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
// Enabled: []schedulerconfig.Plugin{
|
||||||
{
|
// {
|
||||||
Name: preBindPluginName,
|
// Name: preBindPluginName,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
for _, pl := range reservePlugins {
|
// for _, pl := range reservePlugins {
|
||||||
prof.Plugins.Reserve.Enabled = append(prof.Plugins.Reserve.Enabled, schedulerconfig.Plugin{
|
// prof.Plugins.Reserve.Enabled = append(prof.Plugins.Reserve.Enabled, schedulerconfig.Plugin{
|
||||||
Name: pl.Name(),
|
// Name: pl.Name(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// // Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "reserve-plugin-unreserve", nil), 2,
|
// testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "reserve-plugin-unreserve", nil), 2,
|
||||||
scheduler.WithProfiles(prof),
|
// scheduler.WithProfiles(prof),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
// scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
// defer testutils.CleanupTest(t, testCtx)
|
||||||
|
|
||||||
preBindPlugin.failPreBind = test.failPreBind
|
// preBindPlugin.failPreBind = test.failPreBind
|
||||||
if test.failReserve {
|
// if test.failReserve {
|
||||||
reservePlugins[test.failReserveIndex].failReserve = true
|
// reservePlugins[test.failReserveIndex].failReserve = true
|
||||||
}
|
// }
|
||||||
// Create a best effort pod.
|
// // Create a best effort pod.
|
||||||
pod, err := createPausePod(testCtx.ClientSet,
|
// pod, err := createPausePod(testCtx.ClientSet,
|
||||||
initPausePod(&pausePodConfig{Name: "test-pod", Namespace: testCtx.NS.Name}))
|
// initPausePod(&pausePodConfig{Name: "test-pod", Namespace: testCtx.NS.Name}))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
t.Errorf("Error while creating a test pod: %v", err)
|
// t.Errorf("Error while creating a test pod: %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if test.failPreBind || test.failReserve {
|
// if test.failPreBind || test.failReserve {
|
||||||
if err = wait.Poll(10*time.Millisecond, 30*time.Second, podSchedulingError(testCtx.ClientSet, pod.Namespace, pod.Name)); err != nil {
|
// if err = wait.Poll(10*time.Millisecond, 30*time.Second, podSchedulingError(testCtx.ClientSet, pod.Namespace, pod.Name)); err != nil {
|
||||||
t.Errorf("Expected a scheduling error, but didn't get it: %v", err)
|
// t.Errorf("Expected a scheduling error, but didn't get it: %v", err)
|
||||||
}
|
// }
|
||||||
for i := numReservePlugins - 1; i >= 0; i-- {
|
// for i := numReservePlugins - 1; i >= 0; i-- {
|
||||||
select {
|
// select {
|
||||||
case event := <-pluginInvokeEventChan:
|
// case event := <-pluginInvokeEventChan:
|
||||||
expectedPluginName := reservePlugins[i].Name()
|
// expectedPluginName := reservePlugins[i].Name()
|
||||||
if expectedPluginName != event.pluginName {
|
// if expectedPluginName != event.pluginName {
|
||||||
t.Errorf("event.pluginName = %s, want %s", event.pluginName, expectedPluginName)
|
// t.Errorf("event.pluginName = %s, want %s", event.pluginName, expectedPluginName)
|
||||||
}
|
// }
|
||||||
case <-time.After(time.Second * 30):
|
// case <-time.After(time.Second * 30):
|
||||||
t.Errorf("pluginInvokeEventChan receive timed out")
|
// t.Errorf("pluginInvokeEventChan receive timed out")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
if err = testutils.WaitForPodToSchedule(testCtx.ClientSet, pod); err != nil {
|
// if err = testutils.WaitForPodToSchedule(testCtx.ClientSet, pod); err != nil {
|
||||||
t.Errorf("Expected the pod to be scheduled, got an error: %v", err)
|
// t.Errorf("Expected the pod to be scheduled, got an error: %v", err)
|
||||||
}
|
// }
|
||||||
for i, pl := range reservePlugins {
|
// for i, pl := range reservePlugins {
|
||||||
if pl.numUnreserveCalled != 0 {
|
// if pl.numUnreserveCalled != 0 {
|
||||||
t.Errorf("reservePlugins[%d].numUnreserveCalled = %d, want 0", i, pl.numUnreserveCalled)
|
// t.Errorf("reservePlugins[%d].numUnreserveCalled = %d, want 0", i, pl.numUnreserveCalled)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
testutils.CleanupPods(testCtx.ClientSet, t, []*v1.Pod{pod})
|
// testutils.CleanupPods(testCtx.ClientSet, t, []*v1.Pod{pod})
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
type pluginInvokeEvent struct {
|
type pluginInvokeEvent struct {
|
||||||
pluginName string
|
pluginName string
|
||||||
@ -1155,26 +1166,28 @@ func TestBindPlugin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup initial unreserve and bind plugins for testing.
|
// Setup initial unreserve and bind plugins for testing.
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
Reserve: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{{Name: reservePlugin.Name()}},
|
Reserve: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{{Name: reservePlugin.Name()}},
|
||||||
|
},
|
||||||
|
Bind: v1beta2.PluginSet{
|
||||||
|
// Put DefaultBinder last.
|
||||||
|
Enabled: []v1beta2.Plugin{{Name: bindPlugin1.Name()}, {Name: bindPlugin2.Name()}, {Name: defaultbinder.Name}},
|
||||||
|
Disabled: []v1beta2.Plugin{{Name: defaultbinder.Name}},
|
||||||
|
},
|
||||||
|
PostBind: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{{Name: postBindPlugin.Name()}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Bind: schedulerconfig.PluginSet{
|
}},
|
||||||
// Put DefaultBinder last.
|
})
|
||||||
Enabled: []schedulerconfig.Plugin{{Name: bindPlugin1.Name()}, {Name: bindPlugin2.Name()}, {Name: defaultbinder.Name}},
|
|
||||||
Disabled: []schedulerconfig.Plugin{{Name: defaultbinder.Name}},
|
|
||||||
},
|
|
||||||
PostBind: schedulerconfig.PluginSet{
|
|
||||||
Enabled: []schedulerconfig.Plugin{{Name: postBindPlugin.Name()}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the scheduler with the test plugin set.
|
// Create the scheduler with the test plugin set.
|
||||||
testCtx := testutils.InitTestSchedulerWithOptions(t, testContext, nil,
|
testCtx := testutils.InitTestSchedulerWithOptions(t, testContext, nil,
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
||||||
testutils.SyncInformerFactory(testCtx)
|
testutils.SyncInformerFactory(testCtx)
|
||||||
go testCtx.Scheduler.Run(testCtx.Ctx)
|
go testCtx.Scheduler.Run(testCtx.Ctx)
|
||||||
@ -1341,29 +1354,31 @@ func TestPostBindPlugin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup initial prebind and postbind plugin for testing.
|
// Setup initial prebind and postbind plugin for testing.
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
PreBind: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
PreBind: v1beta2.PluginSet{
|
||||||
{
|
Enabled: []v1beta2.Plugin{
|
||||||
Name: preBindPluginName,
|
{
|
||||||
|
Name: preBindPluginName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PostBind: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{
|
||||||
|
Name: postBindPluginName,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PostBind: schedulerconfig.PluginSet{
|
}},
|
||||||
Enabled: []schedulerconfig.Plugin{
|
})
|
||||||
{
|
|
||||||
Name: postBindPluginName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "postbind-plugin", nil), 2,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "postbind-plugin", nil), 2,
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
defer testutils.CleanupTest(t, testCtx)
|
||||||
|
|
||||||
@ -1404,7 +1419,7 @@ func TestPostBindPlugin(t *testing.T) {
|
|||||||
func TestPermitPlugin(t *testing.T) {
|
func TestPermitPlugin(t *testing.T) {
|
||||||
// Create a plugin registry for testing. Register only a permit plugin.
|
// Create a plugin registry for testing. Register only a permit plugin.
|
||||||
perPlugin := &PermitPlugin{name: permitPluginName}
|
perPlugin := &PermitPlugin{name: permitPluginName}
|
||||||
registry, prof := initRegistryAndConfig(perPlugin)
|
registry, prof := initRegistryAndConfig(t, perPlugin)
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "permit-plugin", nil), 2,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "permit-plugin", nil), 2,
|
||||||
@ -1501,7 +1516,7 @@ func TestMultiplePermitPlugins(t *testing.T) {
|
|||||||
// Create a plugin registry for testing.
|
// Create a plugin registry for testing.
|
||||||
perPlugin1 := &PermitPlugin{name: "permit-plugin-1"}
|
perPlugin1 := &PermitPlugin{name: "permit-plugin-1"}
|
||||||
perPlugin2 := &PermitPlugin{name: "permit-plugin-2"}
|
perPlugin2 := &PermitPlugin{name: "permit-plugin-2"}
|
||||||
registry, prof := initRegistryAndConfig(perPlugin1, perPlugin2)
|
registry, prof := initRegistryAndConfig(t, perPlugin1, perPlugin2)
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "multi-permit-plugin", nil), 2,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "multi-permit-plugin", nil), 2,
|
||||||
@ -1556,7 +1571,7 @@ func TestPermitPluginsCancelled(t *testing.T) {
|
|||||||
// Create a plugin registry for testing.
|
// Create a plugin registry for testing.
|
||||||
perPlugin1 := &PermitPlugin{name: "permit-plugin-1"}
|
perPlugin1 := &PermitPlugin{name: "permit-plugin-1"}
|
||||||
perPlugin2 := &PermitPlugin{name: "permit-plugin-2"}
|
perPlugin2 := &PermitPlugin{name: "permit-plugin-2"}
|
||||||
registry, prof := initRegistryAndConfig(perPlugin1, perPlugin2)
|
registry, prof := initRegistryAndConfig(t, perPlugin1, perPlugin2)
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "permit-plugins", nil), 2,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "permit-plugins", nil), 2,
|
||||||
@ -1597,7 +1612,7 @@ func TestPermitPluginsCancelled(t *testing.T) {
|
|||||||
func TestCoSchedulingWithPermitPlugin(t *testing.T) {
|
func TestCoSchedulingWithPermitPlugin(t *testing.T) {
|
||||||
// Create a plugin registry for testing. Register only a permit plugin.
|
// Create a plugin registry for testing. Register only a permit plugin.
|
||||||
permitPlugin := &PermitPlugin{name: permitPluginName}
|
permitPlugin := &PermitPlugin{name: permitPluginName}
|
||||||
registry, prof := initRegistryAndConfig(permitPlugin)
|
registry, prof := initRegistryAndConfig(t, permitPlugin)
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
// TODO Make the subtests not share scheduler instances.
|
// TODO Make the subtests not share scheduler instances.
|
||||||
@ -1687,22 +1702,22 @@ func TestFilterPlugin(t *testing.T) {
|
|||||||
registry := frameworkruntime.Registry{filterPluginName: newPlugin(filterPlugin)}
|
registry := frameworkruntime.Registry{filterPluginName: newPlugin(filterPlugin)}
|
||||||
|
|
||||||
// Setup initial filter plugin for testing.
|
// Setup initial filter plugin for testing.
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
Filter: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
Filter: v1beta2.PluginSet{
|
||||||
{
|
Enabled: []v1beta2.Plugin{
|
||||||
Name: filterPluginName,
|
{Name: filterPluginName},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}
|
})
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "filter-plugin", nil), 1,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "filter-plugin", nil), 1,
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
defer testutils.CleanupTest(t, testCtx)
|
||||||
|
|
||||||
@ -1759,22 +1774,22 @@ func TestPreScorePlugin(t *testing.T) {
|
|||||||
registry := frameworkruntime.Registry{preScorePluginName: newPlugin(preScorePlugin)}
|
registry := frameworkruntime.Registry{preScorePluginName: newPlugin(preScorePlugin)}
|
||||||
|
|
||||||
// Setup initial pre-score plugin for testing.
|
// Setup initial pre-score plugin for testing.
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
PreScore: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
PreScore: v1beta2.PluginSet{
|
||||||
{
|
Enabled: []v1beta2.Plugin{
|
||||||
Name: preScorePluginName,
|
{Name: preScorePluginName},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}
|
})
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "pre-score-plugin", nil), 2,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "pre-score-plugin", nil), 2,
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
defer testutils.CleanupTest(t, testCtx)
|
||||||
|
|
||||||
@ -1826,7 +1841,7 @@ func TestPreScorePlugin(t *testing.T) {
|
|||||||
func TestPreemptWithPermitPlugin(t *testing.T) {
|
func TestPreemptWithPermitPlugin(t *testing.T) {
|
||||||
// Create a plugin registry for testing. Register only a permit plugin.
|
// Create a plugin registry for testing. Register only a permit plugin.
|
||||||
permitPlugin := &PermitPlugin{}
|
permitPlugin := &PermitPlugin{}
|
||||||
registry, prof := initRegistryAndConfig(permitPlugin)
|
registry, prof := initRegistryAndConfig(t, permitPlugin)
|
||||||
|
|
||||||
// Create the master and the scheduler with the test plugin set.
|
// Create the master and the scheduler with the test plugin set.
|
||||||
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "preempt-with-permit-plugin", nil), 0,
|
testCtx := initTestSchedulerForFrameworkTest(t, testutils.InitTestMaster(t, "preempt-with-permit-plugin", nil), 0,
|
||||||
@ -1941,23 +1956,25 @@ func initTestSchedulerForFrameworkTest(t *testing.T, testCtx *testutils.TestCont
|
|||||||
|
|
||||||
// initRegistryAndConfig returns registry and plugins config based on give plugins.
|
// initRegistryAndConfig returns registry and plugins config based on give plugins.
|
||||||
// TODO: refactor it to a more generic functions that accepts all kinds of Plugins as arguments
|
// TODO: refactor it to a more generic functions that accepts all kinds of Plugins as arguments
|
||||||
func initRegistryAndConfig(pp ...*PermitPlugin) (registry frameworkruntime.Registry, prof schedulerconfig.KubeSchedulerProfile) {
|
func initRegistryAndConfig(t *testing.T, pp ...*PermitPlugin) (frameworkruntime.Registry, schedulerconfig.KubeSchedulerProfile) {
|
||||||
|
var registry frameworkruntime.Registry
|
||||||
if len(pp) == 0 {
|
if len(pp) == 0 {
|
||||||
return
|
return frameworkruntime.Registry{}, schedulerconfig.KubeSchedulerProfile{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
versionedCfg := v1beta2.KubeSchedulerConfiguration{
|
||||||
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
|
Plugins: &v1beta2.Plugins{
|
||||||
|
Permit: v1beta2.PluginSet{},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}
|
||||||
registry = frameworkruntime.Registry{}
|
registry = frameworkruntime.Registry{}
|
||||||
var plugins []schedulerconfig.Plugin
|
|
||||||
for _, p := range pp {
|
for _, p := range pp {
|
||||||
registry.Register(p.Name(), newPermitPlugin(p))
|
registry.Register(p.Name(), newPermitPlugin(p))
|
||||||
plugins = append(plugins, schedulerconfig.Plugin{Name: p.Name()})
|
versionedCfg.Profiles[0].Plugins.Permit.Enabled = append(versionedCfg.Profiles[0].Plugins.Permit.Enabled, v1beta2.Plugin{Name: p.Name()})
|
||||||
}
|
}
|
||||||
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, versionedCfg)
|
||||||
prof.SchedulerName = v1.DefaultSchedulerName
|
return registry, cfg.Profiles[0]
|
||||||
prof.Plugins = &schedulerconfig.Plugins{
|
|
||||||
Permit: schedulerconfig.PluginSet{
|
|
||||||
Enabled: plugins,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -40,16 +40,18 @@ import (
|
|||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
"k8s.io/kubernetes/pkg/scheduler"
|
"k8s.io/kubernetes/pkg/scheduler"
|
||||||
schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing"
|
||||||
framework "k8s.io/kubernetes/pkg/scheduler/framework"
|
framework "k8s.io/kubernetes/pkg/scheduler/framework"
|
||||||
frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
|
frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
|
||||||
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
||||||
"k8s.io/kubernetes/plugin/pkg/admission/priority"
|
"k8s.io/kubernetes/plugin/pkg/admission/priority"
|
||||||
testutils "k8s.io/kubernetes/test/integration/util"
|
testutils "k8s.io/kubernetes/test/integration/util"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
var lowPriority, mediumPriority, highPriority = int32(100), int32(200), int32(300)
|
var lowPriority, mediumPriority, highPriority = int32(100), int32(200), int32(300)
|
||||||
@ -132,25 +134,28 @@ func TestPreemption(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error registering a filter: %v", err)
|
t.Fatalf("Error registering a filter: %v", err)
|
||||||
}
|
}
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
Filter: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
Filter: v1beta2.PluginSet{
|
||||||
{Name: filterPluginName},
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: filterPluginName},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreFilter: v1beta2.PluginSet{
|
||||||
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: filterPluginName},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PreFilter: schedulerconfig.PluginSet{
|
}},
|
||||||
Enabled: []schedulerconfig.Plugin{
|
})
|
||||||
{Name: filterPluginName},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
testCtx := testutils.InitTestSchedulerWithOptions(t,
|
testCtx := testutils.InitTestSchedulerWithOptions(t,
|
||||||
testutils.InitTestMaster(t, "preemption", nil),
|
testutils.InitTestMaster(t, "preemption", nil),
|
||||||
nil,
|
nil,
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
scheduler.WithFrameworkOutOfTreeRegistry(registry))
|
||||||
testutils.SyncInformerFactory(testCtx)
|
testutils.SyncInformerFactory(testCtx)
|
||||||
go testCtx.Scheduler.Run(testCtx.Ctx)
|
go testCtx.Scheduler.Run(testCtx.Ctx)
|
||||||
|
@ -29,9 +29,10 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
"k8s.io/kubernetes/pkg/scheduler"
|
"k8s.io/kubernetes/pkg/scheduler"
|
||||||
schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality"
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/imagelocality"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity"
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity"
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeaffinity"
|
||||||
@ -39,28 +40,31 @@ import (
|
|||||||
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
||||||
testutils "k8s.io/kubernetes/test/integration/util"
|
testutils "k8s.io/kubernetes/test/integration/util"
|
||||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file tests the scheduler priority functions.
|
// This file tests the scheduler priority functions.
|
||||||
func initTestSchedulerForPriorityTest(t *testing.T, scorePluginName string) *testutils.TestContext {
|
func initTestSchedulerForPriorityTest(t *testing.T, scorePluginName string) *testutils.TestContext {
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
Score: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedulerconfig.Plugin{
|
Score: v1beta2.PluginSet{
|
||||||
{Name: scorePluginName, Weight: 1},
|
Enabled: []v1beta2.Plugin{
|
||||||
},
|
{Name: scorePluginName, Weight: pointer.Int32Ptr(1)},
|
||||||
Disabled: []schedulerconfig.Plugin{
|
},
|
||||||
{Name: "*"},
|
Disabled: []v1beta2.Plugin{
|
||||||
|
{Name: "*"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}
|
})
|
||||||
testCtx := testutils.InitTestSchedulerWithOptions(
|
testCtx := testutils.InitTestSchedulerWithOptions(
|
||||||
t,
|
t,
|
||||||
testutils.InitTestMaster(t, strings.ToLower(scorePluginName), nil),
|
testutils.InitTestMaster(t, strings.ToLower(scorePluginName), nil),
|
||||||
nil,
|
nil,
|
||||||
scheduler.WithProfiles(prof),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
)
|
)
|
||||||
testutils.SyncInformerFactory(testCtx)
|
testutils.SyncInformerFactory(testCtx)
|
||||||
go testCtx.Scheduler.Run(testCtx.Ctx)
|
go testCtx.Scheduler.Run(testCtx.Ctx)
|
||||||
|
@ -34,9 +34,11 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta1"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
||||||
"k8s.io/kubernetes/pkg/scheduler"
|
"k8s.io/kubernetes/pkg/scheduler"
|
||||||
schedapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework"
|
"k8s.io/kubernetes/pkg/scheduler/framework"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/serviceaffinity"
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/serviceaffinity"
|
||||||
frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
|
frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
|
||||||
@ -44,38 +46,44 @@ import (
|
|||||||
testfwk "k8s.io/kubernetes/test/integration/framework"
|
testfwk "k8s.io/kubernetes/test/integration/framework"
|
||||||
testutils "k8s.io/kubernetes/test/integration/util"
|
testutils "k8s.io/kubernetes/test/integration/util"
|
||||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServiceAffinityEnqueue(t *testing.T) {
|
func TestServiceAffinityEnqueue(t *testing.T) {
|
||||||
profile := schedapi.KubeSchedulerProfile{
|
cfg := configtesting.V1beta1ToInternalWithDefaults(t, v1beta1.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta1.KubeSchedulerProfile{{
|
||||||
Plugins: &schedapi.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
PreFilter: schedapi.PluginSet{
|
Plugins: &v1beta1.Plugins{
|
||||||
Enabled: []schedapi.Plugin{
|
PreFilter: &v1beta1.PluginSet{
|
||||||
{Name: serviceaffinity.Name},
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: serviceaffinity.Name},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Filter: &v1beta1.PluginSet{
|
||||||
|
Enabled: []v1beta1.Plugin{
|
||||||
|
{Name: serviceaffinity.Name},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Filter: schedapi.PluginSet{
|
PluginConfig: []v1beta1.PluginConfig{
|
||||||
Enabled: []schedapi.Plugin{
|
{
|
||||||
{Name: serviceaffinity.Name},
|
Name: serviceaffinity.Name,
|
||||||
|
Args: runtime.RawExtension{
|
||||||
|
Object: &v1beta1.ServiceAffinityArgs{
|
||||||
|
AffinityLabels: []string{"hostname"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
PluginConfig: []schedapi.PluginConfig{
|
})
|
||||||
{
|
|
||||||
Name: serviceaffinity.Name,
|
|
||||||
Args: &schedapi.ServiceAffinityArgs{
|
|
||||||
AffinityLabels: []string{"hostname"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
// Use zero backoff seconds to bypass backoffQ.
|
// Use zero backoff seconds to bypass backoffQ.
|
||||||
testCtx := testutils.InitTestSchedulerWithOptions(
|
testCtx := testutils.InitTestSchedulerWithOptions(
|
||||||
t,
|
t,
|
||||||
testutils.InitTestMaster(t, "serviceaffinity-enqueue", nil),
|
testutils.InitTestMaster(t, "serviceaffinity-enqueue", nil),
|
||||||
nil,
|
nil,
|
||||||
scheduler.WithProfiles(profile),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithPodInitialBackoffSeconds(0),
|
scheduler.WithPodInitialBackoffSeconds(0),
|
||||||
scheduler.WithPodMaxBackoffSeconds(0),
|
scheduler.WithPodMaxBackoffSeconds(0),
|
||||||
)
|
)
|
||||||
@ -239,16 +247,17 @@ func TestCustomResourceEnqueue(t *testing.T) {
|
|||||||
return &fakeCRPlugin{}, nil
|
return &fakeCRPlugin{}, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
profile := schedapi.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedapi.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
Filter: schedapi.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Enabled: []schedapi.Plugin{
|
Filter: v1beta2.PluginSet{
|
||||||
{Name: "fakeCRPlugin"},
|
Enabled: []v1beta2.Plugin{
|
||||||
|
{Name: "fakeCRPlugin"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}}})
|
||||||
}
|
|
||||||
|
|
||||||
testCtx.KubeConfig = server.ClientConfig
|
testCtx.KubeConfig = server.ClientConfig
|
||||||
testCtx.ClientSet = kubernetes.NewForConfigOrDie(server.ClientConfig)
|
testCtx.ClientSet = kubernetes.NewForConfigOrDie(server.ClientConfig)
|
||||||
@ -263,7 +272,7 @@ func TestCustomResourceEnqueue(t *testing.T) {
|
|||||||
t,
|
t,
|
||||||
testCtx,
|
testCtx,
|
||||||
nil,
|
nil,
|
||||||
scheduler.WithProfiles(profile),
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
scheduler.WithFrameworkOutOfTreeRegistry(registry),
|
scheduler.WithFrameworkOutOfTreeRegistry(registry),
|
||||||
scheduler.WithPodInitialBackoffSeconds(0),
|
scheduler.WithPodInitialBackoffSeconds(0),
|
||||||
scheduler.WithPodMaxBackoffSeconds(0),
|
scheduler.WithPodMaxBackoffSeconds(0),
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
@ -36,12 +37,15 @@ import (
|
|||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
"k8s.io/client-go/tools/events"
|
"k8s.io/client-go/tools/events"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
"k8s.io/kubernetes/pkg/scheduler"
|
"k8s.io/kubernetes/pkg/scheduler"
|
||||||
kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
|
configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/profile"
|
"k8s.io/kubernetes/pkg/scheduler/profile"
|
||||||
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
||||||
"k8s.io/kubernetes/test/integration/framework"
|
"k8s.io/kubernetes/test/integration/framework"
|
||||||
testutils "k8s.io/kubernetes/test/integration/util"
|
testutils "k8s.io/kubernetes/test/integration/util"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type nodeMutationFunc func(t *testing.T, n *v1.Node, nodeLister corelisters.NodeLister, c clientset.Interface)
|
type nodeMutationFunc func(t *testing.T, n *v1.Node, nodeLister corelisters.NodeLister, c clientset.Interface)
|
||||||
@ -67,7 +71,7 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
|
|||||||
|
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
policy string
|
policy string
|
||||||
expectedPlugins map[string][]kubeschedulerconfig.Plugin
|
expectedPlugins config.Plugins
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
policy: `{
|
policy: `{
|
||||||
@ -80,21 +84,17 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
|
|||||||
{"name" : "ImageLocalityPriority", "weight" : 1}
|
{"name" : "ImageLocalityPriority", "weight" : 1}
|
||||||
]
|
]
|
||||||
}`,
|
}`,
|
||||||
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
expectedPlugins: config.Plugins{
|
||||||
"QueueSortPlugin": {{Name: "PrioritySort"}},
|
QueueSort: config.PluginSet{Enabled: []config.Plugin{{Name: "PrioritySort"}}},
|
||||||
"PreFilterPlugin": {
|
PreFilter: config.PluginSet{Enabled: []config.Plugin{{Name: "NodeResourcesFit"}}},
|
||||||
{Name: "NodeResourcesFit"},
|
Filter: config.PluginSet{Enabled: []config.Plugin{
|
||||||
},
|
|
||||||
"FilterPlugin": {
|
|
||||||
{Name: "NodeUnschedulable"},
|
{Name: "NodeUnschedulable"},
|
||||||
{Name: "NodeResourcesFit"},
|
{Name: "NodeResourcesFit"},
|
||||||
{Name: "TaintToleration"},
|
{Name: "TaintToleration"},
|
||||||
},
|
}},
|
||||||
"PostFilterPlugin": {{Name: "DefaultPreemption"}},
|
PostFilter: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultPreemption"}}},
|
||||||
"ScorePlugin": {
|
Score: config.PluginSet{Enabled: []config.Plugin{{Name: "ImageLocality", Weight: 1}}},
|
||||||
{Name: "ImageLocality", Weight: 1},
|
Bind: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultBinder"}}},
|
||||||
},
|
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -102,17 +102,17 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
|
|||||||
"kind" : "Policy",
|
"kind" : "Policy",
|
||||||
"apiVersion" : "v1"
|
"apiVersion" : "v1"
|
||||||
}`,
|
}`,
|
||||||
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
expectedPlugins: config.Plugins{
|
||||||
"QueueSortPlugin": {{Name: "PrioritySort"}},
|
QueueSort: config.PluginSet{Enabled: []config.Plugin{{Name: "PrioritySort"}}},
|
||||||
"PreFilterPlugin": {
|
PreFilter: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "NodeResourcesFit"},
|
{Name: "NodeResourcesFit"},
|
||||||
{Name: "NodePorts"},
|
{Name: "NodePorts"},
|
||||||
{Name: "NodeAffinity"},
|
{Name: "NodeAffinity"},
|
||||||
{Name: "VolumeBinding"},
|
{Name: "VolumeBinding"},
|
||||||
{Name: "PodTopologySpread"},
|
{Name: "PodTopologySpread"},
|
||||||
{Name: "InterPodAffinity"},
|
{Name: "InterPodAffinity"},
|
||||||
},
|
}},
|
||||||
"FilterPlugin": {
|
Filter: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "NodeUnschedulable"},
|
{Name: "NodeUnschedulable"},
|
||||||
{Name: "NodeResourcesFit"},
|
{Name: "NodeResourcesFit"},
|
||||||
{Name: "NodeName"},
|
{Name: "NodeName"},
|
||||||
@ -128,15 +128,15 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
|
|||||||
{Name: "VolumeZone"},
|
{Name: "VolumeZone"},
|
||||||
{Name: "PodTopologySpread"},
|
{Name: "PodTopologySpread"},
|
||||||
{Name: "InterPodAffinity"},
|
{Name: "InterPodAffinity"},
|
||||||
},
|
}},
|
||||||
"PostFilterPlugin": {{Name: "DefaultPreemption"}},
|
PostFilter: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultPreemption"}}},
|
||||||
"PreScorePlugin": {
|
PreScore: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "PodTopologySpread"},
|
{Name: "PodTopologySpread"},
|
||||||
{Name: "InterPodAffinity"},
|
{Name: "InterPodAffinity"},
|
||||||
{Name: "NodeAffinity"},
|
{Name: "NodeAffinity"},
|
||||||
{Name: "TaintToleration"},
|
{Name: "TaintToleration"},
|
||||||
},
|
}},
|
||||||
"ScorePlugin": {
|
Score: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "NodeResourcesBalancedAllocation", Weight: 1},
|
{Name: "NodeResourcesBalancedAllocation", Weight: 1},
|
||||||
{Name: "PodTopologySpread", Weight: 2},
|
{Name: "PodTopologySpread", Weight: 2},
|
||||||
{Name: "ImageLocality", Weight: 1},
|
{Name: "ImageLocality", Weight: 1},
|
||||||
@ -145,10 +145,10 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
|
|||||||
{Name: "NodeAffinity", Weight: 1},
|
{Name: "NodeAffinity", Weight: 1},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 10000},
|
{Name: "NodePreferAvoidPods", Weight: 10000},
|
||||||
{Name: "TaintToleration", Weight: 1},
|
{Name: "TaintToleration", Weight: 1},
|
||||||
},
|
}},
|
||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
Reserve: config.PluginSet{Enabled: []config.Plugin{{Name: "VolumeBinding"}}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
PreBind: config.PluginSet{Enabled: []config.Plugin{{Name: "VolumeBinding"}}},
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
Bind: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultBinder"}}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -158,14 +158,14 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
|
|||||||
"predicates" : [],
|
"predicates" : [],
|
||||||
"priorities" : []
|
"priorities" : []
|
||||||
}`,
|
}`,
|
||||||
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
expectedPlugins: config.Plugins{
|
||||||
"QueueSortPlugin": {{Name: "PrioritySort"}},
|
QueueSort: config.PluginSet{Enabled: []config.Plugin{{Name: "PrioritySort"}}},
|
||||||
"FilterPlugin": {
|
Filter: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "NodeUnschedulable"},
|
{Name: "NodeUnschedulable"},
|
||||||
{Name: "TaintToleration"},
|
{Name: "TaintToleration"},
|
||||||
},
|
}},
|
||||||
"PostFilterPlugin": {{Name: "DefaultPreemption"}},
|
PostFilter: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultPreemption"}}},
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
Bind: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultBinder"}}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -177,38 +177,38 @@ priorities:
|
|||||||
- name: ImageLocalityPriority
|
- name: ImageLocalityPriority
|
||||||
weight: 1
|
weight: 1
|
||||||
`,
|
`,
|
||||||
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
expectedPlugins: config.Plugins{
|
||||||
"QueueSortPlugin": {{Name: "PrioritySort"}},
|
QueueSort: config.PluginSet{Enabled: []config.Plugin{{Name: "PrioritySort"}}},
|
||||||
"PreFilterPlugin": {
|
PreFilter: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "NodeResourcesFit"},
|
{Name: "NodeResourcesFit"},
|
||||||
},
|
}},
|
||||||
"FilterPlugin": {
|
Filter: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "NodeUnschedulable"},
|
{Name: "NodeUnschedulable"},
|
||||||
{Name: "NodeResourcesFit"},
|
{Name: "NodeResourcesFit"},
|
||||||
{Name: "TaintToleration"},
|
{Name: "TaintToleration"},
|
||||||
},
|
}},
|
||||||
"PostFilterPlugin": {{Name: "DefaultPreemption"}},
|
PostFilter: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultPreemption"}}},
|
||||||
"ScorePlugin": {
|
Score: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "ImageLocality", Weight: 1},
|
{Name: "ImageLocality", Weight: 1},
|
||||||
},
|
}},
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
Bind: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultBinder"}}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
policy: `apiVersion: v1
|
policy: `apiVersion: v1
|
||||||
kind: Policy
|
kind: Policy
|
||||||
`,
|
`,
|
||||||
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
expectedPlugins: config.Plugins{
|
||||||
"QueueSortPlugin": {{Name: "PrioritySort"}},
|
QueueSort: config.PluginSet{Enabled: []config.Plugin{{Name: "PrioritySort"}}},
|
||||||
"PreFilterPlugin": {
|
PreFilter: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "NodeResourcesFit"},
|
{Name: "NodeResourcesFit"},
|
||||||
{Name: "NodePorts"},
|
{Name: "NodePorts"},
|
||||||
{Name: "NodeAffinity"},
|
{Name: "NodeAffinity"},
|
||||||
{Name: "VolumeBinding"},
|
{Name: "VolumeBinding"},
|
||||||
{Name: "PodTopologySpread"},
|
{Name: "PodTopologySpread"},
|
||||||
{Name: "InterPodAffinity"},
|
{Name: "InterPodAffinity"},
|
||||||
},
|
}},
|
||||||
"FilterPlugin": {
|
Filter: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "NodeUnschedulable"},
|
{Name: "NodeUnschedulable"},
|
||||||
{Name: "NodeResourcesFit"},
|
{Name: "NodeResourcesFit"},
|
||||||
{Name: "NodeName"},
|
{Name: "NodeName"},
|
||||||
@ -224,15 +224,15 @@ kind: Policy
|
|||||||
{Name: "VolumeZone"},
|
{Name: "VolumeZone"},
|
||||||
{Name: "PodTopologySpread"},
|
{Name: "PodTopologySpread"},
|
||||||
{Name: "InterPodAffinity"},
|
{Name: "InterPodAffinity"},
|
||||||
},
|
}},
|
||||||
"PostFilterPlugin": {{Name: "DefaultPreemption"}},
|
PostFilter: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultPreemption"}}},
|
||||||
"PreScorePlugin": {
|
PreScore: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "PodTopologySpread"},
|
{Name: "PodTopologySpread"},
|
||||||
{Name: "InterPodAffinity"},
|
{Name: "InterPodAffinity"},
|
||||||
{Name: "NodeAffinity"},
|
{Name: "NodeAffinity"},
|
||||||
{Name: "TaintToleration"},
|
{Name: "TaintToleration"},
|
||||||
},
|
}},
|
||||||
"ScorePlugin": {
|
Score: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "NodeResourcesBalancedAllocation", Weight: 1},
|
{Name: "NodeResourcesBalancedAllocation", Weight: 1},
|
||||||
{Name: "PodTopologySpread", Weight: 2},
|
{Name: "PodTopologySpread", Weight: 2},
|
||||||
{Name: "ImageLocality", Weight: 1},
|
{Name: "ImageLocality", Weight: 1},
|
||||||
@ -241,10 +241,10 @@ kind: Policy
|
|||||||
{Name: "NodeAffinity", Weight: 1},
|
{Name: "NodeAffinity", Weight: 1},
|
||||||
{Name: "NodePreferAvoidPods", Weight: 10000},
|
{Name: "NodePreferAvoidPods", Weight: 10000},
|
||||||
{Name: "TaintToleration", Weight: 1},
|
{Name: "TaintToleration", Weight: 1},
|
||||||
},
|
}},
|
||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
Reserve: config.PluginSet{Enabled: []config.Plugin{{Name: "VolumeBinding"}}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
PreBind: config.PluginSet{Enabled: []config.Plugin{{Name: "VolumeBinding"}}},
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
Bind: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultBinder"}}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -253,14 +253,14 @@ kind: Policy
|
|||||||
predicates: []
|
predicates: []
|
||||||
priorities: []
|
priorities: []
|
||||||
`,
|
`,
|
||||||
expectedPlugins: map[string][]kubeschedulerconfig.Plugin{
|
expectedPlugins: config.Plugins{
|
||||||
"QueueSortPlugin": {{Name: "PrioritySort"}},
|
QueueSort: config.PluginSet{Enabled: []config.Plugin{{Name: "PrioritySort"}}},
|
||||||
"FilterPlugin": {
|
Filter: config.PluginSet{Enabled: []config.Plugin{
|
||||||
{Name: "NodeUnschedulable"},
|
{Name: "NodeUnschedulable"},
|
||||||
{Name: "TaintToleration"},
|
{Name: "TaintToleration"},
|
||||||
},
|
}},
|
||||||
"PostFilterPlugin": {{Name: "DefaultPreemption"}},
|
PostFilter: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultPreemption"}}},
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
Bind: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultBinder"}}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
@ -268,7 +268,7 @@ priorities: []
|
|||||||
configPolicyName := fmt.Sprintf("scheduler-custom-policy-config-%d", i)
|
configPolicyName := fmt.Sprintf("scheduler-custom-policy-config-%d", i)
|
||||||
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{kubeschedulerconfig.SchedulerPolicyConfigMapKey: test.policy},
|
Data: map[string]string{config.SchedulerPolicyConfigMapKey: test.policy},
|
||||||
}
|
}
|
||||||
|
|
||||||
policyConfigMap.APIVersion = "v1"
|
policyConfigMap.APIVersion = "v1"
|
||||||
@ -282,30 +282,20 @@ priorities: []
|
|||||||
informerFactory,
|
informerFactory,
|
||||||
profile.NewRecorderFactory(eventBroadcaster),
|
profile.NewRecorderFactory(eventBroadcaster),
|
||||||
nil,
|
nil,
|
||||||
scheduler.WithLegacyPolicySource(&kubeschedulerconfig.SchedulerPolicySource{
|
scheduler.WithProfiles([]config.KubeSchedulerProfile(nil)...),
|
||||||
ConfigMap: &kubeschedulerconfig.SchedulerPolicyConfigMapSource{
|
scheduler.WithLegacyPolicySource(&config.SchedulerPolicySource{
|
||||||
|
ConfigMap: &config.SchedulerPolicyConfigMapSource{
|
||||||
Namespace: policyConfigMap.Namespace,
|
Namespace: policyConfigMap.Namespace,
|
||||||
Name: policyConfigMap.Name,
|
Name: policyConfigMap.Name,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
scheduler.WithProfiles(kubeschedulerconfig.KubeSchedulerProfile{
|
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
|
||||||
PluginConfig: []kubeschedulerconfig.PluginConfig{
|
|
||||||
{
|
|
||||||
Name: "VolumeBinding",
|
|
||||||
Args: &kubeschedulerconfig.VolumeBindingArgs{
|
|
||||||
BindTimeoutSeconds: 30,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("couldn't make scheduler config for test %d: %v", i, err)
|
t.Fatalf("couldn't make scheduler config for test %d: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
schedPlugins := sched.Profiles[v1.DefaultSchedulerName].ListPlugins()
|
schedPlugins := sched.Profiles[v1.DefaultSchedulerName].ListPlugins()
|
||||||
if diff := cmp.Diff(test.expectedPlugins, schedPlugins); diff != "" {
|
if diff := cmp.Diff(&test.expectedPlugins, schedPlugins); diff != "" {
|
||||||
t.Errorf("unexpected plugins diff (-want, +got): %s", diff)
|
t.Errorf("unexpected plugins diff (-want, +got): %s", diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,27 +319,33 @@ func TestSchedulerCreationFromNonExistentConfigMap(t *testing.T) {
|
|||||||
stopCh := make(chan struct{})
|
stopCh := make(chan struct{})
|
||||||
eventBroadcaster.StartRecordingToSink(stopCh)
|
eventBroadcaster.StartRecordingToSink(stopCh)
|
||||||
|
|
||||||
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
|
PluginConfig: []v1beta2.PluginConfig{
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: runtime.RawExtension{
|
||||||
|
Object: &v1beta2.VolumeBindingArgs{
|
||||||
|
BindTimeoutSeconds: pointer.Int64Ptr(30),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
_, err := scheduler.New(clientSet,
|
_, err := scheduler.New(clientSet,
|
||||||
informerFactory,
|
informerFactory,
|
||||||
profile.NewRecorderFactory(eventBroadcaster),
|
profile.NewRecorderFactory(eventBroadcaster),
|
||||||
nil,
|
nil,
|
||||||
scheduler.WithLegacyPolicySource(&kubeschedulerconfig.SchedulerPolicySource{
|
scheduler.WithLegacyPolicySource(&config.SchedulerPolicySource{
|
||||||
ConfigMap: &kubeschedulerconfig.SchedulerPolicyConfigMapSource{
|
ConfigMap: &config.SchedulerPolicyConfigMapSource{
|
||||||
Namespace: "non-existent-config",
|
Namespace: "non-existent-config",
|
||||||
Name: "non-existent-config",
|
Name: "non-existent-config",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
scheduler.WithProfiles(kubeschedulerconfig.KubeSchedulerProfile{
|
scheduler.WithProfiles(cfg.Profiles...),
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
|
||||||
PluginConfig: []kubeschedulerconfig.PluginConfig{
|
|
||||||
{
|
|
||||||
Name: "VolumeBinding",
|
|
||||||
Args: &kubeschedulerconfig.VolumeBindingArgs{
|
|
||||||
BindTimeoutSeconds: 30,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -560,8 +556,22 @@ func TestMultipleSchedulers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5. create and start a scheduler with name "foo-scheduler"
|
// 5. create and start a scheduler with name "foo-scheduler"
|
||||||
fooProf := kubeschedulerconfig.KubeSchedulerProfile{SchedulerName: fooScheduler}
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
testCtx = testutils.InitTestSchedulerWithOptions(t, testCtx, nil, scheduler.WithProfiles(fooProf))
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
|
SchedulerName: pointer.StringPtr(fooScheduler),
|
||||||
|
PluginConfig: []v1beta2.PluginConfig{
|
||||||
|
{
|
||||||
|
Name: "VolumeBinding",
|
||||||
|
Args: runtime.RawExtension{
|
||||||
|
Object: &v1beta2.VolumeBindingArgs{
|
||||||
|
BindTimeoutSeconds: pointer.Int64Ptr(30),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
testCtx = testutils.InitTestSchedulerWithOptions(t, testCtx, nil, scheduler.WithProfiles(cfg.Profiles...))
|
||||||
testutils.SyncInformerFactory(testCtx)
|
testutils.SyncInformerFactory(testCtx)
|
||||||
go testCtx.Scheduler.Run(testCtx.Ctx)
|
go testCtx.Scheduler.Run(testCtx.Ctx)
|
||||||
|
|
||||||
@ -622,14 +632,14 @@ func TestMultipleSchedulers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMultipleSchedulingProfiles(t *testing.T) {
|
func TestMultipleSchedulingProfiles(t *testing.T) {
|
||||||
testCtx := initTest(t, "multi-scheduler", scheduler.WithProfiles(
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
kubeschedulerconfig.KubeSchedulerProfile{
|
Profiles: []v1beta2.KubeSchedulerProfile{
|
||||||
SchedulerName: "default-scheduler",
|
{SchedulerName: pointer.StringPtr("default-scheduler")},
|
||||||
|
{SchedulerName: pointer.StringPtr("custom-scheduler")},
|
||||||
},
|
},
|
||||||
kubeschedulerconfig.KubeSchedulerProfile{
|
})
|
||||||
SchedulerName: "custom-scheduler",
|
|
||||||
},
|
testCtx := initTest(t, "multi-scheduler", scheduler.WithProfiles(cfg.Profiles...))
|
||||||
))
|
|
||||||
defer testutils.CleanupTest(t, testCtx)
|
defer testutils.CleanupTest(t, testCtx)
|
||||||
|
|
||||||
node := &v1.Node{
|
node := &v1.Node{
|
||||||
|
@ -35,14 +35,16 @@ import (
|
|||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/restmapper"
|
"k8s.io/client-go/restmapper"
|
||||||
"k8s.io/client-go/scale"
|
"k8s.io/client-go/scale"
|
||||||
|
"k8s.io/kube-scheduler/config/v1beta2"
|
||||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||||
"k8s.io/kubernetes/pkg/controller/disruption"
|
"k8s.io/kubernetes/pkg/controller/disruption"
|
||||||
"k8s.io/kubernetes/pkg/scheduler"
|
"k8s.io/kubernetes/pkg/scheduler"
|
||||||
schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption"
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultpreemption"
|
||||||
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
||||||
testutils "k8s.io/kubernetes/test/integration/util"
|
testutils "k8s.io/kubernetes/test/integration/util"
|
||||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// initDisruptionController initializes and runs a Disruption Controller to properly
|
// initDisruptionController initializes and runs a Disruption Controller to properly
|
||||||
@ -90,19 +92,21 @@ func initTest(t *testing.T, nsPrefix string, opts ...scheduler.Option) *testutil
|
|||||||
// initTestDisablePreemption initializes a test environment and creates master and scheduler with default
|
// initTestDisablePreemption initializes a test environment and creates master and scheduler with default
|
||||||
// configuration but with pod preemption disabled.
|
// configuration but with pod preemption disabled.
|
||||||
func initTestDisablePreemption(t *testing.T, nsPrefix string) *testutils.TestContext {
|
func initTestDisablePreemption(t *testing.T, nsPrefix string) *testutils.TestContext {
|
||||||
prof := schedulerconfig.KubeSchedulerProfile{
|
cfg := configtesting.V1beta2ToInternalWithDefaults(t, v1beta2.KubeSchedulerConfiguration{
|
||||||
SchedulerName: v1.DefaultSchedulerName,
|
Profiles: []v1beta2.KubeSchedulerProfile{{
|
||||||
Plugins: &schedulerconfig.Plugins{
|
SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName),
|
||||||
PostFilter: schedulerconfig.PluginSet{
|
Plugins: &v1beta2.Plugins{
|
||||||
Disabled: []schedulerconfig.Plugin{
|
PostFilter: v1beta2.PluginSet{
|
||||||
{Name: defaultpreemption.Name},
|
Disabled: []v1beta2.Plugin{
|
||||||
|
{Name: defaultpreemption.Name},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}
|
})
|
||||||
testCtx := testutils.InitTestSchedulerWithOptions(
|
testCtx := testutils.InitTestSchedulerWithOptions(
|
||||||
t, testutils.InitTestMaster(t, nsPrefix, nil), nil,
|
t, testutils.InitTestMaster(t, nsPrefix, nil), nil,
|
||||||
scheduler.WithProfiles(prof))
|
scheduler.WithProfiles(cfg.Profiles...))
|
||||||
testutils.SyncInformerFactory(testCtx)
|
testutils.SyncInformerFactory(testCtx)
|
||||||
go testCtx.Scheduler.Run(testCtx.Ctx)
|
go testCtx.Scheduler.Run(testCtx.Ctx)
|
||||||
return testCtx
|
return testCtx
|
||||||
|
Loading…
Reference in New Issue
Block a user