From 02f77a1b84c232c6304ea89bb7f518d3984e202e Mon Sep 17 00:00:00 2001 From: kerthcet Date: Fri, 29 Jul 2022 08:47:48 +0800 Subject: [PATCH] Feat: ga component config in kube-scheduler Signed-off-by: kerthcet --- cmd/kube-scheduler/app/options/configfile.go | 5 +- .../app/options/options_test.go | 399 +++++- cmd/kube-scheduler/app/server_test.go | 128 +- pkg/generated/openapi/zz_generated.openapi.go | 1125 +++++++++++++++++ pkg/scheduler/apis/config/latest/latest.go | 6 +- pkg/scheduler/apis/config/scheme/scheme.go | 6 +- .../apis/config/scheme/scheme_test.go | 561 ++++++++ pkg/scheduler/apis/config/testing/config.go | 13 + .../apis/config/testing/defaults/defaults.go | 170 +++ pkg/scheduler/apis/config/v1/conversion.go | 107 ++ .../apis/config/v1/default_plugins.go | 135 ++ .../apis/config/v1/default_plugins_test.go | 523 ++++++++ pkg/scheduler/apis/config/v1/defaults.go | 242 ++++ pkg/scheduler/apis/config/v1/defaults_test.go | 646 ++++++++++ pkg/scheduler/apis/config/v1/doc.go | 24 + pkg/scheduler/apis/config/v1/register.go | 42 + .../apis/config/v1/zz_generated.conversion.go | 940 ++++++++++++++ .../apis/config/v1/zz_generated.deepcopy.go | 22 + .../apis/config/v1/zz_generated.defaults.go | 73 ++ .../apis/config/validation/validation.go | 4 + .../apis/config/validation/validation_test.go | 360 +++++- pkg/scheduler/scheduler.go | 6 +- .../k8s.io/kube-scheduler/config/v1/doc.go | 21 + .../kube-scheduler/config/v1/register.go | 50 + .../k8s.io/kube-scheduler/config/v1/types.go | 377 ++++++ .../config/v1/types_pluginargs.go | 225 ++++ .../config/v1/zz_generated.deepcopy.go | 603 +++++++++ .../scheduler/plugins/plugins_test.go | 106 +- .../scheduler/preemption/preemption_test.go | 28 +- test/integration/scheduler/queue_test.go | 12 +- test/integration/scheduler/scheduler_test.go | 14 +- .../scheduler/scoring/priorities_test.go | 28 +- vendor/modules.txt | 1 + 33 files changed, 6872 insertions(+), 130 deletions(-) create mode 100644 pkg/scheduler/apis/config/v1/conversion.go create mode 100644 pkg/scheduler/apis/config/v1/default_plugins.go create mode 100644 pkg/scheduler/apis/config/v1/default_plugins_test.go create mode 100644 pkg/scheduler/apis/config/v1/defaults.go create mode 100644 pkg/scheduler/apis/config/v1/defaults_test.go create mode 100644 pkg/scheduler/apis/config/v1/doc.go create mode 100644 pkg/scheduler/apis/config/v1/register.go create mode 100644 pkg/scheduler/apis/config/v1/zz_generated.conversion.go create mode 100644 pkg/scheduler/apis/config/v1/zz_generated.deepcopy.go create mode 100644 pkg/scheduler/apis/config/v1/zz_generated.defaults.go create mode 100644 staging/src/k8s.io/kube-scheduler/config/v1/doc.go create mode 100644 staging/src/k8s.io/kube-scheduler/config/v1/register.go create mode 100644 staging/src/k8s.io/kube-scheduler/config/v1/types.go create mode 100644 staging/src/k8s.io/kube-scheduler/config/v1/types_pluginargs.go create mode 100644 staging/src/k8s.io/kube-scheduler/config/v1/zz_generated.deepcopy.go diff --git a/cmd/kube-scheduler/app/options/configfile.go b/cmd/kube-scheduler/app/options/configfile.go index 84802da767f..170f541b0c2 100644 --- a/cmd/kube-scheduler/app/options/configfile.go +++ b/cmd/kube-scheduler/app/options/configfile.go @@ -26,6 +26,7 @@ import ( "k8s.io/klog/v2" "k8s.io/kubernetes/pkg/scheduler/apis/config" "k8s.io/kubernetes/pkg/scheduler/apis/config/scheme" + configv1 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1" configv1beta2 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2" configv1beta3 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3" ) @@ -70,8 +71,10 @@ func encodeConfig(cfg *config.KubeSchedulerConfiguration) (*bytes.Buffer, error) encoder = scheme.Codecs.EncoderForVersion(info.Serializer, configv1beta2.SchemeGroupVersion) case configv1beta3.SchemeGroupVersion.String(): encoder = scheme.Codecs.EncoderForVersion(info.Serializer, configv1beta3.SchemeGroupVersion) + case configv1.SchemeGroupVersion.String(): + encoder = scheme.Codecs.EncoderForVersion(info.Serializer, configv1.SchemeGroupVersion) default: - encoder = scheme.Codecs.EncoderForVersion(info.Serializer, configv1beta3.SchemeGroupVersion) + encoder = scheme.Codecs.EncoderForVersion(info.Serializer, configv1.SchemeGroupVersion) } if err := encoder.Encode(cfg, buf); err != nil { return buf, err diff --git a/cmd/kube-scheduler/app/options/options_test.go b/cmd/kube-scheduler/app/options/options_test.go index 0cc9cb7b200..7f03425261d 100644 --- a/cmd/kube-scheduler/app/options/options_test.go +++ b/cmd/kube-scheduler/app/options/options_test.go @@ -34,6 +34,7 @@ import ( apiserveroptions "k8s.io/apiserver/pkg/server/options" componentbaseconfig "k8s.io/component-base/config" "k8s.io/component-base/logs" + v1 "k8s.io/kube-scheduler/config/v1" "k8s.io/kube-scheduler/config/v1beta2" "k8s.io/kube-scheduler/config/v1beta3" kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config" @@ -78,7 +79,7 @@ func TestSchedulerOptions(t *testing.T) { configFile := filepath.Join(tmpDir, "scheduler.yaml") configKubeconfig := filepath.Join(tmpDir, "config.kubeconfig") if err := os.WriteFile(configFile, []byte(fmt.Sprintf(` -apiVersion: kubescheduler.config.k8s.io/v1beta3 +apiVersion: kubescheduler.config.k8s.io/v1 kind: KubeSchedulerConfiguration clientConnection: kubeconfig: "%s" @@ -119,6 +120,17 @@ leaderElection: t.Fatal(err) } + v1beta3VersionConfig := filepath.Join(tmpDir, "scheduler_v1beta3_api_version.yaml") + if err := os.WriteFile(v1beta3VersionConfig, []byte(fmt.Sprintf(` +apiVersion: kubescheduler.config.k8s.io/v1beta3 +kind: KubeSchedulerConfiguration +clientConnection: + kubeconfig: "%s" +leaderElection: + leaderElect: true`, configKubeconfig)), os.FileMode(0600)); err != nil { + t.Fatal(err) + } + v1beta2VersionConfig := filepath.Join(tmpDir, "scheduler_v1beta2_api_version.yaml") if err := os.WriteFile(v1beta2VersionConfig, []byte(fmt.Sprintf(` apiVersion: kubescheduler.config.k8s.io/v1beta2 @@ -153,7 +165,7 @@ leaderElection: unknownFieldConfig := filepath.Join(tmpDir, "scheduler_invalid_unknown_field.yaml") if err := os.WriteFile(unknownFieldConfig, []byte(fmt.Sprintf(` -apiVersion: kubescheduler.config.k8s.io/v1beta2 +apiVersion: kubescheduler.config.k8s.io/v1 kind: KubeSchedulerConfiguration clientConnection: kubeconfig: "%s" @@ -165,7 +177,7 @@ foo: bar`, configKubeconfig)), os.FileMode(0600)); err != nil { duplicateFieldConfig := filepath.Join(tmpDir, "scheduler_invalid_duplicate_fields.yaml") if err := os.WriteFile(duplicateFieldConfig, []byte(fmt.Sprintf(` -apiVersion: kubescheduler.config.k8s.io/v1beta2 +apiVersion: kubescheduler.config.k8s.io/v1 kind: KubeSchedulerConfiguration clientConnection: kubeconfig: "%s" @@ -202,6 +214,37 @@ users: // plugin config pluginConfigFile := filepath.Join(tmpDir, "plugin.yaml") if err := os.WriteFile(pluginConfigFile, []byte(fmt.Sprintf(` +apiVersion: kubescheduler.config.k8s.io/v1 +kind: KubeSchedulerConfiguration +clientConnection: + kubeconfig: "%s" +profiles: +- plugins: + reserve: + enabled: + - name: foo + - name: bar + disabled: + - name: VolumeBinding + preBind: + enabled: + - name: foo + disabled: + - name: VolumeBinding + pluginConfig: + - name: InterPodAffinity + args: + hardPodAffinityWeight: 2 + - name: foo + args: + bar: baz +`, configKubeconfig)), os.FileMode(0600)); err != nil { + t.Fatal(err) + } + + // v1beta3 plugin config + v1beta3PluginConfigFile := filepath.Join(tmpDir, "v1beta3_plugin.yaml") + if err := os.WriteFile(v1beta3PluginConfigFile, []byte(fmt.Sprintf(` apiVersion: kubescheduler.config.k8s.io/v1beta3 kind: KubeSchedulerConfiguration clientConnection: @@ -264,6 +307,33 @@ profiles: // multiple profiles config multiProfilesConfig := filepath.Join(tmpDir, "multi-profiles.yaml") if err := os.WriteFile(multiProfilesConfig, []byte(fmt.Sprintf(` +apiVersion: kubescheduler.config.k8s.io/v1 +kind: KubeSchedulerConfiguration +clientConnection: + kubeconfig: "%s" +profiles: +- schedulerName: "foo-profile" + plugins: + reserve: + enabled: + - name: foo + - name: VolumeBinding + disabled: + - name: VolumeBinding +- schedulerName: "bar-profile" + plugins: + preBind: + disabled: + - name: VolumeBinding + pluginConfig: + - name: foo +`, configKubeconfig)), os.FileMode(0600)); err != nil { + t.Fatal(err) + } + + // v1beta3 multiple profiles config + v1beta3MultiProfilesConfig := filepath.Join(tmpDir, "v1beta3_multi-profiles.yaml") + if err := os.WriteFile(v1beta3MultiProfilesConfig, []byte(fmt.Sprintf(` apiVersion: kubescheduler.config.k8s.io/v1beta3 kind: KubeSchedulerConfiguration clientConnection: @@ -336,9 +406,80 @@ profiles: checkErrFn func(err error) bool }{ { - name: "v1beta3 config file", + name: "v1 config file", options: &Options{ ConfigFile: configFile, + ComponentConfig: func() *kubeschedulerconfig.KubeSchedulerConfiguration { + cfg := configtesting.V1ToInternalWithDefaults(t, v1.KubeSchedulerConfiguration{}) + return cfg + }(), + SecureServing: (&apiserveroptions.SecureServingOptions{ + ServerCert: apiserveroptions.GeneratableKeyCert{ + CertDirectory: "/a/b/c", + PairName: "kube-scheduler", + }, + HTTP2MaxStreamsPerConnection: 47, + }).WithLoopback(), + Authentication: &apiserveroptions.DelegatingAuthenticationOptions{ + CacheTTL: 10 * time.Second, + ClientCert: apiserveroptions.ClientCertAuthenticationOptions{}, + RequestHeader: apiserveroptions.RequestHeaderAuthenticationOptions{ + UsernameHeaders: []string{"x-remote-user"}, + GroupHeaders: []string{"x-remote-group"}, + ExtraHeaderPrefixes: []string{"x-remote-extra-"}, + }, + RemoteKubeConfigFileOptional: true, + }, + Authorization: &apiserveroptions.DelegatingAuthorizationOptions{ + AllowCacheTTL: 10 * time.Second, + DenyCacheTTL: 10 * time.Second, + RemoteKubeConfigFileOptional: true, + AlwaysAllowPaths: []string{"/healthz", "/readyz", "/livez"}, // note: this does not match /healthz/ or /healthz/* + AlwaysAllowGroups: []string{"system:masters"}, + }, + Logs: logs.NewOptions(), + }, + expectedUsername: "config", + expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{ + TypeMeta: metav1.TypeMeta{ + APIVersion: v1.SchemeGroupVersion.String(), + }, + Parallelism: 16, + 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, + Profiles: []kubeschedulerconfig.KubeSchedulerProfile{ + { + SchedulerName: "default-scheduler", + Plugins: defaults.PluginsV1, + PluginConfig: defaults.PluginConfigsV1, + }, + }, + }, + }, + { + name: "v1beta3 config file", + options: &Options{ + ConfigFile: v1beta3VersionConfig, ComponentConfig: func() *kubeschedulerconfig.KubeSchedulerConfiguration { cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{}) return cfg @@ -406,7 +547,6 @@ profiles: }, }, }, - { name: "v1beta2 config file", options: &Options{ @@ -546,7 +686,7 @@ profiles: expectedUsername: "flag", expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{ TypeMeta: metav1.TypeMeta{ - APIVersion: v1beta3.SchemeGroupVersion.String(), + APIVersion: v1.SchemeGroupVersion.String(), }, Parallelism: 16, DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{ @@ -574,8 +714,8 @@ profiles: Profiles: []kubeschedulerconfig.KubeSchedulerProfile{ { SchedulerName: "default-scheduler", - Plugins: defaults.PluginsV1beta3, - PluginConfig: defaults.PluginConfigsV1beta3, + Plugins: defaults.PluginsV1, + PluginConfig: defaults.PluginConfigsV1, }, }, }, @@ -616,7 +756,7 @@ profiles: }, expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{ TypeMeta: metav1.TypeMeta{ - APIVersion: v1beta3.SchemeGroupVersion.String(), + APIVersion: v1.SchemeGroupVersion.String(), }, Parallelism: 16, DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{ @@ -644,8 +784,8 @@ profiles: Profiles: []kubeschedulerconfig.KubeSchedulerProfile{ { SchedulerName: "default-scheduler", - Plugins: defaults.PluginsV1beta3, - PluginConfig: defaults.PluginConfigsV1beta3, + Plugins: defaults.PluginsV1, + PluginConfig: defaults.PluginConfigsV1, }, }, }, @@ -660,7 +800,7 @@ profiles: expectedUsername: "config", expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{ TypeMeta: metav1.TypeMeta{ - APIVersion: v1beta3.SchemeGroupVersion.String(), + APIVersion: v1.SchemeGroupVersion.String(), }, Parallelism: 16, DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{ @@ -706,6 +846,127 @@ profiles: {Name: names.VolumeBinding}, }, }, + MultiPoint: defaults.PluginsV1.MultiPoint, + }, + PluginConfig: []kubeschedulerconfig.PluginConfig{ + { + Name: "InterPodAffinity", + Args: &kubeschedulerconfig.InterPodAffinityArgs{ + HardPodAffinityWeight: 2, + }, + }, + { + Name: "foo", + Args: &runtime.Unknown{ + Raw: []byte(`{"bar":"baz"}`), + ContentType: "application/json", + }, + }, + { + Name: "DefaultPreemption", + Args: &kubeschedulerconfig.DefaultPreemptionArgs{ + MinCandidateNodesPercentage: 10, + MinCandidateNodesAbsolute: 100, + }, + }, + { + Name: "NodeAffinity", + Args: &kubeschedulerconfig.NodeAffinityArgs{}, + }, + { + Name: "NodeResourcesBalancedAllocation", + Args: &kubeschedulerconfig.NodeResourcesBalancedAllocationArgs{ + Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, + }, + { + Name: "NodeResourcesFit", + Args: &kubeschedulerconfig.NodeResourcesFitArgs{ + ScoringStrategy: &kubeschedulerconfig.ScoringStrategy{ + Type: kubeschedulerconfig.LeastAllocated, + 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: "v1beta3 plugin config", + options: &Options{ + ConfigFile: v1beta3PluginConfigFile, + Logs: logs.NewOptions(), + }, + expectedUsername: "config", + expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{ + TypeMeta: metav1.TypeMeta{ + APIVersion: v1beta3.SchemeGroupVersion.String(), + }, + Parallelism: 16, + 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, + Profiles: []kubeschedulerconfig.KubeSchedulerProfile{ + { + SchedulerName: "default-scheduler", + Plugins: &kubeschedulerconfig.Plugins{ + QueueSort: defaults.PluginsV1beta3.QueueSort, + PreFilter: defaults.PluginsV1beta3.PreFilter, + Filter: defaults.PluginsV1beta3.Filter, + PostFilter: defaults.PluginsV1beta3.PostFilter, + PreScore: defaults.PluginsV1beta3.PreScore, + Score: defaults.PluginsV1beta3.Score, + Reserve: kubeschedulerconfig.PluginSet{ + Enabled: []kubeschedulerconfig.Plugin{ + {Name: "foo"}, + {Name: "bar"}, + }, + Disabled: []kubeschedulerconfig.Plugin{ + {Name: "VolumeBinding"}, + }, + }, + PreBind: kubeschedulerconfig.PluginSet{ + Enabled: []kubeschedulerconfig.Plugin{ + {Name: "foo"}, + }, + Disabled: []kubeschedulerconfig.Plugin{ + {Name: "VolumeBinding"}, + }, + }, + Bind: defaults.PluginsV1beta3.Bind, MultiPoint: defaults.PluginsV1beta3.MultiPoint, }, PluginConfig: []kubeschedulerconfig.PluginConfig{ @@ -886,6 +1147,120 @@ profiles: Logs: logs.NewOptions(), }, expectedUsername: "config", + expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{ + TypeMeta: metav1.TypeMeta{ + APIVersion: v1.SchemeGroupVersion.String(), + }, + Parallelism: 16, + 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, + Profiles: []kubeschedulerconfig.KubeSchedulerProfile{ + { + SchedulerName: "foo-profile", + Plugins: &kubeschedulerconfig.Plugins{ + MultiPoint: defaults.PluginsV1.MultiPoint, + Reserve: kubeschedulerconfig.PluginSet{ + Enabled: []kubeschedulerconfig.Plugin{ + {Name: "foo"}, + {Name: names.VolumeBinding}, + }, + Disabled: []kubeschedulerconfig.Plugin{ + {Name: names.VolumeBinding}, + }, + }, + }, + PluginConfig: defaults.PluginConfigsV1, + }, + { + SchedulerName: "bar-profile", + Plugins: &kubeschedulerconfig.Plugins{ + MultiPoint: defaults.PluginsV1.MultiPoint, + PreBind: kubeschedulerconfig.PluginSet{ + Disabled: []kubeschedulerconfig.Plugin{ + {Name: names.VolumeBinding}, + }, + }, + }, + PluginConfig: []kubeschedulerconfig.PluginConfig{ + { + Name: "foo", + }, + { + Name: "DefaultPreemption", + Args: &kubeschedulerconfig.DefaultPreemptionArgs{ + MinCandidateNodesPercentage: 10, + MinCandidateNodesAbsolute: 100, + }, + }, + { + Name: "InterPodAffinity", + Args: &kubeschedulerconfig.InterPodAffinityArgs{ + HardPodAffinityWeight: 1, + }, + }, + { + Name: "NodeAffinity", + Args: &kubeschedulerconfig.NodeAffinityArgs{}, + }, + { + Name: "NodeResourcesBalancedAllocation", + Args: &kubeschedulerconfig.NodeResourcesBalancedAllocationArgs{ + Resources: []kubeschedulerconfig.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, + }, + { + Name: "NodeResourcesFit", + Args: &kubeschedulerconfig.NodeResourcesFitArgs{ + ScoringStrategy: &kubeschedulerconfig.ScoringStrategy{ + Type: kubeschedulerconfig.LeastAllocated, + 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: "v1beta3 multiple profiles", + options: &Options{ + ConfigFile: v1beta3MultiProfilesConfig, + Logs: logs.NewOptions(), + }, + expectedUsername: "config", expectedConfig: kubeschedulerconfig.KubeSchedulerConfiguration{ TypeMeta: metav1.TypeMeta{ APIVersion: v1beta3.SchemeGroupVersion.String(), diff --git a/cmd/kube-scheduler/app/server_test.go b/cmd/kube-scheduler/app/server_test.go index 4edb0d07ba4..a0ef12e05cf 100644 --- a/cmd/kube-scheduler/app/server_test.go +++ b/cmd/kube-scheduler/app/server_test.go @@ -82,6 +82,44 @@ users: t.Fatal(err) } + // plugin config + pluginConfigFilev1 := filepath.Join(tmpDir, "pluginv1.yaml") + if err := os.WriteFile(pluginConfigFilev1, []byte(fmt.Sprintf(` +apiVersion: kubescheduler.config.k8s.io/v1 +kind: KubeSchedulerConfiguration +clientConnection: + kubeconfig: "%s" +profiles: +- plugins: + multiPoint: + enabled: + - name: DefaultBinder + - name: PrioritySort + - name: DefaultPreemption + - name: VolumeBinding + - name: NodeResourcesFit + - name: NodePorts + - name: InterPodAffinity + - name: TaintToleration + disabled: + - name: "*" + preFilter: + disabled: + - name: VolumeBinding + - name: InterPodAffinity + filter: + disabled: + - name: VolumeBinding + - name: InterPodAffinity + - name: TaintToleration + score: + disabled: + - name: VolumeBinding + - name: NodeResourcesFit +`, configKubeconfig)), os.FileMode(0600)); err != nil { + t.Fatal(err) + } + // plugin config pluginConfigFilev1beta3 := filepath.Join(tmpDir, "pluginv1beta3.yaml") if err := os.WriteFile(pluginConfigFilev1beta3, []byte(fmt.Sprintf(` @@ -157,6 +195,25 @@ profiles: t.Fatal(err) } + // out-of-tree plugin config v1 + outOfTreePluginConfigFilev1 := filepath.Join(tmpDir, "outOfTreePluginv1.yaml") + if err := os.WriteFile(outOfTreePluginConfigFilev1, []byte(fmt.Sprintf(` +apiVersion: kubescheduler.config.k8s.io/v1beta3 +kind: KubeSchedulerConfiguration +clientConnection: + kubeconfig: "%s" +profiles: +- plugins: + preFilter: + enabled: + - name: Foo + filter: + enabled: + - name: Foo +`, configKubeconfig)), os.FileMode(0600)); err != nil { + t.Fatal(err) + } + // out-of-tree plugin config v1beta3 outOfTreePluginConfigFilev1beta3 := filepath.Join(tmpDir, "outOfTreePluginv1beta3.yaml") if err := os.WriteFile(outOfTreePluginConfigFilev1beta3, []byte(fmt.Sprintf(` @@ -198,7 +255,7 @@ profiles: // multiple profiles config multiProfilesConfig := filepath.Join(tmpDir, "multi-profiles.yaml") if err := os.WriteFile(multiProfilesConfig, []byte(fmt.Sprintf(` -apiVersion: kubescheduler.config.k8s.io/v1beta2 +apiVersion: kubescheduler.config.k8s.io/v1 kind: KubeSchedulerConfiguration clientConnection: kubeconfig: "%s" @@ -228,7 +285,7 @@ profiles: // empty leader-election config emptyLeaderElectionConfig := filepath.Join(tmpDir, "empty-leader-election-config.yaml") if err := os.WriteFile(emptyLeaderElectionConfig, []byte(fmt.Sprintf(` -apiVersion: kubescheduler.config.k8s.io/v1beta3 +apiVersion: kubescheduler.config.k8s.io/v1 kind: KubeSchedulerConfiguration clientConnection: kubeconfig: "%s" @@ -239,7 +296,7 @@ clientConnection: // leader-election config leaderElectionConfig := filepath.Join(tmpDir, "leader-election-config.yaml") if err := os.WriteFile(leaderElectionConfig, []byte(fmt.Sprintf(` -apiVersion: kubescheduler.config.k8s.io/v1beta3 +apiVersion: kubescheduler.config.k8s.io/v1 kind: KubeSchedulerConfiguration clientConnection: kubeconfig: "%s" @@ -372,6 +429,46 @@ leaderElection: }, }, }, + { + name: "component configuration v1", + flags: []string{ + "--config", pluginConfigFilev1, + "--kubeconfig", configKubeconfig, + }, + wantPlugins: map[string]*config.Plugins{ + "default-scheduler": { + Bind: config.PluginSet{Enabled: []config.Plugin{{Name: "DefaultBinder"}}}, + Filter: config.PluginSet{ + Enabled: []config.Plugin{ + {Name: "NodeResourcesFit"}, + {Name: "NodePorts"}, + }, + }, + PreFilter: config.PluginSet{ + 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: "out-of-tree component configuration v1beta2", flags: []string{ @@ -422,6 +519,31 @@ leaderElection: }, }, }, + { + name: "out-of-tree component configuration v1", + flags: []string{ + "--config", outOfTreePluginConfigFilev1, + "--kubeconfig", configKubeconfig, + }, + registryOptions: []Option{WithPlugin("Foo", newFoo)}, + wantPlugins: map[string]*config.Plugins{ + "default-scheduler": { + Bind: defaults.ExpandedPluginsV1.Bind, + Filter: config.PluginSet{ + Enabled: append(defaults.ExpandedPluginsV1.Filter.Enabled, config.Plugin{Name: "Foo"}), + }, + PreFilter: config.PluginSet{ + Enabled: append(defaults.ExpandedPluginsV1.PreFilter.Enabled, config.Plugin{Name: "Foo"}), + }, + PostFilter: defaults.ExpandedPluginsV1.PostFilter, + PreScore: defaults.ExpandedPluginsV1.PreScore, + QueueSort: defaults.ExpandedPluginsV1.QueueSort, + Score: defaults.ExpandedPluginsV1.Score, + Reserve: defaults.ExpandedPluginsV1.Reserve, + PreBind: defaults.ExpandedPluginsV1.PreBind, + }, + }, + }, { name: "leader election CLI args, along with --config arg", flags: []string{ diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index ac6f925eb7e..92206ed1226 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -999,6 +999,26 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPTablesConfiguration": schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyIPTablesConfiguration(ref), "k8s.io/kube-proxy/config/v1alpha1.KubeProxyIPVSConfiguration": schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyIPVSConfiguration(ref), "k8s.io/kube-proxy/config/v1alpha1.KubeProxyWinkernelConfiguration": schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyWinkernelConfiguration(ref), + "k8s.io/kube-scheduler/config/v1.DefaultPreemptionArgs": schema_k8sio_kube_scheduler_config_v1_DefaultPreemptionArgs(ref), + "k8s.io/kube-scheduler/config/v1.Extender": schema_k8sio_kube_scheduler_config_v1_Extender(ref), + "k8s.io/kube-scheduler/config/v1.ExtenderManagedResource": schema_k8sio_kube_scheduler_config_v1_ExtenderManagedResource(ref), + "k8s.io/kube-scheduler/config/v1.ExtenderTLSConfig": schema_k8sio_kube_scheduler_config_v1_ExtenderTLSConfig(ref), + "k8s.io/kube-scheduler/config/v1.InterPodAffinityArgs": schema_k8sio_kube_scheduler_config_v1_InterPodAffinityArgs(ref), + "k8s.io/kube-scheduler/config/v1.KubeSchedulerConfiguration": schema_k8sio_kube_scheduler_config_v1_KubeSchedulerConfiguration(ref), + "k8s.io/kube-scheduler/config/v1.KubeSchedulerProfile": schema_k8sio_kube_scheduler_config_v1_KubeSchedulerProfile(ref), + "k8s.io/kube-scheduler/config/v1.NodeAffinityArgs": schema_k8sio_kube_scheduler_config_v1_NodeAffinityArgs(ref), + "k8s.io/kube-scheduler/config/v1.NodeResourcesBalancedAllocationArgs": schema_k8sio_kube_scheduler_config_v1_NodeResourcesBalancedAllocationArgs(ref), + "k8s.io/kube-scheduler/config/v1.NodeResourcesFitArgs": schema_k8sio_kube_scheduler_config_v1_NodeResourcesFitArgs(ref), + "k8s.io/kube-scheduler/config/v1.Plugin": schema_k8sio_kube_scheduler_config_v1_Plugin(ref), + "k8s.io/kube-scheduler/config/v1.PluginConfig": schema_k8sio_kube_scheduler_config_v1_PluginConfig(ref), + "k8s.io/kube-scheduler/config/v1.PluginSet": schema_k8sio_kube_scheduler_config_v1_PluginSet(ref), + "k8s.io/kube-scheduler/config/v1.Plugins": schema_k8sio_kube_scheduler_config_v1_Plugins(ref), + "k8s.io/kube-scheduler/config/v1.PodTopologySpreadArgs": schema_k8sio_kube_scheduler_config_v1_PodTopologySpreadArgs(ref), + "k8s.io/kube-scheduler/config/v1.RequestedToCapacityRatioParam": schema_k8sio_kube_scheduler_config_v1_RequestedToCapacityRatioParam(ref), + "k8s.io/kube-scheduler/config/v1.ResourceSpec": schema_k8sio_kube_scheduler_config_v1_ResourceSpec(ref), + "k8s.io/kube-scheduler/config/v1.ScoringStrategy": schema_k8sio_kube_scheduler_config_v1_ScoringStrategy(ref), + "k8s.io/kube-scheduler/config/v1.UtilizationShapePoint": schema_k8sio_kube_scheduler_config_v1_UtilizationShapePoint(ref), + "k8s.io/kube-scheduler/config/v1.VolumeBindingArgs": schema_k8sio_kube_scheduler_config_v1_VolumeBindingArgs(ref), "k8s.io/kube-scheduler/config/v1beta2.DefaultPreemptionArgs": schema_k8sio_kube_scheduler_config_v1beta2_DefaultPreemptionArgs(ref), "k8s.io/kube-scheduler/config/v1beta2.Extender": schema_k8sio_kube_scheduler_config_v1beta2_Extender(ref), "k8s.io/kube-scheduler/config/v1beta2.ExtenderManagedResource": schema_k8sio_kube_scheduler_config_v1beta2_ExtenderManagedResource(ref), @@ -49962,6 +49982,1111 @@ func schema_k8sio_kube_proxy_config_v1alpha1_KubeProxyWinkernelConfiguration(ref } } +func schema_k8sio_kube_scheduler_config_v1_DefaultPreemptionArgs(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DefaultPreemptionArgs holds arguments used to configure the DefaultPreemption plugin.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "minCandidateNodesPercentage": { + SchemaProps: spec.SchemaProps{ + Description: "MinCandidateNodesPercentage is the minimum number of candidates to shortlist when dry running preemption as a percentage of number of nodes. Must be in the range [0, 100]. Defaults to 10% of the cluster size if unspecified.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "minCandidateNodesAbsolute": { + SchemaProps: spec.SchemaProps{ + Description: "MinCandidateNodesAbsolute is the absolute minimum number of candidates to shortlist. The likely number of candidates enumerated for dry running preemption is given by the formula: numCandidates = max(numNodes * minCandidateNodesPercentage, minCandidateNodesAbsolute) We say \"likely\" because there are other factors such as PDB violations that play a role in the number of candidates shortlisted. Must be at least 0 nodes. Defaults to 100 nodes if unspecified.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} + +func schema_k8sio_kube_scheduler_config_v1_Extender(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Extender holds the parameters used to communicate with the extender. If a verb is unspecified/empty, it is assumed that the extender chose not to provide that extension.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "urlPrefix": { + SchemaProps: spec.SchemaProps{ + Description: "URLPrefix at which the extender is available", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "filterVerb": { + SchemaProps: spec.SchemaProps{ + Description: "Verb for the filter call, empty if not supported. This verb is appended to the URLPrefix when issuing the filter call to extender.", + Type: []string{"string"}, + Format: "", + }, + }, + "preemptVerb": { + SchemaProps: spec.SchemaProps{ + Description: "Verb for the preempt call, empty if not supported. This verb is appended to the URLPrefix when issuing the preempt call to extender.", + Type: []string{"string"}, + Format: "", + }, + }, + "prioritizeVerb": { + SchemaProps: spec.SchemaProps{ + Description: "Verb for the prioritize call, empty if not supported. This verb is appended to the URLPrefix when issuing the prioritize call to extender.", + Type: []string{"string"}, + Format: "", + }, + }, + "weight": { + SchemaProps: spec.SchemaProps{ + Description: "The numeric multiplier for the node scores that the prioritize call generates. The weight should be a positive integer", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "bindVerb": { + SchemaProps: spec.SchemaProps{ + Description: "Verb for the bind call, empty if not supported. This verb is appended to the URLPrefix when issuing the bind call to extender. If this method is implemented by the extender, it is the extender's responsibility to bind the pod to apiserver. Only one extender can implement this function.", + Type: []string{"string"}, + Format: "", + }, + }, + "enableHTTPS": { + SchemaProps: spec.SchemaProps{ + Description: "EnableHTTPS specifies whether https should be used to communicate with the extender", + Type: []string{"boolean"}, + Format: "", + }, + }, + "tlsConfig": { + SchemaProps: spec.SchemaProps{ + Description: "TLSConfig specifies the transport layer security config", + Ref: ref("k8s.io/kube-scheduler/config/v1.ExtenderTLSConfig"), + }, + }, + "httpTimeout": { + SchemaProps: spec.SchemaProps{ + Description: "HTTPTimeout specifies the timeout duration for a call to the extender. Filter timeout fails the scheduling of the pod. Prioritize timeout is ignored, k8s/other extenders priorities are used to select the node.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "nodeCacheCapable": { + SchemaProps: spec.SchemaProps{ + Description: "NodeCacheCapable specifies that the extender is capable of caching node information, so the scheduler should only send minimal information about the eligible nodes assuming that the extender already cached full details of all nodes in the cluster", + Type: []string{"boolean"}, + Format: "", + }, + }, + "managedResources": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "ManagedResources is a list of extended resources that are managed by this extender. - A pod will be sent to the extender on the Filter, Prioritize and Bind\n (if the extender is the binder) phases iff the pod requests at least\n one of the extended resources in this list. If empty or unspecified,\n all pods will be sent to this extender.\n- If IgnoredByScheduler is set to true for a resource, kube-scheduler\n will skip checking the resource in predicates.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.ExtenderManagedResource"), + }, + }, + }, + }, + }, + "ignorable": { + SchemaProps: spec.SchemaProps{ + Description: "Ignorable specifies if the extender is ignorable, i.e. scheduling should not fail when the extender returns an error or is not reachable.", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + Required: []string{"urlPrefix"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Duration", "k8s.io/kube-scheduler/config/v1.ExtenderManagedResource", "k8s.io/kube-scheduler/config/v1.ExtenderTLSConfig"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_ExtenderManagedResource(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ExtenderManagedResource describes the arguments of extended resources managed by an extender.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name is the extended resource name.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "ignoredByScheduler": { + SchemaProps: spec.SchemaProps{ + Description: "IgnoredByScheduler indicates whether kube-scheduler should ignore this resource when applying predicates.", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + +func schema_k8sio_kube_scheduler_config_v1_ExtenderTLSConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ExtenderTLSConfig contains settings to enable TLS with extender", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "insecure": { + SchemaProps: spec.SchemaProps{ + Description: "Server should be accessed without verifying the TLS certificate. For testing only.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "serverName": { + SchemaProps: spec.SchemaProps{ + Description: "ServerName is passed to the server for SNI and is used in the client to check server certificates against. If ServerName is empty, the hostname used to contact the server is used.", + Type: []string{"string"}, + Format: "", + }, + }, + "certFile": { + SchemaProps: spec.SchemaProps{ + Description: "Server requires TLS client certificate authentication", + Type: []string{"string"}, + Format: "", + }, + }, + "keyFile": { + SchemaProps: spec.SchemaProps{ + Description: "Server requires TLS client certificate authentication", + Type: []string{"string"}, + Format: "", + }, + }, + "caFile": { + SchemaProps: spec.SchemaProps{ + Description: "Trusted root certificates for server", + Type: []string{"string"}, + Format: "", + }, + }, + "certData": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "CertData holds PEM-encoded bytes (typically read from a client certificate file). CertData takes precedence over CertFile", + Type: []string{"string"}, + Format: "byte", + }, + }, + "keyData": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "KeyData holds PEM-encoded bytes (typically read from a client certificate key file). KeyData takes precedence over KeyFile", + Type: []string{"string"}, + Format: "byte", + }, + }, + "caData": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "CAData holds PEM-encoded bytes (typically read from a root certificates bundle). CAData takes precedence over CAFile", + Type: []string{"string"}, + Format: "byte", + }, + }, + }, + }, + }, + } +} + +func schema_k8sio_kube_scheduler_config_v1_InterPodAffinityArgs(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "InterPodAffinityArgs holds arguments used to configure the InterPodAffinity plugin.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "hardPodAffinityWeight": { + SchemaProps: spec.SchemaProps{ + Description: "HardPodAffinityWeight is the scoring weight for existing pods with a matching hard affinity to the incoming pod.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} + +func schema_k8sio_kube_scheduler_config_v1_KubeSchedulerConfiguration(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KubeSchedulerConfiguration configures a scheduler", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "parallelism": { + SchemaProps: spec.SchemaProps{ + Description: "Parallelism defines the amount of parallelism in algorithms for scheduling a Pods. Must be greater than 0. Defaults to 16", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "leaderElection": { + SchemaProps: spec.SchemaProps{ + Description: "LeaderElection defines the configuration of leader election client.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/component-base/config/v1alpha1.LeaderElectionConfiguration"), + }, + }, + "clientConnection": { + SchemaProps: spec.SchemaProps{ + Description: "ClientConnection specifies the kubeconfig file and client connection settings for the proxy server to use when communicating with the apiserver.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/component-base/config/v1alpha1.ClientConnectionConfiguration"), + }, + }, + "enableProfiling": { + SchemaProps: spec.SchemaProps{ + Description: "enableProfiling enables profiling via web interface host:port/debug/pprof/", + Type: []string{"boolean"}, + Format: "", + }, + }, + "enableContentionProfiling": { + SchemaProps: spec.SchemaProps{ + Description: "enableContentionProfiling enables lock contention profiling, if enableProfiling is true.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "percentageOfNodesToScore": { + SchemaProps: spec.SchemaProps{ + Description: "PercentageOfNodesToScore is the percentage of all nodes that once found feasible for running a pod, the scheduler stops its search for more feasible nodes in the cluster. This helps improve scheduler's performance. Scheduler always tries to find at least \"minFeasibleNodesToFind\" feasible nodes no matter what the value of this flag is. Example: if the cluster size is 500 nodes and the value of this flag is 30, then scheduler stops finding further feasible nodes once it finds 150 feasible ones. When the value is 0, default percentage (5%--50% based on the size of the cluster) of the nodes will be scored.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "podInitialBackoffSeconds": { + SchemaProps: spec.SchemaProps{ + Description: "PodInitialBackoffSeconds is the initial backoff for unschedulable pods. If specified, it must be greater than 0. If this value is null, the default value (1s) will be used.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "podMaxBackoffSeconds": { + SchemaProps: spec.SchemaProps{ + Description: "PodMaxBackoffSeconds is the max backoff for unschedulable pods. If specified, it must be greater than podInitialBackoffSeconds. If this value is null, the default value (10s) will be used.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "profiles": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "schedulerName", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "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.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.KubeSchedulerProfile"), + }, + }, + }, + }, + }, + "extenders": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Extenders are the list of scheduler extenders, each holding the values of how to communicate with the extender. These extenders are shared by all scheduler profiles.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.Extender"), + }, + }, + }, + }, + }, + }, + Required: []string{"leaderElection", "clientConnection"}, + }, + }, + Dependencies: []string{ + "k8s.io/component-base/config/v1alpha1.ClientConnectionConfiguration", "k8s.io/component-base/config/v1alpha1.LeaderElectionConfiguration", "k8s.io/kube-scheduler/config/v1.Extender", "k8s.io/kube-scheduler/config/v1.KubeSchedulerProfile"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_KubeSchedulerProfile(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "KubeSchedulerProfile is a scheduling profile.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "schedulerName": { + SchemaProps: spec.SchemaProps{ + Description: "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.", + Type: []string{"string"}, + Format: "", + }, + }, + "plugins": { + SchemaProps: spec.SchemaProps{ + Description: "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.", + Ref: ref("k8s.io/kube-scheduler/config/v1.Plugins"), + }, + }, + "pluginConfig": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "name", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "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.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginConfig"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/kube-scheduler/config/v1.PluginConfig", "k8s.io/kube-scheduler/config/v1.Plugins"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_NodeAffinityArgs(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "NodeAffinityArgs holds arguments to configure the NodeAffinity plugin.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "addedAffinity": { + SchemaProps: spec.SchemaProps{ + Description: "AddedAffinity is applied to all Pods additionally to the NodeAffinity specified in the PodSpec. That is, Nodes need to satisfy AddedAffinity AND .spec.NodeAffinity. AddedAffinity is empty by default (all Nodes match). When AddedAffinity is used, some Pods with affinity requirements that match a specific Node (such as Daemonset Pods) might remain unschedulable.", + Ref: ref("k8s.io/api/core/v1.NodeAffinity"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/api/core/v1.NodeAffinity"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_NodeResourcesBalancedAllocationArgs(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "NodeResourcesBalancedAllocationArgs holds arguments used to configure NodeResourcesBalancedAllocation plugin.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "resources": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "name", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Resources to be managed, the default is \"cpu\" and \"memory\" if not specified.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.ResourceSpec"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/kube-scheduler/config/v1.ResourceSpec"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_NodeResourcesFitArgs(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "NodeResourcesFitArgs holds arguments used to configure the NodeResourcesFit plugin.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "ignoredResources": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "IgnoredResources is the list of resources that NodeResources fit filter should ignore. This doesn't apply to scoring.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "ignoredResourceGroups": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "IgnoredResourceGroups defines the list of resource groups that NodeResources fit filter should ignore. e.g. if group is [\"example.com\"], it will ignore all resource names that begin with \"example.com\", such as \"example.com/aaa\" and \"example.com/bbb\". A resource group name can't contain '/'. This doesn't apply to scoring.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "scoringStrategy": { + SchemaProps: spec.SchemaProps{ + Description: "ScoringStrategy selects the node resource scoring strategy. The default strategy is LeastAllocated with an equal \"cpu\" and \"memory\" weight.", + Ref: ref("k8s.io/kube-scheduler/config/v1.ScoringStrategy"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/kube-scheduler/config/v1.ScoringStrategy"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_Plugin(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Plugin specifies a plugin name and its weight when applicable. Weight is used only for Score plugins.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name defines the name of plugin", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "weight": { + SchemaProps: spec.SchemaProps{ + Description: "Weight defines the weight of plugin, only used for Score plugins.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + +func schema_k8sio_kube_scheduler_config_v1_PluginConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PluginConfig specifies arguments that should be passed to a plugin at the time of initialization. A plugin that is invoked at multiple extension points is initialized once. Args can have arbitrary structure. It is up to the plugin to process these Args.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name defines the name of plugin being configured", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "args": { + SchemaProps: spec.SchemaProps{ + Description: "Args defines the arguments passed to the plugins at the time of initialization. Args can have arbitrary structure.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/runtime.RawExtension"), + }, + }, + }, + Required: []string{"name"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/runtime.RawExtension"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_PluginSet(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PluginSet specifies enabled and disabled plugins for an extension point. If an array is empty, missing, or nil, default plugins at that extension point will be used.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "enabled": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Enabled specifies plugins that should be enabled in addition to default plugins. If the default plugin is also configured in the scheduler config file, the weight of plugin will be overridden accordingly. These are called after default plugins and in the same order specified here.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.Plugin"), + }, + }, + }, + }, + }, + "disabled": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "name", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Disabled specifies default plugins that should be disabled. When all default plugins need to be disabled, an array containing only one \"*\" should be provided.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.Plugin"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/kube-scheduler/config/v1.Plugin"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_Plugins(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Plugins include multiple extension points. When specified, the list of plugins for a particular extension point are the only ones enabled. If an extension point is omitted from the config, then the default set of plugins is used for that extension point. Enabled plugins are called in the order specified here, after default plugins. If they need to be invoked before default plugins, default plugins must be disabled and re-enabled here in desired order.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "queueSort": { + SchemaProps: spec.SchemaProps{ + Description: "QueueSort is a list of plugins that should be invoked when sorting pods in the scheduling queue.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + "preFilter": { + SchemaProps: spec.SchemaProps{ + Description: "PreFilter is a list of plugins that should be invoked at \"PreFilter\" extension point of the scheduling framework.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + "filter": { + SchemaProps: spec.SchemaProps{ + Description: "Filter is a list of plugins that should be invoked when filtering out nodes that cannot run the Pod.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + "postFilter": { + SchemaProps: spec.SchemaProps{ + Description: "PostFilter is a list of plugins that are invoked after filtering phase, but only when no feasible nodes were found for the pod.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + "preScore": { + SchemaProps: spec.SchemaProps{ + Description: "PreScore is a list of plugins that are invoked before scoring.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + "score": { + SchemaProps: spec.SchemaProps{ + Description: "Score is a list of plugins that should be invoked when ranking nodes that have passed the filtering phase.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + "reserve": { + SchemaProps: spec.SchemaProps{ + Description: "Reserve is a list of plugins invoked when reserving/unreserving resources after a node is assigned to run the pod.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + "permit": { + SchemaProps: spec.SchemaProps{ + Description: "Permit is a list of plugins that control binding of a Pod. These plugins can prevent or delay binding of a Pod.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + "preBind": { + SchemaProps: spec.SchemaProps{ + Description: "PreBind is a list of plugins that should be invoked before a pod is bound.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + "bind": { + SchemaProps: spec.SchemaProps{ + Description: "Bind is a list of plugins that should be invoked at \"Bind\" extension point of the scheduling framework. The scheduler call these plugins in order. Scheduler skips the rest of these plugins as soon as one returns success.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + "postBind": { + SchemaProps: spec.SchemaProps{ + Description: "PostBind is a list of plugins that should be invoked after a pod is successfully bound.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + "multiPoint": { + SchemaProps: spec.SchemaProps{ + Description: "MultiPoint is a simplified config section to enable plugins for all valid extension points. Plugins enabled through MultiPoint will automatically register for every individual extension point the plugin has implemented. Disabling a plugin through MultiPoint disables that behavior. The same is true for disabling \"*\" through MultiPoint (no default plugins will be automatically registered). Plugins can still be disabled through their individual extension points.\n\nIn terms of precedence, plugin config follows this basic hierarchy\n 1. Specific extension points\n 2. Explicitly configured MultiPoint plugins\n 3. The set of default plugins, as MultiPoint plugins\nThis implies that a higher precedence plugin will run first and overwrite any settings within MultiPoint. Explicitly user-configured plugins also take a higher precedence over default plugins. Within this hierarchy, an Enabled setting takes precedence over Disabled. For example, if a plugin is set in both `multiPoint.Enabled` and `multiPoint.Disabled`, the plugin will be enabled. Similarly, including `multiPoint.Disabled = '*'` and `multiPoint.Enabled = pluginA` will still register that specific plugin through MultiPoint. This follows the same behavior as all other extension point configurations.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.PluginSet"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/kube-scheduler/config/v1.PluginSet"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_PodTopologySpreadArgs(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PodTopologySpreadArgs holds arguments used to configure the PodTopologySpread plugin.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "defaultConstraints": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "DefaultConstraints defines topology spread constraints to be applied to Pods that don't define any in `pod.spec.topologySpreadConstraints`. `.defaultConstraints[*].labelSelectors` must be empty, as they are deduced from the Pod's membership to Services, ReplicationControllers, ReplicaSets or StatefulSets. When not empty, .defaultingType must be \"List\".", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.TopologySpreadConstraint"), + }, + }, + }, + }, + }, + "defaultingType": { + SchemaProps: spec.SchemaProps{ + Description: "DefaultingType determines how .defaultConstraints are deduced. Can be one of \"System\" or \"List\".\n\n- \"System\": Use kubernetes defined constraints that spread Pods among\n Nodes and Zones.\n- \"List\": Use constraints defined in .defaultConstraints.\n\nDefaults to \"System\".", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/api/core/v1.TopologySpreadConstraint"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_RequestedToCapacityRatioParam(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RequestedToCapacityRatioParam define RequestedToCapacityRatio parameters", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "shape": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Shape is a list of points defining the scoring function shape.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.UtilizationShapePoint"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/kube-scheduler/config/v1.UtilizationShapePoint"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_ResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ResourceSpec represents a single resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name of the resource.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "weight": { + SchemaProps: spec.SchemaProps{ + Description: "Weight of the resource.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + +func schema_k8sio_kube_scheduler_config_v1_ScoringStrategy(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ScoringStrategy define ScoringStrategyType for node resource plugin", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "type": { + SchemaProps: spec.SchemaProps{ + Description: "Type selects which strategy to run.", + Type: []string{"string"}, + Format: "", + }, + }, + "resources": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "topologyKey", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Resources to consider when scoring. The default resource set includes \"cpu\" and \"memory\" with an equal weight. Allowed weights go from 1 to 100. Weight defaults to 1 if not specified or explicitly set to 0.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.ResourceSpec"), + }, + }, + }, + }, + }, + "requestedToCapacityRatio": { + SchemaProps: spec.SchemaProps{ + Description: "Arguments specific to RequestedToCapacityRatio strategy.", + Ref: ref("k8s.io/kube-scheduler/config/v1.RequestedToCapacityRatioParam"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/kube-scheduler/config/v1.RequestedToCapacityRatioParam", "k8s.io/kube-scheduler/config/v1.ResourceSpec"}, + } +} + +func schema_k8sio_kube_scheduler_config_v1_UtilizationShapePoint(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "UtilizationShapePoint represents single point of priority function shape.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "utilization": { + SchemaProps: spec.SchemaProps{ + Description: "Utilization (x axis). Valid values are 0 to 100. Fully utilized node maps to 100.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "score": { + SchemaProps: spec.SchemaProps{ + Description: "Score assigned to given utilization (y axis). Valid values are 0 to 10.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"utilization", "score"}, + }, + }, + } +} + +func schema_k8sio_kube_scheduler_config_v1_VolumeBindingArgs(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "VolumeBindingArgs holds arguments used to configure the VolumeBinding plugin.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "bindTimeoutSeconds": { + SchemaProps: spec.SchemaProps{ + Description: "BindTimeoutSeconds is the timeout in seconds in volume binding operation. Value must be non-negative integer. The value zero indicates no waiting. If this value is nil, the default value (600) will be used.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "shape": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Shape specifies the points defining the score function shape, which is used to score nodes based on the utilization of statically provisioned PVs. The utilization is calculated by dividing the total requested storage of the pod by the total capacity of feasible PVs on each node. Each point contains utilization (ranges from 0 to 100) and its associated score (ranges from 0 to 10). You can turn the priority by specifying different scores for different utilization numbers. The default shape points are: 1) 0 for 0 utilization 2) 10 for 100 utilization All points must be sorted in increasing order by utilization.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/kube-scheduler/config/v1.UtilizationShapePoint"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/kube-scheduler/config/v1.UtilizationShapePoint"}, + } +} + func schema_k8sio_kube_scheduler_config_v1beta2_DefaultPreemptionArgs(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/scheduler/apis/config/latest/latest.go b/pkg/scheduler/apis/config/latest/latest.go index 1833b873fe9..49c196c8a25 100644 --- a/pkg/scheduler/apis/config/latest/latest.go +++ b/pkg/scheduler/apis/config/latest/latest.go @@ -18,7 +18,7 @@ package latest import ( "k8s.io/component-base/config/v1alpha1" - "k8s.io/kube-scheduler/config/v1beta3" + v1 "k8s.io/kube-scheduler/config/v1" "k8s.io/kubernetes/pkg/scheduler/apis/config" "k8s.io/kubernetes/pkg/scheduler/apis/config/scheme" ) @@ -26,7 +26,7 @@ import ( // Default creates a default configuration of the latest versioned type. // This function needs to be updated whenever we bump the scheduler's component config version. func Default() (*config.KubeSchedulerConfiguration, error) { - versionedCfg := v1beta3.KubeSchedulerConfiguration{} + versionedCfg := v1.KubeSchedulerConfiguration{} versionedCfg.DebuggingConfiguration = *v1alpha1.NewRecommendedDebuggingConfiguration() scheme.Scheme.Default(&versionedCfg) @@ -38,6 +38,6 @@ func Default() (*config.KubeSchedulerConfiguration, error) { // because the field will be cleared later by API machinery during // conversion. See KubeSchedulerConfiguration internal type definition for // more details. - cfg.TypeMeta.APIVersion = v1beta3.SchemeGroupVersion.String() + cfg.TypeMeta.APIVersion = v1.SchemeGroupVersion.String() return &cfg, nil } diff --git a/pkg/scheduler/apis/config/scheme/scheme.go b/pkg/scheduler/apis/config/scheme/scheme.go index f8bbad2d1fe..375b49b569a 100644 --- a/pkg/scheduler/apis/config/scheme/scheme.go +++ b/pkg/scheduler/apis/config/scheme/scheme.go @@ -21,6 +21,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" config "k8s.io/kubernetes/pkg/scheduler/apis/config" + configv1 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1" configv1beta2 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2" configv1beta3 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3" ) @@ -42,7 +43,10 @@ func AddToScheme(scheme *runtime.Scheme) { utilruntime.Must(config.AddToScheme(scheme)) utilruntime.Must(configv1beta2.AddToScheme(scheme)) utilruntime.Must(configv1beta3.AddToScheme(scheme)) + utilruntime.Must(configv1.AddToScheme(scheme)) utilruntime.Must(scheme.SetVersionPriority( + configv1.SchemeGroupVersion, configv1beta3.SchemeGroupVersion, - configv1beta2.SchemeGroupVersion)) + configv1beta2.SchemeGroupVersion, + )) } diff --git a/pkg/scheduler/apis/config/scheme/scheme_test.go b/pkg/scheduler/apis/config/scheme/scheme_test.go index 8970352f8aa..8ff33d84ed3 100644 --- a/pkg/scheduler/apis/config/scheme/scheme_test.go +++ b/pkg/scheduler/apis/config/scheme/scheme_test.go @@ -24,6 +24,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + v1 "k8s.io/kube-scheduler/config/v1" "k8s.io/kube-scheduler/config/v1beta2" "k8s.io/kube-scheduler/config/v1beta3" "k8s.io/kubernetes/pkg/scheduler/apis/config" @@ -723,6 +724,347 @@ profiles: }, }, }, + // v1 tests + { + name: "v1 all plugin args in default profile", + data: []byte(` +apiVersion: kubescheduler.config.k8s.io/v1 +kind: KubeSchedulerConfiguration +profiles: +- pluginConfig: + - name: DefaultPreemption + args: + minCandidateNodesPercentage: 50 + minCandidateNodesAbsolute: 500 + - name: InterPodAffinity + args: + hardPodAffinityWeight: 5 + - name: NodeResourcesFit + args: + ignoredResources: ["foo"] + - name: PodTopologySpread + args: + defaultConstraints: + - maxSkew: 1 + topologyKey: zone + whenUnsatisfiable: ScheduleAnyway + - name: VolumeBinding + args: + bindTimeoutSeconds: 300 + - name: NodeAffinity + args: + addedAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: foo + operator: In + values: ["bar"] + - name: NodeResourcesBalancedAllocation + args: + resources: + - name: cpu # default weight(1) will be set. + - name: memory # weight 0 will be replaced by 1. + weight: 0 + - name: scalar0 + weight: 1 + - name: scalar1 # default weight(1) will be set for scalar1 + - name: scalar2 # weight 0 will be replaced by 1. + weight: 0 + - name: scalar3 + weight: 2 +`), + wantProfiles: []config.KubeSchedulerProfile{ + { + SchedulerName: "default-scheduler", + Plugins: defaults.PluginsV1, + PluginConfig: []config.PluginConfig{ + { + Name: "DefaultPreemption", + Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 500}, + }, + { + Name: "InterPodAffinity", + Args: &config.InterPodAffinityArgs{HardPodAffinityWeight: 5}, + }, + { + Name: "NodeResourcesFit", + Args: &config.NodeResourcesFitArgs{ + IgnoredResources: []string{"foo"}, + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + }, + }, + }, + }, + { + Name: "PodTopologySpread", + Args: &config.PodTopologySpreadArgs{ + DefaultConstraints: []corev1.TopologySpreadConstraint{ + {MaxSkew: 1, TopologyKey: "zone", WhenUnsatisfiable: corev1.ScheduleAnyway}, + }, + DefaultingType: config.SystemDefaulting, + }, + }, + { + Name: "VolumeBinding", + Args: &config.VolumeBindingArgs{ + BindTimeoutSeconds: 300, + }, + }, + { + Name: "NodeAffinity", + Args: &config.NodeAffinityArgs{ + AddedAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + { + MatchExpressions: []corev1.NodeSelectorRequirement{ + { + Key: "foo", + Operator: corev1.NodeSelectorOpIn, + Values: []string{"bar"}, + }, + }, + }, + }, + }, + }, + }, + }, + { + Name: "NodeResourcesBalancedAllocation", + Args: &config.NodeResourcesBalancedAllocationArgs{ + Resources: []config.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + {Name: "scalar0", Weight: 1}, + {Name: "scalar1", Weight: 1}, + {Name: "scalar2", Weight: 1}, + {Name: "scalar3", Weight: 2}}, + }, + }, + }, + }, + }, + }, + { + name: "v1 plugins can include version and kind", + data: []byte(` +apiVersion: kubescheduler.config.k8s.io/v1 +kind: KubeSchedulerConfiguration +profiles: +- pluginConfig: + - name: DefaultPreemption + args: + apiVersion: kubescheduler.config.k8s.io/v1 + kind: DefaultPreemptionArgs + minCandidateNodesPercentage: 50 +`), + wantProfiles: []config.KubeSchedulerProfile{ + { + SchedulerName: "default-scheduler", + Plugins: defaults.PluginsV1, + PluginConfig: []config.PluginConfig{ + { + Name: "DefaultPreemption", + Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 100}, + }, + { + Name: "InterPodAffinity", + Args: &config.InterPodAffinityArgs{ + HardPodAffinityWeight: 1, + }, + }, + { + Name: "NodeAffinity", + Args: &config.NodeAffinityArgs{}, + }, + { + Name: "NodeResourcesBalancedAllocation", + Args: &config.NodeResourcesBalancedAllocationArgs{ + Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, + }, + { + Name: "NodeResourcesFit", + Args: &config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + 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, + }, + }, + }, + }, + }, + }, + { + name: "plugin group and kind should match the type", + data: []byte(` +apiVersion: kubescheduler.config.k8s.io/v1 +kind: KubeSchedulerConfiguration +profiles: +- pluginConfig: + - name: DefaultPreemption + args: + apiVersion: kubescheduler.config.k8s.io/v1 + kind: InterPodAffinityArgs +`), + wantErr: `decoding .profiles[0].pluginConfig[0]: args for plugin DefaultPreemption were not of type DefaultPreemptionArgs.kubescheduler.config.k8s.io, got InterPodAffinityArgs.kubescheduler.config.k8s.io`, + }, + { + name: "v1 NodResourcesFitArgs shape encoding is strict", + data: []byte(` +apiVersion: kubescheduler.config.k8s.io/v1 +kind: KubeSchedulerConfiguration +profiles: +- pluginConfig: + - name: NodeResourcesFit + args: + scoringStrategy: + requestedToCapacityRatio: + shape: + - Score: 2 + Utilization: 1 +`), + wantErr: `strict decoding error: decoding .profiles[0].pluginConfig[0]: strict decoding error: decoding args for plugin NodeResourcesFit: strict decoding error: unknown field "scoringStrategy.requestedToCapacityRatio.shape[0].Score", unknown field "scoringStrategy.requestedToCapacityRatio.shape[0].Utilization"`, + }, + { + name: "v1 NodeResourcesFitArgs resources encoding is strict", + data: []byte(` +apiVersion: kubescheduler.config.k8s.io/v1 +kind: KubeSchedulerConfiguration +profiles: +- pluginConfig: + - name: NodeResourcesFit + args: + scoringStrategy: + resources: + - Name: cpu + Weight: 1 +`), + wantErr: `strict decoding error: decoding .profiles[0].pluginConfig[0]: strict decoding error: decoding args for plugin NodeResourcesFit: strict decoding error: unknown field "scoringStrategy.resources[0].Name", unknown field "scoringStrategy.resources[0].Weight"`, + }, + { + name: "out-of-tree plugin args", + data: []byte(` +apiVersion: kubescheduler.config.k8s.io/v1 +kind: KubeSchedulerConfiguration +profiles: +- pluginConfig: + - name: OutOfTreePlugin + args: + foo: bar +`), + wantProfiles: []config.KubeSchedulerProfile{ + { + SchedulerName: "default-scheduler", + Plugins: defaults.PluginsV1, + PluginConfig: append([]config.PluginConfig{ + { + Name: "OutOfTreePlugin", + Args: &runtime.Unknown{ + ContentType: "application/json", + Raw: []byte(`{"foo":"bar"}`), + }, + }, + }, defaults.PluginConfigsV1...), + }, + }, + }, + { + name: "empty and no plugin args", + data: []byte(` +apiVersion: kubescheduler.config.k8s.io/v1 +kind: KubeSchedulerConfiguration +profiles: +- pluginConfig: + - name: DefaultPreemption + args: + - name: InterPodAffinity + args: + - name: NodeResourcesFit + - name: OutOfTreePlugin + args: + - name: VolumeBinding + args: + - name: PodTopologySpread + - name: NodeAffinity + - name: NodeResourcesBalancedAllocation +`), + wantProfiles: []config.KubeSchedulerProfile{ + { + SchedulerName: "default-scheduler", + Plugins: defaults.PluginsV1, + PluginConfig: []config.PluginConfig{ + { + Name: "DefaultPreemption", + Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100}, + }, + { + Name: "InterPodAffinity", + Args: &config.InterPodAffinityArgs{ + HardPodAffinityWeight: 1, + }, + }, + { + Name: "NodeResourcesFit", + Args: &config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{ + {Name: "cpu", Weight: 1}, + {Name: "memory", Weight: 1}, + }, + }, + }, + }, + {Name: "OutOfTreePlugin"}, + { + Name: "VolumeBinding", + Args: &config.VolumeBindingArgs{ + BindTimeoutSeconds: 600, + }, + }, + { + Name: "PodTopologySpread", + Args: &config.PodTopologySpreadArgs{ + DefaultingType: config.SystemDefaulting, + }, + }, + { + Name: "NodeAffinity", + Args: &config.NodeAffinityArgs{}, + }, + { + Name: "NodeResourcesBalancedAllocation", + Args: &config.NodeResourcesBalancedAllocationArgs{ + Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, + }, + }, + }, + }, + }, } decoder := Codecs.UniversalDecoder() for _, tt := range testCases { @@ -1193,6 +1535,225 @@ profiles: foo: bar name: OutOfTreePlugin schedulerName: "" +`, + }, + //v1 tests + { + name: "v1 in-tree and out-of-tree plugins", + version: v1.SchemeGroupVersion, + obj: &v1.KubeSchedulerConfiguration{ + Profiles: []v1.KubeSchedulerProfile{ + { + PluginConfig: []v1.PluginConfig{ + { + Name: "InterPodAffinity", + Args: runtime.RawExtension{ + Object: &v1.InterPodAffinityArgs{ + HardPodAffinityWeight: pointer.Int32Ptr(5), + }, + }, + }, + { + Name: "VolumeBinding", + Args: runtime.RawExtension{ + Object: &v1.VolumeBindingArgs{ + BindTimeoutSeconds: pointer.Int64Ptr(300), + Shape: []v1.UtilizationShapePoint{ + { + Utilization: 0, + Score: 0, + }, + { + Utilization: 100, + Score: 10, + }, + }, + }, + }, + }, + { + Name: "NodeResourcesFit", + Args: runtime.RawExtension{ + Object: &v1.NodeResourcesFitArgs{ + ScoringStrategy: &v1.ScoringStrategy{ + Type: v1.RequestedToCapacityRatio, + Resources: []v1.ResourceSpec{{Name: "cpu", Weight: 1}}, + RequestedToCapacityRatio: &v1.RequestedToCapacityRatioParam{ + Shape: []v1.UtilizationShapePoint{ + {Utilization: 1, Score: 2}, + }, + }, + }, + }, + }, + }, + { + Name: "PodTopologySpread", + Args: runtime.RawExtension{ + Object: &v1.PodTopologySpreadArgs{ + DefaultConstraints: []corev1.TopologySpreadConstraint{}, + }, + }, + }, + { + Name: "OutOfTreePlugin", + Args: runtime.RawExtension{ + Raw: []byte(`{"foo":"bar"}`), + }, + }, + }, + }, + }, + }, + want: `apiVersion: kubescheduler.config.k8s.io/v1 +clientConnection: + acceptContentTypes: "" + burst: 0 + contentType: "" + kubeconfig: "" + qps: 0 +kind: KubeSchedulerConfiguration +leaderElection: + leaderElect: null + leaseDuration: 0s + renewDeadline: 0s + resourceLock: "" + resourceName: "" + resourceNamespace: "" + retryPeriod: 0s +profiles: +- pluginConfig: + - args: + apiVersion: kubescheduler.config.k8s.io/v1 + hardPodAffinityWeight: 5 + kind: InterPodAffinityArgs + name: InterPodAffinity + - args: + apiVersion: kubescheduler.config.k8s.io/v1 + bindTimeoutSeconds: 300 + kind: VolumeBindingArgs + shape: + - score: 0 + utilization: 0 + - score: 10 + utilization: 100 + name: VolumeBinding + - args: + apiVersion: kubescheduler.config.k8s.io/v1 + kind: NodeResourcesFitArgs + scoringStrategy: + requestedToCapacityRatio: + shape: + - score: 2 + utilization: 1 + resources: + - name: cpu + weight: 1 + type: RequestedToCapacityRatio + name: NodeResourcesFit + - args: + apiVersion: kubescheduler.config.k8s.io/v1 + kind: PodTopologySpreadArgs + name: PodTopologySpread + - args: + foo: bar + name: OutOfTreePlugin +`, + }, + { + name: "v1 in-tree and out-of-tree plugins from internal", + version: v1.SchemeGroupVersion, + obj: &config.KubeSchedulerConfiguration{ + Parallelism: 8, + Profiles: []config.KubeSchedulerProfile{ + { + PluginConfig: []config.PluginConfig{ + { + Name: "InterPodAffinity", + Args: &config.InterPodAffinityArgs{ + HardPodAffinityWeight: 5, + }, + }, + { + Name: "NodeResourcesFit", + Args: &config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}}, + }, + }, + }, + { + Name: "VolumeBinding", + Args: &config.VolumeBindingArgs{ + BindTimeoutSeconds: 300, + }, + }, + { + Name: "PodTopologySpread", + Args: &config.PodTopologySpreadArgs{}, + }, + { + Name: "OutOfTreePlugin", + Args: &runtime.Unknown{ + Raw: []byte(`{"foo":"bar"}`), + }, + }, + }, + }, + }, + }, + want: `apiVersion: kubescheduler.config.k8s.io/v1 +clientConnection: + acceptContentTypes: "" + burst: 0 + contentType: "" + kubeconfig: "" + qps: 0 +enableContentionProfiling: false +enableProfiling: false +kind: KubeSchedulerConfiguration +leaderElection: + leaderElect: false + leaseDuration: 0s + renewDeadline: 0s + resourceLock: "" + resourceName: "" + resourceNamespace: "" + retryPeriod: 0s +parallelism: 8 +percentageOfNodesToScore: 0 +podInitialBackoffSeconds: 0 +podMaxBackoffSeconds: 0 +profiles: +- pluginConfig: + - args: + apiVersion: kubescheduler.config.k8s.io/v1 + hardPodAffinityWeight: 5 + kind: InterPodAffinityArgs + name: InterPodAffinity + - args: + apiVersion: kubescheduler.config.k8s.io/v1 + kind: NodeResourcesFitArgs + scoringStrategy: + resources: + - name: cpu + weight: 1 + type: LeastAllocated + name: NodeResourcesFit + - args: + apiVersion: kubescheduler.config.k8s.io/v1 + bindTimeoutSeconds: 300 + kind: VolumeBindingArgs + name: VolumeBinding + - args: + apiVersion: kubescheduler.config.k8s.io/v1 + kind: PodTopologySpreadArgs + name: PodTopologySpread + - args: + foo: bar + name: OutOfTreePlugin + schedulerName: "" `, }, } diff --git a/pkg/scheduler/apis/config/testing/config.go b/pkg/scheduler/apis/config/testing/config.go index c564fc55caf..63ae7ee7618 100644 --- a/pkg/scheduler/apis/config/testing/config.go +++ b/pkg/scheduler/apis/config/testing/config.go @@ -20,6 +20,7 @@ import ( "testing" "k8s.io/component-base/config/v1alpha1" + v1 "k8s.io/kube-scheduler/config/v1" "k8s.io/kube-scheduler/config/v1beta2" "k8s.io/kube-scheduler/config/v1beta3" "k8s.io/kubernetes/pkg/scheduler/apis/config" @@ -49,3 +50,15 @@ func V1beta3ToInternalWithDefaults(t *testing.T, versionedCfg v1beta3.KubeSchedu } return &cfg } + +// V1ToInternalWithDefaults creates a v1 default configuration. +func V1ToInternalWithDefaults(t *testing.T, versionedCfg v1.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 +} diff --git a/pkg/scheduler/apis/config/testing/defaults/defaults.go b/pkg/scheduler/apis/config/testing/defaults/defaults.go index 07e0d3ca696..b6d4825a630 100644 --- a/pkg/scheduler/apis/config/testing/defaults/defaults.go +++ b/pkg/scheduler/apis/config/testing/defaults/defaults.go @@ -320,3 +320,173 @@ var PluginConfigsV1beta3 = []config.PluginConfig{ }, }, } + +// PluginsV1 is the set of default v1 plugins (before MultiPoint expansion) +var PluginsV1 = &config.Plugins{ + MultiPoint: config.PluginSet{ + Enabled: []config.Plugin{ + {Name: names.PrioritySort}, + {Name: names.NodeUnschedulable}, + {Name: names.NodeName}, + {Name: names.TaintToleration, Weight: 3}, + {Name: names.NodeAffinity, Weight: 2}, + {Name: names.NodePorts}, + {Name: names.NodeResourcesFit, Weight: 1}, + {Name: names.VolumeRestrictions}, + {Name: names.EBSLimits}, + {Name: names.GCEPDLimits}, + {Name: names.NodeVolumeLimits}, + {Name: names.AzureDiskLimits}, + {Name: names.VolumeBinding}, + {Name: names.VolumeZone}, + {Name: names.PodTopologySpread, Weight: 2}, + {Name: names.InterPodAffinity, Weight: 2}, + {Name: names.DefaultPreemption}, + {Name: names.NodeResourcesBalancedAllocation, Weight: 1}, + {Name: names.ImageLocality, Weight: 1}, + {Name: names.DefaultBinder}, + }, + }, +} + +// ExpandedPluginsV1 default set of v1 plugins after MultiPoint expansion +var ExpandedPluginsV1 = &config.Plugins{ + QueueSort: config.PluginSet{ + Enabled: []config.Plugin{ + {Name: names.PrioritySort}, + }, + }, + PreFilter: config.PluginSet{ + Enabled: []config.Plugin{ + {Name: names.NodeAffinity}, + {Name: names.NodePorts}, + {Name: names.NodeResourcesFit}, + {Name: names.VolumeRestrictions}, + {Name: names.VolumeBinding}, + {Name: names.PodTopologySpread}, + {Name: names.InterPodAffinity}, + }, + }, + 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.TaintToleration}, + {Name: names.NodeAffinity}, + {Name: names.PodTopologySpread}, + {Name: names.InterPodAffinity}, + }, + }, + Score: config.PluginSet{ + Enabled: []config.Plugin{ + // Weight is tripled because: + // - This is a score coming from user preference. + // - Usage of node tainting to group nodes in the cluster is increasing becoming a use-case + // for many user workloads + {Name: names.TaintToleration, Weight: 3}, + // Weight is doubled because: + // - This is a score coming from user preference. + {Name: names.NodeAffinity, Weight: 2}, + {Name: names.NodeResourcesFit, Weight: 1}, + // Weight is tripled because: + // - This is a score coming from user preference. + // - Usage of node tainting to group nodes in the cluster is increasing becoming a use-case + // for many user workloads + {Name: names.VolumeBinding, 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}, + // Weight is doubled because: + // - This is a score coming from user preference. + {Name: names.InterPodAffinity, Weight: 2}, + {Name: names.NodeResourcesBalancedAllocation, Weight: 1}, + {Name: names.ImageLocality, 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}, + }, + }, +} + +// PluginConfigsV1 default plugin configurations. +var PluginConfigsV1 = []config.PluginConfig{ + { + Name: "DefaultPreemption", + Args: &config.DefaultPreemptionArgs{ + MinCandidateNodesPercentage: 10, + MinCandidateNodesAbsolute: 100, + }, + }, + { + Name: "InterPodAffinity", + Args: &config.InterPodAffinityArgs{ + HardPodAffinityWeight: 1, + }, + }, + { + Name: "NodeAffinity", + Args: &config.NodeAffinityArgs{}, + }, + { + Name: "NodeResourcesBalancedAllocation", + Args: &config.NodeResourcesBalancedAllocationArgs{ + Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, + }, + { + Name: "NodeResourcesFit", + Args: &config.NodeResourcesFitArgs{ + ScoringStrategy: &config.ScoringStrategy{ + Type: config.LeastAllocated, + 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, + }, + }, +} diff --git a/pkg/scheduler/apis/config/v1/conversion.go b/pkg/scheduler/apis/config/v1/conversion.go new file mode 100644 index 00000000000..18115f93f49 --- /dev/null +++ b/pkg/scheduler/apis/config/v1/conversion.go @@ -0,0 +1,107 @@ +/* +Copyright 2022 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 v1 + +import ( + "fmt" + "sync" + + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + v1 "k8s.io/kube-scheduler/config/v1" + "k8s.io/kubernetes/pkg/scheduler/apis/config" +) + +var ( + // pluginArgConversionScheme is a scheme with internal and v1 registered, + // used for defaulting/converting typed PluginConfig Args. + // Access via getPluginArgConversionScheme() + pluginArgConversionScheme *runtime.Scheme + initPluginArgConversionScheme sync.Once +) + +func GetPluginArgConversionScheme() *runtime.Scheme { + initPluginArgConversionScheme.Do(func() { + // set up the scheme used for plugin arg conversion + pluginArgConversionScheme = runtime.NewScheme() + utilruntime.Must(AddToScheme(pluginArgConversionScheme)) + utilruntime.Must(config.AddToScheme(pluginArgConversionScheme)) + }) + return pluginArgConversionScheme +} + +func Convert_v1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in *v1.KubeSchedulerConfiguration, out *config.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := autoConvert_v1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in, out, s); err != nil { + return err + } + return convertToInternalPluginConfigArgs(out) +} + +// convertToInternalPluginConfigArgs converts PluginConfig#Args into internal +// types using a scheme, after applying defaults. +func convertToInternalPluginConfigArgs(out *config.KubeSchedulerConfiguration) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + prof := &out.Profiles[i] + for j := range prof.PluginConfig { + args := prof.PluginConfig[j].Args + if args == nil { + continue + } + if _, isUnknown := args.(*runtime.Unknown); isUnknown { + continue + } + internalArgs, err := scheme.ConvertToVersion(args, config.SchemeGroupVersion) + if err != nil { + return fmt.Errorf("converting .Profiles[%d].PluginConfig[%d].Args into internal type: %w", i, j, err) + } + prof.PluginConfig[j].Args = internalArgs + } + } + return nil +} + +func Convert_config_KubeSchedulerConfiguration_To_v1_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := autoConvert_config_KubeSchedulerConfiguration_To_v1_KubeSchedulerConfiguration(in, out, s); err != nil { + return err + } + return convertToExternalPluginConfigArgs(out) +} + +// convertToExternalPluginConfigArgs converts PluginConfig#Args into +// external (versioned) types using a scheme. +func convertToExternalPluginConfigArgs(out *v1.KubeSchedulerConfiguration) error { + scheme := GetPluginArgConversionScheme() + for i := range out.Profiles { + for j := range out.Profiles[i].PluginConfig { + args := out.Profiles[i].PluginConfig[j].Args + if args.Object == nil { + continue + } + if _, isUnknown := args.Object.(*runtime.Unknown); isUnknown { + continue + } + externalArgs, err := scheme.ConvertToVersion(args.Object, SchemeGroupVersion) + if err != nil { + return err + } + out.Profiles[i].PluginConfig[j].Args.Object = externalArgs + } + } + return nil +} diff --git a/pkg/scheduler/apis/config/v1/default_plugins.go b/pkg/scheduler/apis/config/v1/default_plugins.go new file mode 100644 index 00000000000..73c3635b57e --- /dev/null +++ b/pkg/scheduler/apis/config/v1/default_plugins.go @@ -0,0 +1,135 @@ +/* +Copyright 2022 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 v1 + +import ( + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog/v2" + v1 "k8s.io/kube-scheduler/config/v1" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" + "k8s.io/utils/pointer" +) + +// getDefaultPlugins returns the default set of plugins. +func getDefaultPlugins() *v1.Plugins { + plugins := &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: names.PrioritySort}, + {Name: names.NodeUnschedulable}, + {Name: names.NodeName}, + {Name: names.TaintToleration, Weight: pointer.Int32(3)}, + {Name: names.NodeAffinity, Weight: pointer.Int32(2)}, + {Name: names.NodePorts}, + {Name: names.NodeResourcesFit, Weight: pointer.Int32(1)}, + {Name: names.VolumeRestrictions}, + {Name: names.EBSLimits}, + {Name: names.GCEPDLimits}, + {Name: names.NodeVolumeLimits}, + {Name: names.AzureDiskLimits}, + {Name: names.VolumeBinding}, + {Name: names.VolumeZone}, + {Name: names.PodTopologySpread, Weight: pointer.Int32(2)}, + {Name: names.InterPodAffinity, Weight: pointer.Int32(2)}, + {Name: names.DefaultPreemption}, + {Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32(1)}, + {Name: names.ImageLocality, Weight: pointer.Int32(1)}, + {Name: names.DefaultBinder}, + }, + }, + } + + return plugins +} + +// mergePlugins merges the custom set into the given default one, handling disabled sets. +func mergePlugins(defaultPlugins, customPlugins *v1.Plugins) *v1.Plugins { + if customPlugins == nil { + return defaultPlugins + } + + defaultPlugins.MultiPoint = mergePluginSet(defaultPlugins.MultiPoint, customPlugins.MultiPoint) + 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 +} + +type pluginIndex struct { + index int + plugin v1.Plugin +} + +func mergePluginSet(defaultPluginSet, customPluginSet v1.PluginSet) v1.PluginSet { + disabledPlugins := sets.NewString() + enabledCustomPlugins := make(map[string]pluginIndex) + // replacedPluginIndex is a set of index of plugins, which have replaced the default plugins. + replacedPluginIndex := sets.NewInt() + var disabled []v1.Plugin + for _, disabledPlugin := range customPluginSet.Disabled { + // if the user is manually disabling any (or all, with "*") default plugins for an extension point, + // we need to track that so that the MultiPoint extension logic in the framework can know to skip + // inserting unspecified default plugins to this point. + disabled = append(disabled, v1.Plugin{Name: disabledPlugin.Name}) + disabledPlugins.Insert(disabledPlugin.Name) + } + + // With MultiPoint, we may now have some disabledPlugins in the default registry + // For example, we enable PluginX with Filter+Score through MultiPoint but disable its Score plugin by default. + for _, disabledPlugin := range defaultPluginSet.Disabled { + disabled = append(disabled, v1.Plugin{Name: disabledPlugin.Name}) + disabledPlugins.Insert(disabledPlugin.Name) + } + + for index, enabledPlugin := range customPluginSet.Enabled { + enabledCustomPlugins[enabledPlugin.Name] = pluginIndex{index, enabledPlugin} + } + var enabledPlugins []v1.Plugin + if !disabledPlugins.Has("*") { + for _, defaultEnabledPlugin := range defaultPluginSet.Enabled { + if disabledPlugins.Has(defaultEnabledPlugin.Name) { + continue + } + // The default plugin is explicitly re-configured, update the default plugin accordingly. + if customPlugin, ok := enabledCustomPlugins[defaultEnabledPlugin.Name]; ok { + klog.InfoS("Default plugin is explicitly re-configured; overriding", "plugin", defaultEnabledPlugin.Name) + // Update the default plugin in place to preserve order. + defaultEnabledPlugin = customPlugin.plugin + replacedPluginIndex.Insert(customPlugin.index) + } + enabledPlugins = append(enabledPlugins, defaultEnabledPlugin) + } + } + + // Append all the custom plugins which haven't replaced any default plugins. + // Note: duplicated custom plugins will still be appended here. + // If so, the instantiation of scheduler framework will detect it and abort. + for index, plugin := range customPluginSet.Enabled { + if !replacedPluginIndex.Has(index) { + enabledPlugins = append(enabledPlugins, plugin) + } + } + return v1.PluginSet{Enabled: enabledPlugins, Disabled: disabled} +} diff --git a/pkg/scheduler/apis/config/v1/default_plugins_test.go b/pkg/scheduler/apis/config/v1/default_plugins_test.go new file mode 100644 index 00000000000..9ec414cdc26 --- /dev/null +++ b/pkg/scheduler/apis/config/v1/default_plugins_test.go @@ -0,0 +1,523 @@ +/* +Copyright 2022 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 v1 + +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" + v1 "k8s.io/kube-scheduler/config/v1" + "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 *v1.Plugins + }{ + { + name: "Feature gates disabled", + wantConfig: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: names.PrioritySort}, + {Name: names.NodeUnschedulable}, + {Name: names.NodeName}, + {Name: names.TaintToleration, Weight: pointer.Int32(3)}, + {Name: names.NodeAffinity, Weight: pointer.Int32(2)}, + {Name: names.NodePorts}, + {Name: names.NodeResourcesFit, Weight: pointer.Int32(1)}, + {Name: names.VolumeRestrictions}, + {Name: names.EBSLimits}, + {Name: names.GCEPDLimits}, + {Name: names.NodeVolumeLimits}, + {Name: names.AzureDiskLimits}, + {Name: names.VolumeBinding}, + {Name: names.VolumeZone}, + {Name: names.PodTopologySpread, Weight: pointer.Int32(2)}, + {Name: names.InterPodAffinity, Weight: pointer.Int32(2)}, + {Name: names.DefaultPreemption}, + {Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32(1)}, + {Name: names.ImageLocality, Weight: pointer.Int32(1)}, + {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 *v1.Plugins + defaultPlugins *v1.Plugins + expectedPlugins *v1.Plugins + }{ + { + name: "AppendCustomPlugin", + customPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "CustomPlugin"}, + }, + }, + }, + defaultPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + {Name: "CustomPlugin"}, + }, + }, + }, + }, + { + name: "InsertAfterDefaultPlugins2", + customPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "CustomPlugin"}, + {Name: "DefaultPlugin2"}, + }, + Disabled: []v1.Plugin{ + {Name: "DefaultPlugin2"}, + }, + }, + }, + defaultPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "CustomPlugin"}, + {Name: "DefaultPlugin2"}, + }, + Disabled: []v1.Plugin{ + {Name: "DefaultPlugin2"}, + }, + }, + }, + }, + { + name: "InsertBeforeAllPlugins", + customPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "CustomPlugin"}, + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + }, + Disabled: []v1.Plugin{ + {Name: "*"}, + }, + }, + }, + defaultPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "CustomPlugin"}, + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + }, + Disabled: []v1.Plugin{ + {Name: "*"}, + }, + }, + }, + }, + { + name: "ReorderDefaultPlugins", + customPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin2"}, + {Name: "DefaultPlugin1"}, + }, + Disabled: []v1.Plugin{ + {Name: "*"}, + }, + }, + }, + defaultPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin2"}, + {Name: "DefaultPlugin1"}, + }, + Disabled: []v1.Plugin{ + {Name: "*"}, + }, + }, + }, + }, + { + name: "ApplyNilCustomPlugin", + customPlugins: nil, + defaultPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + }, + }, + }, + }, + { + name: "CustomPluginOverrideDefaultPlugin", + customPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "Plugin1", Weight: pointer.Int32Ptr(2)}, + {Name: "Plugin3", Weight: pointer.Int32Ptr(3)}, + }, + }, + }, + defaultPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "Plugin1"}, + {Name: "Plugin2"}, + {Name: "Plugin3"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "Plugin1", Weight: pointer.Int32Ptr(2)}, + {Name: "Plugin2"}, + {Name: "Plugin3", Weight: pointer.Int32Ptr(3)}, + }, + }, + }, + }, + { + name: "OrderPreserveAfterOverride", + customPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "Plugin2", Weight: pointer.Int32Ptr(2)}, + {Name: "Plugin1", Weight: pointer.Int32Ptr(1)}, + }, + }, + }, + defaultPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "Plugin1"}, + {Name: "Plugin2"}, + {Name: "Plugin3"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "Plugin1", Weight: pointer.Int32Ptr(1)}, + {Name: "Plugin2", Weight: pointer.Int32Ptr(2)}, + {Name: "Plugin3"}, + }, + }, + }, + }, + { + name: "RepeatedCustomPlugin", + customPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "Plugin1"}, + {Name: "Plugin2", Weight: pointer.Int32Ptr(2)}, + {Name: "Plugin3"}, + {Name: "Plugin2", Weight: pointer.Int32Ptr(4)}, + }, + }, + }, + defaultPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "Plugin1"}, + {Name: "Plugin2"}, + {Name: "Plugin3"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + Filter: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "Plugin1"}, + {Name: "Plugin2", Weight: pointer.Int32Ptr(4)}, + {Name: "Plugin3"}, + {Name: "Plugin2", Weight: pointer.Int32Ptr(2)}, + }, + }, + }, + }, + { + name: "Append custom MultiPoint plugin", + customPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "CustomPlugin"}, + }, + }, + }, + defaultPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + {Name: "CustomPlugin"}, + }, + }, + }, + }, + { + name: "Append disabled Multipoint plugins", + customPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "CustomPlugin"}, + {Name: "CustomPlugin2"}, + }, + Disabled: []v1.Plugin{ + {Name: "DefaultPlugin2"}, + }, + }, + Score: v1.PluginSet{ + Disabled: []v1.Plugin{ + {Name: "CustomPlugin2"}, + }, + }, + }, + defaultPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "DefaultPlugin2"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin1"}, + {Name: "CustomPlugin"}, + {Name: "CustomPlugin2"}, + }, + Disabled: []v1.Plugin{ + {Name: "DefaultPlugin2"}, + }, + }, + Score: v1.PluginSet{ + Disabled: []v1.Plugin{ + {Name: "CustomPlugin2"}, + }, + }, + }, + }, + { + name: "override default MultiPoint plugins with custom value", + customPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin", Weight: pointer.Int32(5)}, + }, + }, + }, + defaultPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin", Weight: pointer.Int32(5)}, + }, + }, + }, + }, + { + name: "disabled MultiPoint plugin in default set", + defaultPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin"}, + }, + Disabled: []v1.Plugin{ + {Name: "DefaultPlugin2"}, + }, + }, + }, + customPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "CustomPlugin"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin"}, + {Name: "CustomPlugin"}, + }, + Disabled: []v1.Plugin{ + {Name: "DefaultPlugin2"}, + }, + }, + }, + }, + { + name: "disabled MultiPoint plugin in default set for specific extension point", + defaultPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin"}, + }, + }, + Score: v1.PluginSet{ + Disabled: []v1.Plugin{ + {Name: "DefaultPlugin2"}, + }, + }, + }, + customPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "CustomPlugin"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin"}, + {Name: "CustomPlugin"}, + }, + }, + Score: v1.PluginSet{ + Disabled: []v1.Plugin{ + {Name: "DefaultPlugin2"}, + }, + }, + }, + }, + { + name: "multipoint with only disabled gets merged", + defaultPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Enabled: []v1.Plugin{ + {Name: "DefaultPlugin"}, + }, + }, + }, + customPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Disabled: []v1.Plugin{ + {Name: "DefaultPlugin"}, + }, + }, + }, + expectedPlugins: &v1.Plugins{ + MultiPoint: v1.PluginSet{ + Disabled: []v1.Plugin{ + {Name: "DefaultPlugin"}, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + gotPlugins := mergePlugins(test.defaultPlugins, test.customPlugins) + if d := cmp.Diff(test.expectedPlugins, gotPlugins); d != "" { + t.Fatalf("plugins mismatch (-want +got):\n%s", d) + } + }) + } +} diff --git a/pkg/scheduler/apis/config/v1/defaults.go b/pkg/scheduler/apis/config/v1/defaults.go new file mode 100644 index 00000000000..6916123f281 --- /dev/null +++ b/pkg/scheduler/apis/config/v1/defaults.go @@ -0,0 +1,242 @@ +/* +Copyright 2022 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 v1 + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apiserver/pkg/util/feature" + componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1" + configv1 "k8s.io/kube-scheduler/config/v1" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/apis/config" + "k8s.io/utils/pointer" +) + +var defaultResourceSpec = []configv1.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: string(v1.ResourceMemory), Weight: 1}, +} + +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +func pluginsNames(p *configv1.Plugins) []string { + if p == nil { + return nil + } + extensions := []configv1.PluginSet{ + p.MultiPoint, + 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 *configv1.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 := configv1.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, configv1.PluginConfig{ + Name: name, + Args: runtime.RawExtension{Object: args}, + }) + } +} + +// SetDefaults_KubeSchedulerConfiguration sets additional defaults +func SetDefaults_KubeSchedulerConfiguration(obj *configv1.KubeSchedulerConfiguration) { + if obj.Parallelism == nil { + obj.Parallelism = pointer.Int32Ptr(16) + } + + if len(obj.Profiles) == 0 { + obj.Profiles = append(obj.Profiles, configv1.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(v1.DefaultSchedulerName) + } + + // Add the default set of plugins and apply the configuration. + for i := range obj.Profiles { + prof := &obj.Profiles[i] + setDefaults_KubeSchedulerProfile(prof) + } + + if obj.PercentageOfNodesToScore == nil { + percentageOfNodesToScore := int32(config.DefaultPercentageOfNodesToScore) + obj.PercentageOfNodesToScore = &percentageOfNodesToScore + } + + if len(obj.LeaderElection.ResourceLock) == 0 { + // Use lease-based leader election to reduce cost. + // We migrated for EndpointsLease lock in 1.17 and starting in 1.20 we + // migrated to Lease lock. + obj.LeaderElection.ResourceLock = "leases" + } + if len(obj.LeaderElection.ResourceNamespace) == 0 { + obj.LeaderElection.ResourceNamespace = configv1.SchedulerDefaultLockObjectNamespace + } + if len(obj.LeaderElection.ResourceName) == 0 { + obj.LeaderElection.ResourceName = configv1.SchedulerDefaultLockObjectName + } + + if len(obj.ClientConnection.ContentType) == 0 { + obj.ClientConnection.ContentType = "application/vnd.kubernetes.protobuf" + } + // Scheduler has an opinion about QPS/Burst, setting specific defaults for itself, instead of generic settings. + if obj.ClientConnection.QPS == 0.0 { + obj.ClientConnection.QPS = 50.0 + } + if obj.ClientConnection.Burst == 0 { + obj.ClientConnection.Burst = 100 + } + + // Use the default LeaderElectionConfiguration options + componentbaseconfigv1alpha1.RecommendedDefaultLeaderElectionConfiguration(&obj.LeaderElection) + + if obj.PodInitialBackoffSeconds == nil { + obj.PodInitialBackoffSeconds = pointer.Int64(1) + } + + if obj.PodMaxBackoffSeconds == nil { + obj.PodMaxBackoffSeconds = pointer.Int64(10) + } + + // Enable profiling by default in the scheduler + if obj.EnableProfiling == nil { + obj.EnableProfiling = pointer.Bool(true) + } + + // Enable contention profiling by default if profiling is enabled + if *obj.EnableProfiling && obj.EnableContentionProfiling == nil { + obj.EnableContentionProfiling = pointer.Bool(true) + } +} + +func SetDefaults_DefaultPreemptionArgs(obj *configv1.DefaultPreemptionArgs) { + if obj.MinCandidateNodesPercentage == nil { + obj.MinCandidateNodesPercentage = pointer.Int32Ptr(10) + } + if obj.MinCandidateNodesAbsolute == nil { + obj.MinCandidateNodesAbsolute = pointer.Int32Ptr(100) + } +} + +func SetDefaults_InterPodAffinityArgs(obj *configv1.InterPodAffinityArgs) { + if obj.HardPodAffinityWeight == nil { + obj.HardPodAffinityWeight = pointer.Int32Ptr(1) + } +} + +func SetDefaults_VolumeBindingArgs(obj *configv1.VolumeBindingArgs) { + if obj.BindTimeoutSeconds == nil { + obj.BindTimeoutSeconds = pointer.Int64Ptr(600) + } + if len(obj.Shape) == 0 && feature.DefaultFeatureGate.Enabled(features.VolumeCapacityPriority) { + obj.Shape = []configv1.UtilizationShapePoint{ + { + Utilization: 0, + Score: 0, + }, + { + Utilization: 100, + Score: int32(config.MaxCustomPriorityScore), + }, + } + } +} + +func SetDefaults_NodeResourcesBalancedAllocationArgs(obj *configv1.NodeResourcesBalancedAllocationArgs) { + if len(obj.Resources) == 0 { + obj.Resources = defaultResourceSpec + return + } + // If the weight is not set or it is explicitly set to 0, then apply the default weight(1) instead. + for i := range obj.Resources { + if obj.Resources[i].Weight == 0 { + obj.Resources[i].Weight = 1 + } + } +} + +func SetDefaults_PodTopologySpreadArgs(obj *configv1.PodTopologySpreadArgs) { + if obj.DefaultingType == "" { + obj.DefaultingType = configv1.SystemDefaulting + } +} + +func SetDefaults_NodeResourcesFitArgs(obj *configv1.NodeResourcesFitArgs) { + if obj.ScoringStrategy == nil { + obj.ScoringStrategy = &configv1.ScoringStrategy{ + Type: configv1.ScoringStrategyType(config.LeastAllocated), + Resources: defaultResourceSpec, + } + } + if len(obj.ScoringStrategy.Resources) == 0 { + // If no resources specified, use the default set. + obj.ScoringStrategy.Resources = append(obj.ScoringStrategy.Resources, defaultResourceSpec...) + } + for i := range obj.ScoringStrategy.Resources { + if obj.ScoringStrategy.Resources[i].Weight == 0 { + obj.ScoringStrategy.Resources[i].Weight = 1 + } + } +} diff --git a/pkg/scheduler/apis/config/v1/defaults_test.go b/pkg/scheduler/apis/config/v1/defaults_test.go new file mode 100644 index 00000000000..e8d0d8e367c --- /dev/null +++ b/pkg/scheduler/apis/config/v1/defaults_test.go @@ -0,0 +1,646 @@ +/* +Copyright 2022 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 v1 + +import ( + "testing" + "time" + + "github.com/google/go-cmp/cmp" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apiserver/pkg/util/feature" + componentbaseconfig "k8s.io/component-base/config/v1alpha1" + "k8s.io/component-base/featuregate" + featuregatetesting "k8s.io/component-base/featuregate/testing" + configv1 "k8s.io/kube-scheduler/config/v1" + "k8s.io/kubernetes/pkg/features" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" + "k8s.io/utils/pointer" +) + +var pluginConfigs = []configv1.PluginConfig{ + { + Name: "DefaultPreemption", + Args: runtime.RawExtension{ + Object: &configv1.DefaultPreemptionArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "DefaultPreemptionArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + MinCandidateNodesPercentage: pointer.Int32Ptr(10), + MinCandidateNodesAbsolute: pointer.Int32Ptr(100), + }}, + }, + { + Name: "InterPodAffinity", + Args: runtime.RawExtension{ + Object: &configv1.InterPodAffinityArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "InterPodAffinityArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + HardPodAffinityWeight: pointer.Int32Ptr(1), + }}, + }, + { + Name: "NodeAffinity", + Args: runtime.RawExtension{Object: &configv1.NodeAffinityArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "NodeAffinityArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + }}, + }, + { + Name: "NodeResourcesBalancedAllocation", + Args: runtime.RawExtension{Object: &configv1.NodeResourcesBalancedAllocationArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "NodeResourcesBalancedAllocationArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + Resources: []configv1.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }}, + }, + { + Name: "NodeResourcesFit", + Args: runtime.RawExtension{Object: &configv1.NodeResourcesFitArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "NodeResourcesFitArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + ScoringStrategy: &configv1.ScoringStrategy{ + Type: configv1.LeastAllocated, + Resources: []configv1.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, + }}, + }, + { + Name: "PodTopologySpread", + Args: runtime.RawExtension{Object: &configv1.PodTopologySpreadArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "PodTopologySpreadArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + DefaultingType: configv1.SystemDefaulting, + }}, + }, + { + Name: "VolumeBinding", + Args: runtime.RawExtension{Object: &configv1.VolumeBindingArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "VolumeBindingArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + BindTimeoutSeconds: pointer.Int64Ptr(600), + }}, + }, +} + +func TestSchedulerDefaults(t *testing.T) { + enable := true + tests := []struct { + name string + config *configv1.KubeSchedulerConfiguration + expected *configv1.KubeSchedulerConfiguration + }{ + { + name: "empty config", + config: &configv1.KubeSchedulerConfiguration{}, + expected: &configv1.KubeSchedulerConfiguration{ + Parallelism: pointer.Int32Ptr(16), + DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{ + EnableProfiling: &enable, + EnableContentionProfiling: &enable, + }, + LeaderElection: 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: "leases", + ResourceNamespace: "kube-system", + ResourceName: "kube-scheduler", + }, + ClientConnection: componentbaseconfig.ClientConnectionConfiguration{ + QPS: 50, + Burst: 100, + ContentType: "application/vnd.kubernetes.protobuf", + }, + PercentageOfNodesToScore: pointer.Int32Ptr(0), + PodInitialBackoffSeconds: pointer.Int64Ptr(1), + PodMaxBackoffSeconds: pointer.Int64Ptr(10), + Profiles: []configv1.KubeSchedulerProfile{ + { + Plugins: getDefaultPlugins(), + PluginConfig: pluginConfigs, + SchedulerName: pointer.StringPtr("default-scheduler"), + }, + }, + }, + }, + { + name: "no scheduler name", + config: &configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{{}}, + }, + expected: &configv1.KubeSchedulerConfiguration{ + Parallelism: pointer.Int32Ptr(16), + DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{ + EnableProfiling: &enable, + EnableContentionProfiling: &enable, + }, + LeaderElection: 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: "leases", + ResourceNamespace: "kube-system", + ResourceName: "kube-scheduler", + }, + ClientConnection: componentbaseconfig.ClientConnectionConfiguration{ + QPS: 50, + Burst: 100, + ContentType: "application/vnd.kubernetes.protobuf", + }, + PercentageOfNodesToScore: pointer.Int32Ptr(0), + PodInitialBackoffSeconds: pointer.Int64Ptr(1), + PodMaxBackoffSeconds: pointer.Int64Ptr(10), + Profiles: []configv1.KubeSchedulerProfile{ + { + SchedulerName: pointer.StringPtr("default-scheduler"), + Plugins: getDefaultPlugins(), + PluginConfig: pluginConfigs}, + }, + }, + }, + { + name: "two profiles", + config: &configv1.KubeSchedulerConfiguration{ + Parallelism: pointer.Int32Ptr(16), + Profiles: []configv1.KubeSchedulerProfile{ + { + PluginConfig: []configv1.PluginConfig{ + {Name: "FooPlugin"}, + }, + }, + { + SchedulerName: pointer.StringPtr("custom-scheduler"), + Plugins: &configv1.Plugins{ + Bind: configv1.PluginSet{ + Enabled: []configv1.Plugin{ + {Name: "BarPlugin"}, + }, + Disabled: []configv1.Plugin{ + {Name: names.DefaultBinder}, + }, + }, + }, + }, + }, + }, + expected: &configv1.KubeSchedulerConfiguration{ + Parallelism: pointer.Int32Ptr(16), + DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{ + EnableProfiling: &enable, + EnableContentionProfiling: &enable, + }, + LeaderElection: 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: "leases", + ResourceNamespace: "kube-system", + ResourceName: "kube-scheduler", + }, + ClientConnection: componentbaseconfig.ClientConnectionConfiguration{ + QPS: 50, + Burst: 100, + ContentType: "application/vnd.kubernetes.protobuf", + }, + PercentageOfNodesToScore: pointer.Int32Ptr(0), + PodInitialBackoffSeconds: pointer.Int64Ptr(1), + PodMaxBackoffSeconds: pointer.Int64Ptr(10), + Profiles: []configv1.KubeSchedulerProfile{ + { + Plugins: getDefaultPlugins(), + PluginConfig: []configv1.PluginConfig{ + {Name: "FooPlugin"}, + { + Name: "DefaultPreemption", + Args: runtime.RawExtension{ + Object: &configv1.DefaultPreemptionArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "DefaultPreemptionArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + MinCandidateNodesPercentage: pointer.Int32Ptr(10), + MinCandidateNodesAbsolute: pointer.Int32Ptr(100), + }}, + }, + { + Name: "InterPodAffinity", + Args: runtime.RawExtension{ + Object: &configv1.InterPodAffinityArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "InterPodAffinityArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + HardPodAffinityWeight: pointer.Int32Ptr(1), + }}, + }, + { + Name: "NodeAffinity", + Args: runtime.RawExtension{Object: &configv1.NodeAffinityArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "NodeAffinityArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + }}, + }, + { + Name: "NodeResourcesBalancedAllocation", + Args: runtime.RawExtension{Object: &configv1.NodeResourcesBalancedAllocationArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "NodeResourcesBalancedAllocationArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + Resources: []configv1.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }}, + }, + { + Name: "NodeResourcesFit", + Args: runtime.RawExtension{Object: &configv1.NodeResourcesFitArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "NodeResourcesFitArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + ScoringStrategy: &configv1.ScoringStrategy{ + Type: configv1.LeastAllocated, + Resources: []configv1.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}}, + }, + }}, + }, + { + Name: "PodTopologySpread", + Args: runtime.RawExtension{Object: &configv1.PodTopologySpreadArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "PodTopologySpreadArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + DefaultingType: configv1.SystemDefaulting, + }}, + }, + { + Name: "VolumeBinding", + Args: runtime.RawExtension{Object: &configv1.VolumeBindingArgs{ + TypeMeta: metav1.TypeMeta{ + Kind: "VolumeBindingArgs", + APIVersion: "kubescheduler.config.k8s.io/v1", + }, + BindTimeoutSeconds: pointer.Int64Ptr(600), + }}, + }, + }, + }, + { + SchedulerName: pointer.StringPtr("custom-scheduler"), + Plugins: &configv1.Plugins{ + MultiPoint: configv1.PluginSet{ + Enabled: []configv1.Plugin{ + {Name: names.PrioritySort}, + {Name: names.NodeUnschedulable}, + {Name: names.NodeName}, + {Name: names.TaintToleration, Weight: pointer.Int32(3)}, + {Name: names.NodeAffinity, Weight: pointer.Int32(2)}, + {Name: names.NodePorts}, + {Name: names.NodeResourcesFit, Weight: pointer.Int32(1)}, + {Name: names.VolumeRestrictions}, + {Name: names.EBSLimits}, + {Name: names.GCEPDLimits}, + {Name: names.NodeVolumeLimits}, + {Name: names.AzureDiskLimits}, + {Name: names.VolumeBinding}, + {Name: names.VolumeZone}, + {Name: names.PodTopologySpread, Weight: pointer.Int32(2)}, + {Name: names.InterPodAffinity, Weight: pointer.Int32(2)}, + {Name: names.DefaultPreemption}, + {Name: names.NodeResourcesBalancedAllocation, Weight: pointer.Int32(1)}, + {Name: names.ImageLocality, Weight: pointer.Int32(1)}, + {Name: names.DefaultBinder}, + }, + }, + Bind: configv1.PluginSet{ + Enabled: []configv1.Plugin{ + {Name: "BarPlugin"}, + }, + Disabled: []configv1.Plugin{ + {Name: names.DefaultBinder}, + }, + }, + }, + PluginConfig: pluginConfigs, + }, + }, + }, + }, + { + name: "Prallelism with no port", + config: &configv1.KubeSchedulerConfiguration{ + Parallelism: pointer.Int32Ptr(16), + }, + expected: &configv1.KubeSchedulerConfiguration{ + Parallelism: pointer.Int32Ptr(16), + DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{ + EnableProfiling: &enable, + EnableContentionProfiling: &enable, + }, + LeaderElection: 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: "leases", + ResourceNamespace: "kube-system", + ResourceName: "kube-scheduler", + }, + ClientConnection: componentbaseconfig.ClientConnectionConfiguration{ + QPS: 50, + Burst: 100, + ContentType: "application/vnd.kubernetes.protobuf", + }, + PercentageOfNodesToScore: pointer.Int32Ptr(0), + PodInitialBackoffSeconds: pointer.Int64Ptr(1), + PodMaxBackoffSeconds: pointer.Int64Ptr(10), + Profiles: []configv1.KubeSchedulerProfile{ + { + Plugins: getDefaultPlugins(), + PluginConfig: pluginConfigs, + SchedulerName: pointer.StringPtr("default-scheduler"), + }, + }, + }, + }, + { + name: "set non default parallelism", + config: &configv1.KubeSchedulerConfiguration{ + Parallelism: pointer.Int32Ptr(8), + }, + expected: &configv1.KubeSchedulerConfiguration{ + Parallelism: pointer.Int32Ptr(8), + DebuggingConfiguration: componentbaseconfig.DebuggingConfiguration{ + EnableProfiling: &enable, + EnableContentionProfiling: &enable, + }, + LeaderElection: 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: "leases", + ResourceNamespace: "kube-system", + ResourceName: "kube-scheduler", + }, + ClientConnection: componentbaseconfig.ClientConnectionConfiguration{ + QPS: 50, + Burst: 100, + ContentType: "application/vnd.kubernetes.protobuf", + }, + PercentageOfNodesToScore: pointer.Int32Ptr(0), + PodInitialBackoffSeconds: pointer.Int64Ptr(1), + PodMaxBackoffSeconds: pointer.Int64Ptr(10), + Profiles: []configv1.KubeSchedulerProfile{ + { + Plugins: getDefaultPlugins(), + PluginConfig: pluginConfigs, + SchedulerName: pointer.StringPtr("default-scheduler"), + }, + }, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + SetDefaults_KubeSchedulerConfiguration(tc.config) + if diff := cmp.Diff(tc.expected, tc.config); diff != "" { + t.Errorf("Got unexpected defaults (-want, +got):\n%s", diff) + } + }) + } +} + +func TestPluginArgsDefaults(t *testing.T) { + tests := []struct { + name string + features map[featuregate.Feature]bool + in runtime.Object + want runtime.Object + }{ + { + name: "DefaultPreemptionArgs empty", + in: &configv1.DefaultPreemptionArgs{}, + want: &configv1.DefaultPreemptionArgs{ + MinCandidateNodesPercentage: pointer.Int32Ptr(10), + MinCandidateNodesAbsolute: pointer.Int32Ptr(100), + }, + }, + { + name: "DefaultPreemptionArgs with value", + in: &configv1.DefaultPreemptionArgs{ + MinCandidateNodesPercentage: pointer.Int32Ptr(50), + }, + want: &configv1.DefaultPreemptionArgs{ + MinCandidateNodesPercentage: pointer.Int32Ptr(50), + MinCandidateNodesAbsolute: pointer.Int32Ptr(100), + }, + }, + { + name: "InterPodAffinityArgs empty", + in: &configv1.InterPodAffinityArgs{}, + want: &configv1.InterPodAffinityArgs{ + HardPodAffinityWeight: pointer.Int32Ptr(1), + }, + }, + { + name: "InterPodAffinityArgs explicit 0", + in: &configv1.InterPodAffinityArgs{ + HardPodAffinityWeight: pointer.Int32Ptr(0), + }, + want: &configv1.InterPodAffinityArgs{ + HardPodAffinityWeight: pointer.Int32Ptr(0), + }, + }, + { + name: "InterPodAffinityArgs with value", + in: &configv1.InterPodAffinityArgs{ + HardPodAffinityWeight: pointer.Int32Ptr(5), + }, + want: &configv1.InterPodAffinityArgs{ + HardPodAffinityWeight: pointer.Int32Ptr(5), + }, + }, + { + name: "NodeResourcesBalancedAllocationArgs resources empty", + in: &configv1.NodeResourcesBalancedAllocationArgs{}, + want: &configv1.NodeResourcesBalancedAllocationArgs{ + Resources: []configv1.ResourceSpec{ + {Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}, + }, + }, + }, + { + name: "NodeResourcesBalancedAllocationArgs with scalar resource", + in: &configv1.NodeResourcesBalancedAllocationArgs{ + Resources: []configv1.ResourceSpec{ + {Name: "scalar.io/scalar1", Weight: 1}, + }, + }, + want: &configv1.NodeResourcesBalancedAllocationArgs{ + Resources: []configv1.ResourceSpec{ + {Name: "scalar.io/scalar1", Weight: 1}, + }, + }, + }, + { + name: "NodeResourcesBalancedAllocationArgs with mixed resources", + in: &configv1.NodeResourcesBalancedAllocationArgs{ + Resources: []configv1.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: "scalar.io/scalar1", Weight: 1}, + }, + }, + want: &configv1.NodeResourcesBalancedAllocationArgs{ + Resources: []configv1.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: "scalar.io/scalar1", Weight: 1}, + }, + }, + }, + { + name: "NodeResourcesBalancedAllocationArgs have resource no weight", + in: &configv1.NodeResourcesBalancedAllocationArgs{ + Resources: []configv1.ResourceSpec{ + {Name: string(v1.ResourceCPU)}, + {Name: "scalar.io/scalar0"}, + {Name: "scalar.io/scalar1", Weight: 1}, + }, + }, + want: &configv1.NodeResourcesBalancedAllocationArgs{ + Resources: []configv1.ResourceSpec{ + {Name: string(v1.ResourceCPU), Weight: 1}, + {Name: "scalar.io/scalar0", Weight: 1}, + {Name: "scalar.io/scalar1", Weight: 1}, + }, + }, + }, + { + name: "PodTopologySpreadArgs resources empty", + in: &configv1.PodTopologySpreadArgs{}, + want: &configv1.PodTopologySpreadArgs{ + DefaultingType: configv1.SystemDefaulting, + }, + }, + { + name: "PodTopologySpreadArgs resources with value", + in: &configv1.PodTopologySpreadArgs{ + DefaultConstraints: []v1.TopologySpreadConstraint{ + { + TopologyKey: "planet", + WhenUnsatisfiable: v1.DoNotSchedule, + MaxSkew: 2, + }, + }, + }, + want: &configv1.PodTopologySpreadArgs{ + DefaultConstraints: []v1.TopologySpreadConstraint{ + { + TopologyKey: "planet", + WhenUnsatisfiable: v1.DoNotSchedule, + MaxSkew: 2, + }, + }, + DefaultingType: configv1.SystemDefaulting, + }, + }, + { + name: "NodeResourcesFitArgs not set", + in: &configv1.NodeResourcesFitArgs{}, + want: &configv1.NodeResourcesFitArgs{ + ScoringStrategy: &configv1.ScoringStrategy{ + Type: configv1.LeastAllocated, + Resources: defaultResourceSpec, + }, + }, + }, + { + name: "NodeResourcesFitArgs Resources empty", + in: &configv1.NodeResourcesFitArgs{ + ScoringStrategy: &configv1.ScoringStrategy{ + Type: configv1.MostAllocated, + }, + }, + want: &configv1.NodeResourcesFitArgs{ + ScoringStrategy: &configv1.ScoringStrategy{ + Type: configv1.MostAllocated, + Resources: defaultResourceSpec, + }, + }, + }, + { + name: "VolumeBindingArgs empty, VolumeCapacityPriority disabled", + features: map[featuregate.Feature]bool{ + features.VolumeCapacityPriority: false, + }, + in: &configv1.VolumeBindingArgs{}, + want: &configv1.VolumeBindingArgs{ + BindTimeoutSeconds: pointer.Int64Ptr(600), + }, + }, + { + name: "VolumeBindingArgs empty, VolumeCapacityPriority enabled", + features: map[featuregate.Feature]bool{ + features.VolumeCapacityPriority: true, + }, + in: &configv1.VolumeBindingArgs{}, + want: &configv1.VolumeBindingArgs{ + BindTimeoutSeconds: pointer.Int64Ptr(600), + Shape: []configv1.UtilizationShapePoint{ + {Utilization: 0, Score: 0}, + {Utilization: 100, Score: 10}, + }, + }, + }, + } + for _, tc := range tests { + scheme := runtime.NewScheme() + utilruntime.Must(AddToScheme(scheme)) + t.Run(tc.name, func(t *testing.T) { + for k, v := range tc.features { + defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, k, v)() + } + scheme.Default(tc.in) + if diff := cmp.Diff(tc.in, tc.want); diff != "" { + t.Errorf("Got unexpected defaults (-want, +got):\n%s", diff) + } + }) + } +} diff --git a/pkg/scheduler/apis/config/v1/doc.go b/pkg/scheduler/apis/config/v1/doc.go new file mode 100644 index 00000000000..7fa215827be --- /dev/null +++ b/pkg/scheduler/apis/config/v1/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2022 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:conversion-gen=k8s.io/kubernetes/pkg/scheduler/apis/config +// +k8s:conversion-gen-external-types=k8s.io/kube-scheduler/config/v1 +// +k8s:defaulter-gen=TypeMeta +// +k8s:defaulter-gen-input=k8s.io/kube-scheduler/config/v1 +// +groupName=kubescheduler.config.k8s.io + +package v1 // import "k8s.io/kubernetes/pkg/scheduler/apis/config/v1" diff --git a/pkg/scheduler/apis/config/v1/register.go b/pkg/scheduler/apis/config/v1/register.go new file mode 100644 index 00000000000..9a32736c837 --- /dev/null +++ b/pkg/scheduler/apis/config/v1/register.go @@ -0,0 +1,42 @@ +/* +Copyright 2022 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 v1 + +import ( + v1 "k8s.io/kube-scheduler/config/v1" +) + +// GroupName is the group name used in this package +const GroupName = v1.GroupName + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = v1.SchemeGroupVersion + +var ( + // localSchemeBuilder extends the SchemeBuilder instance with the external types. In this package, + // defaulting and conversion init funcs are registered as well. + localSchemeBuilder = &v1.SchemeBuilder + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addDefaultingFuncs) +} diff --git a/pkg/scheduler/apis/config/v1/zz_generated.conversion.go b/pkg/scheduler/apis/config/v1/zz_generated.conversion.go new file mode 100644 index 00000000000..792131e5eec --- /dev/null +++ b/pkg/scheduler/apis/config/v1/zz_generated.conversion.go @@ -0,0 +1,940 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1 + +import ( + unsafe "unsafe" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + v1alpha1 "k8s.io/component-base/config/v1alpha1" + v1 "k8s.io/kube-scheduler/config/v1" + config "k8s.io/kubernetes/pkg/scheduler/apis/config" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*v1.DefaultPreemptionArgs)(nil), (*config.DefaultPreemptionArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(a.(*v1.DefaultPreemptionArgs), b.(*config.DefaultPreemptionArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.DefaultPreemptionArgs)(nil), (*v1.DefaultPreemptionArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_DefaultPreemptionArgs_To_v1_DefaultPreemptionArgs(a.(*config.DefaultPreemptionArgs), b.(*v1.DefaultPreemptionArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Extender)(nil), (*config.Extender)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Extender_To_config_Extender(a.(*v1.Extender), b.(*config.Extender), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Extender)(nil), (*v1.Extender)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Extender_To_v1_Extender(a.(*config.Extender), b.(*v1.Extender), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ExtenderManagedResource)(nil), (*config.ExtenderManagedResource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ExtenderManagedResource_To_config_ExtenderManagedResource(a.(*v1.ExtenderManagedResource), b.(*config.ExtenderManagedResource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ExtenderManagedResource)(nil), (*v1.ExtenderManagedResource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ExtenderManagedResource_To_v1_ExtenderManagedResource(a.(*config.ExtenderManagedResource), b.(*v1.ExtenderManagedResource), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ExtenderTLSConfig)(nil), (*config.ExtenderTLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ExtenderTLSConfig_To_config_ExtenderTLSConfig(a.(*v1.ExtenderTLSConfig), b.(*config.ExtenderTLSConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ExtenderTLSConfig)(nil), (*v1.ExtenderTLSConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ExtenderTLSConfig_To_v1_ExtenderTLSConfig(a.(*config.ExtenderTLSConfig), b.(*v1.ExtenderTLSConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.InterPodAffinityArgs)(nil), (*config.InterPodAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_InterPodAffinityArgs_To_config_InterPodAffinityArgs(a.(*v1.InterPodAffinityArgs), b.(*config.InterPodAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.InterPodAffinityArgs)(nil), (*v1.InterPodAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_InterPodAffinityArgs_To_v1_InterPodAffinityArgs(a.(*config.InterPodAffinityArgs), b.(*v1.InterPodAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.KubeSchedulerProfile)(nil), (*config.KubeSchedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile(a.(*v1.KubeSchedulerProfile), b.(*config.KubeSchedulerProfile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.KubeSchedulerProfile)(nil), (*v1.KubeSchedulerProfile)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile(a.(*config.KubeSchedulerProfile), b.(*v1.KubeSchedulerProfile), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeAffinityArgs)(nil), (*config.NodeAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeAffinityArgs_To_config_NodeAffinityArgs(a.(*v1.NodeAffinityArgs), b.(*config.NodeAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeAffinityArgs)(nil), (*v1.NodeAffinityArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeAffinityArgs_To_v1_NodeAffinityArgs(a.(*config.NodeAffinityArgs), b.(*v1.NodeAffinityArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeResourcesBalancedAllocationArgs)(nil), (*config.NodeResourcesBalancedAllocationArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(a.(*v1.NodeResourcesBalancedAllocationArgs), b.(*config.NodeResourcesBalancedAllocationArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeResourcesBalancedAllocationArgs)(nil), (*v1.NodeResourcesBalancedAllocationArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeResourcesBalancedAllocationArgs_To_v1_NodeResourcesBalancedAllocationArgs(a.(*config.NodeResourcesBalancedAllocationArgs), b.(*v1.NodeResourcesBalancedAllocationArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.NodeResourcesFitArgs)(nil), (*config.NodeResourcesFitArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(a.(*v1.NodeResourcesFitArgs), b.(*config.NodeResourcesFitArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.NodeResourcesFitArgs)(nil), (*v1.NodeResourcesFitArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_NodeResourcesFitArgs_To_v1_NodeResourcesFitArgs(a.(*config.NodeResourcesFitArgs), b.(*v1.NodeResourcesFitArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Plugin)(nil), (*config.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Plugin_To_config_Plugin(a.(*v1.Plugin), b.(*config.Plugin), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Plugin)(nil), (*v1.Plugin)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Plugin_To_v1_Plugin(a.(*config.Plugin), b.(*v1.Plugin), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PluginConfig)(nil), (*config.PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PluginConfig_To_config_PluginConfig(a.(*v1.PluginConfig), b.(*config.PluginConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PluginConfig)(nil), (*v1.PluginConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PluginConfig_To_v1_PluginConfig(a.(*config.PluginConfig), b.(*v1.PluginConfig), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PluginSet)(nil), (*config.PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PluginSet_To_config_PluginSet(a.(*v1.PluginSet), b.(*config.PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PluginSet)(nil), (*v1.PluginSet)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PluginSet_To_v1_PluginSet(a.(*config.PluginSet), b.(*v1.PluginSet), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.Plugins)(nil), (*config.Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Plugins_To_config_Plugins(a.(*v1.Plugins), b.(*config.Plugins), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.Plugins)(nil), (*v1.Plugins)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_Plugins_To_v1_Plugins(a.(*config.Plugins), b.(*v1.Plugins), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.PodTopologySpreadArgs)(nil), (*config.PodTopologySpreadArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(a.(*v1.PodTopologySpreadArgs), b.(*config.PodTopologySpreadArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.PodTopologySpreadArgs)(nil), (*v1.PodTopologySpreadArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_PodTopologySpreadArgs_To_v1_PodTopologySpreadArgs(a.(*config.PodTopologySpreadArgs), b.(*v1.PodTopologySpreadArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.RequestedToCapacityRatioParam)(nil), (*config.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(a.(*v1.RequestedToCapacityRatioParam), b.(*config.RequestedToCapacityRatioParam), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.RequestedToCapacityRatioParam)(nil), (*v1.RequestedToCapacityRatioParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_RequestedToCapacityRatioParam_To_v1_RequestedToCapacityRatioParam(a.(*config.RequestedToCapacityRatioParam), b.(*v1.RequestedToCapacityRatioParam), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ResourceSpec)(nil), (*config.ResourceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ResourceSpec_To_config_ResourceSpec(a.(*v1.ResourceSpec), b.(*config.ResourceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ResourceSpec)(nil), (*v1.ResourceSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ResourceSpec_To_v1_ResourceSpec(a.(*config.ResourceSpec), b.(*v1.ResourceSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.ScoringStrategy)(nil), (*config.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ScoringStrategy_To_config_ScoringStrategy(a.(*v1.ScoringStrategy), b.(*config.ScoringStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.ScoringStrategy)(nil), (*v1.ScoringStrategy)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_ScoringStrategy_To_v1_ScoringStrategy(a.(*config.ScoringStrategy), b.(*v1.ScoringStrategy), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.UtilizationShapePoint)(nil), (*config.UtilizationShapePoint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_UtilizationShapePoint_To_config_UtilizationShapePoint(a.(*v1.UtilizationShapePoint), b.(*config.UtilizationShapePoint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.UtilizationShapePoint)(nil), (*v1.UtilizationShapePoint)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_UtilizationShapePoint_To_v1_UtilizationShapePoint(a.(*config.UtilizationShapePoint), b.(*v1.UtilizationShapePoint), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1.VolumeBindingArgs)(nil), (*config.VolumeBindingArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_VolumeBindingArgs_To_config_VolumeBindingArgs(a.(*v1.VolumeBindingArgs), b.(*config.VolumeBindingArgs), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*config.VolumeBindingArgs)(nil), (*v1.VolumeBindingArgs)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_VolumeBindingArgs_To_v1_VolumeBindingArgs(a.(*config.VolumeBindingArgs), b.(*v1.VolumeBindingArgs), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*config.KubeSchedulerConfiguration)(nil), (*v1.KubeSchedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_config_KubeSchedulerConfiguration_To_v1_KubeSchedulerConfiguration(a.(*config.KubeSchedulerConfiguration), b.(*v1.KubeSchedulerConfiguration), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1.KubeSchedulerConfiguration)(nil), (*config.KubeSchedulerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(a.(*v1.KubeSchedulerConfiguration), b.(*config.KubeSchedulerConfiguration), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in *v1.DefaultPreemptionArgs, out *config.DefaultPreemptionArgs, s conversion.Scope) error { + if err := metav1.Convert_Pointer_int32_To_int32(&in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage, s); err != nil { + return err + } + if err := metav1.Convert_Pointer_int32_To_int32(&in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute, s); err != nil { + return err + } + return nil +} + +// Convert_v1_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs is an autogenerated conversion function. +func Convert_v1_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in *v1.DefaultPreemptionArgs, out *config.DefaultPreemptionArgs, s conversion.Scope) error { + return autoConvert_v1_DefaultPreemptionArgs_To_config_DefaultPreemptionArgs(in, out, s) +} + +func autoConvert_config_DefaultPreemptionArgs_To_v1_DefaultPreemptionArgs(in *config.DefaultPreemptionArgs, out *v1.DefaultPreemptionArgs, s conversion.Scope) error { + if err := metav1.Convert_int32_To_Pointer_int32(&in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage, s); err != nil { + return err + } + if err := metav1.Convert_int32_To_Pointer_int32(&in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute, s); err != nil { + return err + } + return nil +} + +// Convert_config_DefaultPreemptionArgs_To_v1_DefaultPreemptionArgs is an autogenerated conversion function. +func Convert_config_DefaultPreemptionArgs_To_v1_DefaultPreemptionArgs(in *config.DefaultPreemptionArgs, out *v1.DefaultPreemptionArgs, s conversion.Scope) error { + return autoConvert_config_DefaultPreemptionArgs_To_v1_DefaultPreemptionArgs(in, out, s) +} + +func autoConvert_v1_Extender_To_config_Extender(in *v1.Extender, out *config.Extender, s conversion.Scope) error { + out.URLPrefix = in.URLPrefix + out.FilterVerb = in.FilterVerb + out.PreemptVerb = in.PreemptVerb + out.PrioritizeVerb = in.PrioritizeVerb + out.Weight = in.Weight + out.BindVerb = in.BindVerb + out.EnableHTTPS = in.EnableHTTPS + out.TLSConfig = (*config.ExtenderTLSConfig)(unsafe.Pointer(in.TLSConfig)) + out.HTTPTimeout = in.HTTPTimeout + out.NodeCacheCapable = in.NodeCacheCapable + out.ManagedResources = *(*[]config.ExtenderManagedResource)(unsafe.Pointer(&in.ManagedResources)) + out.Ignorable = in.Ignorable + return nil +} + +// Convert_v1_Extender_To_config_Extender is an autogenerated conversion function. +func Convert_v1_Extender_To_config_Extender(in *v1.Extender, out *config.Extender, s conversion.Scope) error { + return autoConvert_v1_Extender_To_config_Extender(in, out, s) +} + +func autoConvert_config_Extender_To_v1_Extender(in *config.Extender, out *v1.Extender, s conversion.Scope) error { + out.URLPrefix = in.URLPrefix + out.FilterVerb = in.FilterVerb + out.PreemptVerb = in.PreemptVerb + out.PrioritizeVerb = in.PrioritizeVerb + out.Weight = in.Weight + out.BindVerb = in.BindVerb + out.EnableHTTPS = in.EnableHTTPS + out.TLSConfig = (*v1.ExtenderTLSConfig)(unsafe.Pointer(in.TLSConfig)) + out.HTTPTimeout = in.HTTPTimeout + out.NodeCacheCapable = in.NodeCacheCapable + out.ManagedResources = *(*[]v1.ExtenderManagedResource)(unsafe.Pointer(&in.ManagedResources)) + out.Ignorable = in.Ignorable + return nil +} + +// Convert_config_Extender_To_v1_Extender is an autogenerated conversion function. +func Convert_config_Extender_To_v1_Extender(in *config.Extender, out *v1.Extender, s conversion.Scope) error { + return autoConvert_config_Extender_To_v1_Extender(in, out, s) +} + +func autoConvert_v1_ExtenderManagedResource_To_config_ExtenderManagedResource(in *v1.ExtenderManagedResource, out *config.ExtenderManagedResource, s conversion.Scope) error { + out.Name = in.Name + out.IgnoredByScheduler = in.IgnoredByScheduler + return nil +} + +// Convert_v1_ExtenderManagedResource_To_config_ExtenderManagedResource is an autogenerated conversion function. +func Convert_v1_ExtenderManagedResource_To_config_ExtenderManagedResource(in *v1.ExtenderManagedResource, out *config.ExtenderManagedResource, s conversion.Scope) error { + return autoConvert_v1_ExtenderManagedResource_To_config_ExtenderManagedResource(in, out, s) +} + +func autoConvert_config_ExtenderManagedResource_To_v1_ExtenderManagedResource(in *config.ExtenderManagedResource, out *v1.ExtenderManagedResource, s conversion.Scope) error { + out.Name = in.Name + out.IgnoredByScheduler = in.IgnoredByScheduler + return nil +} + +// Convert_config_ExtenderManagedResource_To_v1_ExtenderManagedResource is an autogenerated conversion function. +func Convert_config_ExtenderManagedResource_To_v1_ExtenderManagedResource(in *config.ExtenderManagedResource, out *v1.ExtenderManagedResource, s conversion.Scope) error { + return autoConvert_config_ExtenderManagedResource_To_v1_ExtenderManagedResource(in, out, s) +} + +func autoConvert_v1_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in *v1.ExtenderTLSConfig, out *config.ExtenderTLSConfig, s conversion.Scope) error { + out.Insecure = in.Insecure + out.ServerName = in.ServerName + out.CertFile = in.CertFile + out.KeyFile = in.KeyFile + out.CAFile = in.CAFile + out.CertData = *(*[]byte)(unsafe.Pointer(&in.CertData)) + out.KeyData = *(*[]byte)(unsafe.Pointer(&in.KeyData)) + out.CAData = *(*[]byte)(unsafe.Pointer(&in.CAData)) + return nil +} + +// Convert_v1_ExtenderTLSConfig_To_config_ExtenderTLSConfig is an autogenerated conversion function. +func Convert_v1_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in *v1.ExtenderTLSConfig, out *config.ExtenderTLSConfig, s conversion.Scope) error { + return autoConvert_v1_ExtenderTLSConfig_To_config_ExtenderTLSConfig(in, out, s) +} + +func autoConvert_config_ExtenderTLSConfig_To_v1_ExtenderTLSConfig(in *config.ExtenderTLSConfig, out *v1.ExtenderTLSConfig, s conversion.Scope) error { + out.Insecure = in.Insecure + out.ServerName = in.ServerName + out.CertFile = in.CertFile + out.KeyFile = in.KeyFile + out.CAFile = in.CAFile + out.CertData = *(*[]byte)(unsafe.Pointer(&in.CertData)) + out.KeyData = *(*[]byte)(unsafe.Pointer(&in.KeyData)) + out.CAData = *(*[]byte)(unsafe.Pointer(&in.CAData)) + return nil +} + +// Convert_config_ExtenderTLSConfig_To_v1_ExtenderTLSConfig is an autogenerated conversion function. +func Convert_config_ExtenderTLSConfig_To_v1_ExtenderTLSConfig(in *config.ExtenderTLSConfig, out *v1.ExtenderTLSConfig, s conversion.Scope) error { + return autoConvert_config_ExtenderTLSConfig_To_v1_ExtenderTLSConfig(in, out, s) +} + +func autoConvert_v1_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in *v1.InterPodAffinityArgs, out *config.InterPodAffinityArgs, s conversion.Scope) error { + if err := metav1.Convert_Pointer_int32_To_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil { + return err + } + return nil +} + +// Convert_v1_InterPodAffinityArgs_To_config_InterPodAffinityArgs is an autogenerated conversion function. +func Convert_v1_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in *v1.InterPodAffinityArgs, out *config.InterPodAffinityArgs, s conversion.Scope) error { + return autoConvert_v1_InterPodAffinityArgs_To_config_InterPodAffinityArgs(in, out, s) +} + +func autoConvert_config_InterPodAffinityArgs_To_v1_InterPodAffinityArgs(in *config.InterPodAffinityArgs, out *v1.InterPodAffinityArgs, s conversion.Scope) error { + if err := metav1.Convert_int32_To_Pointer_int32(&in.HardPodAffinityWeight, &out.HardPodAffinityWeight, s); err != nil { + return err + } + return nil +} + +// Convert_config_InterPodAffinityArgs_To_v1_InterPodAffinityArgs is an autogenerated conversion function. +func Convert_config_InterPodAffinityArgs_To_v1_InterPodAffinityArgs(in *config.InterPodAffinityArgs, out *v1.InterPodAffinityArgs, s conversion.Scope) error { + return autoConvert_config_InterPodAffinityArgs_To_v1_InterPodAffinityArgs(in, out, s) +} + +func autoConvert_v1_KubeSchedulerConfiguration_To_config_KubeSchedulerConfiguration(in *v1.KubeSchedulerConfiguration, out *config.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := metav1.Convert_Pointer_int32_To_int32(&in.Parallelism, &out.Parallelism, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_LeaderElectionConfiguration_To_config_LeaderElectionConfiguration(&in.LeaderElection, &out.LeaderElection, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_ClientConnectionConfiguration_To_config_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil { + return err + } + if err := v1alpha1.Convert_v1alpha1_DebuggingConfiguration_To_config_DebuggingConfiguration(&in.DebuggingConfiguration, &out.DebuggingConfiguration, s); err != nil { + return err + } + if err := metav1.Convert_Pointer_int32_To_int32(&in.PercentageOfNodesToScore, &out.PercentageOfNodesToScore, s); err != nil { + return err + } + if err := metav1.Convert_Pointer_int64_To_int64(&in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds, s); err != nil { + return err + } + if err := metav1.Convert_Pointer_int64_To_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, 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_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.Extenders = *(*[]config.Extender)(unsafe.Pointer(&in.Extenders)) + return nil +} + +func autoConvert_config_KubeSchedulerConfiguration_To_v1_KubeSchedulerConfiguration(in *config.KubeSchedulerConfiguration, out *v1.KubeSchedulerConfiguration, s conversion.Scope) error { + if err := metav1.Convert_int32_To_Pointer_int32(&in.Parallelism, &out.Parallelism, s); err != nil { + return err + } + if err := v1alpha1.Convert_config_LeaderElectionConfiguration_To_v1alpha1_LeaderElectionConfiguration(&in.LeaderElection, &out.LeaderElection, s); err != nil { + return err + } + if err := v1alpha1.Convert_config_ClientConnectionConfiguration_To_v1alpha1_ClientConnectionConfiguration(&in.ClientConnection, &out.ClientConnection, s); err != nil { + return err + } + // WARNING: in.HealthzBindAddress requires manual conversion: does not exist in peer-type + // WARNING: in.MetricsBindAddress requires manual conversion: does not exist in peer-type + if err := v1alpha1.Convert_config_DebuggingConfiguration_To_v1alpha1_DebuggingConfiguration(&in.DebuggingConfiguration, &out.DebuggingConfiguration, s); err != nil { + return err + } + if err := metav1.Convert_int32_To_Pointer_int32(&in.PercentageOfNodesToScore, &out.PercentageOfNodesToScore, s); err != nil { + return err + } + if err := metav1.Convert_int64_To_Pointer_int64(&in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds, s); err != nil { + return err + } + if err := metav1.Convert_int64_To_Pointer_int64(&in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds, s); err != nil { + return err + } + if in.Profiles != nil { + in, out := &in.Profiles, &out.Profiles + *out = make([]v1.KubeSchedulerProfile, len(*in)) + for i := range *in { + if err := Convert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Profiles = nil + } + out.Extenders = *(*[]v1.Extender)(unsafe.Pointer(&in.Extenders)) + return nil +} + +func autoConvert_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in *v1.KubeSchedulerProfile, out *config.KubeSchedulerProfile, s conversion.Scope) error { + if err := metav1.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_v1_Plugins_To_config_Plugins(*in, *out, s); err != nil { + return err + } + } else { + out.Plugins = nil + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]config.PluginConfig, len(*in)) + for i := range *in { + if err := Convert_v1_PluginConfig_To_config_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfig = nil + } + return nil +} + +// Convert_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile is an autogenerated conversion function. +func Convert_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in *v1.KubeSchedulerProfile, out *config.KubeSchedulerProfile, s conversion.Scope) error { + return autoConvert_v1_KubeSchedulerProfile_To_config_KubeSchedulerProfile(in, out, s) +} + +func autoConvert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile(in *config.KubeSchedulerProfile, out *v1.KubeSchedulerProfile, s conversion.Scope) error { + if err := metav1.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(v1.Plugins) + if err := Convert_config_Plugins_To_v1_Plugins(*in, *out, s); err != nil { + return err + } + } else { + out.Plugins = nil + } + if in.PluginConfig != nil { + in, out := &in.PluginConfig, &out.PluginConfig + *out = make([]v1.PluginConfig, len(*in)) + for i := range *in { + if err := Convert_config_PluginConfig_To_v1_PluginConfig(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.PluginConfig = nil + } + return nil +} + +// Convert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile is an autogenerated conversion function. +func Convert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile(in *config.KubeSchedulerProfile, out *v1.KubeSchedulerProfile, s conversion.Scope) error { + return autoConvert_config_KubeSchedulerProfile_To_v1_KubeSchedulerProfile(in, out, s) +} + +func autoConvert_v1_NodeAffinityArgs_To_config_NodeAffinityArgs(in *v1.NodeAffinityArgs, out *config.NodeAffinityArgs, s conversion.Scope) error { + out.AddedAffinity = (*corev1.NodeAffinity)(unsafe.Pointer(in.AddedAffinity)) + return nil +} + +// Convert_v1_NodeAffinityArgs_To_config_NodeAffinityArgs is an autogenerated conversion function. +func Convert_v1_NodeAffinityArgs_To_config_NodeAffinityArgs(in *v1.NodeAffinityArgs, out *config.NodeAffinityArgs, s conversion.Scope) error { + return autoConvert_v1_NodeAffinityArgs_To_config_NodeAffinityArgs(in, out, s) +} + +func autoConvert_config_NodeAffinityArgs_To_v1_NodeAffinityArgs(in *config.NodeAffinityArgs, out *v1.NodeAffinityArgs, s conversion.Scope) error { + out.AddedAffinity = (*corev1.NodeAffinity)(unsafe.Pointer(in.AddedAffinity)) + return nil +} + +// Convert_config_NodeAffinityArgs_To_v1_NodeAffinityArgs is an autogenerated conversion function. +func Convert_config_NodeAffinityArgs_To_v1_NodeAffinityArgs(in *config.NodeAffinityArgs, out *v1.NodeAffinityArgs, s conversion.Scope) error { + return autoConvert_config_NodeAffinityArgs_To_v1_NodeAffinityArgs(in, out, s) +} + +func autoConvert_v1_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in *v1.NodeResourcesBalancedAllocationArgs, out *config.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) + return nil +} + +// Convert_v1_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs is an autogenerated conversion function. +func Convert_v1_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in *v1.NodeResourcesBalancedAllocationArgs, out *config.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + return autoConvert_v1_NodeResourcesBalancedAllocationArgs_To_config_NodeResourcesBalancedAllocationArgs(in, out, s) +} + +func autoConvert_config_NodeResourcesBalancedAllocationArgs_To_v1_NodeResourcesBalancedAllocationArgs(in *config.NodeResourcesBalancedAllocationArgs, out *v1.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + out.Resources = *(*[]v1.ResourceSpec)(unsafe.Pointer(&in.Resources)) + return nil +} + +// Convert_config_NodeResourcesBalancedAllocationArgs_To_v1_NodeResourcesBalancedAllocationArgs is an autogenerated conversion function. +func Convert_config_NodeResourcesBalancedAllocationArgs_To_v1_NodeResourcesBalancedAllocationArgs(in *config.NodeResourcesBalancedAllocationArgs, out *v1.NodeResourcesBalancedAllocationArgs, s conversion.Scope) error { + return autoConvert_config_NodeResourcesBalancedAllocationArgs_To_v1_NodeResourcesBalancedAllocationArgs(in, out, s) +} + +func autoConvert_v1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1.NodeResourcesFitArgs, out *config.NodeResourcesFitArgs, s conversion.Scope) error { + out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) + out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*config.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) + return nil +} + +// Convert_v1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs is an autogenerated conversion function. +func Convert_v1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in *v1.NodeResourcesFitArgs, out *config.NodeResourcesFitArgs, s conversion.Scope) error { + return autoConvert_v1_NodeResourcesFitArgs_To_config_NodeResourcesFitArgs(in, out, s) +} + +func autoConvert_config_NodeResourcesFitArgs_To_v1_NodeResourcesFitArgs(in *config.NodeResourcesFitArgs, out *v1.NodeResourcesFitArgs, s conversion.Scope) error { + out.IgnoredResources = *(*[]string)(unsafe.Pointer(&in.IgnoredResources)) + out.IgnoredResourceGroups = *(*[]string)(unsafe.Pointer(&in.IgnoredResourceGroups)) + out.ScoringStrategy = (*v1.ScoringStrategy)(unsafe.Pointer(in.ScoringStrategy)) + return nil +} + +// Convert_config_NodeResourcesFitArgs_To_v1_NodeResourcesFitArgs is an autogenerated conversion function. +func Convert_config_NodeResourcesFitArgs_To_v1_NodeResourcesFitArgs(in *config.NodeResourcesFitArgs, out *v1.NodeResourcesFitArgs, s conversion.Scope) error { + return autoConvert_config_NodeResourcesFitArgs_To_v1_NodeResourcesFitArgs(in, out, s) +} + +func autoConvert_v1_Plugin_To_config_Plugin(in *v1.Plugin, out *config.Plugin, s conversion.Scope) error { + out.Name = in.Name + if err := metav1.Convert_Pointer_int32_To_int32(&in.Weight, &out.Weight, s); err != nil { + return err + } + return nil +} + +// Convert_v1_Plugin_To_config_Plugin is an autogenerated conversion function. +func Convert_v1_Plugin_To_config_Plugin(in *v1.Plugin, out *config.Plugin, s conversion.Scope) error { + return autoConvert_v1_Plugin_To_config_Plugin(in, out, s) +} + +func autoConvert_config_Plugin_To_v1_Plugin(in *config.Plugin, out *v1.Plugin, s conversion.Scope) error { + out.Name = in.Name + if err := metav1.Convert_int32_To_Pointer_int32(&in.Weight, &out.Weight, s); err != nil { + return err + } + return nil +} + +// Convert_config_Plugin_To_v1_Plugin is an autogenerated conversion function. +func Convert_config_Plugin_To_v1_Plugin(in *config.Plugin, out *v1.Plugin, s conversion.Scope) error { + return autoConvert_config_Plugin_To_v1_Plugin(in, out, s) +} + +func autoConvert_v1_PluginConfig_To_config_PluginConfig(in *v1.PluginConfig, out *config.PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +// Convert_v1_PluginConfig_To_config_PluginConfig is an autogenerated conversion function. +func Convert_v1_PluginConfig_To_config_PluginConfig(in *v1.PluginConfig, out *config.PluginConfig, s conversion.Scope) error { + return autoConvert_v1_PluginConfig_To_config_PluginConfig(in, out, s) +} + +func autoConvert_config_PluginConfig_To_v1_PluginConfig(in *config.PluginConfig, out *v1.PluginConfig, s conversion.Scope) error { + out.Name = in.Name + if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Args, &out.Args, s); err != nil { + return err + } + return nil +} + +// Convert_config_PluginConfig_To_v1_PluginConfig is an autogenerated conversion function. +func Convert_config_PluginConfig_To_v1_PluginConfig(in *config.PluginConfig, out *v1.PluginConfig, s conversion.Scope) error { + return autoConvert_config_PluginConfig_To_v1_PluginConfig(in, out, s) +} + +func autoConvert_v1_PluginSet_To_config_PluginSet(in *v1.PluginSet, out *config.PluginSet, s conversion.Scope) error { + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]config.Plugin, len(*in)) + for i := range *in { + if err := Convert_v1_Plugin_To_config_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Enabled = nil + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]config.Plugin, len(*in)) + for i := range *in { + if err := Convert_v1_Plugin_To_config_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Disabled = nil + } + return nil +} + +// Convert_v1_PluginSet_To_config_PluginSet is an autogenerated conversion function. +func Convert_v1_PluginSet_To_config_PluginSet(in *v1.PluginSet, out *config.PluginSet, s conversion.Scope) error { + return autoConvert_v1_PluginSet_To_config_PluginSet(in, out, s) +} + +func autoConvert_config_PluginSet_To_v1_PluginSet(in *config.PluginSet, out *v1.PluginSet, s conversion.Scope) error { + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]v1.Plugin, len(*in)) + for i := range *in { + if err := Convert_config_Plugin_To_v1_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Enabled = nil + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]v1.Plugin, len(*in)) + for i := range *in { + if err := Convert_config_Plugin_To_v1_Plugin(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Disabled = nil + } + return nil +} + +// Convert_config_PluginSet_To_v1_PluginSet is an autogenerated conversion function. +func Convert_config_PluginSet_To_v1_PluginSet(in *config.PluginSet, out *v1.PluginSet, s conversion.Scope) error { + return autoConvert_config_PluginSet_To_v1_PluginSet(in, out, s) +} + +func autoConvert_v1_Plugins_To_config_Plugins(in *v1.Plugins, out *config.Plugins, s conversion.Scope) error { + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.QueueSort, &out.QueueSort, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.PreFilter, &out.PreFilter, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.Filter, &out.Filter, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.PostFilter, &out.PostFilter, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.PreScore, &out.PreScore, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.Score, &out.Score, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.Reserve, &out.Reserve, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.Permit, &out.Permit, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.PreBind, &out.PreBind, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.Bind, &out.Bind, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.PostBind, &out.PostBind, s); err != nil { + return err + } + if err := Convert_v1_PluginSet_To_config_PluginSet(&in.MultiPoint, &out.MultiPoint, s); err != nil { + return err + } + return nil +} + +// Convert_v1_Plugins_To_config_Plugins is an autogenerated conversion function. +func Convert_v1_Plugins_To_config_Plugins(in *v1.Plugins, out *config.Plugins, s conversion.Scope) error { + return autoConvert_v1_Plugins_To_config_Plugins(in, out, s) +} + +func autoConvert_config_Plugins_To_v1_Plugins(in *config.Plugins, out *v1.Plugins, s conversion.Scope) error { + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.QueueSort, &out.QueueSort, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.PreFilter, &out.PreFilter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.Filter, &out.Filter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.PostFilter, &out.PostFilter, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.PreScore, &out.PreScore, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.Score, &out.Score, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.Reserve, &out.Reserve, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.Permit, &out.Permit, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.PreBind, &out.PreBind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.Bind, &out.Bind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.PostBind, &out.PostBind, s); err != nil { + return err + } + if err := Convert_config_PluginSet_To_v1_PluginSet(&in.MultiPoint, &out.MultiPoint, s); err != nil { + return err + } + return nil +} + +// Convert_config_Plugins_To_v1_Plugins is an autogenerated conversion function. +func Convert_config_Plugins_To_v1_Plugins(in *config.Plugins, out *v1.Plugins, s conversion.Scope) error { + return autoConvert_config_Plugins_To_v1_Plugins(in, out, s) +} + +func autoConvert_v1_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in *v1.PodTopologySpreadArgs, out *config.PodTopologySpreadArgs, s conversion.Scope) error { + out.DefaultConstraints = *(*[]corev1.TopologySpreadConstraint)(unsafe.Pointer(&in.DefaultConstraints)) + out.DefaultingType = config.PodTopologySpreadConstraintsDefaulting(in.DefaultingType) + return nil +} + +// Convert_v1_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs is an autogenerated conversion function. +func Convert_v1_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in *v1.PodTopologySpreadArgs, out *config.PodTopologySpreadArgs, s conversion.Scope) error { + return autoConvert_v1_PodTopologySpreadArgs_To_config_PodTopologySpreadArgs(in, out, s) +} + +func autoConvert_config_PodTopologySpreadArgs_To_v1_PodTopologySpreadArgs(in *config.PodTopologySpreadArgs, out *v1.PodTopologySpreadArgs, s conversion.Scope) error { + out.DefaultConstraints = *(*[]corev1.TopologySpreadConstraint)(unsafe.Pointer(&in.DefaultConstraints)) + out.DefaultingType = v1.PodTopologySpreadConstraintsDefaulting(in.DefaultingType) + return nil +} + +// Convert_config_PodTopologySpreadArgs_To_v1_PodTopologySpreadArgs is an autogenerated conversion function. +func Convert_config_PodTopologySpreadArgs_To_v1_PodTopologySpreadArgs(in *config.PodTopologySpreadArgs, out *v1.PodTopologySpreadArgs, s conversion.Scope) error { + return autoConvert_config_PodTopologySpreadArgs_To_v1_PodTopologySpreadArgs(in, out, s) +} + +func autoConvert_v1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { + out.Shape = *(*[]config.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_v1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_v1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in *v1.RequestedToCapacityRatioParam, out *config.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_v1_RequestedToCapacityRatioParam_To_config_RequestedToCapacityRatioParam(in, out, s) +} + +func autoConvert_config_RequestedToCapacityRatioParam_To_v1_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1.RequestedToCapacityRatioParam, s conversion.Scope) error { + out.Shape = *(*[]v1.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_config_RequestedToCapacityRatioParam_To_v1_RequestedToCapacityRatioParam is an autogenerated conversion function. +func Convert_config_RequestedToCapacityRatioParam_To_v1_RequestedToCapacityRatioParam(in *config.RequestedToCapacityRatioParam, out *v1.RequestedToCapacityRatioParam, s conversion.Scope) error { + return autoConvert_config_RequestedToCapacityRatioParam_To_v1_RequestedToCapacityRatioParam(in, out, s) +} + +func autoConvert_v1_ResourceSpec_To_config_ResourceSpec(in *v1.ResourceSpec, out *config.ResourceSpec, s conversion.Scope) error { + out.Name = in.Name + out.Weight = in.Weight + return nil +} + +// Convert_v1_ResourceSpec_To_config_ResourceSpec is an autogenerated conversion function. +func Convert_v1_ResourceSpec_To_config_ResourceSpec(in *v1.ResourceSpec, out *config.ResourceSpec, s conversion.Scope) error { + return autoConvert_v1_ResourceSpec_To_config_ResourceSpec(in, out, s) +} + +func autoConvert_config_ResourceSpec_To_v1_ResourceSpec(in *config.ResourceSpec, out *v1.ResourceSpec, s conversion.Scope) error { + out.Name = in.Name + out.Weight = in.Weight + return nil +} + +// Convert_config_ResourceSpec_To_v1_ResourceSpec is an autogenerated conversion function. +func Convert_config_ResourceSpec_To_v1_ResourceSpec(in *config.ResourceSpec, out *v1.ResourceSpec, s conversion.Scope) error { + return autoConvert_config_ResourceSpec_To_v1_ResourceSpec(in, out, s) +} + +func autoConvert_v1_ScoringStrategy_To_config_ScoringStrategy(in *v1.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + out.Type = config.ScoringStrategyType(in.Type) + out.Resources = *(*[]config.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*config.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_v1_ScoringStrategy_To_config_ScoringStrategy is an autogenerated conversion function. +func Convert_v1_ScoringStrategy_To_config_ScoringStrategy(in *v1.ScoringStrategy, out *config.ScoringStrategy, s conversion.Scope) error { + return autoConvert_v1_ScoringStrategy_To_config_ScoringStrategy(in, out, s) +} + +func autoConvert_config_ScoringStrategy_To_v1_ScoringStrategy(in *config.ScoringStrategy, out *v1.ScoringStrategy, s conversion.Scope) error { + out.Type = v1.ScoringStrategyType(in.Type) + out.Resources = *(*[]v1.ResourceSpec)(unsafe.Pointer(&in.Resources)) + out.RequestedToCapacityRatio = (*v1.RequestedToCapacityRatioParam)(unsafe.Pointer(in.RequestedToCapacityRatio)) + return nil +} + +// Convert_config_ScoringStrategy_To_v1_ScoringStrategy is an autogenerated conversion function. +func Convert_config_ScoringStrategy_To_v1_ScoringStrategy(in *config.ScoringStrategy, out *v1.ScoringStrategy, s conversion.Scope) error { + return autoConvert_config_ScoringStrategy_To_v1_ScoringStrategy(in, out, s) +} + +func autoConvert_v1_UtilizationShapePoint_To_config_UtilizationShapePoint(in *v1.UtilizationShapePoint, out *config.UtilizationShapePoint, s conversion.Scope) error { + out.Utilization = in.Utilization + out.Score = in.Score + return nil +} + +// Convert_v1_UtilizationShapePoint_To_config_UtilizationShapePoint is an autogenerated conversion function. +func Convert_v1_UtilizationShapePoint_To_config_UtilizationShapePoint(in *v1.UtilizationShapePoint, out *config.UtilizationShapePoint, s conversion.Scope) error { + return autoConvert_v1_UtilizationShapePoint_To_config_UtilizationShapePoint(in, out, s) +} + +func autoConvert_config_UtilizationShapePoint_To_v1_UtilizationShapePoint(in *config.UtilizationShapePoint, out *v1.UtilizationShapePoint, s conversion.Scope) error { + out.Utilization = in.Utilization + out.Score = in.Score + return nil +} + +// Convert_config_UtilizationShapePoint_To_v1_UtilizationShapePoint is an autogenerated conversion function. +func Convert_config_UtilizationShapePoint_To_v1_UtilizationShapePoint(in *config.UtilizationShapePoint, out *v1.UtilizationShapePoint, s conversion.Scope) error { + return autoConvert_config_UtilizationShapePoint_To_v1_UtilizationShapePoint(in, out, s) +} + +func autoConvert_v1_VolumeBindingArgs_To_config_VolumeBindingArgs(in *v1.VolumeBindingArgs, out *config.VolumeBindingArgs, s conversion.Scope) error { + if err := metav1.Convert_Pointer_int64_To_int64(&in.BindTimeoutSeconds, &out.BindTimeoutSeconds, s); err != nil { + return err + } + out.Shape = *(*[]config.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_v1_VolumeBindingArgs_To_config_VolumeBindingArgs is an autogenerated conversion function. +func Convert_v1_VolumeBindingArgs_To_config_VolumeBindingArgs(in *v1.VolumeBindingArgs, out *config.VolumeBindingArgs, s conversion.Scope) error { + return autoConvert_v1_VolumeBindingArgs_To_config_VolumeBindingArgs(in, out, s) +} + +func autoConvert_config_VolumeBindingArgs_To_v1_VolumeBindingArgs(in *config.VolumeBindingArgs, out *v1.VolumeBindingArgs, s conversion.Scope) error { + if err := metav1.Convert_int64_To_Pointer_int64(&in.BindTimeoutSeconds, &out.BindTimeoutSeconds, s); err != nil { + return err + } + out.Shape = *(*[]v1.UtilizationShapePoint)(unsafe.Pointer(&in.Shape)) + return nil +} + +// Convert_config_VolumeBindingArgs_To_v1_VolumeBindingArgs is an autogenerated conversion function. +func Convert_config_VolumeBindingArgs_To_v1_VolumeBindingArgs(in *config.VolumeBindingArgs, out *v1.VolumeBindingArgs, s conversion.Scope) error { + return autoConvert_config_VolumeBindingArgs_To_v1_VolumeBindingArgs(in, out, s) +} diff --git a/pkg/scheduler/apis/config/v1/zz_generated.deepcopy.go b/pkg/scheduler/apis/config/v1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..87181b43048 --- /dev/null +++ b/pkg/scheduler/apis/config/v1/zz_generated.deepcopy.go @@ -0,0 +1,22 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 diff --git a/pkg/scheduler/apis/config/v1/zz_generated.defaults.go b/pkg/scheduler/apis/config/v1/zz_generated.defaults.go new file mode 100644 index 00000000000..ac93d735c4f --- /dev/null +++ b/pkg/scheduler/apis/config/v1/zz_generated.defaults.go @@ -0,0 +1,73 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + v1 "k8s.io/kube-scheduler/config/v1" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&v1.DefaultPreemptionArgs{}, func(obj interface{}) { SetObjectDefaults_DefaultPreemptionArgs(obj.(*v1.DefaultPreemptionArgs)) }) + scheme.AddTypeDefaultingFunc(&v1.InterPodAffinityArgs{}, func(obj interface{}) { SetObjectDefaults_InterPodAffinityArgs(obj.(*v1.InterPodAffinityArgs)) }) + scheme.AddTypeDefaultingFunc(&v1.KubeSchedulerConfiguration{}, func(obj interface{}) { + SetObjectDefaults_KubeSchedulerConfiguration(obj.(*v1.KubeSchedulerConfiguration)) + }) + scheme.AddTypeDefaultingFunc(&v1.NodeResourcesBalancedAllocationArgs{}, func(obj interface{}) { + SetObjectDefaults_NodeResourcesBalancedAllocationArgs(obj.(*v1.NodeResourcesBalancedAllocationArgs)) + }) + scheme.AddTypeDefaultingFunc(&v1.NodeResourcesFitArgs{}, func(obj interface{}) { SetObjectDefaults_NodeResourcesFitArgs(obj.(*v1.NodeResourcesFitArgs)) }) + scheme.AddTypeDefaultingFunc(&v1.PodTopologySpreadArgs{}, func(obj interface{}) { SetObjectDefaults_PodTopologySpreadArgs(obj.(*v1.PodTopologySpreadArgs)) }) + scheme.AddTypeDefaultingFunc(&v1.VolumeBindingArgs{}, func(obj interface{}) { SetObjectDefaults_VolumeBindingArgs(obj.(*v1.VolumeBindingArgs)) }) + return nil +} + +func SetObjectDefaults_DefaultPreemptionArgs(in *v1.DefaultPreemptionArgs) { + SetDefaults_DefaultPreemptionArgs(in) +} + +func SetObjectDefaults_InterPodAffinityArgs(in *v1.InterPodAffinityArgs) { + SetDefaults_InterPodAffinityArgs(in) +} + +func SetObjectDefaults_KubeSchedulerConfiguration(in *v1.KubeSchedulerConfiguration) { + SetDefaults_KubeSchedulerConfiguration(in) +} + +func SetObjectDefaults_NodeResourcesBalancedAllocationArgs(in *v1.NodeResourcesBalancedAllocationArgs) { + SetDefaults_NodeResourcesBalancedAllocationArgs(in) +} + +func SetObjectDefaults_NodeResourcesFitArgs(in *v1.NodeResourcesFitArgs) { + SetDefaults_NodeResourcesFitArgs(in) +} + +func SetObjectDefaults_PodTopologySpreadArgs(in *v1.PodTopologySpreadArgs) { + SetDefaults_PodTopologySpreadArgs(in) +} + +func SetObjectDefaults_VolumeBindingArgs(in *v1.VolumeBindingArgs) { + SetDefaults_VolumeBindingArgs(in) +} diff --git a/pkg/scheduler/apis/config/validation/validation.go b/pkg/scheduler/apis/config/validation/validation.go index 69ea1aac074..277714c38a0 100644 --- a/pkg/scheduler/apis/config/validation/validation.go +++ b/pkg/scheduler/apis/config/validation/validation.go @@ -134,6 +134,10 @@ var invalidPluginsByVersion = []invalidPlugins{ schemeGroupVersion: v1beta3.SchemeGroupVersion.String(), plugins: []string{}, }, + { + schemeGroupVersion: v1.SchemeGroupVersion.String(), + plugins: []string{"SelectorSpread"}, + }, } // isPluginInvalid checks if a given plugin was removed/deprecated in the given component diff --git a/pkg/scheduler/apis/config/validation/validation_test.go b/pkg/scheduler/apis/config/validation/validation_test.go index 4489fa78095..f99ba0bbbca 100644 --- a/pkg/scheduler/apis/config/validation/validation_test.go +++ b/pkg/scheduler/apis/config/validation/validation_test.go @@ -17,13 +17,14 @@ limitations under the License. package validation import ( - "fmt" + "strings" "testing" "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" componentbaseconfig "k8s.io/component-base/config" "k8s.io/kubernetes/pkg/scheduler/apis/config" + configv1 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1" "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2" "k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3" ) @@ -196,10 +197,11 @@ func TestValidateKubeSchedulerConfigurationV1beta2(t *testing.T) { extenderDuplicateBind.Extenders = append(extenderDuplicateBind.Extenders, config.Extender{ PrioritizeVerb: "prioritize", BindVerb: "bar", + Weight: 1, }) - goodInvalidPlugins := validConfig.DeepCopy() - goodInvalidPlugins.Profiles[0].Plugins.Score.Enabled = append(goodInvalidPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "PodTopologySpread", Weight: 2}) + validPlugins := validConfig.DeepCopy() + validPlugins.Profiles[0].Plugins.Score.Enabled = append(validPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "PodTopologySpread", Weight: 2}) scenarios := map[string]struct { expectedToFail bool @@ -213,74 +215,91 @@ func TestValidateKubeSchedulerConfigurationV1beta2(t *testing.T) { "bad-parallelism-invalid-value": { expectedToFail: true, config: invalidParallelismValue, + errorString: "should be an integer value greater than zero", }, "bad-resource-name-not-set": { expectedToFail: true, config: resourceNameNotSet, + errorString: "resourceName is required", }, "bad-resource-namespace-not-set": { expectedToFail: true, config: resourceNamespaceNotSet, + errorString: "resourceNamespace is required", }, "non-empty-metrics-bind-addr": { expectedToFail: true, config: metricsBindAddrInvalid, + errorString: "must be empty or with an explicit 0 port", }, "non-empty-healthz-bind-addr": { expectedToFail: true, config: healthzBindAddrInvalid, + errorString: "must be empty or with an explicit 0 port", }, "bad-percentage-of-nodes-to-score": { expectedToFail: true, config: percentageOfNodesToScore101, + errorString: "not in valid range [0-100]", }, "scheduler-name-not-set": { expectedToFail: true, config: schedulerNameNotSet, + errorString: "Required value", }, "repeated-scheduler-name": { expectedToFail: true, config: repeatedSchedulerName, + errorString: "Duplicate value", }, "different-queue-sort": { expectedToFail: true, config: differentQueueSort, + errorString: "has to match for all profiles", }, "one-empty-queue-sort": { expectedToFail: true, config: oneEmptyQueueSort, + errorString: "has to match for all profiles", }, "extender-negative-weight": { expectedToFail: true, config: extenderNegativeWeight, + errorString: "must have a positive weight applied to it", }, "extender-duplicate-managed-resources": { expectedToFail: true, config: extenderDuplicateManagedResource, + errorString: "duplicate extender managed resource name", }, "extender-duplicate-bind": { expectedToFail: true, config: extenderDuplicateBind, + errorString: "only one extender can implement bind", }, "invalid-node-percentage": { expectedToFail: true, config: invalidNodePercentage, + errorString: "not in valid range [0, 100]", }, "invalid-plugin-args": { expectedToFail: true, config: invalidPluginArgs, + errorString: "has to match plugin args", }, "duplicated-plugin-config": { expectedToFail: true, config: duplicatedPluginConfig, + errorString: "Duplicate value: \"config\"", }, "mismatch-queue-sort": { expectedToFail: true, config: mismatchQueueSort, + errorString: "has to match for all profiles", }, - "good-invalid-plugins": { + "valid-plugins": { expectedToFail: false, - config: goodInvalidPlugins, + config: validPlugins, }, } @@ -293,9 +312,8 @@ func TestValidateKubeSchedulerConfigurationV1beta2(t *testing.T) { if errs != nil && !scenario.expectedToFail { t.Errorf("Unexpected failure: %+v", errs) } - fmt.Println(errs) - if errs != nil && scenario.errorString != "" && errs.Error() != scenario.errorString { + if errs != nil && scenario.errorString != "" && !strings.Contains(errs.Error(), scenario.errorString) { t.Errorf("Unexpected error string\n want:\t%s\n got:\t%s", scenario.errorString, errs.Error()) } }) @@ -470,10 +488,11 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) { extenderDuplicateBind.Extenders = append(extenderDuplicateBind.Extenders, config.Extender{ PrioritizeVerb: "prioritize", BindVerb: "bar", + Weight: 1, }) - goodInvalidPlugins := validConfig.DeepCopy() - goodInvalidPlugins.Profiles[0].Plugins.Score.Enabled = append(goodInvalidPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "PodTopologySpread", Weight: 2}) + validPlugins := validConfig.DeepCopy() + validPlugins.Profiles[0].Plugins.Score.Enabled = append(validPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "PodTopologySpread", Weight: 2}) scenarios := map[string]struct { expectedToFail bool @@ -487,74 +506,91 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) { "bad-parallelism-invalid-value": { expectedToFail: true, config: invalidParallelismValue, + errorString: "should be an integer value greater than zero", }, "bad-resource-name-not-set": { expectedToFail: true, config: resourceNameNotSet, + errorString: "resourceName is required", }, "bad-resource-namespace-not-set": { expectedToFail: true, config: resourceNamespaceNotSet, + errorString: "resourceNamespace is required", }, "non-empty-metrics-bind-addr": { expectedToFail: true, config: metricsBindAddrInvalid, + errorString: "must be empty or with an explicit 0 port", }, "non-empty-healthz-bind-addr": { expectedToFail: true, config: healthzBindAddrInvalid, + errorString: "must be empty or with an explicit 0 port", }, "bad-percentage-of-nodes-to-score": { expectedToFail: true, config: percentageOfNodesToScore101, + errorString: "not in valid range [0-100]", }, "scheduler-name-not-set": { expectedToFail: true, config: schedulerNameNotSet, + errorString: "Required value", }, "repeated-scheduler-name": { expectedToFail: true, config: repeatedSchedulerName, + errorString: "Duplicate value", }, "different-queue-sort": { expectedToFail: true, config: differentQueueSort, + errorString: "has to match for all profiles", }, "one-empty-queue-sort": { expectedToFail: true, config: oneEmptyQueueSort, + errorString: "has to match for all profiles", }, "extender-negative-weight": { expectedToFail: true, config: extenderNegativeWeight, + errorString: "must have a positive weight applied to it", }, "extender-duplicate-managed-resources": { expectedToFail: true, config: extenderDuplicateManagedResource, + errorString: "duplicate extender managed resource name", }, "extender-duplicate-bind": { expectedToFail: true, config: extenderDuplicateBind, + errorString: "only one extender can implement bind", }, "invalid-node-percentage": { expectedToFail: true, config: invalidNodePercentage, + errorString: "not in valid range [0, 100]", }, "invalid-plugin-args": { expectedToFail: true, config: invalidPluginArgs, + errorString: "has to match plugin args", }, "duplicated-plugin-config": { expectedToFail: true, config: duplicatedPluginConfig, + errorString: "Duplicate value: \"config\"", }, "mismatch-queue-sort": { expectedToFail: true, config: mismatchQueueSort, + errorString: "has to match for all profiles", }, - "good-invalid-plugins": { + "valid-plugins": { expectedToFail: false, - config: goodInvalidPlugins, + config: validPlugins, }, } @@ -567,9 +603,307 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) { if errs != nil && !scenario.expectedToFail { t.Errorf("Unexpected failure: %+v", errs) } - fmt.Println(errs) - if errs != nil && scenario.errorString != "" && errs.Error() != scenario.errorString { + if errs != nil && scenario.errorString != "" && !strings.Contains(errs.Error(), scenario.errorString) { + t.Errorf("Unexpected error string\n want:\t%s\n got:\t%s", scenario.errorString, errs.Error()) + } + }) + } +} + +func TestValidateKubeSchedulerConfigurationV1(t *testing.T) { + podInitialBackoffSeconds := int64(1) + podMaxBackoffSeconds := int64(1) + validConfig := &config.KubeSchedulerConfiguration{ + TypeMeta: metav1.TypeMeta{ + APIVersion: configv1.SchemeGroupVersion.String(), + }, + Parallelism: 8, + ClientConnection: componentbaseconfig.ClientConnectionConfiguration{ + AcceptContentTypes: "application/json", + ContentType: "application/json", + QPS: 10, + Burst: 10, + }, + LeaderElection: componentbaseconfig.LeaderElectionConfiguration{ + ResourceLock: "configmap", + LeaderElect: true, + LeaseDuration: metav1.Duration{Duration: 30 * time.Second}, + RenewDeadline: metav1.Duration{Duration: 15 * time.Second}, + RetryPeriod: metav1.Duration{Duration: 5 * time.Second}, + ResourceNamespace: "name", + ResourceName: "name", + }, + PodInitialBackoffSeconds: podInitialBackoffSeconds, + PodMaxBackoffSeconds: podMaxBackoffSeconds, + 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: "*"}}, + }, + }, + PluginConfig: []config.PluginConfig{ + { + Name: "DefaultPreemption", + Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100}, + }, + }, + }, + { + SchedulerName: "other", + Plugins: &config.Plugins{ + QueueSort: config.PluginSet{ + Enabled: []config.Plugin{{Name: "CustomSort"}}, + }, + Bind: config.PluginSet{ + Enabled: []config.Plugin{{Name: "CustomBind"}}, + }, + }, + }, + }, + Extenders: []config.Extender{ + { + PrioritizeVerb: "prioritize", + Weight: 1, + }, + }, + } + + invalidParallelismValue := validConfig.DeepCopy() + invalidParallelismValue.Parallelism = 0 + + resourceNameNotSet := validConfig.DeepCopy() + resourceNameNotSet.LeaderElection.ResourceName = "" + + resourceNamespaceNotSet := validConfig.DeepCopy() + resourceNamespaceNotSet.LeaderElection.ResourceNamespace = "" + + enableContentProfilingSetWithoutEnableProfiling := validConfig.DeepCopy() + enableContentProfilingSetWithoutEnableProfiling.EnableProfiling = false + enableContentProfilingSetWithoutEnableProfiling.EnableContentionProfiling = true + + metricsBindAddrInvalid := validConfig.DeepCopy() + metricsBindAddrInvalid.MetricsBindAddress = "0.0.0.0:9090" + + healthzBindAddrInvalid := validConfig.DeepCopy() + healthzBindAddrInvalid.HealthzBindAddress = "0.0.0.0:9090" + + 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 + + extenderNegativeWeight := validConfig.DeepCopy() + extenderNegativeWeight.Extenders[0].Weight = -1 + + invalidNodePercentage := validConfig.DeepCopy() + invalidNodePercentage.Profiles[0].PluginConfig = []config.PluginConfig{ + { + Name: "DefaultPreemption", + Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 200, MinCandidateNodesAbsolute: 100}, + }, + } + + invalidPluginArgs := validConfig.DeepCopy() + invalidPluginArgs.Profiles[0].PluginConfig = []config.PluginConfig{ + { + Name: "DefaultPreemption", + Args: &config.InterPodAffinityArgs{}, + }, + } + + duplicatedPluginConfig := validConfig.DeepCopy() + duplicatedPluginConfig.Profiles[0].PluginConfig = []config.PluginConfig{ + { + Name: "config", + }, + { + Name: "config", + }, + } + + mismatchQueueSort := validConfig.DeepCopy() + mismatchQueueSort.Profiles = []config.KubeSchedulerProfile{ + { + SchedulerName: "me", + Plugins: &config.Plugins{ + QueueSort: config.PluginSet{ + Enabled: []config.Plugin{{Name: "PrioritySort"}}, + }, + }, + PluginConfig: []config.PluginConfig{ + { + Name: "PrioritySort", + }, + }, + }, + { + SchedulerName: "other", + Plugins: &config.Plugins{ + QueueSort: config.PluginSet{ + Enabled: []config.Plugin{{Name: "CustomSort"}}, + }, + }, + PluginConfig: []config.PluginConfig{ + { + Name: "CustomSort", + }, + }, + }, + } + + extenderDuplicateManagedResource := validConfig.DeepCopy() + extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{ + {Name: "foo", IgnoredByScheduler: false}, + {Name: "foo", IgnoredByScheduler: false}, + } + + extenderDuplicateBind := validConfig.DeepCopy() + extenderDuplicateBind.Extenders[0].BindVerb = "foo" + extenderDuplicateBind.Extenders = append(extenderDuplicateBind.Extenders, config.Extender{ + PrioritizeVerb: "prioritize", + BindVerb: "bar", + Weight: 1, + }) + + validPlugins := validConfig.DeepCopy() + validPlugins.Profiles[0].Plugins.Score.Enabled = append(validPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "PodTopologySpread", Weight: 2}) + + invalidPlugins := validConfig.DeepCopy() + invalidPlugins.Profiles[0].Plugins.Score.Enabled = append(invalidPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "SelectorSpread"}) + + scenarios := map[string]struct { + expectedToFail bool + config *config.KubeSchedulerConfiguration + errorString string + }{ + "good": { + expectedToFail: false, + config: validConfig, + }, + "bad-parallelism-invalid-value": { + expectedToFail: true, + config: invalidParallelismValue, + errorString: "should be an integer value greater than zero", + }, + "bad-resource-name-not-set": { + expectedToFail: true, + config: resourceNameNotSet, + errorString: "resourceName is required", + }, + "bad-resource-namespace-not-set": { + expectedToFail: true, + config: resourceNamespaceNotSet, + errorString: "resourceNamespace is required", + }, + "non-empty-metrics-bind-addr": { + expectedToFail: true, + config: metricsBindAddrInvalid, + errorString: "must be empty or with an explicit 0 port", + }, + "non-empty-healthz-bind-addr": { + expectedToFail: true, + config: healthzBindAddrInvalid, + errorString: "must be empty or with an explicit 0 port", + }, + "bad-percentage-of-nodes-to-score": { + expectedToFail: true, + config: percentageOfNodesToScore101, + errorString: "not in valid range [0-100]", + }, + "scheduler-name-not-set": { + expectedToFail: true, + config: schedulerNameNotSet, + errorString: "Required value", + }, + "repeated-scheduler-name": { + expectedToFail: true, + config: repeatedSchedulerName, + errorString: "Duplicate value", + }, + "different-queue-sort": { + expectedToFail: true, + config: differentQueueSort, + errorString: "has to match for all profiles", + }, + "one-empty-queue-sort": { + expectedToFail: true, + config: oneEmptyQueueSort, + errorString: "has to match for all profiles", + }, + "extender-negative-weight": { + expectedToFail: true, + config: extenderNegativeWeight, + errorString: "must have a positive weight applied to it", + }, + "extender-duplicate-managed-resources": { + expectedToFail: true, + config: extenderDuplicateManagedResource, + errorString: "duplicate extender managed resource name", + }, + "extender-duplicate-bind": { + expectedToFail: true, + config: extenderDuplicateBind, + errorString: "only one extender can implement bind", + }, + "invalid-node-percentage": { + expectedToFail: true, + config: invalidNodePercentage, + errorString: "not in valid range [0, 100]", + }, + "invalid-plugin-args": { + expectedToFail: true, + config: invalidPluginArgs, + errorString: "has to match plugin args", + }, + "duplicated-plugin-config": { + expectedToFail: true, + config: duplicatedPluginConfig, + errorString: "Duplicate value: \"config\"", + }, + "mismatch-queue-sort": { + expectedToFail: true, + config: mismatchQueueSort, + errorString: "has to match for all profiles", + }, + "valid-plugins": { + expectedToFail: false, + config: validPlugins, + }, + "invalid-plugins": { + expectedToFail: true, + config: invalidPlugins, + errorString: "\"SelectorSpread\": was invalid", + }, + } + + for name, scenario := range scenarios { + t.Run(name, func(t *testing.T) { + errs := ValidateKubeSchedulerConfiguration(scenario.config) + if errs == nil && scenario.expectedToFail { + t.Error("Unexpected success") + } + if errs != nil && !scenario.expectedToFail { + t.Errorf("Unexpected failure: %+v", errs) + } + + if errs != nil && scenario.errorString != "" && !strings.Contains(errs.Error(), scenario.errorString) { t.Errorf("Unexpected error string\n want:\t%s\n got:\t%s", scenario.errorString, errs.Error()) } }) diff --git a/pkg/scheduler/scheduler.go b/pkg/scheduler/scheduler.go index 61ab633330a..060dcc31ba0 100644 --- a/pkg/scheduler/scheduler.go +++ b/pkg/scheduler/scheduler.go @@ -33,7 +33,7 @@ import ( restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" "k8s.io/klog/v2" - "k8s.io/kube-scheduler/config/v1beta3" + configv1 "k8s.io/kube-scheduler/config/v1" schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config" "k8s.io/kubernetes/pkg/scheduler/apis/config/scheme" "k8s.io/kubernetes/pkg/scheduler/framework" @@ -131,7 +131,7 @@ type ScheduleResult struct { // WithComponentConfigVersion sets the component config version to the // KubeSchedulerConfiguration version used. The string should be the full // scheme group/version of the external type we converted from (for example -// "kubescheduler.config.k8s.io/v1beta2") +// "kubescheduler.config.k8s.io/v1") func WithComponentConfigVersion(apiVersion string) Option { return func(o *schedulerOptions) { o.componentConfigVersion = apiVersion @@ -246,7 +246,7 @@ func New(client clientset.Interface, } if options.applyDefaultProfile { - var versionedCfg v1beta3.KubeSchedulerConfiguration + var versionedCfg configv1.KubeSchedulerConfiguration scheme.Scheme.Default(&versionedCfg) cfg := schedulerapi.KubeSchedulerConfiguration{} if err := scheme.Scheme.Convert(&versionedCfg, &cfg, nil); err != nil { diff --git a/staging/src/k8s.io/kube-scheduler/config/v1/doc.go b/staging/src/k8s.io/kube-scheduler/config/v1/doc.go new file mode 100644 index 00000000000..bbc4641e72c --- /dev/null +++ b/staging/src/k8s.io/kube-scheduler/config/v1/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2022 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:openapi-gen=true +// +groupName=kubescheduler.config.k8s.io + +package v1 // import "k8s.io/kube-scheduler/config/v1" diff --git a/staging/src/k8s.io/kube-scheduler/config/v1/register.go b/staging/src/k8s.io/kube-scheduler/config/v1/register.go new file mode 100644 index 00000000000..58adac5dceb --- /dev/null +++ b/staging/src/k8s.io/kube-scheduler/config/v1/register.go @@ -0,0 +1,50 @@ +/* +Copyright 2022 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 v1 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name used in this package +const GroupName = "kubescheduler.config.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} + +var ( + // SchemeBuilder is the scheme builder with scheme init functions to run for this API package + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme is a global function that registers this API group & version to a scheme + AddToScheme = SchemeBuilder.AddToScheme +) + +// addKnownTypes registers known types to the given scheme +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &KubeSchedulerConfiguration{}, + &DefaultPreemptionArgs{}, + &InterPodAffinityArgs{}, + &NodeResourcesBalancedAllocationArgs{}, + &NodeResourcesFitArgs{}, + &PodTopologySpreadArgs{}, + &VolumeBindingArgs{}, + &NodeAffinityArgs{}, + ) + return nil +} diff --git a/staging/src/k8s.io/kube-scheduler/config/v1/types.go b/staging/src/k8s.io/kube-scheduler/config/v1/types.go new file mode 100644 index 00000000000..4e104600a41 --- /dev/null +++ b/staging/src/k8s.io/kube-scheduler/config/v1/types.go @@ -0,0 +1,377 @@ +/* +Copyright 2022 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 v1 + +import ( + "bytes" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + componentbaseconfigv1alpha1 "k8s.io/component-base/config/v1alpha1" + "sigs.k8s.io/yaml" +) + +const ( + // SchedulerDefaultLockObjectNamespace defines default scheduler lock object namespace ("kube-system") + SchedulerDefaultLockObjectNamespace string = metav1.NamespaceSystem + + // SchedulerDefaultLockObjectName defines default scheduler lock object name ("kube-scheduler") + SchedulerDefaultLockObjectName = "kube-scheduler" + + // SchedulerDefaultProviderName defines the default provider names + SchedulerDefaultProviderName = "DefaultProvider" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// KubeSchedulerConfiguration configures a scheduler +type KubeSchedulerConfiguration struct { + metav1.TypeMeta `json:",inline"` + + // Parallelism defines the amount of parallelism in algorithms for scheduling a Pods. Must be greater than 0. Defaults to 16 + Parallelism *int32 `json:"parallelism,omitempty"` + + // LeaderElection defines the configuration of leader election client. + LeaderElection componentbaseconfigv1alpha1.LeaderElectionConfiguration `json:"leaderElection"` + + // ClientConnection specifies the kubeconfig file and client connection + // settings for the proxy server to use when communicating with the apiserver. + ClientConnection componentbaseconfigv1alpha1.ClientConnectionConfiguration `json:"clientConnection"` + + // DebuggingConfiguration holds configuration for Debugging related features + // TODO: We might wanna make this a substruct like Debugging componentbaseconfigv1alpha1.DebuggingConfiguration + componentbaseconfigv1alpha1.DebuggingConfiguration `json:",inline"` + + // PercentageOfNodesToScore is the percentage of all nodes that once found feasible + // for running a pod, the scheduler stops its search for more feasible nodes in + // the cluster. This helps improve scheduler's performance. Scheduler always tries to find + // at least "minFeasibleNodesToFind" feasible nodes no matter what the value of this flag is. + // Example: if the cluster size is 500 nodes and the value of this flag is 30, + // then scheduler stops finding further feasible nodes once it finds 150 feasible ones. + // When the value is 0, default percentage (5%--50% based on the size of the cluster) of the + // nodes will be scored. + PercentageOfNodesToScore *int32 `json:"percentageOfNodesToScore,omitempty"` + + // PodInitialBackoffSeconds is the initial backoff for unschedulable pods. + // If specified, it must be greater than 0. If this value is null, the default value (1s) + // will be used. + PodInitialBackoffSeconds *int64 `json:"podInitialBackoffSeconds,omitempty"` + + // PodMaxBackoffSeconds is the max backoff for unschedulable pods. + // If specified, it must be greater than podInitialBackoffSeconds. If this value is null, + // the default value (10s) will be used. + PodMaxBackoffSeconds *int64 `json:"podMaxBackoffSeconds,omitempty"` + + // 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,omitempty"` + + // Extenders are the list of scheduler extenders, each holding the values of how to communicate + // with the extender. These extenders are shared by all scheduler profiles. + // +listType=set + Extenders []Extender `json:"extenders,omitempty"` +} + +// DecodeNestedObjects decodes plugin args for known types. +func (c *KubeSchedulerConfiguration) DecodeNestedObjects(d runtime.Decoder) error { + var strictDecodingErrs []error + for i := range c.Profiles { + prof := &c.Profiles[i] + for j := range prof.PluginConfig { + err := prof.PluginConfig[j].decodeNestedObjects(d) + if err != nil { + decodingErr := fmt.Errorf("decoding .profiles[%d].pluginConfig[%d]: %w", i, j, err) + if runtime.IsStrictDecodingError(err) { + strictDecodingErrs = append(strictDecodingErrs, decodingErr) + } else { + return decodingErr + } + } + } + } + if len(strictDecodingErrs) > 0 { + return runtime.NewStrictDecodingError(strictDecodingErrs) + } + return nil +} + +// EncodeNestedObjects encodes plugin args. +func (c *KubeSchedulerConfiguration) EncodeNestedObjects(e runtime.Encoder) error { + for i := range c.Profiles { + prof := &c.Profiles[i] + for j := range prof.PluginConfig { + err := prof.PluginConfig[j].encodeNestedObjects(e) + if err != nil { + return fmt.Errorf("encoding .profiles[%d].pluginConfig[%d]: %w", i, j, err) + } + } + } + return nil +} + +// 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. + // +listType=map + // +listMapKey=name + PluginConfig []PluginConfig `json:"pluginConfig,omitempty"` +} + +// Plugins include multiple extension points. When specified, the list of plugins for +// a particular extension point are the only ones enabled. If an extension point is +// omitted from the config, then the default set of plugins is used for that extension point. +// Enabled plugins are called in the order specified here, after default plugins. If they need to +// be invoked before default plugins, default plugins must be disabled and re-enabled here in desired order. +type Plugins struct { + // QueueSort is a list of plugins that should be invoked when sorting pods in the scheduling queue. + QueueSort PluginSet `json:"queueSort,omitempty"` + + // PreFilter is a list of plugins that should be invoked at "PreFilter" extension point of the scheduling framework. + PreFilter PluginSet `json:"preFilter,omitempty"` + + // Filter is a list of plugins that should be invoked when filtering out nodes that cannot run the Pod. + Filter PluginSet `json:"filter,omitempty"` + + // PostFilter is a list of plugins that are invoked after filtering phase, but only when no feasible nodes were found for the pod. + PostFilter PluginSet `json:"postFilter,omitempty"` + + // PreScore is a list of plugins that are invoked before scoring. + PreScore PluginSet `json:"preScore,omitempty"` + + // Score is a list of plugins that should be invoked when ranking nodes that have passed the filtering phase. + Score PluginSet `json:"score,omitempty"` + + // Reserve is a list of plugins invoked when reserving/unreserving resources + // after a node is assigned to run the pod. + Reserve PluginSet `json:"reserve,omitempty"` + + // Permit is a list of plugins that control binding of a Pod. These plugins can prevent or delay binding of a Pod. + Permit PluginSet `json:"permit,omitempty"` + + // PreBind is a list of plugins that should be invoked before a pod is bound. + PreBind PluginSet `json:"preBind,omitempty"` + + // Bind is a list of plugins that should be invoked at "Bind" extension point of the scheduling framework. + // The scheduler call these plugins in order. Scheduler skips the rest of these plugins as soon as one returns success. + Bind PluginSet `json:"bind,omitempty"` + + // PostBind is a list of plugins that should be invoked after a pod is successfully bound. + PostBind PluginSet `json:"postBind,omitempty"` + + // MultiPoint is a simplified config section to enable plugins for all valid extension points. + // Plugins enabled through MultiPoint will automatically register for every individual extension + // point the plugin has implemented. Disabling a plugin through MultiPoint disables that behavior. + // The same is true for disabling "*" through MultiPoint (no default plugins will be automatically registered). + // Plugins can still be disabled through their individual extension points. + // + // In terms of precedence, plugin config follows this basic hierarchy + // 1. Specific extension points + // 2. Explicitly configured MultiPoint plugins + // 3. The set of default plugins, as MultiPoint plugins + // This implies that a higher precedence plugin will run first and overwrite any settings within MultiPoint. + // Explicitly user-configured plugins also take a higher precedence over default plugins. + // Within this hierarchy, an Enabled setting takes precedence over Disabled. For example, if a plugin is + // set in both `multiPoint.Enabled` and `multiPoint.Disabled`, the plugin will be enabled. Similarly, + // including `multiPoint.Disabled = '*'` and `multiPoint.Enabled = pluginA` will still register that specific + // plugin through MultiPoint. This follows the same behavior as all other extension point configurations. + MultiPoint PluginSet `json:"multiPoint,omitempty"` +} + +// PluginSet specifies enabled and disabled plugins for an extension point. +// If an array is empty, missing, or nil, default plugins at that extension point will be used. +type PluginSet struct { + // Enabled specifies plugins that should be enabled in addition to default plugins. + // If the default plugin is also configured in the scheduler config file, the weight of plugin will + // be overridden accordingly. + // These are called after default plugins and in the same order specified here. + // +listType=atomic + Enabled []Plugin `json:"enabled,omitempty"` + // Disabled specifies default plugins that should be disabled. + // When all default plugins need to be disabled, an array containing only one "*" should be provided. + // +listType=map + // +listMapKey=name + Disabled []Plugin `json:"disabled,omitempty"` +} + +// Plugin specifies a plugin name and its weight when applicable. Weight is used only for Score plugins. +type Plugin struct { + // Name defines the name of plugin + Name string `json:"name"` + // Weight defines the weight of plugin, only used for Score plugins. + Weight *int32 `json:"weight,omitempty"` +} + +// PluginConfig specifies arguments that should be passed to a plugin at the time of initialization. +// A plugin that is invoked at multiple extension points is initialized once. Args can have arbitrary structure. +// It is up to the plugin to process these Args. +type PluginConfig struct { + // Name defines the name of plugin being configured + Name string `json:"name"` + // Args defines the arguments passed to the plugins at the time of initialization. Args can have arbitrary structure. + Args runtime.RawExtension `json:"args,omitempty"` +} + +func (c *PluginConfig) decodeNestedObjects(d runtime.Decoder) error { + gvk := SchemeGroupVersion.WithKind(c.Name + "Args") + // dry-run to detect and skip out-of-tree plugin args. + if _, _, err := d.Decode(nil, &gvk, nil); runtime.IsNotRegisteredError(err) { + return nil + } + + var strictDecodingErr error + obj, parsedGvk, err := d.Decode(c.Args.Raw, &gvk, nil) + if err != nil { + decodingArgsErr := fmt.Errorf("decoding args for plugin %s: %w", c.Name, err) + if obj != nil && runtime.IsStrictDecodingError(err) { + strictDecodingErr = runtime.NewStrictDecodingError([]error{decodingArgsErr}) + } else { + return decodingArgsErr + } + } + if parsedGvk.GroupKind() != gvk.GroupKind() { + return fmt.Errorf("args for plugin %s were not of type %s, got %s", c.Name, gvk.GroupKind(), parsedGvk.GroupKind()) + } + c.Args.Object = obj + return strictDecodingErr +} + +func (c *PluginConfig) encodeNestedObjects(e runtime.Encoder) error { + if c.Args.Object == nil { + return nil + } + var buf bytes.Buffer + err := e.Encode(c.Args.Object, &buf) + if err != nil { + return err + } + // The encoder might be a YAML encoder, but the parent encoder expects + // JSON output, so we convert YAML back to JSON. + // This is a no-op if produces JSON. + json, err := yaml.YAMLToJSON(buf.Bytes()) + if err != nil { + return err + } + c.Args.Raw = json + return nil +} + +// Extender holds the parameters used to communicate with the extender. If a verb is unspecified/empty, +// it is assumed that the extender chose not to provide that extension. +type Extender struct { + // URLPrefix at which the extender is available + URLPrefix string `json:"urlPrefix"` + // Verb for the filter call, empty if not supported. This verb is appended to the URLPrefix when issuing the filter call to extender. + FilterVerb string `json:"filterVerb,omitempty"` + // Verb for the preempt call, empty if not supported. This verb is appended to the URLPrefix when issuing the preempt call to extender. + PreemptVerb string `json:"preemptVerb,omitempty"` + // Verb for the prioritize call, empty if not supported. This verb is appended to the URLPrefix when issuing the prioritize call to extender. + PrioritizeVerb string `json:"prioritizeVerb,omitempty"` + // The numeric multiplier for the node scores that the prioritize call generates. + // The weight should be a positive integer + Weight int64 `json:"weight,omitempty"` + // Verb for the bind call, empty if not supported. This verb is appended to the URLPrefix when issuing the bind call to extender. + // If this method is implemented by the extender, it is the extender's responsibility to bind the pod to apiserver. Only one extender + // can implement this function. + BindVerb string `json:"bindVerb,omitempty"` + // EnableHTTPS specifies whether https should be used to communicate with the extender + EnableHTTPS bool `json:"enableHTTPS,omitempty"` + // TLSConfig specifies the transport layer security config + TLSConfig *ExtenderTLSConfig `json:"tlsConfig,omitempty"` + // HTTPTimeout specifies the timeout duration for a call to the extender. Filter timeout fails the scheduling of the pod. Prioritize + // timeout is ignored, k8s/other extenders priorities are used to select the node. + HTTPTimeout metav1.Duration `json:"httpTimeout,omitempty"` + // NodeCacheCapable specifies that the extender is capable of caching node information, + // so the scheduler should only send minimal information about the eligible nodes + // assuming that the extender already cached full details of all nodes in the cluster + NodeCacheCapable bool `json:"nodeCacheCapable,omitempty"` + // ManagedResources is a list of extended resources that are managed by + // this extender. + // - A pod will be sent to the extender on the Filter, Prioritize and Bind + // (if the extender is the binder) phases iff the pod requests at least + // one of the extended resources in this list. If empty or unspecified, + // all pods will be sent to this extender. + // - If IgnoredByScheduler is set to true for a resource, kube-scheduler + // will skip checking the resource in predicates. + // +optional + // +listType=atomic + ManagedResources []ExtenderManagedResource `json:"managedResources,omitempty"` + // Ignorable specifies if the extender is ignorable, i.e. scheduling should not + // fail when the extender returns an error or is not reachable. + Ignorable bool `json:"ignorable,omitempty"` +} + +// ExtenderManagedResource describes the arguments of extended resources +// managed by an extender. +type ExtenderManagedResource struct { + // Name is the extended resource name. + Name string `json:"name"` + // IgnoredByScheduler indicates whether kube-scheduler should ignore this + // resource when applying predicates. + IgnoredByScheduler bool `json:"ignoredByScheduler,omitempty"` +} + +// ExtenderTLSConfig contains settings to enable TLS with extender +type ExtenderTLSConfig struct { + // Server should be accessed without verifying the TLS certificate. For testing only. + Insecure bool `json:"insecure,omitempty"` + // ServerName is passed to the server for SNI and is used in the client to check server + // certificates against. If ServerName is empty, the hostname used to contact the + // server is used. + ServerName string `json:"serverName,omitempty"` + + // Server requires TLS client certificate authentication + CertFile string `json:"certFile,omitempty"` + // Server requires TLS client certificate authentication + KeyFile string `json:"keyFile,omitempty"` + // Trusted root certificates for server + CAFile string `json:"caFile,omitempty"` + + // CertData holds PEM-encoded bytes (typically read from a client certificate file). + // CertData takes precedence over CertFile + // +listType=atomic + CertData []byte `json:"certData,omitempty"` + // KeyData holds PEM-encoded bytes (typically read from a client certificate key file). + // KeyData takes precedence over KeyFile + // +listType=atomic + KeyData []byte `json:"keyData,omitempty"` + // CAData holds PEM-encoded bytes (typically read from a root certificates bundle). + // CAData takes precedence over CAFile + // +listType=atomic + CAData []byte `json:"caData,omitempty"` +} diff --git a/staging/src/k8s.io/kube-scheduler/config/v1/types_pluginargs.go b/staging/src/k8s.io/kube-scheduler/config/v1/types_pluginargs.go new file mode 100644 index 00000000000..2698a47696f --- /dev/null +++ b/staging/src/k8s.io/kube-scheduler/config/v1/types_pluginargs.go @@ -0,0 +1,225 @@ +/* +Copyright 2022 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 v1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// DefaultPreemptionArgs holds arguments used to configure the +// DefaultPreemption plugin. +type DefaultPreemptionArgs struct { + metav1.TypeMeta `json:",inline"` + + // MinCandidateNodesPercentage is the minimum number of candidates to + // shortlist when dry running preemption as a percentage of number of nodes. + // Must be in the range [0, 100]. Defaults to 10% of the cluster size if + // unspecified. + MinCandidateNodesPercentage *int32 `json:"minCandidateNodesPercentage,omitempty"` + // MinCandidateNodesAbsolute is the absolute minimum number of candidates to + // shortlist. The likely number of candidates enumerated for dry running + // preemption is given by the formula: + // numCandidates = max(numNodes * minCandidateNodesPercentage, minCandidateNodesAbsolute) + // We say "likely" because there are other factors such as PDB violations + // that play a role in the number of candidates shortlisted. Must be at least + // 0 nodes. Defaults to 100 nodes if unspecified. + MinCandidateNodesAbsolute *int32 `json:"minCandidateNodesAbsolute,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// InterPodAffinityArgs holds arguments used to configure the InterPodAffinity plugin. +type InterPodAffinityArgs struct { + metav1.TypeMeta `json:",inline"` + + // HardPodAffinityWeight is the scoring weight for existing pods with a + // matching hard affinity to the incoming pod. + HardPodAffinityWeight *int32 `json:"hardPodAffinityWeight,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeResourcesFitArgs holds arguments used to configure the NodeResourcesFit plugin. +type NodeResourcesFitArgs struct { + metav1.TypeMeta `json:",inline"` + + // IgnoredResources is the list of resources that NodeResources fit filter + // should ignore. This doesn't apply to scoring. + // +listType=atomic + IgnoredResources []string `json:"ignoredResources,omitempty"` + // IgnoredResourceGroups defines the list of resource groups that NodeResources fit filter should ignore. + // e.g. if group is ["example.com"], it will ignore all resource names that begin + // with "example.com", such as "example.com/aaa" and "example.com/bbb". + // A resource group name can't contain '/'. This doesn't apply to scoring. + // +listType=atomic + IgnoredResourceGroups []string `json:"ignoredResourceGroups,omitempty"` + + // ScoringStrategy selects the node resource scoring strategy. + // The default strategy is LeastAllocated with an equal "cpu" and "memory" weight. + ScoringStrategy *ScoringStrategy `json:"scoringStrategy,omitempty"` +} + +// PodTopologySpreadConstraintsDefaulting defines how to set default constraints +// for the PodTopologySpread plugin. +type PodTopologySpreadConstraintsDefaulting string + +const ( + // SystemDefaulting instructs to use the kubernetes defined default. + SystemDefaulting PodTopologySpreadConstraintsDefaulting = "System" + // ListDefaulting instructs to use the config provided default. + ListDefaulting PodTopologySpreadConstraintsDefaulting = "List" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// PodTopologySpreadArgs holds arguments used to configure the PodTopologySpread plugin. +type PodTopologySpreadArgs struct { + metav1.TypeMeta `json:",inline"` + + // DefaultConstraints defines topology spread constraints to be applied to + // Pods that don't define any in `pod.spec.topologySpreadConstraints`. + // `.defaultConstraints[*].labelSelectors` must be empty, as they are + // deduced from the Pod's membership to Services, ReplicationControllers, + // ReplicaSets or StatefulSets. + // When not empty, .defaultingType must be "List". + // +optional + // +listType=atomic + DefaultConstraints []corev1.TopologySpreadConstraint `json:"defaultConstraints,omitempty"` + + // DefaultingType determines how .defaultConstraints are deduced. Can be one + // of "System" or "List". + // + // - "System": Use kubernetes defined constraints that spread Pods among + // Nodes and Zones. + // - "List": Use constraints defined in .defaultConstraints. + // + // Defaults to "System". + // +optional + DefaultingType PodTopologySpreadConstraintsDefaulting `json:"defaultingType,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeResourcesBalancedAllocationArgs holds arguments used to configure NodeResourcesBalancedAllocation plugin. +type NodeResourcesBalancedAllocationArgs struct { + metav1.TypeMeta `json:",inline"` + + // Resources to be managed, the default is "cpu" and "memory" if not specified. + // +listType=map + // +listMapKey=name + Resources []ResourceSpec `json:"resources,omitempty"` +} + +// UtilizationShapePoint represents single point of priority function shape. +type UtilizationShapePoint struct { + // Utilization (x axis). Valid values are 0 to 100. Fully utilized node maps to 100. + Utilization int32 `json:"utilization"` + // Score assigned to given utilization (y axis). Valid values are 0 to 10. + Score int32 `json:"score"` +} + +// ResourceSpec represents a single resource. +type ResourceSpec struct { + // Name of the resource. + Name string `json:"name"` + // Weight of the resource. + Weight int64 `json:"weight,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VolumeBindingArgs holds arguments used to configure the VolumeBinding plugin. +type VolumeBindingArgs struct { + metav1.TypeMeta `json:",inline"` + + // BindTimeoutSeconds is the timeout in seconds in volume binding operation. + // Value must be non-negative integer. The value zero indicates no waiting. + // If this value is nil, the default value (600) will be used. + BindTimeoutSeconds *int64 `json:"bindTimeoutSeconds,omitempty"` + + // Shape specifies the points defining the score function shape, which is + // used to score nodes based on the utilization of statically provisioned + // PVs. The utilization is calculated by dividing the total requested + // storage of the pod by the total capacity of feasible PVs on each node. + // Each point contains utilization (ranges from 0 to 100) and its + // associated score (ranges from 0 to 10). You can turn the priority by + // specifying different scores for different utilization numbers. + // The default shape points are: + // 1) 0 for 0 utilization + // 2) 10 for 100 utilization + // All points must be sorted in increasing order by utilization. + // +featureGate=VolumeCapacityPriority + // +optional + // +listType=atomic + Shape []UtilizationShapePoint `json:"shape,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// NodeAffinityArgs holds arguments to configure the NodeAffinity plugin. +type NodeAffinityArgs struct { + metav1.TypeMeta `json:",inline"` + + // AddedAffinity is applied to all Pods additionally to the NodeAffinity + // specified in the PodSpec. That is, Nodes need to satisfy AddedAffinity + // AND .spec.NodeAffinity. AddedAffinity is empty by default (all Nodes + // match). + // When AddedAffinity is used, some Pods with affinity requirements that match + // a specific Node (such as Daemonset Pods) might remain unschedulable. + // +optional + AddedAffinity *corev1.NodeAffinity `json:"addedAffinity,omitempty"` +} + +// ScoringStrategyType the type of scoring strategy used in NodeResourcesFit plugin. +type ScoringStrategyType string + +const ( + // LeastAllocated strategy prioritizes nodes with least allocated resources. + LeastAllocated ScoringStrategyType = "LeastAllocated" + // MostAllocated strategy prioritizes nodes with most allocated resources. + MostAllocated ScoringStrategyType = "MostAllocated" + // RequestedToCapacityRatio strategy allows specifying a custom shape function + // to score nodes based on the request to capacity ratio. + RequestedToCapacityRatio ScoringStrategyType = "RequestedToCapacityRatio" +) + +// ScoringStrategy define ScoringStrategyType for node resource plugin +type ScoringStrategy struct { + // Type selects which strategy to run. + Type ScoringStrategyType `json:"type,omitempty"` + + // Resources to consider when scoring. + // The default resource set includes "cpu" and "memory" with an equal weight. + // Allowed weights go from 1 to 100. + // Weight defaults to 1 if not specified or explicitly set to 0. + // +listType=map + // +listMapKey=topologyKey + Resources []ResourceSpec `json:"resources,omitempty"` + + // Arguments specific to RequestedToCapacityRatio strategy. + RequestedToCapacityRatio *RequestedToCapacityRatioParam `json:"requestedToCapacityRatio,omitempty"` +} + +// RequestedToCapacityRatioParam define RequestedToCapacityRatio parameters +type RequestedToCapacityRatioParam struct { + // Shape is a list of points defining the scoring function shape. + // +listType=atomic + Shape []UtilizationShapePoint `json:"shape,omitempty"` +} diff --git a/staging/src/k8s.io/kube-scheduler/config/v1/zz_generated.deepcopy.go b/staging/src/k8s.io/kube-scheduler/config/v1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..0b5f11edc1e --- /dev/null +++ b/staging/src/k8s.io/kube-scheduler/config/v1/zz_generated.deepcopy.go @@ -0,0 +1,603 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DefaultPreemptionArgs) DeepCopyInto(out *DefaultPreemptionArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.MinCandidateNodesPercentage != nil { + in, out := &in.MinCandidateNodesPercentage, &out.MinCandidateNodesPercentage + *out = new(int32) + **out = **in + } + if in.MinCandidateNodesAbsolute != nil { + in, out := &in.MinCandidateNodesAbsolute, &out.MinCandidateNodesAbsolute + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefaultPreemptionArgs. +func (in *DefaultPreemptionArgs) DeepCopy() *DefaultPreemptionArgs { + if in == nil { + return nil + } + out := new(DefaultPreemptionArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DefaultPreemptionArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Extender) DeepCopyInto(out *Extender) { + *out = *in + if in.TLSConfig != nil { + in, out := &in.TLSConfig, &out.TLSConfig + *out = new(ExtenderTLSConfig) + (*in).DeepCopyInto(*out) + } + out.HTTPTimeout = in.HTTPTimeout + if in.ManagedResources != nil { + in, out := &in.ManagedResources, &out.ManagedResources + *out = make([]ExtenderManagedResource, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Extender. +func (in *Extender) DeepCopy() *Extender { + if in == nil { + return nil + } + out := new(Extender) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderManagedResource) DeepCopyInto(out *ExtenderManagedResource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderManagedResource. +func (in *ExtenderManagedResource) DeepCopy() *ExtenderManagedResource { + if in == nil { + return nil + } + out := new(ExtenderManagedResource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtenderTLSConfig) DeepCopyInto(out *ExtenderTLSConfig) { + *out = *in + if in.CertData != nil { + in, out := &in.CertData, &out.CertData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.KeyData != nil { + in, out := &in.KeyData, &out.KeyData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.CAData != nil { + in, out := &in.CAData, &out.CAData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtenderTLSConfig. +func (in *ExtenderTLSConfig) DeepCopy() *ExtenderTLSConfig { + if in == nil { + return nil + } + out := new(ExtenderTLSConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InterPodAffinityArgs) DeepCopyInto(out *InterPodAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.HardPodAffinityWeight != nil { + in, out := &in.HardPodAffinityWeight, &out.HardPodAffinityWeight + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InterPodAffinityArgs. +func (in *InterPodAffinityArgs) DeepCopy() *InterPodAffinityArgs { + if in == nil { + return nil + } + out := new(InterPodAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InterPodAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KubeSchedulerConfiguration) DeepCopyInto(out *KubeSchedulerConfiguration) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Parallelism != nil { + in, out := &in.Parallelism, &out.Parallelism + *out = new(int32) + **out = **in + } + in.LeaderElection.DeepCopyInto(&out.LeaderElection) + out.ClientConnection = in.ClientConnection + in.DebuggingConfiguration.DeepCopyInto(&out.DebuggingConfiguration) + if in.PercentageOfNodesToScore != nil { + in, out := &in.PercentageOfNodesToScore, &out.PercentageOfNodesToScore + *out = new(int32) + **out = **in + } + if in.PodInitialBackoffSeconds != nil { + in, out := &in.PodInitialBackoffSeconds, &out.PodInitialBackoffSeconds + *out = new(int64) + **out = **in + } + if in.PodMaxBackoffSeconds != nil { + in, out := &in.PodMaxBackoffSeconds, &out.PodMaxBackoffSeconds + *out = new(int64) + **out = **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]) + } + } + if in.Extenders != nil { + in, out := &in.Extenders, &out.Extenders + *out = make([]Extender, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeSchedulerConfiguration. +func (in *KubeSchedulerConfiguration) DeepCopy() *KubeSchedulerConfiguration { + if in == nil { + return nil + } + out := new(KubeSchedulerConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *KubeSchedulerConfiguration) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// 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 *NodeAffinityArgs) DeepCopyInto(out *NodeAffinityArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.AddedAffinity != nil { + in, out := &in.AddedAffinity, &out.AddedAffinity + *out = new(corev1.NodeAffinity) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeAffinityArgs. +func (in *NodeAffinityArgs) DeepCopy() *NodeAffinityArgs { + if in == nil { + return nil + } + out := new(NodeAffinityArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeAffinityArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopyInto(out *NodeResourcesBalancedAllocationArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesBalancedAllocationArgs. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopy() *NodeResourcesBalancedAllocationArgs { + if in == nil { + return nil + } + out := new(NodeResourcesBalancedAllocationArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeResourcesBalancedAllocationArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeResourcesFitArgs) DeepCopyInto(out *NodeResourcesFitArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.IgnoredResources != nil { + in, out := &in.IgnoredResources, &out.IgnoredResources + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.IgnoredResourceGroups != nil { + in, out := &in.IgnoredResourceGroups, &out.IgnoredResourceGroups + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ScoringStrategy != nil { + in, out := &in.ScoringStrategy, &out.ScoringStrategy + *out = new(ScoringStrategy) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeResourcesFitArgs. +func (in *NodeResourcesFitArgs) DeepCopy() *NodeResourcesFitArgs { + if in == nil { + return nil + } + out := new(NodeResourcesFitArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NodeResourcesFitArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// 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 + if in.Weight != nil { + in, out := &in.Weight, &out.Weight + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugin. +func (in *Plugin) DeepCopy() *Plugin { + if in == nil { + return nil + } + out := new(Plugin) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginConfig) DeepCopyInto(out *PluginConfig) { + *out = *in + in.Args.DeepCopyInto(&out.Args) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConfig. +func (in *PluginConfig) DeepCopy() *PluginConfig { + if in == nil { + return nil + } + out := new(PluginConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginSet) DeepCopyInto(out *PluginSet) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = make([]Plugin, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Disabled != nil { + in, out := &in.Disabled, &out.Disabled + *out = make([]Plugin, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginSet. +func (in *PluginSet) DeepCopy() *PluginSet { + if in == nil { + return nil + } + out := new(PluginSet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Plugins) DeepCopyInto(out *Plugins) { + *out = *in + in.QueueSort.DeepCopyInto(&out.QueueSort) + in.PreFilter.DeepCopyInto(&out.PreFilter) + in.Filter.DeepCopyInto(&out.Filter) + in.PostFilter.DeepCopyInto(&out.PostFilter) + in.PreScore.DeepCopyInto(&out.PreScore) + in.Score.DeepCopyInto(&out.Score) + in.Reserve.DeepCopyInto(&out.Reserve) + in.Permit.DeepCopyInto(&out.Permit) + in.PreBind.DeepCopyInto(&out.PreBind) + in.Bind.DeepCopyInto(&out.Bind) + in.PostBind.DeepCopyInto(&out.PostBind) + in.MultiPoint.DeepCopyInto(&out.MultiPoint) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugins. +func (in *Plugins) DeepCopy() *Plugins { + if in == nil { + return nil + } + out := new(Plugins) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodTopologySpreadArgs) DeepCopyInto(out *PodTopologySpreadArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.DefaultConstraints != nil { + in, out := &in.DefaultConstraints, &out.DefaultConstraints + *out = make([]corev1.TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTopologySpreadArgs. +func (in *PodTopologySpreadArgs) DeepCopy() *PodTopologySpreadArgs { + if in == nil { + return nil + } + out := new(PodTopologySpreadArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodTopologySpreadArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RequestedToCapacityRatioParam) DeepCopyInto(out *RequestedToCapacityRatioParam) { + *out = *in + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RequestedToCapacityRatioParam. +func (in *RequestedToCapacityRatioParam) DeepCopy() *RequestedToCapacityRatioParam { + if in == nil { + return nil + } + out := new(RequestedToCapacityRatioParam) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceSpec) DeepCopyInto(out *ResourceSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSpec. +func (in *ResourceSpec) DeepCopy() *ResourceSpec { + if in == nil { + return nil + } + out := new(ResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScoringStrategy) DeepCopyInto(out *ScoringStrategy) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]ResourceSpec, len(*in)) + copy(*out, *in) + } + if in.RequestedToCapacityRatio != nil { + in, out := &in.RequestedToCapacityRatio, &out.RequestedToCapacityRatio + *out = new(RequestedToCapacityRatioParam) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScoringStrategy. +func (in *ScoringStrategy) DeepCopy() *ScoringStrategy { + if in == nil { + return nil + } + out := new(ScoringStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UtilizationShapePoint) DeepCopyInto(out *UtilizationShapePoint) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UtilizationShapePoint. +func (in *UtilizationShapePoint) DeepCopy() *UtilizationShapePoint { + if in == nil { + return nil + } + out := new(UtilizationShapePoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeBindingArgs) DeepCopyInto(out *VolumeBindingArgs) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.BindTimeoutSeconds != nil { + in, out := &in.BindTimeoutSeconds, &out.BindTimeoutSeconds + *out = new(int64) + **out = **in + } + if in.Shape != nil { + in, out := &in.Shape, &out.Shape + *out = make([]UtilizationShapePoint, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeBindingArgs. +func (in *VolumeBindingArgs) DeepCopy() *VolumeBindingArgs { + if in == nil { + return nil + } + out := new(VolumeBindingArgs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VolumeBindingArgs) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/test/integration/scheduler/plugins/plugins_test.go b/test/integration/scheduler/plugins/plugins_test.go index 57c49135d2f..4e7b544c1f6 100644 --- a/test/integration/scheduler/plugins/plugins_test.go +++ b/test/integration/scheduler/plugins/plugins_test.go @@ -33,7 +33,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" clientset "k8s.io/client-go/kubernetes" listersv1 "k8s.io/client-go/listers/core/v1" - "k8s.io/kube-scheduler/config/v1beta3" + configv1 "k8s.io/kube-scheduler/config/v1" "k8s.io/kubernetes/pkg/scheduler" schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config" configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing" @@ -674,32 +674,32 @@ func TestPostFilterPlugin(t *testing.T) { } // Setup plugins for testing. - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{{ SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), - Plugins: &v1beta3.Plugins{ - Filter: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + Plugins: &configv1.Plugins{ + Filter: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: filterPluginName}, }, }, - Score: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + Score: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: scorePluginName}, }, // disable default in-tree Score plugins // to make it easy to control configured ScorePlugins failure - Disabled: []v1beta3.Plugin{ + Disabled: []configv1.Plugin{ {Name: "*"}, }, }, - PostFilter: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + PostFilter: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: postfilterPluginName}, }, // Need to disable default in-tree PostFilter plugins, as they will // call RunFilterPlugins and hence impact the "numFilterCalled". - Disabled: []v1beta3.Plugin{ + Disabled: []configv1.Plugin{ {Name: "*"}, }, }, @@ -919,13 +919,13 @@ func TestPrebindPlugin(t *testing.T) { // Setup initial prebind and filter plugin in different profiles. // The second profile ensures the embedded filter plugin is exclusively called, and hence // we can use its internal `numFilterCalled` to perform some precise checking logic. - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{ { SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), - Plugins: &v1beta3.Plugins{ - PreBind: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + Plugins: &configv1.Plugins{ + PreBind: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: preBindPluginName}, }, }, @@ -933,9 +933,9 @@ func TestPrebindPlugin(t *testing.T) { }, { SchedulerName: pointer.StringPtr("2nd-scheduler"), - Plugins: &v1beta3.Plugins{ - Filter: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + Plugins: &configv1.Plugins{ + Filter: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: filterPluginName}, }, }, @@ -1464,25 +1464,25 @@ func TestBindPlugin(t *testing.T) { } // Setup initial unreserve and bind plugins for testing. - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{{ SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), - Plugins: &v1beta3.Plugins{ - MultiPoint: v1beta3.PluginSet{ - Disabled: []v1beta3.Plugin{ + Plugins: &configv1.Plugins{ + MultiPoint: configv1.PluginSet{ + Disabled: []configv1.Plugin{ {Name: defaultbinder.Name}, }, }, - Reserve: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{{Name: reservePlugin.Name()}}, + Reserve: configv1.PluginSet{ + Enabled: []configv1.Plugin{{Name: reservePlugin.Name()}}, }, - Bind: v1beta3.PluginSet{ + Bind: configv1.PluginSet{ // Put DefaultBinder last. - Enabled: []v1beta3.Plugin{{Name: bindPlugin1.Name()}, {Name: bindPlugin2.Name()}, {Name: defaultbinder.Name}}, - Disabled: []v1beta3.Plugin{{Name: defaultbinder.Name}}, + Enabled: []configv1.Plugin{{Name: bindPlugin1.Name()}, {Name: bindPlugin2.Name()}, {Name: defaultbinder.Name}}, + Disabled: []configv1.Plugin{{Name: defaultbinder.Name}}, }, - PostBind: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{{Name: postBindPlugin.Name()}}, + PostBind: configv1.PluginSet{ + Enabled: []configv1.Plugin{{Name: postBindPlugin.Name()}}, }, }, }}, @@ -2105,24 +2105,24 @@ func TestPreemptWithPermitPlugin(t *testing.T) { } // Setup initial permit and filter plugins in the profile. - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{ { SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), - Plugins: &v1beta3.Plugins{ - Permit: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + Plugins: &configv1.Plugins{ + Permit: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: permitPluginName}, }, }, - Filter: v1beta3.PluginSet{ + Filter: configv1.PluginSet{ // Ensure the fake filter plugin is always called; otherwise noderesources // would fail first and exit the Filter phase. - Enabled: []v1beta3.Plugin{ + Enabled: []configv1.Plugin{ {Name: filterPluginName}, {Name: noderesources.Name}, }, - Disabled: []v1beta3.Plugin{ + Disabled: []configv1.Plugin{ {Name: noderesources.Name}, }, }, @@ -2354,17 +2354,17 @@ func TestActivatePods(t *testing.T) { }} // Setup initial filter plugin for testing. - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{{ SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), - Plugins: &v1beta3.Plugins{ - PreFilter: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + Plugins: &configv1.Plugins{ + PreFilter: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: jobPluginName}, }, }, - PostBind: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + PostBind: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: jobPluginName}, }, }, @@ -2440,11 +2440,11 @@ func initRegistryAndConfig(t *testing.T, plugins ...framework.Plugin) (framework } registry := frameworkruntime.Registry{} - pls := &v1beta3.Plugins{} + pls := &configv1.Plugins{} for _, p := range plugins { registry.Register(p.Name(), newPlugin(p)) - plugin := v1beta3.Plugin{Name: p.Name()} + plugin := configv1.Plugin{Name: p.Name()} switch p.(type) { case *PreFilterPlugin: @@ -2463,7 +2463,7 @@ func initRegistryAndConfig(t *testing.T, plugins ...framework.Plugin) (framework pls.Bind.Enabled = append(pls.Bind.Enabled, plugin) // It's intentional to disable the DefaultBind plugin. Otherwise, DefaultBinder's failure would fail // a pod's scheduling, as well as the test BindPlugin's execution. - pls.Bind.Disabled = []v1beta3.Plugin{{Name: defaultbinder.Name}} + pls.Bind.Disabled = []configv1.Plugin{{Name: defaultbinder.Name}} case *PostBindPlugin: pls.PostBind.Enabled = append(pls.PostBind.Enabled, plugin) case *PermitPlugin: @@ -2471,12 +2471,12 @@ func initRegistryAndConfig(t *testing.T, plugins ...framework.Plugin) (framework } } - versionedCfg := v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{{ + versionedCfg := configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{{ SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), Plugins: pls, }}, } - cfg := configtesting.V1beta3ToInternalWithDefaults(t, versionedCfg) + cfg := configtesting.V1ToInternalWithDefaults(t, versionedCfg) return registry, cfg.Profiles[0] } diff --git a/test/integration/scheduler/preemption/preemption_test.go b/test/integration/scheduler/preemption/preemption_test.go index 099ebb01f09..f71498d40e5 100644 --- a/test/integration/scheduler/preemption/preemption_test.go +++ b/test/integration/scheduler/preemption/preemption_test.go @@ -37,7 +37,7 @@ import ( clientset "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" "k8s.io/klog/v2" - "k8s.io/kube-scheduler/config/v1beta3" + configv1 "k8s.io/kube-scheduler/config/v1" podutil "k8s.io/kubernetes/pkg/api/v1/pod" "k8s.io/kubernetes/pkg/apis/scheduling" "k8s.io/kubernetes/pkg/scheduler" @@ -150,17 +150,17 @@ func TestPreemption(t *testing.T) { if err != nil { t.Fatalf("Error registering a filter: %v", err) } - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{{ SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), - Plugins: &v1beta3.Plugins{ - Filter: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + Plugins: &configv1.Plugins{ + Filter: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: filterPluginName}, }, }, - PreFilter: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + PreFilter: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: filterPluginName}, }, }, @@ -986,7 +986,7 @@ func TestNominatedNodeCleanUp(t *testing.T) { podNamesToDelete []string // Register dummy plugin to simulate particular scheduling failures. Optional. - customPlugins *v1beta3.Plugins + customPlugins *configv1.Plugins outOfTreeRegistry frameworkruntime.Registry }{ { @@ -1068,9 +1068,9 @@ func TestNominatedNodeCleanUp(t *testing.T) { waitForNominatedNodeName, }, podNamesToDelete: []string{fmt.Sprintf("low-%v", doNotFailMe)}, - customPlugins: &v1beta3.Plugins{ - PreBind: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + customPlugins: &configv1.Plugins{ + PreBind: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: alwaysFailPlugin}, }, }, @@ -1081,8 +1081,8 @@ func TestNominatedNodeCleanUp(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{{ SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), Plugins: tt.customPlugins, }}, diff --git a/test/integration/scheduler/queue_test.go b/test/integration/scheduler/queue_test.go index 23039d10191..5efaf06e484 100644 --- a/test/integration/scheduler/queue_test.go +++ b/test/integration/scheduler/queue_test.go @@ -34,7 +34,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" - "k8s.io/kube-scheduler/config/v1beta3" + configv1 "k8s.io/kube-scheduler/config/v1" apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing" "k8s.io/kubernetes/pkg/scheduler" configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing" @@ -211,12 +211,12 @@ func TestCustomResourceEnqueue(t *testing.T) { return &fakeCRPlugin{}, nil }, } - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{{ SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), - Plugins: &v1beta3.Plugins{ - Filter: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + Plugins: &configv1.Plugins{ + Filter: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: "fakeCRPlugin"}, }, }, diff --git a/test/integration/scheduler/scheduler_test.go b/test/integration/scheduler/scheduler_test.go index c81b192d2c2..656811bb5cc 100644 --- a/test/integration/scheduler/scheduler_test.go +++ b/test/integration/scheduler/scheduler_test.go @@ -34,7 +34,7 @@ import ( clientset "k8s.io/client-go/kubernetes" corelisters "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" - "k8s.io/kube-scheduler/config/v1beta3" + configv1 "k8s.io/kube-scheduler/config/v1" "k8s.io/kubernetes/pkg/scheduler" configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing" st "k8s.io/kubernetes/pkg/scheduler/testing" @@ -252,14 +252,14 @@ func TestMultipleSchedulers(t *testing.T) { } // 5. create and start a scheduler with name "foo-scheduler" - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{{ SchedulerName: pointer.StringPtr(fooScheduler), - PluginConfig: []v1beta3.PluginConfig{ + PluginConfig: []configv1.PluginConfig{ { Name: "VolumeBinding", Args: runtime.RawExtension{ - Object: &v1beta3.VolumeBindingArgs{ + Object: &configv1.VolumeBindingArgs{ BindTimeoutSeconds: pointer.Int64Ptr(30), }, }, @@ -328,8 +328,8 @@ func TestMultipleSchedulers(t *testing.T) { } func TestMultipleSchedulingProfiles(t *testing.T) { - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{ {SchedulerName: pointer.StringPtr("default-scheduler")}, {SchedulerName: pointer.StringPtr("custom-scheduler")}, }, diff --git a/test/integration/scheduler/scoring/priorities_test.go b/test/integration/scheduler/scoring/priorities_test.go index c757d6bbaae..3f75ab5eab1 100644 --- a/test/integration/scheduler/scoring/priorities_test.go +++ b/test/integration/scheduler/scoring/priorities_test.go @@ -31,7 +31,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" utilfeature "k8s.io/apiserver/pkg/util/feature" featuregatetesting "k8s.io/component-base/featuregate/testing" - "k8s.io/kube-scheduler/config/v1beta3" + configv1 "k8s.io/kube-scheduler/config/v1" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/scheduler" configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing" @@ -74,15 +74,15 @@ const ( // This file tests the scheduler priority functions. func initTestSchedulerForPriorityTest(t *testing.T, scorePluginName string) *testutils.TestContext { - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{{ SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), - Plugins: &v1beta3.Plugins{ - Score: v1beta3.PluginSet{ - Enabled: []v1beta3.Plugin{ + Plugins: &configv1.Plugins{ + Score: configv1.PluginSet{ + Enabled: []configv1.Plugin{ {Name: scorePluginName, Weight: pointer.Int32Ptr(1)}, }, - Disabled: []v1beta3.Plugin{ + Disabled: []configv1.Plugin{ {Name: "*"}, }, }, @@ -101,20 +101,20 @@ func initTestSchedulerForPriorityTest(t *testing.T, scorePluginName string) *tes } func initTestSchedulerForNodeResourcesTest(t *testing.T) *testutils.TestContext { - cfg := configtesting.V1beta3ToInternalWithDefaults(t, v1beta3.KubeSchedulerConfiguration{ - Profiles: []v1beta3.KubeSchedulerProfile{ + cfg := configtesting.V1ToInternalWithDefaults(t, configv1.KubeSchedulerConfiguration{ + Profiles: []configv1.KubeSchedulerProfile{ { SchedulerName: pointer.StringPtr(v1.DefaultSchedulerName), }, { SchedulerName: pointer.StringPtr("gpu-binpacking-scheduler"), - PluginConfig: []v1beta3.PluginConfig{ + PluginConfig: []configv1.PluginConfig{ { Name: noderesources.Name, - Args: runtime.RawExtension{Object: &v1beta3.NodeResourcesFitArgs{ - ScoringStrategy: &v1beta3.ScoringStrategy{ - Type: v1beta3.MostAllocated, - Resources: []v1beta3.ResourceSpec{ + Args: runtime.RawExtension{Object: &configv1.NodeResourcesFitArgs{ + ScoringStrategy: &configv1.ScoringStrategy{ + Type: configv1.MostAllocated, + Resources: []configv1.ResourceSpec{ {Name: string(v1.ResourceCPU), Weight: 1}, {Name: string(v1.ResourceMemory), Weight: 1}, {Name: resourceGPU, Weight: 2}}, diff --git a/vendor/modules.txt b/vendor/modules.txt index c55eba077cb..af0ced7a9f1 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -2213,6 +2213,7 @@ k8s.io/kube-openapi/pkg/validation/validate k8s.io/kube-proxy/config/v1alpha1 # k8s.io/kube-scheduler v0.0.0 => ./staging/src/k8s.io/kube-scheduler ## explicit; go 1.18 +k8s.io/kube-scheduler/config/v1 k8s.io/kube-scheduler/config/v1beta2 k8s.io/kube-scheduler/config/v1beta3 k8s.io/kube-scheduler/extender/v1