Merge pull request #88087 from alculquicondor/mutiprofiles-api

Add Schedulings Profiles to kubescheduler.config.k8s.io/v1alpha2
This commit is contained in:
Kubernetes Prow Robot 2020-02-24 14:43:35 -08:00 committed by GitHub
commit f6525dbc81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 721 additions and 234 deletions

View File

@ -38,6 +38,7 @@ type DeprecatedOptions struct {
UseLegacyPolicyConfig bool
AlgorithmProvider string
HardPodAffinitySymmetricWeight int32
SchedulerName string
}
// AddFlags adds flags for the deprecated options.
@ -59,14 +60,14 @@ func (o *DeprecatedOptions) AddFlags(fs *pflag.FlagSet, cfg *kubeschedulerconfig
fs.StringVar(&cfg.ClientConnection.ContentType, "kube-api-content-type", cfg.ClientConnection.ContentType, "DEPRECATED: content type of requests sent to apiserver.")
fs.Float32Var(&cfg.ClientConnection.QPS, "kube-api-qps", cfg.ClientConnection.QPS, "DEPRECATED: QPS to use while talking with kubernetes apiserver")
fs.Int32Var(&cfg.ClientConnection.Burst, "kube-api-burst", cfg.ClientConnection.Burst, "DEPRECATED: burst to use while talking with kubernetes apiserver")
fs.StringVar(&cfg.SchedulerName, "scheduler-name", cfg.SchedulerName, "DEPRECATED: name of the scheduler, used to select which pods will be processed by this scheduler, based on pod's \"spec.schedulerName\".")
fs.StringVar(&cfg.LeaderElection.ResourceNamespace, "lock-object-namespace", cfg.LeaderElection.ResourceNamespace, "DEPRECATED: define the namespace of the lock object. Will be removed in favor of leader-elect-resource-namespace.")
fs.StringVar(&cfg.LeaderElection.ResourceName, "lock-object-name", cfg.LeaderElection.ResourceName, "DEPRECATED: define the name of the lock object. Will be removed in favor of leader-elect-resource-name")
fs.Int32Var(&o.HardPodAffinitySymmetricWeight, "hard-pod-affinity-symmetric-weight", interpodaffinity.DefaultHardPodAffinityWeight,
fs.Int32Var(&o.HardPodAffinitySymmetricWeight, "hard-pod-affinity-symmetric-weight", o.HardPodAffinitySymmetricWeight,
"DEPRECATED: RequiredDuringScheduling affinity is not symmetric, but there is an implicit PreferredDuringScheduling affinity rule corresponding "+
"to every RequiredDuringScheduling affinity rule. --hard-pod-affinity-symmetric-weight represents the weight of implicit PreferredDuringScheduling affinity rule. Must be in the range 0-100."+
"This option was moved to the policy configuration file")
fs.StringVar(&o.SchedulerName, "scheduler-name", o.SchedulerName, "DEPRECATED: name of the scheduler, used to select which pods will be processed by this scheduler, based on pod's \"spec.schedulerName\".")
// MarkDeprecated hides the flag from the help. We don't want that:
// fs.MarkDeprecated("hard-pod-affinity-symmetric-weight", "This option was moved to the policy configuration file")
}
@ -120,11 +121,17 @@ func (o *DeprecatedOptions) ApplyTo(cfg *kubeschedulerconfig.KubeSchedulerConfig
}
}
// The following deprecated options affect the only existing profile that is
// added by default.
profile := &cfg.Profiles[0]
if len(o.SchedulerName) > 0 {
profile.SchedulerName = o.SchedulerName
}
if o.HardPodAffinitySymmetricWeight != interpodaffinity.DefaultHardPodAffinityWeight {
args := interpodaffinity.Args{
HardPodAffinityWeight: &o.HardPodAffinitySymmetricWeight,
}
cfg.PluginConfig = append(cfg.PluginConfig, plugins.NewPluginConfig(interpodaffinity.Name, args))
profile.PluginConfig = append(profile.PluginConfig, plugins.NewPluginConfig(interpodaffinity.Name, args))
}
return nil

View File

@ -48,6 +48,7 @@ import (
kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
kubeschedulerscheme "k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"
"k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity"
)
// Options has all the params needed to run a Scheduler
@ -98,8 +99,10 @@ func NewOptions() (*Options, error) {
Authentication: apiserveroptions.NewDelegatingAuthenticationOptions(),
Authorization: apiserveroptions.NewDelegatingAuthorizationOptions(),
Deprecated: &DeprecatedOptions{
UseLegacyPolicyConfig: false,
PolicyConfigMapNamespace: metav1.NamespaceSystem,
UseLegacyPolicyConfig: false,
PolicyConfigMapNamespace: metav1.NamespaceSystem,
SchedulerName: corev1.DefaultSchedulerName,
HardPodAffinitySymmetricWeight: interpodaffinity.DefaultHardPodAffinityWeight,
},
}
@ -239,11 +242,12 @@ func (o *Options) Config() (*schedulerappconfig.Config, error) {
}
coreBroadcaster := record.NewBroadcaster()
coreRecorder := coreBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: c.ComponentConfig.SchedulerName})
// Set up leader election if enabled.
var leaderElectionConfig *leaderelection.LeaderElectionConfig
if c.ComponentConfig.LeaderElection.LeaderElect {
// Use the scheduler name in the first profile to record leader election.
coreRecorder := coreBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: c.ComponentConfig.Profiles[0].SchedulerName})
leaderElectionConfig, err = makeLeaderElectionConfig(c.ComponentConfig.LeaderElection, leaderElectionClient, coreRecorder)
if err != nil {
return nil, err

View File

@ -138,6 +138,7 @@ leaderElection:
if err := ioutil.WriteFile(v1alpha1Config, []byte(fmt.Sprintf(`
apiVersion: kubescheduler.config.k8s.io/v1alpha1
kind: KubeSchedulerConfiguration
schedulerName: "my-old-scheduler"
clientConnection:
kubeconfig: "%s"
leaderElection:
@ -225,20 +226,21 @@ apiVersion: kubescheduler.config.k8s.io/v1alpha2
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: "%s"
plugins:
reserve:
enabled:
- name: foo
- name: bar
disabled:
- name: baz
preBind:
enabled:
- name: foo
disabled:
- name: baz
pluginConfig:
- name: foo
profiles:
- plugins:
reserve:
enabled:
- name: foo
- name: bar
disabled:
- name: baz
preBind:
enabled:
- name: foo
disabled:
- name: baz
pluginConfig:
- name: foo
`, configKubeconfig)), os.FileMode(0600)); err != nil {
t.Fatal(err)
}
@ -319,7 +321,6 @@ plugins:
},
expectedUsername: "config",
expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
SchedulerName: "default-scheduler",
AlgorithmSource: kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &defaultSource},
HealthzBindAddress: "0.0.0.0:10251",
MetricsBindAddress: "0.0.0.0:10251",
@ -348,7 +349,9 @@ plugins:
BindTimeoutSeconds: defaultBindTimeoutSeconds,
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
Plugins: nil,
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
{SchedulerName: "default-scheduler"},
},
},
},
{
@ -410,7 +413,6 @@ plugins:
},
expectedUsername: "flag",
expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
SchedulerName: "default-scheduler",
AlgorithmSource: kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &defaultSource},
HealthzBindAddress: "", // defaults empty when not running from config file
MetricsBindAddress: "", // defaults empty when not running from config file
@ -439,6 +441,9 @@ plugins:
BindTimeoutSeconds: defaultBindTimeoutSeconds,
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
{SchedulerName: "default-scheduler"},
},
},
},
{
@ -474,7 +479,6 @@ plugins:
},
},
expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
SchedulerName: "default-scheduler",
AlgorithmSource: kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &defaultSource},
HealthzBindAddress: "", // defaults empty when not running from config file
MetricsBindAddress: "", // defaults empty when not running from config file
@ -503,6 +507,9 @@ plugins:
BindTimeoutSeconds: defaultBindTimeoutSeconds,
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
{SchedulerName: "default-scheduler"},
},
},
expectedUsername: "none, http",
},
@ -513,7 +520,6 @@ plugins:
},
expectedUsername: "config",
expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
SchedulerName: "default-scheduler",
AlgorithmSource: kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &defaultSource},
HealthzBindAddress: "0.0.0.0:10251",
MetricsBindAddress: "0.0.0.0:10251",
@ -542,39 +548,44 @@ plugins:
BindTimeoutSeconds: defaultBindTimeoutSeconds,
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
Plugins: &kubeschedulerconfig.Plugins{
Reserve: &kubeschedulerconfig.PluginSet{
Enabled: []kubeschedulerconfig.Plugin{
{
Name: "foo",
},
{
Name: "bar",
},
},
Disabled: []kubeschedulerconfig.Plugin{
{
Name: "baz",
},
},
},
PreBind: &kubeschedulerconfig.PluginSet{
Enabled: []kubeschedulerconfig.Plugin{
{
Name: "foo",
},
},
Disabled: []kubeschedulerconfig.Plugin{
{
Name: "baz",
},
},
},
},
PluginConfig: []kubeschedulerconfig.PluginConfig{
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
{
Name: "foo",
Args: runtime.Unknown{},
SchedulerName: "default-scheduler",
Plugins: &kubeschedulerconfig.Plugins{
Reserve: &kubeschedulerconfig.PluginSet{
Enabled: []kubeschedulerconfig.Plugin{
{
Name: "foo",
},
{
Name: "bar",
},
},
Disabled: []kubeschedulerconfig.Plugin{
{
Name: "baz",
},
},
},
PreBind: &kubeschedulerconfig.PluginSet{
Enabled: []kubeschedulerconfig.Plugin{
{
Name: "foo",
},
},
Disabled: []kubeschedulerconfig.Plugin{
{
Name: "baz",
},
},
},
},
PluginConfig: []kubeschedulerconfig.PluginConfig{
{
Name: "foo",
Args: runtime.Unknown{},
},
},
},
},
},
@ -586,7 +597,6 @@ plugins:
},
expectedUsername: "config",
expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
SchedulerName: "default-scheduler",
AlgorithmSource: kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &defaultSource},
HealthzBindAddress: "0.0.0.0:10251",
MetricsBindAddress: "0.0.0.0:10251",
@ -615,19 +625,24 @@ plugins:
BindTimeoutSeconds: defaultBindTimeoutSeconds,
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
Plugins: &kubeschedulerconfig.Plugins{
PreScore: &kubeschedulerconfig.PluginSet{
Enabled: []kubeschedulerconfig.Plugin{
{
Name: "foo",
},
{
Name: "bar",
},
},
Disabled: []kubeschedulerconfig.Plugin{
{
Name: "baz",
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: &kubeschedulerconfig.Plugins{
PreScore: &kubeschedulerconfig.PluginSet{
Enabled: []kubeschedulerconfig.Plugin{
{
Name: "foo",
},
{
Name: "bar",
},
},
Disabled: []kubeschedulerconfig.Plugin{
{
Name: "baz",
},
},
},
},
},
@ -653,7 +668,6 @@ plugins:
},
expectedUsername: "flag",
expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
SchedulerName: "default-scheduler",
AlgorithmSource: kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &defaultSource},
DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{
EnableProfiling: true,
@ -680,24 +694,74 @@ plugins:
BindTimeoutSeconds: defaultBindTimeoutSeconds,
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
PluginConfig: []kubeschedulerconfig.PluginConfig{
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
{
Name: "InterPodAffinity",
Args: runtime.Unknown{
Raw: []byte(`{"hardPodAffinityWeight":5}`),
SchedulerName: "default-scheduler",
PluginConfig: []kubeschedulerconfig.PluginConfig{
{
Name: "InterPodAffinity",
Args: runtime.Unknown{
Raw: []byte(`{"hardPodAffinityWeight":5}`),
},
},
},
},
},
},
},
{
name: "v1alpha1 config with HardPodAffinitySymmetricWeight",
name: "Deprecated SchedulerName flag",
options: &Options{
ComponentConfig: func() kubeschedulerconfig.KubeSchedulerConfiguration {
cfg, _ := newDefaultComponentConfig()
cfg.ClientConnection.Kubeconfig = flagKubeconfig
return *cfg
}(),
Deprecated: &DeprecatedOptions{
SchedulerName: "my-nice-scheduler",
HardPodAffinitySymmetricWeight: 1,
},
},
expectedUsername: "flag",
expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
AlgorithmSource: kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &defaultSource},
DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{
EnableProfiling: true,
EnableContentionProfiling: true,
},
LeaderElection: kubeschedulerconfig.KubeSchedulerLeaderElectionConfiguration{
LeaderElectionConfiguration: 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: "endpointsleases",
ResourceNamespace: "kube-system",
ResourceName: "kube-scheduler",
},
},
ClientConnection: componentbaseconfig.ClientConnectionConfiguration{
Kubeconfig: flagKubeconfig,
QPS: 50,
Burst: 100,
ContentType: "application/vnd.kubernetes.protobuf",
},
PercentageOfNodesToScore: defaultPercentageOfNodesToScore,
BindTimeoutSeconds: defaultBindTimeoutSeconds,
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
{SchedulerName: "my-nice-scheduler"},
},
},
},
{
name: "v1alpha1 config with SchedulerName and HardPodAffinitySymmetricWeight",
options: &Options{
ConfigFile: v1alpha1Config,
},
expectedUsername: "config",
expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
SchedulerName: "default-scheduler",
AlgorithmSource: kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &defaultSource},
HealthzBindAddress: "0.0.0.0:10251",
MetricsBindAddress: "0.0.0.0:10251",
@ -726,11 +790,16 @@ plugins:
BindTimeoutSeconds: defaultBindTimeoutSeconds,
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
PluginConfig: []kubeschedulerconfig.PluginConfig{
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
{
Name: "InterPodAffinity",
Args: runtime.Unknown{
Raw: []byte(`{"hardPodAffinityWeight":3}`),
SchedulerName: "my-old-scheduler",
PluginConfig: []kubeschedulerconfig.PluginConfig{
{
Name: "InterPodAffinity",
Args: runtime.Unknown{
Raw: []byte(`{"hardPodAffinityWeight":3}`),
},
},
},
},
},
@ -743,7 +812,6 @@ plugins:
},
expectedUsername: "config",
expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
SchedulerName: "default-scheduler",
AlgorithmSource: kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &defaultSource},
HealthzBindAddress: "0.0.0.0:10251",
MetricsBindAddress: "0.0.0.0:10251",
@ -772,7 +840,9 @@ plugins:
BindTimeoutSeconds: defaultBindTimeoutSeconds,
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
Plugins: nil,
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
{SchedulerName: "default-scheduler"},
},
},
},
{
@ -790,7 +860,6 @@ plugins:
},
expectedUsername: "config",
expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{
SchedulerName: "default-scheduler",
AlgorithmSource: kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &defaultSource},
HealthzBindAddress: "0.0.0.0:10251",
MetricsBindAddress: "0.0.0.0:10251",
@ -819,7 +888,9 @@ plugins:
BindTimeoutSeconds: defaultBindTimeoutSeconds,
PodInitialBackoffSeconds: defaultPodInitialBackoffSeconds,
PodMaxBackoffSeconds: defaultPodMaxBackoffSeconds,
Plugins: nil,
Profiles: []kubeschedulerconfig.KubeSchedulerProfile{
{SchedulerName: "default-scheduler"},
},
},
},
{

View File

@ -19,6 +19,7 @@ package app
import (
"context"
"errors"
"fmt"
"io"
"net/http"
@ -171,12 +172,17 @@ func Run(ctx context.Context, cc schedulerserverconfig.CompletedConfig, outOfTre
}
}
if len(cc.ComponentConfig.Profiles) != 1 {
// TODO(#85737): Support more than one profile.
return errors.New("multiple scheduling profiles are unsupported")
}
profile := cc.ComponentConfig.Profiles[0]
// Prepare event clients.
if _, err := cc.Client.Discovery().ServerResourcesForGroupVersion(eventsv1beta1.SchemeGroupVersion.String()); err == nil {
cc.Broadcaster = events.NewBroadcaster(&events.EventSinkImpl{Interface: cc.EventClient.Events("")})
cc.Recorder = cc.Broadcaster.NewRecorder(scheme.Scheme, cc.ComponentConfig.SchedulerName)
cc.Recorder = cc.Broadcaster.NewRecorder(scheme.Scheme, profile.SchedulerName)
} else {
recorder := cc.CoreBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: cc.ComponentConfig.SchedulerName})
recorder := cc.CoreBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: profile.SchedulerName})
cc.Recorder = record.NewEventRecorderAdapter(recorder)
}
@ -186,14 +192,14 @@ func Run(ctx context.Context, cc schedulerserverconfig.CompletedConfig, outOfTre
cc.PodInformer,
cc.Recorder,
ctx.Done(),
scheduler.WithName(cc.ComponentConfig.SchedulerName),
scheduler.WithName(profile.SchedulerName),
scheduler.WithAlgorithmSource(cc.ComponentConfig.AlgorithmSource),
scheduler.WithPreemptionDisabled(cc.ComponentConfig.DisablePreemption),
scheduler.WithPercentageOfNodesToScore(cc.ComponentConfig.PercentageOfNodesToScore),
scheduler.WithBindTimeoutSeconds(cc.ComponentConfig.BindTimeoutSeconds),
scheduler.WithFrameworkOutOfTreeRegistry(outOfTreeRegistry),
scheduler.WithFrameworkPlugins(cc.ComponentConfig.Plugins),
scheduler.WithFrameworkPluginConfig(cc.ComponentConfig.PluginConfig),
scheduler.WithFrameworkPlugins(profile.Plugins),
scheduler.WithFrameworkPluginConfig(profile.PluginConfig),
scheduler.WithPodMaxBackoffSeconds(cc.ComponentConfig.PodMaxBackoffSeconds),
scheduler.WithPodInitialBackoffSeconds(cc.ComponentConfig.PodInitialBackoffSeconds),
)

View File

@ -46,9 +46,6 @@ const (
type KubeSchedulerConfiguration struct {
metav1.TypeMeta
// SchedulerName is name of the scheduler, used to select which pods
// will be processed by this scheduler, based on pod's "spec.SchedulerName".
SchedulerName string
// AlgorithmSource specifies the scheduler algorithm source.
AlgorithmSource SchedulerAlgorithmSource
@ -97,15 +94,33 @@ type KubeSchedulerConfiguration struct {
// the default value (10s) will be used.
PodMaxBackoffSeconds int64
// Plugins specify the set of plugins that should be enabled or disabled. Enabled plugins are the
// ones that should be enabled in addition to the default plugins. Disabled plugins are any of the
// default plugins that should be disabled.
// When no enabled or disabled plugin is specified for an extension point, default plugins for
// that extension point will be used if there is any.
// Profiles are scheduling profiles that kube-scheduler supports. Pods can
// choose to be scheduled under a particular profile by setting its associated
// scheduler name. Pods that don't specify any scheduler name are scheduled
// with the "default-scheduler" profile, if present here.
Profiles []KubeSchedulerProfile
}
// KubeSchedulerProfile is a scheduling profile.
type KubeSchedulerProfile struct {
// SchedulerName is the name of the scheduler associated to this profile.
// If SchedulerName matches with the pod's "spec.schedulerName", then the pod
// is scheduled with this profile.
SchedulerName string
// Plugins specify the set of plugins that should be enabled or disabled.
// Enabled plugins are the ones that should be enabled in addition to the
// default plugins. Disabled plugins are any of the default plugins that
// should be disabled.
// When no enabled or disabled plugin is specified for an extension point,
// default plugins for that extension point will be used if there is any.
// If a QueueSort plugin is specified, the same QueueSort Plugin and
// PluginConfig must be specified for all profiles.
Plugins *Plugins
// PluginConfig is an optional set of custom plugin arguments for each plugin.
// Omitting config args for a plugin is equivalent to using the default config for that plugin.
// Omitting config args for a plugin is equivalent to using the default config
// for that plugin.
PluginConfig []PluginConfig
}

View File

@ -19,6 +19,7 @@ package v1alpha1
import (
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/kube-scheduler/config/v1alpha1"
"k8s.io/kubernetes/pkg/scheduler/apis/config"
@ -31,14 +32,40 @@ func Convert_v1alpha1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfigur
if err := autoConvert_v1alpha1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in, out, s); err != nil {
return err
}
var profile config.KubeSchedulerProfile
if err := metav1.Convert_Pointer_string_To_string(&in.SchedulerName, &profile.SchedulerName, s); err != nil {
return err
}
if in.Plugins != nil {
profile.Plugins = &config.Plugins{}
if err := Convert_v1alpha1_Plugins_To_config_Plugins(in.Plugins, profile.Plugins, s); err != nil {
return err
}
} else {
profile.Plugins = nil
}
if in.PluginConfig != nil {
profile.PluginConfig = make([]config.PluginConfig, len(in.PluginConfig))
for i := range in.PluginConfig {
if err := Convert_v1alpha1_PluginConfig_To_config_PluginConfig(&in.PluginConfig[i], &profile.PluginConfig[i], s); err != nil {
return err
}
}
}
if in.HardPodAffinitySymmetricWeight != nil {
args := interpodaffinity.Args{HardPodAffinityWeight: in.HardPodAffinitySymmetricWeight}
plCfg := plugins.NewPluginConfig(interpodaffinity.Name, args)
out.PluginConfig = append(out.PluginConfig, plCfg)
profile.PluginConfig = append(profile.PluginConfig, plCfg)
}
out.Profiles = []config.KubeSchedulerProfile{profile}
return nil
}
func Convert_config_KubeSchedulerConfiguration_To_v1alpha1_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1alpha1.KubeSchedulerConfiguration, s conversion.Scope) error {
// Conversion from internal to v1alpha1 is not relevant for kube-scheduler.
return autoConvert_config_KubeSchedulerConfiguration_To_v1alpha1_KubeSchedulerConfiguration(in, out, s)
}
// Convert_v1alpha1_KubeSchedulerLeaderElectionConfiguration_To_config_KubeSchedulerLeaderElectionConfiguration handles deprecated parameters for leader election.
func Convert_v1alpha1_KubeSchedulerLeaderElectionConfiguration_To_config_KubeSchedulerLeaderElectionConfiguration(in *v1alpha1.KubeSchedulerLeaderElectionConfiguration, out *config.KubeSchedulerLeaderElectionConfiguration, s conversion.Scope) error {
if err := autoConvert_v1alpha1_KubeSchedulerLeaderElectionConfiguration_To_config_KubeSchedulerLeaderElectionConfiguration(in, out, s); err != nil {

View File

@ -30,33 +30,76 @@ import (
"k8s.io/utils/pointer"
)
func TestConvertHardPodAffinitySymmetricWeight(t *testing.T) {
func TestConvertKubeSchedulerConfiguration(t *testing.T) {
cases := []struct {
name string
cfg v1alpha1.KubeSchedulerConfiguration
want config.KubeSchedulerConfiguration
}{
{
name: "no weight",
},
{
name: "custom weight",
name: "scheduler name",
cfg: v1alpha1.KubeSchedulerConfiguration{
HardPodAffinitySymmetricWeight: pointer.Int32Ptr(3),
SchedulerName: pointer.StringPtr("custom-name"),
},
want: config.KubeSchedulerConfiguration{
PluginConfig: []config.PluginConfig{
Profiles: []config.KubeSchedulerProfile{
{SchedulerName: "custom-name"},
},
},
},
{
name: "plugins and plugin config",
cfg: v1alpha1.KubeSchedulerConfiguration{
Plugins: &v1alpha1.Plugins{
QueueSort: &v1alpha1.PluginSet{
Enabled: []v1alpha1.Plugin{
{Name: "FooPlugin"},
},
},
},
PluginConfig: []v1alpha1.PluginConfig{
{Name: "FooPlugin"},
},
},
want: config.KubeSchedulerConfiguration{
Profiles: []config.KubeSchedulerProfile{
{
Name: "InterPodAffinity",
Args: runtime.Unknown{
Raw: []byte(`{"hardPodAffinityWeight":3}`),
Plugins: &config.Plugins{
QueueSort: &config.PluginSet{
Enabled: []config.Plugin{
{Name: "FooPlugin"},
},
},
},
PluginConfig: []config.PluginConfig{
{Name: "FooPlugin"},
},
},
},
},
},
{
name: "custom weight and existing PluginConfig",
name: "custom hard pod affinity weight",
cfg: v1alpha1.KubeSchedulerConfiguration{
HardPodAffinitySymmetricWeight: pointer.Int32Ptr(3),
},
want: config.KubeSchedulerConfiguration{
Profiles: []config.KubeSchedulerProfile{
{
PluginConfig: []config.PluginConfig{
{
Name: "InterPodAffinity",
Args: runtime.Unknown{
Raw: []byte(`{"hardPodAffinityWeight":3}`),
},
},
},
},
},
},
},
{
name: "custom hard pod affinity weight and existing PluginConfig",
cfg: v1alpha1.KubeSchedulerConfiguration{
HardPodAffinitySymmetricWeight: pointer.Int32Ptr(3),
PluginConfig: []v1alpha1.PluginConfig{
@ -69,17 +112,21 @@ func TestConvertHardPodAffinitySymmetricWeight(t *testing.T) {
},
},
want: config.KubeSchedulerConfiguration{
PluginConfig: []config.PluginConfig{
Profiles: []config.KubeSchedulerProfile{
{
Name: "InterPodAffinity",
Args: runtime.Unknown{
Raw: []byte(`{"hardPodAffinityWeight":5}`),
},
},
{
Name: "InterPodAffinity",
Args: runtime.Unknown{
Raw: []byte(`{"hardPodAffinityWeight":3}`),
PluginConfig: []config.PluginConfig{
{
Name: "InterPodAffinity",
Args: runtime.Unknown{
Raw: []byte(`{"hardPodAffinityWeight":5}`),
},
},
{
Name: "InterPodAffinity",
Args: runtime.Unknown{
Raw: []byte(`{"hardPodAffinityWeight":3}`),
},
},
},
},
},

View File

@ -38,11 +38,6 @@ func init() {
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {
if err := s.AddGeneratedConversionFunc((*config.KubeSchedulerConfiguration)(nil), (*v1alpha1.KubeSchedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_KubeSchedulerConfiguration_To_v1alpha1_KubeSchedulerConfiguration(a.(*config.KubeSchedulerConfiguration), b.(*v1alpha1.KubeSchedulerConfiguration), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1alpha1.Plugin)(nil), (*config.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_Plugin_To_config_Plugin(a.(*v1alpha1.Plugin), b.(*config.Plugin), scope)
}); err != nil {
@ -113,6 +108,11 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddConversionFunc((*config.KubeSchedulerConfiguration)(nil), (*v1alpha1.KubeSchedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_KubeSchedulerConfiguration_To_v1alpha1_KubeSchedulerConfiguration(a.(*config.KubeSchedulerConfiguration), b.(*v1alpha1.KubeSchedulerConfiguration), scope)
}); err != nil {
return err
}
if err := s.AddConversionFunc((*config.KubeSchedulerLeaderElectionConfiguration)(nil), (*v1alpha1.KubeSchedulerLeaderElectionConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_KubeSchedulerLeaderElectionConfiguration_To_v1alpha1_KubeSchedulerLeaderElectionConfiguration(a.(*config.KubeSchedulerLeaderElectionConfiguration), b.(*v1alpha1.KubeSchedulerLeaderElectionConfiguration), scope)
}); err != nil {
@ -142,9 +142,7 @@ func RegisterConversions(s *runtime.Scheme) error {
}
func autoConvert_v1alpha1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in *v1alpha1.KubeSchedulerConfiguration, out *config.KubeSchedulerConfiguration, s conversion.Scope) error {
if err := v1.Convert_Pointer_string_To_string(&in.SchedulerName, &out.SchedulerName, s); err != nil {
return err
}
// WARNING: in.SchedulerName requires manual conversion: does not exist in peer-type
if err := Convert_v1alpha1_SchedulerAlgorithmSource_To_config_SchedulerAlgorithmSource(&in.AlgorithmSource, &out.AlgorithmSource, s); err != nil {
return err
}
@ -179,23 +177,12 @@ func autoConvert_v1alpha1_KubeSchedulerConfiguration_To_config_KubeSchedulerConf
if err := v1.Convert_Pointer_int64_To_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, s); err != nil {
return err
}
if in.Plugins != nil {
in, out := &in.Plugins, &out.Plugins
*out = new(config.Plugins)
if err := Convert_v1alpha1_Plugins_To_config_Plugins(*in, *out, s); err != nil {
return err
}
} else {
out.Plugins = nil
}
out.PluginConfig = *(*[]config.PluginConfig)(unsafe.Pointer(&in.PluginConfig))
// WARNING: in.Plugins requires manual conversion: does not exist in peer-type
// WARNING: in.PluginConfig requires manual conversion: does not exist in peer-type
return nil
}
func autoConvert_config_KubeSchedulerConfiguration_To_v1alpha1_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1alpha1.KubeSchedulerConfiguration, s conversion.Scope) error {
if err := v1.Convert_string_To_Pointer_string(&in.SchedulerName, &out.SchedulerName, s); err != nil {
return err
}
if err := Convert_config_SchedulerAlgorithmSource_To_v1alpha1_SchedulerAlgorithmSource(&in.AlgorithmSource, &out.AlgorithmSource, s); err != nil {
return err
}
@ -229,24 +216,10 @@ func autoConvert_config_KubeSchedulerConfiguration_To_v1alpha1_KubeSchedulerConf
if err := v1.Convert_int64_To_Pointer_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, s); err != nil {
return err
}
if in.Plugins != nil {
in, out := &in.Plugins, &out.Plugins
*out = new(v1alpha1.Plugins)
if err := Convert_config_Plugins_To_v1alpha1_Plugins(*in, *out, s); err != nil {
return err
}
} else {
out.Plugins = nil
}
out.PluginConfig = *(*[]v1alpha1.PluginConfig)(unsafe.Pointer(&in.PluginConfig))
// WARNING: in.Profiles requires manual conversion: does not exist in peer-type
return nil
}
// Convert_config_KubeSchedulerConfiguration_To_v1alpha1_KubeSchedulerConfiguration is an autogenerated conversion function.
func Convert_config_KubeSchedulerConfiguration_To_v1alpha1_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1alpha1.KubeSchedulerConfiguration, s conversion.Scope) error {
return autoConvert_config_KubeSchedulerConfiguration_To_v1alpha1_KubeSchedulerConfiguration(in, out, s)
}
func autoConvert_v1alpha1_KubeSchedulerLeaderElectionConfiguration_To_config_KubeSchedulerLeaderElectionConfiguration(in *v1alpha1.KubeSchedulerLeaderElectionConfiguration, out *config.KubeSchedulerLeaderElectionConfiguration, s conversion.Scope) error {
if err := componentbaseconfigv1alpha1.Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(&in.LeaderElectionConfiguration, &out.LeaderElectionConfiguration, s); err != nil {
return err

View File

@ -21,6 +21,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/component-base/config/v1alpha1:go_default_library",
"//staging/src/k8s.io/kube-scheduler/config/v1alpha2:go_default_library",
"//vendor/k8s.io/utils/pointer:go_default_library",
],
)
@ -32,6 +33,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/component-base/config/v1alpha1:go_default_library",
"//staging/src/k8s.io/kube-scheduler/config/v1alpha2:go_default_library",
"//vendor/github.com/google/go-cmp/cmp:go_default_library",
"//vendor/k8s.io/utils/pointer:go_default_library",
],
)

View File

@ -24,6 +24,7 @@ import (
componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1"
"k8s.io/kube-scheduler/config/v1alpha2"
"k8s.io/kubernetes/pkg/scheduler/apis/config"
"k8s.io/utils/pointer"
// this package shouldn't really depend on other k8s.io/kubernetes code
api "k8s.io/kubernetes/pkg/apis/core"
@ -36,9 +37,13 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error {
// SetDefaults_KubeSchedulerConfiguration sets additional defaults
func SetDefaults_KubeSchedulerConfiguration(obj *v1alpha2.KubeSchedulerConfiguration) {
if obj.SchedulerName == nil {
val := api.DefaultSchedulerName
obj.SchedulerName = &val
if len(obj.Profiles) == 0 {
obj.Profiles = append(obj.Profiles, v1alpha2.KubeSchedulerProfile{})
}
// Only apply a default scheduler name when there is a single profile.
// Validation will ensure that every profile has a non-empty unique name.
if len(obj.Profiles) == 1 && obj.Profiles[0].SchedulerName == nil {
obj.Profiles[0].SchedulerName = pointer.StringPtr(api.DefaultSchedulerName)
}
if obj.AlgorithmSource.Policy == nil &&

View File

@ -17,10 +17,10 @@ limitations under the License.
package v1alpha2
import (
"reflect"
"testing"
"time"
"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
componentbaseconfig "k8s.io/component-base/config/v1alpha1"
"k8s.io/kube-scheduler/config/v1alpha2"
@ -38,7 +38,6 @@ func TestSchedulerDefaults(t *testing.T) {
name: "empty config",
config: &v1alpha2.KubeSchedulerConfiguration{},
expected: &v1alpha2.KubeSchedulerConfiguration{
SchedulerName: pointer.StringPtr("default-scheduler"),
AlgorithmSource: v1alpha2.SchedulerAlgorithmSource{Provider: pointer.StringPtr("DefaultProvider")},
HealthzBindAddress: pointer.StringPtr("0.0.0.0:10251"),
MetricsBindAddress: pointer.StringPtr("0.0.0.0:10251"),
@ -67,7 +66,128 @@ func TestSchedulerDefaults(t *testing.T) {
BindTimeoutSeconds: pointer.Int64Ptr(600),
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
Plugins: nil,
Profiles: []v1alpha2.KubeSchedulerProfile{
{SchedulerName: pointer.StringPtr("default-scheduler")},
},
},
},
{
name: "no scheduler name",
config: &v1alpha2.KubeSchedulerConfiguration{
Profiles: []v1alpha2.KubeSchedulerProfile{
{
PluginConfig: []v1alpha2.PluginConfig{
{Name: "FooPlugin"},
},
},
},
},
expected: &v1alpha2.KubeSchedulerConfiguration{
AlgorithmSource: v1alpha2.SchedulerAlgorithmSource{Provider: pointer.StringPtr("DefaultProvider")},
HealthzBindAddress: pointer.StringPtr("0.0.0.0:10251"),
MetricsBindAddress: pointer.StringPtr("0.0.0.0:10251"),
DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{
EnableProfiling: &enable,
EnableContentionProfiling: &enable,
},
LeaderElection: v1alpha2.KubeSchedulerLeaderElectionConfiguration{
LeaderElectionConfiguration: componentbaseconfig.LeaderElectionConfiguration{
LeaderElect: pointer.BoolPtr(true),
LeaseDuration: metav1.Duration{Duration: 15 * time.Second},
RenewDeadline: metav1.Duration{Duration: 10 * time.Second},
RetryPeriod: metav1.Duration{Duration: 2 * time.Second},
ResourceLock: "endpointsleases",
ResourceNamespace: "kube-system",
ResourceName: "kube-scheduler",
},
},
ClientConnection: componentbaseconfig.ClientConnectionConfiguration{
QPS: 50,
Burst: 100,
ContentType: "application/vnd.kubernetes.protobuf",
},
DisablePreemption: pointer.BoolPtr(false),
PercentageOfNodesToScore: pointer.Int32Ptr(0),
BindTimeoutSeconds: pointer.Int64Ptr(600),
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
Profiles: []v1alpha2.KubeSchedulerProfile{
{
SchedulerName: pointer.StringPtr("default-scheduler"),
PluginConfig: []v1alpha2.PluginConfig{
{Name: "FooPlugin"},
},
},
},
},
},
{
name: "two profiles",
config: &v1alpha2.KubeSchedulerConfiguration{
Profiles: []v1alpha2.KubeSchedulerProfile{
{
PluginConfig: []v1alpha2.PluginConfig{
{Name: "FooPlugin"},
},
},
{
SchedulerName: pointer.StringPtr("custom-scheduler"),
Plugins: &v1alpha2.Plugins{
Bind: &v1alpha2.PluginSet{
Enabled: []v1alpha2.Plugin{
{Name: "BarPlugin"},
},
},
},
},
},
},
expected: &v1alpha2.KubeSchedulerConfiguration{
AlgorithmSource: v1alpha2.SchedulerAlgorithmSource{Provider: pointer.StringPtr("DefaultProvider")},
HealthzBindAddress: pointer.StringPtr("0.0.0.0:10251"),
MetricsBindAddress: pointer.StringPtr("0.0.0.0:10251"),
DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{
EnableProfiling: &enable,
EnableContentionProfiling: &enable,
},
LeaderElection: v1alpha2.KubeSchedulerLeaderElectionConfiguration{
LeaderElectionConfiguration: componentbaseconfig.LeaderElectionConfiguration{
LeaderElect: pointer.BoolPtr(true),
LeaseDuration: metav1.Duration{Duration: 15 * time.Second},
RenewDeadline: metav1.Duration{Duration: 10 * time.Second},
RetryPeriod: metav1.Duration{Duration: 2 * time.Second},
ResourceLock: "endpointsleases",
ResourceNamespace: "kube-system",
ResourceName: "kube-scheduler",
},
},
ClientConnection: componentbaseconfig.ClientConnectionConfiguration{
QPS: 50,
Burst: 100,
ContentType: "application/vnd.kubernetes.protobuf",
},
DisablePreemption: pointer.BoolPtr(false),
PercentageOfNodesToScore: pointer.Int32Ptr(0),
BindTimeoutSeconds: pointer.Int64Ptr(600),
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
Profiles: []v1alpha2.KubeSchedulerProfile{
{
PluginConfig: []v1alpha2.PluginConfig{
{Name: "FooPlugin"},
},
},
{
SchedulerName: pointer.StringPtr("custom-scheduler"),
Plugins: &v1alpha2.Plugins{
Bind: &v1alpha2.PluginSet{
Enabled: []v1alpha2.Plugin{
{Name: "BarPlugin"},
},
},
},
},
},
},
},
{
@ -77,7 +197,6 @@ func TestSchedulerDefaults(t *testing.T) {
HealthzBindAddress: pointer.StringPtr("1.2.3.4"),
},
expected: &v1alpha2.KubeSchedulerConfiguration{
SchedulerName: pointer.StringPtr("default-scheduler"),
AlgorithmSource: v1alpha2.SchedulerAlgorithmSource{Provider: pointer.StringPtr("DefaultProvider")},
HealthzBindAddress: pointer.StringPtr("1.2.3.4:10251"),
MetricsBindAddress: pointer.StringPtr("1.2.3.4:10251"),
@ -106,7 +225,9 @@ func TestSchedulerDefaults(t *testing.T) {
BindTimeoutSeconds: pointer.Int64Ptr(600),
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
Plugins: nil,
Profiles: []v1alpha2.KubeSchedulerProfile{
{SchedulerName: pointer.StringPtr("default-scheduler")},
},
},
},
{
@ -116,7 +237,6 @@ func TestSchedulerDefaults(t *testing.T) {
HealthzBindAddress: pointer.StringPtr(":12345"),
},
expected: &v1alpha2.KubeSchedulerConfiguration{
SchedulerName: pointer.StringPtr("default-scheduler"),
AlgorithmSource: v1alpha2.SchedulerAlgorithmSource{Provider: pointer.StringPtr("DefaultProvider")},
HealthzBindAddress: pointer.StringPtr("0.0.0.0:12345"),
MetricsBindAddress: pointer.StringPtr("0.0.0.0:12345"),
@ -145,15 +265,17 @@ func TestSchedulerDefaults(t *testing.T) {
BindTimeoutSeconds: pointer.Int64Ptr(600),
PodInitialBackoffSeconds: pointer.Int64Ptr(1),
PodMaxBackoffSeconds: pointer.Int64Ptr(10),
Plugins: nil,
Profiles: []v1alpha2.KubeSchedulerProfile{
{SchedulerName: pointer.StringPtr("default-scheduler")},
},
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
SetDefaults_KubeSchedulerConfiguration(tc.config)
if !reflect.DeepEqual(tc.expected, tc.config) {
t.Errorf("Expected:\n%#v\n\nGot:\n%#v", tc.expected, tc.config)
if diff := cmp.Diff(tc.expected, tc.config); diff != "" {
t.Errorf("Got unexpected defaults (-want, +got):\n%s", diff)
}
})
}

View File

@ -58,6 +58,16 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1alpha2.KubeSchedulerProfile)(nil), (*config.KubeSchedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha2_KubeSchedulerProfile_To_config_KubeSchedulerProfile(a.(*v1alpha2.KubeSchedulerProfile), b.(*config.KubeSchedulerProfile), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*config.KubeSchedulerProfile)(nil), (*v1alpha2.KubeSchedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_config_KubeSchedulerProfile_To_v1alpha2_KubeSchedulerProfile(a.(*config.KubeSchedulerProfile), b.(*v1alpha2.KubeSchedulerProfile), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1alpha2.Plugin)(nil), (*config.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha2_Plugin_To_config_Plugin(a.(*v1alpha2.Plugin), b.(*config.Plugin), scope)
}); err != nil {
@ -142,9 +152,6 @@ func RegisterConversions(s *runtime.Scheme) error {
}
func autoConvert_v1alpha2_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in *v1alpha2.KubeSchedulerConfiguration, out *config.KubeSchedulerConfiguration, s conversion.Scope) error {
if err := v1.Convert_Pointer_string_To_string(&in.SchedulerName, &out.SchedulerName, s); err != nil {
return err
}
if err := Convert_v1alpha2_SchedulerAlgorithmSource_To_config_SchedulerAlgorithmSource(&in.AlgorithmSource, &out.AlgorithmSource, s); err != nil {
return err
}
@ -178,16 +185,17 @@ func autoConvert_v1alpha2_KubeSchedulerConfiguration_To_config_KubeSchedulerConf
if err := v1.Convert_Pointer_int64_To_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, s); err != nil {
return err
}
if in.Plugins != nil {
in, out := &in.Plugins, &out.Plugins
*out = new(config.Plugins)
if err := Convert_v1alpha2_Plugins_To_config_Plugins(*in, *out, s); err != nil {
return err
if in.Profiles != nil {
in, out := &in.Profiles, &out.Profiles
*out = make([]config.KubeSchedulerProfile, len(*in))
for i := range *in {
if err := Convert_v1alpha2_KubeSchedulerProfile_To_config_KubeSchedulerProfile(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Plugins = nil
out.Profiles = nil
}
out.PluginConfig = *(*[]config.PluginConfig)(unsafe.Pointer(&in.PluginConfig))
return nil
}
@ -197,9 +205,6 @@ func Convert_v1alpha2_KubeSchedulerConfiguration_To_config_KubeSchedulerConfigur
}
func autoConvert_config_KubeSchedulerConfiguration_To_v1alpha2_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1alpha2.KubeSchedulerConfiguration, s conversion.Scope) error {
if err := v1.Convert_string_To_Pointer_string(&in.SchedulerName, &out.SchedulerName, s); err != nil {
return err
}
if err := Convert_config_SchedulerAlgorithmSource_To_v1alpha2_SchedulerAlgorithmSource(&in.AlgorithmSource, &out.AlgorithmSource, s); err != nil {
return err
}
@ -233,16 +238,17 @@ func autoConvert_config_KubeSchedulerConfiguration_To_v1alpha2_KubeSchedulerConf
if err := v1.Convert_int64_To_Pointer_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, s); err != nil {
return err
}
if in.Plugins != nil {
in, out := &in.Plugins, &out.Plugins
*out = new(v1alpha2.Plugins)
if err := Convert_config_Plugins_To_v1alpha2_Plugins(*in, *out, s); err != nil {
return err
if in.Profiles != nil {
in, out := &in.Profiles, &out.Profiles
*out = make([]v1alpha2.KubeSchedulerProfile, len(*in))
for i := range *in {
if err := Convert_config_KubeSchedulerProfile_To_v1alpha2_KubeSchedulerProfile(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Plugins = nil
out.Profiles = nil
}
out.PluginConfig = *(*[]v1alpha2.PluginConfig)(unsafe.Pointer(&in.PluginConfig))
return nil
}
@ -275,6 +281,50 @@ func Convert_config_KubeSchedulerLeaderElectionConfiguration_To_v1alpha2_KubeSch
return autoConvert_config_KubeSchedulerLeaderElectionConfiguration_To_v1alpha2_KubeSchedulerLeaderElectionConfiguration(in, out, s)
}
func autoConvert_v1alpha2_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in *v1alpha2.KubeSchedulerProfile, out *config.KubeSchedulerProfile, s conversion.Scope) error {
if err := v1.Convert_Pointer_string_To_string(&in.SchedulerName, &out.SchedulerName, s); err != nil {
return err
}
if in.Plugins != nil {
in, out := &in.Plugins, &out.Plugins
*out = new(config.Plugins)
if err := Convert_v1alpha2_Plugins_To_config_Plugins(*in, *out, s); err != nil {
return err
}
} else {
out.Plugins = nil
}
out.PluginConfig = *(*[]config.PluginConfig)(unsafe.Pointer(&in.PluginConfig))
return nil
}
// Convert_v1alpha2_KubeSchedulerProfile_To_config_KubeSchedulerProfile is an autogenerated conversion function.
func Convert_v1alpha2_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in *v1alpha2.KubeSchedulerProfile, out *config.KubeSchedulerProfile, s conversion.Scope) error {
return autoConvert_v1alpha2_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in, out, s)
}
func autoConvert_config_KubeSchedulerProfile_To_v1alpha2_KubeSchedulerProfile(in *config.KubeSchedulerProfile, out *v1alpha2.KubeSchedulerProfile, s conversion.Scope) error {
if err := v1.Convert_string_To_Pointer_string(&in.SchedulerName, &out.SchedulerName, s); err != nil {
return err
}
if in.Plugins != nil {
in, out := &in.Plugins, &out.Plugins
*out = new(v1alpha2.Plugins)
if err := Convert_config_Plugins_To_v1alpha2_Plugins(*in, *out, s); err != nil {
return err
}
} else {
out.Plugins = nil
}
out.PluginConfig = *(*[]v1alpha2.PluginConfig)(unsafe.Pointer(&in.PluginConfig))
return nil
}
// Convert_config_KubeSchedulerProfile_To_v1alpha2_KubeSchedulerProfile is an autogenerated conversion function.
func Convert_config_KubeSchedulerProfile_To_v1alpha2_KubeSchedulerProfile(in *config.KubeSchedulerProfile, out *v1alpha2.KubeSchedulerProfile, s conversion.Scope) error {
return autoConvert_config_KubeSchedulerProfile_To_v1alpha2_KubeSchedulerProfile(in, out, s)
}
func autoConvert_v1alpha2_Plugin_To_config_Plugin(in *v1alpha2.Plugin, out *config.Plugin, s conversion.Scope) error {
out.Name = in.Name
if err := v1.Convert_Pointer_int32_To_int32(&in.Weight, &out.Weight, s); err != nil {

View File

@ -14,6 +14,7 @@ go_library(
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//staging/src/k8s.io/component-base/config/validation:go_default_library",
"//vendor/github.com/google/go-cmp/cmp:go_default_library",
],
)

View File

@ -20,6 +20,7 @@ import (
"errors"
"fmt"
"github.com/google/go-cmp/cmp"
v1 "k8s.io/api/core/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
@ -34,9 +35,23 @@ import (
func ValidateKubeSchedulerConfiguration(cc *config.KubeSchedulerConfiguration) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, componentbasevalidation.ValidateClientConnectionConfiguration(&cc.ClientConnection, field.NewPath("clientConnection"))...)
allErrs = append(allErrs, ValidateKubeSchedulerLeaderElectionConfiguration(&cc.LeaderElection, field.NewPath("leaderElection"))...)
if len(cc.SchedulerName) == 0 {
allErrs = append(allErrs, field.Required(field.NewPath("schedulerName"), ""))
allErrs = append(allErrs, validateKubeSchedulerLeaderElectionConfiguration(field.NewPath("leaderElection"), &cc.LeaderElection)...)
profilesPath := field.NewPath("profiles")
if len(cc.Profiles) == 0 {
allErrs = append(allErrs, field.Required(profilesPath, ""))
} else {
existingProfiles := make(map[string]int, len(cc.Profiles))
for i := range cc.Profiles {
profile := &cc.Profiles[i]
path := profilesPath.Index(i)
allErrs = append(allErrs, validateKubeSchedulerProfile(path, profile)...)
if idx, ok := existingProfiles[profile.SchedulerName]; ok {
allErrs = append(allErrs, field.Duplicate(path.Child("schedulerName"), profilesPath.Index(idx).Child("schedulerName")))
}
existingProfiles[profile.SchedulerName] = i
}
allErrs = append(allErrs, validateCommonQueueSort(profilesPath, cc.Profiles)...)
}
for _, msg := range validation.IsValidSocketAddr(cc.HealthzBindAddress) {
allErrs = append(allErrs, field.Invalid(field.NewPath("healthzBindAddress"), cc.HealthzBindAddress, msg))
@ -59,13 +74,39 @@ func ValidateKubeSchedulerConfiguration(cc *config.KubeSchedulerConfiguration) f
return allErrs
}
// ValidateKubeSchedulerLeaderElectionConfiguration ensures validation of the KubeSchedulerLeaderElectionConfiguration struct
func ValidateKubeSchedulerLeaderElectionConfiguration(cc *config.KubeSchedulerLeaderElectionConfiguration, fldPath *field.Path) field.ErrorList {
func validateKubeSchedulerProfile(path *field.Path, profile *config.KubeSchedulerProfile) field.ErrorList {
allErrs := field.ErrorList{}
if len(profile.SchedulerName) == 0 {
allErrs = append(allErrs, field.Required(path.Child("schedulerName"), ""))
}
return allErrs
}
func validateCommonQueueSort(path *field.Path, profiles []config.KubeSchedulerProfile) field.ErrorList {
allErrs := field.ErrorList{}
var canon *config.PluginSet
if profiles[0].Plugins != nil {
canon = profiles[0].Plugins.QueueSort
}
for i := 1; i < len(profiles); i++ {
var curr *config.PluginSet
if profiles[i].Plugins != nil {
curr = profiles[i].Plugins.QueueSort
}
if !cmp.Equal(canon, curr) {
allErrs = append(allErrs, field.Invalid(path.Index(i).Child("plugins", "queueSort"), curr, "has to match for all profiles"))
}
}
// TODO(#88093): Validate that all plugin configs for the queue sort extension match.
return allErrs
}
func validateKubeSchedulerLeaderElectionConfiguration(fldPath *field.Path, cc *config.KubeSchedulerLeaderElectionConfiguration) field.ErrorList {
allErrs := field.ErrorList{}
if !cc.LeaderElectionConfiguration.LeaderElect {
return allErrs
}
allErrs = append(allErrs, componentbasevalidation.ValidateLeaderElectionConfiguration(&cc.LeaderElectionConfiguration, field.NewPath("leaderElectionConfiguration"))...)
allErrs = append(allErrs, componentbasevalidation.ValidateLeaderElectionConfiguration(&cc.LeaderElectionConfiguration, fldPath)...)
return allErrs
}

View File

@ -32,7 +32,6 @@ func TestValidateKubeSchedulerConfiguration(t *testing.T) {
podInitialBackoffSeconds := int64(1)
podMaxBackoffSeconds := int64(1)
validConfig := &config.KubeSchedulerConfiguration{
SchedulerName: "me",
HealthzBindAddress: "0.0.0.0:10254",
MetricsBindAddress: "0.0.0.0:10254",
ClientConnection: componentbaseconfig.ClientConnectionConfiguration{
@ -64,6 +63,30 @@ func TestValidateKubeSchedulerConfiguration(t *testing.T) {
PodMaxBackoffSeconds: podMaxBackoffSeconds,
BindTimeoutSeconds: testTimeout,
PercentageOfNodesToScore: 35,
Profiles: []config.KubeSchedulerProfile{
{
SchedulerName: "me",
Plugins: &config.Plugins{
QueueSort: &config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
Score: &config.PluginSet{
Disabled: []config.Plugin{{Name: "*"}},
},
},
},
{
SchedulerName: "other",
Plugins: &config.Plugins{
QueueSort: &config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomSort"}},
},
Bind: &config.PluginSet{
Enabled: []config.Plugin{{Name: "CustomBind"}},
},
},
},
},
}
resourceNameNotSet := validConfig.DeepCopy()
@ -91,6 +114,18 @@ func TestValidateKubeSchedulerConfiguration(t *testing.T) {
percentageOfNodesToScore101 := validConfig.DeepCopy()
percentageOfNodesToScore101.PercentageOfNodesToScore = int32(101)
schedulerNameNotSet := validConfig.DeepCopy()
schedulerNameNotSet.Profiles[1].SchedulerName = ""
repeatedSchedulerName := validConfig.DeepCopy()
repeatedSchedulerName.Profiles[0].SchedulerName = "other"
differentQueueSort := validConfig.DeepCopy()
differentQueueSort.Profiles[1].Plugins.QueueSort.Enabled[0].Name = "AnotherSort"
oneEmptyQueueSort := validConfig.DeepCopy()
oneEmptyQueueSort.Profiles[0].Plugins = nil
scenarios := map[string]struct {
expectedToFail bool
config *config.KubeSchedulerConfiguration
@ -127,16 +162,34 @@ func TestValidateKubeSchedulerConfiguration(t *testing.T) {
expectedToFail: true,
config: percentageOfNodesToScore101,
},
"scheduler-name-not-set": {
expectedToFail: true,
config: schedulerNameNotSet,
},
"repeated-scheduler-name": {
expectedToFail: true,
config: repeatedSchedulerName,
},
"different-queue-sort": {
expectedToFail: true,
config: differentQueueSort,
},
"one-empty-queue-sort": {
expectedToFail: true,
config: oneEmptyQueueSort,
},
}
for name, scenario := range scenarios {
errs := ValidateKubeSchedulerConfiguration(scenario.config)
if len(errs) == 0 && scenario.expectedToFail {
t.Errorf("Unexpected success for scenario: %s", name)
}
if len(errs) > 0 && !scenario.expectedToFail {
t.Errorf("Unexpected failure for scenario: %s - %+v", name, errs)
}
t.Run(name, func(t *testing.T) {
errs := ValidateKubeSchedulerConfiguration(scenario.config)
if len(errs) == 0 && scenario.expectedToFail {
t.Error("Unexpected success")
}
if len(errs) > 0 && !scenario.expectedToFail {
t.Errorf("Unexpected failure: %+v", errs)
}
})
}
}

View File

@ -105,14 +105,9 @@ func (in *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerConfigurati
out.LeaderElection = in.LeaderElection
out.ClientConnection = in.ClientConnection
out.DebuggingConfiguration = in.DebuggingConfiguration
if in.Plugins != nil {
in, out := &in.Plugins, &out.Plugins
*out = new(Plugins)
(*in).DeepCopyInto(*out)
}
if in.PluginConfig != nil {
in, out := &in.PluginConfig, &out.PluginConfig
*out = make([]PluginConfig, len(*in))
if in.Profiles != nil {
in, out := &in.Profiles, &out.Profiles
*out = make([]KubeSchedulerProfile, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
@ -155,6 +150,34 @@ func (in *KubeSchedulerLeaderElectionConfiguration) DeepCopy() *KubeSchedulerLea
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeSchedulerProfile) DeepCopyInto(out *KubeSchedulerProfile) {
*out = *in
if in.Plugins != nil {
in, out := &in.Plugins, &out.Plugins
*out = new(Plugins)
(*in).DeepCopyInto(*out)
}
if in.PluginConfig != nil {
in, out := &in.PluginConfig, &out.PluginConfig
*out = make([]PluginConfig, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerProfile.
func (in *KubeSchedulerProfile) DeepCopy() *KubeSchedulerProfile {
if in == nil {
return nil
}
out := new(KubeSchedulerProfile)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *LabelPreference) DeepCopyInto(out *LabelPreference) {
*out = *in

View File

@ -39,9 +39,6 @@ const (
type KubeSchedulerConfiguration struct {
metav1.TypeMeta `json:",inline"`
// SchedulerName is name of the scheduler, used to select which pods
// will be processed by this scheduler, based on pod's "spec.SchedulerName".
SchedulerName *string `json:"schedulerName,omitempty"`
// AlgorithmSource specifies the scheduler algorithm source.
AlgorithmSource SchedulerAlgorithmSource `json:"algorithmSource"`
@ -90,15 +87,35 @@ type KubeSchedulerConfiguration struct {
// the default value (10s) will be used.
PodMaxBackoffSeconds *int64 `json:"podMaxBackoffSeconds"`
// Plugins specify the set of plugins that should be enabled or disabled. Enabled plugins are the
// ones that should be enabled in addition to the default plugins. Disabled plugins are any of the
// default plugins that should be disabled.
// When no enabled or disabled plugin is specified for an extension point, default plugins for
// that extension point will be used if there is any.
// Profiles are scheduling profiles that kube-scheduler supports. Pods can
// choose to be scheduled under a particular profile by setting its associated
// scheduler name. Pods that don't specify any scheduler name are scheduled
// with the "default-scheduler" profile, if present here.
// +listType=map
// +listMapKey=schedulerName
Profiles []KubeSchedulerProfile `json:"profiles"`
}
// KubeSchedulerProfile is a scheduling profile.
type KubeSchedulerProfile struct {
// SchedulerName is the name of the scheduler associated to this profile.
// If SchedulerName matches with the pod's "spec.schedulerName", then the pod
// is scheduled with this profile.
SchedulerName *string `json:"schedulerName,omitempty"`
// Plugins specify the set of plugins that should be enabled or disabled.
// Enabled plugins are the ones that should be enabled in addition to the
// default plugins. Disabled plugins are any of the default plugins that
// should be disabled.
// When no enabled or disabled plugin is specified for an extension point,
// default plugins for that extension point will be used if there is any.
// If a QueueSort plugin is specified, the same QueueSort Plugin and
// PluginConfig must be specified for all profiles.
Plugins *Plugins `json:"plugins,omitempty"`
// PluginConfig is an optional set of custom plugin arguments for each plugin.
// Omitting config args for a plugin is equivalent to using the default config for that plugin.
// Omitting config args for a plugin is equivalent to using the default config
// for that plugin.
// +listType=map
// +listMapKey=name
PluginConfig []PluginConfig `json:"pluginConfig,omitempty"`

View File

@ -28,11 +28,6 @@ import (
func (in *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerConfiguration) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.SchedulerName != nil {
in, out := &in.SchedulerName, &out.SchedulerName
*out = new(string)
**out = **in
}
in.AlgorithmSource.DeepCopyInto(&out.AlgorithmSource)
in.LeaderElection.DeepCopyInto(&out.LeaderElection)
out.ClientConnection = in.ClientConnection
@ -72,14 +67,9 @@ func (in *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerConfigurati
*out = new(int64)
**out = **in
}
if in.Plugins != nil {
in, out := &in.Plugins, &out.Plugins
*out = new(Plugins)
(*in).DeepCopyInto(*out)
}
if in.PluginConfig != nil {
in, out := &in.PluginConfig, &out.PluginConfig
*out = make([]PluginConfig, len(*in))
if in.Profiles != nil {
in, out := &in.Profiles, &out.Profiles
*out = make([]KubeSchedulerProfile, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
@ -122,6 +112,39 @@ func (in *KubeSchedulerLeaderElectionConfiguration) DeepCopy() *KubeSchedulerLea
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeSchedulerProfile) DeepCopyInto(out *KubeSchedulerProfile) {
*out = *in
if in.SchedulerName != nil {
in, out := &in.SchedulerName, &out.SchedulerName
*out = new(string)
**out = **in
}
if in.Plugins != nil {
in, out := &in.Plugins, &out.Plugins
*out = new(Plugins)
(*in).DeepCopyInto(*out)
}
if in.PluginConfig != nil {
in, out := &in.PluginConfig, &out.PluginConfig
*out = make([]PluginConfig, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerProfile.
func (in *KubeSchedulerProfile) DeepCopy() *KubeSchedulerProfile {
if in == nil {
return nil
}
out := new(KubeSchedulerProfile)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Plugin) DeepCopyInto(out *Plugin) {
*out = *in