diff --git a/pkg/scheduler/apis/config/scheme/BUILD b/pkg/scheduler/apis/config/scheme/BUILD index 7331f914ffb..df12007b9ef 100644 --- a/pkg/scheduler/apis/config/scheme/BUILD +++ b/pkg/scheduler/apis/config/scheme/BUILD @@ -34,10 +34,14 @@ go_test( srcs = ["scheme_test.go"], embed = [":go_default_library"], deps = [ + "//pkg/features:go_default_library", "//pkg/scheduler/apis/config:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", + "//staging/src/k8s.io/component-base/featuregate:go_default_library", + "//staging/src/k8s.io/component-base/featuregate/testing:go_default_library", "//staging/src/k8s.io/kube-scheduler/config/v1beta1:go_default_library", "//vendor/github.com/google/go-cmp/cmp:go_default_library", "//vendor/k8s.io/utils/pointer:go_default_library", diff --git a/pkg/scheduler/apis/config/scheme/scheme_test.go b/pkg/scheduler/apis/config/scheme/scheme_test.go index 1fc41b7869d..3756ae7c113 100644 --- a/pkg/scheduler/apis/config/scheme/scheme_test.go +++ b/pkg/scheduler/apis/config/scheme/scheme_test.go @@ -24,7 +24,11 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/util/feature" + "k8s.io/component-base/featuregate" + featuregatetesting "k8s.io/component-base/featuregate/testing" "k8s.io/kube-scheduler/config/v1beta1" + "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/scheduler/apis/config" "k8s.io/utils/pointer" "sigs.k8s.io/yaml" @@ -34,6 +38,7 @@ func TestCodecsDecodePluginConfig(t *testing.T) { testCases := []struct { name string data []byte + feature featuregate.Feature wantErr string wantProfiles []config.KubeSchedulerProfile }{ @@ -257,6 +262,7 @@ profiles: args: - name: VolumeBinding args: + - name: PodTopologySpread `), wantProfiles: []config.KubeSchedulerProfile{ { @@ -291,6 +297,73 @@ profiles: BindTimeoutSeconds: 600, }, }, + { + Name: "PodTopologySpread", + Args: &config.PodTopologySpreadArgs{}, + }, + }, + }, + }, + }, + { + name: "empty PodTopologySpread, feature DefaultPodTopologySpread enabled", + data: []byte(` +apiVersion: kubescheduler.config.k8s.io/v1beta1 +kind: KubeSchedulerConfiguration +profiles: +- pluginConfig: + - name: PodTopologySpread + args: + defaultConstraints: +`), + feature: features.DefaultPodTopologySpread, + wantProfiles: []config.KubeSchedulerProfile{ + { + SchedulerName: "default-scheduler", + PluginConfig: []config.PluginConfig{ + { + Name: "PodTopologySpread", + Args: &config.PodTopologySpreadArgs{ + DefaultConstraints: []corev1.TopologySpreadConstraint{ + { + MaxSkew: 3, + TopologyKey: corev1.LabelHostname, + WhenUnsatisfiable: corev1.ScheduleAnyway, + }, + { + MaxSkew: 5, + TopologyKey: corev1.LabelZoneFailureDomainStable, + WhenUnsatisfiable: corev1.ScheduleAnyway, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "empty array PodTopologySpread, feature DefaultPodTopologySpread enabled", + data: []byte(` +apiVersion: kubescheduler.config.k8s.io/v1beta1 +kind: KubeSchedulerConfiguration +profiles: +- pluginConfig: + - name: PodTopologySpread + args: + defaultConstraints: [] +`), + feature: features.DefaultPodTopologySpread, + wantProfiles: []config.KubeSchedulerProfile{ + { + SchedulerName: "default-scheduler", + PluginConfig: []config.PluginConfig{ + { + Name: "PodTopologySpread", + Args: &config.PodTopologySpreadArgs{ + DefaultConstraints: []corev1.TopologySpreadConstraint{}, + }, + }, }, }, }, @@ -299,6 +372,9 @@ profiles: decoder := Codecs.UniversalDecoder() for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { + if tt.feature != "" { + defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, tt.feature, true)() + } obj, gvk, err := decoder.Decode(tt.data, nil, nil) if err != nil { if tt.wantErr != err.Error() { @@ -373,6 +449,14 @@ func TestCodecsEncodePluginConfig(t *testing.T) { }, }, }, + { + Name: "PodTopologySpread", + Args: runtime.RawExtension{ + Object: &v1beta1.PodTopologySpreadArgs{ + DefaultConstraints: []corev1.TopologySpreadConstraint{}, + }, + }, + }, { Name: "OutOfTreePlugin", Args: runtime.RawExtension{ @@ -428,6 +512,11 @@ profiles: - name: mem weight: 2 name: NodeResourcesLeastAllocated + - args: + apiVersion: kubescheduler.config.k8s.io/v1beta1 + defaultConstraints: [] + kind: PodTopologySpreadArgs + name: PodTopologySpread - args: foo: bar name: OutOfTreePlugin @@ -458,6 +547,10 @@ profiles: BindTimeoutSeconds: 300, }, }, + { + Name: "PodTopologySpread", + Args: &config.PodTopologySpreadArgs{}, + }, { Name: "OutOfTreePlugin", Args: &runtime.Unknown{ @@ -510,6 +603,11 @@ profiles: bindTimeoutSeconds: 300 kind: VolumeBindingArgs name: VolumeBinding + - args: + apiVersion: kubescheduler.config.k8s.io/v1beta1 + defaultConstraints: null + kind: PodTopologySpreadArgs + name: PodTopologySpread - args: foo: bar name: OutOfTreePlugin diff --git a/pkg/scheduler/apis/config/v1beta1/defaults_test.go b/pkg/scheduler/apis/config/v1beta1/defaults_test.go index 5142d510602..6212b0ce32f 100644 --- a/pkg/scheduler/apis/config/v1beta1/defaults_test.go +++ b/pkg/scheduler/apis/config/v1beta1/defaults_test.go @@ -25,7 +25,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - utilfeature "k8s.io/apiserver/pkg/util/feature" + "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" @@ -391,7 +391,7 @@ func TestPluginArgsDefaults(t *testing.T) { }, }, { - name: "PodTopologySpreadArgs resources empty, NewPodTopologySpread feature enabled", + name: "PodTopologySpreadArgs resources empty, DefaultPodTopologySpread feature enabled", feature: features.DefaultPodTopologySpread, in: &v1beta1.PodTopologySpreadArgs{}, want: &v1beta1.PodTopologySpreadArgs{ @@ -409,13 +409,23 @@ func TestPluginArgsDefaults(t *testing.T) { }, }, }, + { + name: "PodTopologySpreadArgs empty array, DefaultPodTopologySpread feature enabled", + feature: features.DefaultPodTopologySpread, + in: &v1beta1.PodTopologySpreadArgs{ + DefaultConstraints: []v1.TopologySpreadConstraint{}, + }, + want: &v1beta1.PodTopologySpreadArgs{ + DefaultConstraints: []v1.TopologySpreadConstraint{}, + }, + }, } for _, tc := range tests { scheme := runtime.NewScheme() utilruntime.Must(AddToScheme(scheme)) t.Run(tc.name, func(t *testing.T) { if tc.feature != "" { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, tc.feature, true)() + defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, tc.feature, true)() } scheme.Default(tc.in) if diff := cmp.Diff(tc.in, tc.want); diff != "" {