diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 40edbeb3044d6..f68fd5e2e5427 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -9046,7 +9046,7 @@ "type": "string" }, "schedulingGates": { - "description": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.\n\nThis is a beta feature enabled by the PodSchedulingReadiness feature gate.", + "description": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.", "items": { "$ref": "#/definitions/io.k8s.api.core.v1.PodSchedulingGate" }, diff --git a/api/openapi-spec/v3/api__v1_openapi.json b/api/openapi-spec/v3/api__v1_openapi.json index 8fbe1d83dcfe3..8a12b6bf3189e 100644 --- a/api/openapi-spec/v3/api__v1_openapi.json +++ b/api/openapi-spec/v3/api__v1_openapi.json @@ -5465,7 +5465,7 @@ "type": "string" }, "schedulingGates": { - "description": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.\n\nThis is a beta feature enabled by the PodSchedulingReadiness feature gate.", + "description": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.", "items": { "allOf": [ { diff --git a/api/openapi-spec/v3/apis__apps__v1_openapi.json b/api/openapi-spec/v3/apis__apps__v1_openapi.json index 95ffc13c79aa6..86c2c30031eec 100644 --- a/api/openapi-spec/v3/apis__apps__v1_openapi.json +++ b/api/openapi-spec/v3/apis__apps__v1_openapi.json @@ -3882,7 +3882,7 @@ "type": "string" }, "schedulingGates": { - "description": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.\n\nThis is a beta feature enabled by the PodSchedulingReadiness feature gate.", + "description": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.", "items": { "allOf": [ { diff --git a/api/openapi-spec/v3/apis__batch__v1_openapi.json b/api/openapi-spec/v3/apis__batch__v1_openapi.json index c169e28f99bb0..147a6c0ff0f99 100644 --- a/api/openapi-spec/v3/apis__batch__v1_openapi.json +++ b/api/openapi-spec/v3/apis__batch__v1_openapi.json @@ -3037,7 +3037,7 @@ "type": "string" }, "schedulingGates": { - "description": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.\n\nThis is a beta feature enabled by the PodSchedulingReadiness feature gate.", + "description": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.", "items": { "allOf": [ { diff --git a/cmd/kube-scheduler/app/server_test.go b/cmd/kube-scheduler/app/server_test.go index ec696ba390be4..f8873787d0a82 100644 --- a/cmd/kube-scheduler/app/server_test.go +++ b/cmd/kube-scheduler/app/server_test.go @@ -239,23 +239,6 @@ leaderElection: "simplified-scheduler": defaults.ExpandedPluginsV1, }, }, - { - name: "default config with a beta feature disabled", - flags: []string{ - "--kubeconfig", configKubeconfig, - "--feature-gates=PodSchedulingReadiness=false", - }, - wantPlugins: map[string]*config.Plugins{ - "default-scheduler": func() *config.Plugins { - plugins := defaults.ExpandedPluginsV1.DeepCopy() - plugins.PreEnqueue = config.PluginSet{} - return plugins - }(), - }, - restoreFeatures: map[featuregate.Feature]bool{ - features.PodSchedulingReadiness: true, - }, - }, { name: "default config", flags: []string{ diff --git a/pkg/api/pod/util.go b/pkg/api/pod/util.go index 959f16aafc47c..38e8a355c6d76 100644 --- a/pkg/api/pod/util.go +++ b/pkg/api/pod/util.go @@ -382,7 +382,6 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po AllowIndivisibleHugePagesValues: false, AllowInvalidLabelValueInSelector: false, AllowInvalidTopologySpreadConstraintLabelSelector: false, - AllowMutableNodeSelectorAndNodeAffinity: utilfeature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness), AllowNamespacedSysctlsForHostNetAndHostIPC: false, AllowNonLocalProjectedTokenPath: false, } @@ -558,11 +557,6 @@ func dropDisabledFields( } } - // If the feature is disabled and not in use, drop the schedulingGates field. - if !utilfeature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness) && !schedulingGatesInUse(oldPodSpec) { - podSpec.SchedulingGates = nil - } - dropDisabledProcMountField(podSpec, oldPodSpec) dropDisabledTopologySpreadConstraintsFields(podSpec, oldPodSpec) @@ -983,14 +977,6 @@ func appArmorInUse(podAnnotations map[string]string) bool { return false } -// schedulingGatesInUse returns true if the pod spec is non-nil and it has SchedulingGates field set. -func schedulingGatesInUse(podSpec *api.PodSpec) bool { - if podSpec == nil { - return false - } - return len(podSpec.SchedulingGates) != 0 -} - // restartableInitContainersInUse returns true if the pod spec is non-nil and // it has any init container with ContainerRestartPolicyAlways. func restartableInitContainersInUse(podSpec *api.PodSpec) bool { diff --git a/pkg/api/pod/util_test.go b/pkg/api/pod/util_test.go index 113529acffd74..903b67bd307f9 100644 --- a/pkg/api/pod/util_test.go +++ b/pkg/api/pod/util_test.go @@ -2563,88 +2563,6 @@ func TestDropHostUsers(t *testing.T) { } -func TestDropSchedulingGates(t *testing.T) { - podWithSchedulingGates := func() *api.Pod { - return &api.Pod{ - Spec: api.PodSpec{ - SchedulingGates: []api.PodSchedulingGate{ - {Name: "foo"}, - {Name: "bar"}, - }, - }, - } - } - podWithoutSchedulingGates := func() *api.Pod { return &api.Pod{} } - - podInfo := []struct { - description string - hasSchedulingGatesField bool - pod func() *api.Pod - }{ - { - description: "has SchedulingGates field", - hasSchedulingGatesField: true, - pod: podWithSchedulingGates, - }, - { - description: "does not have SchedulingGates field", - hasSchedulingGatesField: false, - pod: podWithoutSchedulingGates, - }, - { - description: "is nil", - hasSchedulingGatesField: false, - pod: func() *api.Pod { return nil }, - }, - } - - for _, enabled := range []bool{true, false} { - for _, oldPodInfo := range podInfo { - for _, newPodInfo := range podInfo { - oldPodHasSchedulingGates, oldPod := oldPodInfo.hasSchedulingGatesField, oldPodInfo.pod() - newPodHasSchedulingGates, newPod := newPodInfo.hasSchedulingGatesField, newPodInfo.pod() - if newPod == nil { - continue - } - - t.Run(fmt.Sprintf("feature enabled=%v, old pod %v, new pod %v", enabled, oldPodInfo.description, newPodInfo.description), func(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, enabled)() - var oldPodSpec *api.PodSpec - if oldPod != nil { - oldPodSpec = &oldPod.Spec - } - dropDisabledFields(&newPod.Spec, nil, oldPodSpec, nil) - // Old Pod should never be changed. - if diff := cmp.Diff(oldPod, oldPodInfo.pod()); diff != "" { - t.Errorf("old pod changed: %v", diff) - } - switch { - case enabled || oldPodHasSchedulingGates: - // New Pod should not be changed if the feature is enabled, or if the old Pod had schedulingGates. - if diff := cmp.Diff(newPod, newPodInfo.pod()); diff != "" { - t.Errorf("new pod changed: %v", diff) - } - case newPodHasSchedulingGates: - // New Pod should be changed. - if reflect.DeepEqual(newPod, newPodInfo.pod()) { - t.Errorf("new pod was not changed") - } - // New Pod should not have SchedulingGates field. - if diff := cmp.Diff(newPod, podWithoutSchedulingGates()); diff != "" { - t.Errorf("new pod has SchedulingGates field: %v", diff) - } - default: - // New pod should not need to be changed. - if diff := cmp.Diff(newPod, newPodInfo.pod()); diff != "" { - t.Errorf("new pod changed: %v", diff) - } - } - }) - } - } - } -} - func TestValidateTopologySpreadConstraintLabelSelectorOption(t *testing.T) { testCases := []struct { name string diff --git a/pkg/apis/core/types.go b/pkg/apis/core/types.go index 71faec40e9a9f..191b9ff1e0249 100644 --- a/pkg/apis/core/types.go +++ b/pkg/apis/core/types.go @@ -3352,9 +3352,6 @@ type PodSpec struct { // // SchedulingGates can only be set at pod creation time, and be removed only afterwards. // - // This is a beta feature enabled by the PodSchedulingReadiness feature gate. - // - // +featureGate=PodSchedulingReadiness // +optional SchedulingGates []PodSchedulingGate // ResourceClaims defines which ResourceClaims must be allocated diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index 61b543cc58764..335ea269e2cf3 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -3974,8 +3974,6 @@ type PodValidationOptions struct { AllowHostIPsField bool // Allow invalid topologySpreadConstraint labelSelector for backward compatibility AllowInvalidTopologySpreadConstraintLabelSelector bool - // Allow node selector additions for gated pods. - AllowMutableNodeSelectorAndNodeAffinity bool // Allow projected token volumes with non-local paths AllowNonLocalProjectedTokenPath bool // Allow namespaced sysctls in hostNet and hostIPC pods @@ -5056,7 +5054,7 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel // Handle validations specific to gated pods. podIsGated := len(oldPod.Spec.SchedulingGates) > 0 - if opts.AllowMutableNodeSelectorAndNodeAffinity && podIsGated { + if podIsGated { // Additions to spec.nodeSelector are allowed (no deletions or mutations) for gated pods. if !apiequality.Semantic.DeepEqual(mungedPodSpec.NodeSelector, oldPod.Spec.NodeSelector) { allErrs = append(allErrs, validateNodeSelectorMutation(specPath.Child("nodeSelector"), mungedPodSpec.NodeSelector, oldPod.Spec.NodeSelector)...) diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index a2e09cbb55665..ef21af8154f07 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -12298,22 +12298,8 @@ func TestValidatePodCreateWithSchedulingGates(t *testing.T) { tests := []struct { name string pod *core.Pod - featureEnabled bool wantFieldErrors field.ErrorList }{{ - name: "create a Pod with nodeName and schedulingGates, feature disabled", - pod: &core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod", Namespace: "ns"}, - Spec: core.PodSpec{ - NodeName: "node", - SchedulingGates: []core.PodSchedulingGate{ - {Name: "foo"}, - }, - }, - }, - featureEnabled: false, - wantFieldErrors: []*field.Error{field.Forbidden(fldPath.Child("nodeName"), "cannot be set until all schedulingGates have been cleared")}, - }, { name: "create a Pod with nodeName and schedulingGates, feature enabled", pod: &core.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "pod", Namespace: "ns"}, @@ -12324,20 +12310,7 @@ func TestValidatePodCreateWithSchedulingGates(t *testing.T) { }, }, }, - featureEnabled: true, wantFieldErrors: []*field.Error{field.Forbidden(fldPath.Child("nodeName"), "cannot be set until all schedulingGates have been cleared")}, - }, { - name: "create a Pod with schedulingGates, feature disabled", - pod: &core.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: "pod", Namespace: "ns"}, - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{ - {Name: "foo"}, - }, - }, - }, - featureEnabled: false, - wantFieldErrors: nil, }, { name: "create a Pod with schedulingGates, feature enabled", pod: &core.Pod{ @@ -12348,15 +12321,12 @@ func TestValidatePodCreateWithSchedulingGates(t *testing.T) { }, }, }, - featureEnabled: true, wantFieldErrors: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, tt.featureEnabled)() - applyEssentials(tt.pod) errs := ValidatePodCreate(tt.pod, PodValidationOptions{}) if diff := cmp.Diff(tt.wantFieldErrors, errs); diff != "" { @@ -12383,7 +12353,6 @@ func TestValidatePodUpdate(t *testing.T) { tests := []struct { new core.Pod old core.Pod - opts PodValidationOptions err string test string }{ @@ -13716,25 +13685,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image", - test: "node selector is immutable when AllowMutableNodeSelector is false", - }, { - old: core.Pod{ - Spec: core.PodSpec{ - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - new: core.Pod{ - Spec: core.PodSpec{ - NodeSelector: map[string]string{ - "foo": "bar", - }, - SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, - }, - }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, test: "adding node selector is allowed for gated pods", }, { old: core.Pod{ @@ -13752,9 +13702,6 @@ func TestValidatePodUpdate(t *testing.T) { }, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image", test: "adding node selector is not allowed for non-gated pods", }, { @@ -13771,9 +13718,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "spec.nodeSelector: Invalid value:", test: "removing node selector is not allowed for gated pods", }, { @@ -13784,10 +13728,7 @@ func TestValidatePodUpdate(t *testing.T) { }, }, }, - new: core.Pod{}, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, + new: core.Pod{}, err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image", test: "removing node selector is not allowed for non-gated pods", }, { @@ -13807,9 +13748,6 @@ func TestValidatePodUpdate(t *testing.T) { }, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, test: "old pod spec has scheduling gate, new pod spec does not, and node selector is added", }, { old: core.Pod{ @@ -13828,9 +13766,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "spec.nodeSelector: Invalid value:", test: "modifying value of existing node selector is not allowed", }, { @@ -13880,9 +13815,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, test: "addition to nodeAffinity is allowed for gated pods", }, { old: core.Pod{ @@ -13911,9 +13843,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:", test: "old RequiredDuringSchedulingIgnoredDuringExecution is non-nil, new RequiredDuringSchedulingIgnoredDuringExecution is nil, pod is gated", }, { @@ -13961,9 +13890,6 @@ func TestValidatePodUpdate(t *testing.T) { }, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image", test: "addition to nodeAffinity is not allowed for non-gated pods", }, { @@ -14012,9 +13938,6 @@ func TestValidatePodUpdate(t *testing.T) { }, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, test: "old pod spec has scheduling gate, new pod spec does not, and node affinity addition occurs", }, { old: core.Pod{ @@ -14053,9 +13976,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:", test: "nodeAffinity deletion from MatchExpressions not allowed", }, { @@ -14101,9 +14021,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:", test: "nodeAffinity deletion from MatchFields not allowed", }, { @@ -14154,9 +14071,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:", test: "nodeAffinity modification of item in MatchExpressions not allowed", }, { @@ -14206,9 +14120,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:", test: "nodeAffinity modification of item in MatchFields not allowed", }, { @@ -14269,9 +14180,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:", test: "nodeSelectorTerms addition on gated pod should fail", }, { @@ -14313,9 +14221,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, test: "preferredDuringSchedulingIgnoredDuringExecution can modified for gated pods", }, { old: core.Pod{ @@ -14365,9 +14270,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, test: "preferredDuringSchedulingIgnoredDuringExecution can have additions for gated pods", }, { old: core.Pod{ @@ -14394,9 +14296,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, test: "preferredDuringSchedulingIgnoredDuringExecution can have removals for gated pods", }, { old: core.Pod{ @@ -14423,9 +14322,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:", test: "new node affinity is nil", }, { @@ -14453,9 +14349,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, test: "preferredDuringSchedulingIgnoredDuringExecution can have removals for gated pods", }, { old: core.Pod{ @@ -14490,9 +14383,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:", test: "empty NodeSelectorTerm (selects nothing) cannot become populated (selects something)", }, { @@ -14520,9 +14410,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, test: "nil affinity can be mutated for gated pods", }, { @@ -14560,9 +14447,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "pod updates may not change fields other than", test: "the podAffinity cannot be updated on gated pods", }, @@ -14601,9 +14485,6 @@ func TestValidatePodUpdate(t *testing.T) { SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}}, }, }, - opts: PodValidationOptions{ - AllowMutableNodeSelectorAndNodeAffinity: true, - }, err: "pod updates may not change fields other than", test: "the podAntiAffinity cannot be updated on gated pods", }, @@ -14634,7 +14515,7 @@ func TestValidatePodUpdate(t *testing.T) { test.old.Spec.RestartPolicy = "Always" } - errs := ValidatePodUpdate(&test.new, &test.old, test.opts) + errs := ValidatePodUpdate(&test.new, &test.old, PodValidationOptions{}) if test.err == "" { if len(errs) != 0 { t.Errorf("unexpected invalid: %s (%+v)\nA: %+v\nB: %+v", test.test, errs, test.new, test.old) diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index 448500822921f..94ea3460aa9f6 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -614,6 +614,7 @@ const ( // kep: https://kep.k8s.io/3521 // alpha: v1.26 // beta: v1.27 + // stable: v1.30 // // Enable users to specify when a Pod is ready for scheduling. PodSchedulingReadiness featuregate.Feature = "PodSchedulingReadiness" @@ -1097,7 +1098,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS PodLifecycleSleepAction: {Default: true, PreRelease: featuregate.Beta}, - PodSchedulingReadiness: {Default: true, PreRelease: featuregate.Beta}, + PodSchedulingReadiness: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // GA in 1.30; remove in 1.32 ProcMountType: {Default: false, PreRelease: featuregate.Alpha}, diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index abfd8f92e3daa..ce4c8f466c7ad 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -26465,7 +26465,7 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA }, }, SchemaProps: spec.SchemaProps{ - Description: "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.\n\nThis is a beta feature enabled by the PodSchedulingReadiness feature gate.", + Description: "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ diff --git a/pkg/registry/core/pod/storage/storage_test.go b/pkg/registry/core/pod/storage/storage_test.go index 03c6de35372b8..d0311b30d6910 100644 --- a/pkg/registry/core/pod/storage/storage_test.go +++ b/pkg/registry/core/pod/storage/storage_test.go @@ -42,10 +42,7 @@ import ( apiserverstorage "k8s.io/apiserver/pkg/storage" storeerr "k8s.io/apiserver/pkg/storage/errors" etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing" - utilfeature "k8s.io/apiserver/pkg/util/feature" - featuregatetesting "k8s.io/component-base/featuregate/testing" api "k8s.io/kubernetes/pkg/apis/core" - "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/securitycontext" ) @@ -752,22 +749,11 @@ func TestEtcdCreateWithConflict(t *testing.T) { func TestEtcdCreateWithSchedulingGates(t *testing.T) { tests := []struct { name string - featureEnabled bool schedulingGates []api.PodSchedulingGate wantErr error }{ { - name: "pod with non-nil schedulingGates, feature disabled", - featureEnabled: false, - schedulingGates: []api.PodSchedulingGate{ - {Name: "foo"}, - {Name: "bar"}, - }, - wantErr: nil, - }, - { - name: "pod with non-nil schedulingGates, feature enabled", - featureEnabled: true, + name: "pod with non-nil schedulingGates", schedulingGates: []api.PodSchedulingGate{ {Name: "foo"}, {Name: "bar"}, @@ -775,56 +761,40 @@ func TestEtcdCreateWithSchedulingGates(t *testing.T) { wantErr: goerrors.New(`Operation cannot be fulfilled on pods/binding "foo": pod foo has non-empty .spec.schedulingGates`), }, { - name: "pod with nil schedulingGates, feature disabled", - featureEnabled: false, - schedulingGates: nil, - wantErr: nil, - }, - { - name: "pod with nil schedulingGates, feature enabled", - featureEnabled: true, + name: "pod with nil schedulingGates", schedulingGates: nil, wantErr: nil, }, } for _, tt := range tests { - for _, flipFeatureGateBeforeBinding := range []bool{false, true} { - if flipFeatureGateBeforeBinding { - tt.name = fmt.Sprintf("%v and flipped before binding", tt.name) + t.Run(tt.name, func(t *testing.T) { + storage, bindingStorage, _, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + ctx := genericapirequest.NewDefaultContext() + + pod := validNewPod() + pod.Spec.SchedulingGates = tt.schedulingGates + if _, err := storage.Create(ctx, pod, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}); err != nil { + t.Fatalf("Unexpected error: %v", err) } - t.Run(tt.name, func(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, tt.featureEnabled)() - storage, bindingStorage, _, server := newStorage(t) - defer server.Terminate(t) - defer storage.Store.DestroyFunc() - ctx := genericapirequest.NewDefaultContext() - - pod := validNewPod() - pod.Spec.SchedulingGates = tt.schedulingGates - if _, err := storage.Create(ctx, pod, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}); err != nil { - t.Fatalf("Unexpected error: %v", err) - } - if flipFeatureGateBeforeBinding { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, !tt.featureEnabled)() + _, err := bindingStorage.Create(ctx, "foo", &api.Binding{ + ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "foo"}, + Target: api.ObjectReference{Name: "machine"}, + }, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) + if tt.wantErr == nil { + if err != nil { + t.Errorf("Want nil err, but got %v", err) } - _, err := bindingStorage.Create(ctx, "foo", &api.Binding{ - ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "foo"}, - Target: api.ObjectReference{Name: "machine"}, - }, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) - if tt.wantErr == nil { - if err != nil { - t.Errorf("Want nil err, but got %v", err) - } - } else { - if err == nil { - t.Errorf("Want %v, but got nil err", tt.wantErr) - } else if tt.wantErr.Error() != err.Error() { - t.Errorf("Want %v, but got %v", tt.wantErr, err) - } + } else { + if err == nil { + t.Errorf("Want %v, but got nil err", tt.wantErr) + } else if tt.wantErr.Error() != err.Error() { + t.Errorf("Want %v, but got %v", tt.wantErr, err) } - }) - } + } + }) } } diff --git a/pkg/registry/core/pod/strategy.go b/pkg/registry/core/pod/strategy.go index ea73d18a3c80e..c72ad557f6525 100644 --- a/pkg/registry/core/pod/strategy.go +++ b/pkg/registry/core/pod/strategy.go @@ -740,8 +740,7 @@ func mutatePodAffinity(pod *api.Pod) { // applySchedulingGatedCondition adds a {type:PodScheduled, reason:SchedulingGated} condition // to a new-created Pod if necessary. func applySchedulingGatedCondition(pod *api.Pod) { - if !utilfeature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness) || - len(pod.Spec.SchedulingGates) == 0 { + if len(pod.Spec.SchedulingGates) == 0 { return } diff --git a/pkg/registry/core/pod/strategy_test.go b/pkg/registry/core/pod/strategy_test.go index c73152aaf9233..89b919cc08d61 100644 --- a/pkg/registry/core/pod/strategy_test.go +++ b/pkg/registry/core/pod/strategy_test.go @@ -314,41 +314,22 @@ func TestGetPodQOS(t *testing.T) { func TestSchedulingGatedCondition(t *testing.T) { tests := []struct { - name string - pod *api.Pod - featureEnabled bool - want api.PodCondition + name string + pod *api.Pod + want api.PodCondition }{ { - name: "pod without .spec.schedulingGates, feature disabled", - pod: &api.Pod{}, - featureEnabled: false, - want: api.PodCondition{}, + name: "pod without .spec.schedulingGates", + pod: &api.Pod{}, + want: api.PodCondition{}, }, { - name: "pod without .spec.schedulingGates, feature enabled", - pod: &api.Pod{}, - featureEnabled: true, - want: api.PodCondition{}, - }, - { - name: "pod with .spec.schedulingGates, feature disabled", - pod: &api.Pod{ - Spec: api.PodSpec{ - SchedulingGates: []api.PodSchedulingGate{{Name: "foo"}}, - }, - }, - featureEnabled: false, - want: api.PodCondition{}, - }, - { - name: "pod with .spec.schedulingGates, feature enabled", + name: "pod with .spec.schedulingGates", pod: &api.Pod{ Spec: api.PodSpec{ SchedulingGates: []api.PodSchedulingGate{{Name: "foo"}}, }, }, - featureEnabled: true, want: api.PodCondition{ Type: api.PodScheduled, Status: api.ConditionFalse, @@ -360,8 +341,6 @@ func TestSchedulingGatedCondition(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, tt.featureEnabled)() - Strategy.PrepareForCreate(genericapirequest.NewContext(), tt.pod) var got api.PodCondition for _, condition := range tt.pod.Status.Conditions { diff --git a/pkg/scheduler/apis/config/testing/defaults/defaults.go b/pkg/scheduler/apis/config/testing/defaults/defaults.go index 34d4a51e814ae..413199253ee5e 100644 --- a/pkg/scheduler/apis/config/testing/defaults/defaults.go +++ b/pkg/scheduler/apis/config/testing/defaults/defaults.go @@ -25,6 +25,7 @@ import ( var PluginsV1 = &config.Plugins{ MultiPoint: config.PluginSet{ Enabled: []config.Plugin{ + {Name: names.SchedulingGates}, {Name: names.PrioritySort}, {Name: names.NodeUnschedulable}, {Name: names.NodeName}, @@ -45,7 +46,6 @@ var PluginsV1 = &config.Plugins{ {Name: names.NodeResourcesBalancedAllocation, Weight: 1}, {Name: names.ImageLocality, Weight: 1}, {Name: names.DefaultBinder}, - {Name: names.SchedulingGates}, }, }, } diff --git a/pkg/scheduler/apis/config/v1/default_plugins.go b/pkg/scheduler/apis/config/v1/default_plugins.go index ded35ef8fa120..fa3174d883186 100644 --- a/pkg/scheduler/apis/config/v1/default_plugins.go +++ b/pkg/scheduler/apis/config/v1/default_plugins.go @@ -31,6 +31,7 @@ func getDefaultPlugins() *v1.Plugins { plugins := &v1.Plugins{ MultiPoint: v1.PluginSet{ Enabled: []v1.Plugin{ + {Name: names.SchedulingGates}, {Name: names.PrioritySort}, {Name: names.NodeUnschedulable}, {Name: names.NodeName}, @@ -60,9 +61,6 @@ func getDefaultPlugins() *v1.Plugins { } func applyFeatureGates(config *v1.Plugins) { - if utilfeature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness) { - config.MultiPoint.Enabled = append(config.MultiPoint.Enabled, v1.Plugin{Name: names.SchedulingGates}) - } if utilfeature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation) { // This plugin should come before DefaultPreemption because if // there is a problem with a Pod and PostFilter gets called to diff --git a/pkg/scheduler/apis/config/v1/default_plugins_test.go b/pkg/scheduler/apis/config/v1/default_plugins_test.go index f05d524340031..706b80a81c8fd 100644 --- a/pkg/scheduler/apis/config/v1/default_plugins_test.go +++ b/pkg/scheduler/apis/config/v1/default_plugins_test.go @@ -37,45 +37,14 @@ func TestApplyFeatureGates(t *testing.T) { wantConfig *v1.Plugins }{ { - name: "Feature gates disabled", + name: "Feature gate DynamicResourceAllocation disabled", features: map[featuregate.Feature]bool{ - features.PodSchedulingReadiness: false, - }, - wantConfig: &v1.Plugins{ - MultiPoint: v1.PluginSet{ - Enabled: []v1.Plugin{ - {Name: names.PrioritySort}, - {Name: names.NodeUnschedulable}, - {Name: names.NodeName}, - {Name: names.TaintToleration, Weight: ptr.To[int32](3)}, - {Name: names.NodeAffinity, Weight: ptr.To[int32](2)}, - {Name: names.NodePorts}, - {Name: names.NodeResourcesFit, Weight: ptr.To[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: ptr.To[int32](2)}, - {Name: names.InterPodAffinity, Weight: ptr.To[int32](2)}, - {Name: names.DefaultPreemption}, - {Name: names.NodeResourcesBalancedAllocation, Weight: ptr.To[int32](1)}, - {Name: names.ImageLocality, Weight: ptr.To[int32](1)}, - {Name: names.DefaultBinder}, - }, - }, - }, - }, - { - name: "Feature gate PodSchedulingReadiness enabled", - features: map[featuregate.Feature]bool{ - features.PodSchedulingReadiness: true, + features.DynamicResourceAllocation: false, }, wantConfig: &v1.Plugins{ MultiPoint: v1.PluginSet{ Enabled: []v1.Plugin{ + {Name: names.SchedulingGates}, {Name: names.PrioritySort}, {Name: names.NodeUnschedulable}, {Name: names.NodeName}, @@ -96,7 +65,6 @@ func TestApplyFeatureGates(t *testing.T) { {Name: names.NodeResourcesBalancedAllocation, Weight: ptr.To[int32](1)}, {Name: names.ImageLocality, Weight: ptr.To[int32](1)}, {Name: names.DefaultBinder}, - {Name: names.SchedulingGates}, }, }, }, @@ -109,6 +77,7 @@ func TestApplyFeatureGates(t *testing.T) { wantConfig: &v1.Plugins{ MultiPoint: v1.PluginSet{ Enabled: []v1.Plugin{ + {Name: names.SchedulingGates}, {Name: names.PrioritySort}, {Name: names.NodeUnschedulable}, {Name: names.NodeName}, @@ -130,7 +99,6 @@ func TestApplyFeatureGates(t *testing.T) { {Name: names.NodeResourcesBalancedAllocation, Weight: ptr.To[int32](1)}, {Name: names.ImageLocality, Weight: ptr.To[int32](1)}, {Name: names.DefaultBinder}, - {Name: names.SchedulingGates}, }, }, }, diff --git a/pkg/scheduler/apis/config/v1/defaults_test.go b/pkg/scheduler/apis/config/v1/defaults_test.go index cdfcc9a60a8ea..7a093236c9750 100644 --- a/pkg/scheduler/apis/config/v1/defaults_test.go +++ b/pkg/scheduler/apis/config/v1/defaults_test.go @@ -331,6 +331,7 @@ func TestSchedulerDefaults(t *testing.T) { Plugins: &configv1.Plugins{ MultiPoint: configv1.PluginSet{ Enabled: []configv1.Plugin{ + {Name: names.SchedulingGates}, {Name: names.PrioritySort}, {Name: names.NodeUnschedulable}, {Name: names.NodeName}, @@ -351,7 +352,6 @@ func TestSchedulerDefaults(t *testing.T) { {Name: names.NodeResourcesBalancedAllocation, Weight: ptr.To[int32](1)}, {Name: names.ImageLocality, Weight: ptr.To[int32](1)}, {Name: names.DefaultBinder}, - {Name: names.SchedulingGates}, }, }, Bind: configv1.PluginSet{ diff --git a/pkg/scheduler/framework/plugins/feature/feature.go b/pkg/scheduler/framework/plugins/feature/feature.go index 1a21769aad0eb..d93a11ff06f0a 100644 --- a/pkg/scheduler/framework/plugins/feature/feature.go +++ b/pkg/scheduler/framework/plugins/feature/feature.go @@ -25,7 +25,6 @@ type Features struct { EnableMinDomainsInPodTopologySpread bool EnableNodeInclusionPolicyInPodTopologySpread bool EnableMatchLabelKeysInPodTopologySpread bool - EnablePodSchedulingReadiness bool EnablePodDisruptionConditions bool EnableInPlacePodVerticalScaling bool EnableSidecarContainers bool diff --git a/pkg/scheduler/framework/plugins/registry.go b/pkg/scheduler/framework/plugins/registry.go index be74711e4a2c5..1eb9d3090daa0 100644 --- a/pkg/scheduler/framework/plugins/registry.go +++ b/pkg/scheduler/framework/plugins/registry.go @@ -51,7 +51,6 @@ func NewInTreeRegistry() runtime.Registry { EnableMinDomainsInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MinDomainsInPodTopologySpread), EnableNodeInclusionPolicyInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.NodeInclusionPolicyInPodTopologySpread), EnableMatchLabelKeysInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MatchLabelKeysInPodTopologySpread), - EnablePodSchedulingReadiness: feature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness), EnablePodDisruptionConditions: feature.DefaultFeatureGate.Enabled(features.PodDisruptionConditions), EnableInPlacePodVerticalScaling: feature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling), EnableSidecarContainers: feature.DefaultFeatureGate.Enabled(features.SidecarContainers), @@ -80,7 +79,7 @@ func NewInTreeRegistry() runtime.Registry { queuesort.Name: queuesort.New, defaultbinder.Name: defaultbinder.New, defaultpreemption.Name: runtime.FactoryAdapter(fts, defaultpreemption.New), - schedulinggates.Name: runtime.FactoryAdapter(fts, schedulinggates.New), + schedulinggates.Name: schedulinggates.New, } return registry diff --git a/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates.go b/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates.go index 4d6c33e988e23..a729c60d43c80 100644 --- a/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates.go +++ b/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates.go @@ -23,7 +23,6 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/kubernetes/pkg/scheduler/framework" - "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names" ) @@ -31,9 +30,7 @@ import ( const Name = names.SchedulingGates // SchedulingGates checks if a Pod carries .spec.schedulingGates. -type SchedulingGates struct { - EnablePodSchedulingReadiness bool -} +type SchedulingGates struct{} var _ framework.PreEnqueuePlugin = &SchedulingGates{} var _ framework.EnqueueExtensions = &SchedulingGates{} @@ -43,7 +40,7 @@ func (pl *SchedulingGates) Name() string { } func (pl *SchedulingGates) PreEnqueue(ctx context.Context, p *v1.Pod) *framework.Status { - if !pl.EnablePodSchedulingReadiness || len(p.Spec.SchedulingGates) == 0 { + if len(p.Spec.SchedulingGates) == 0 { return nil } gates := make([]string, 0, len(p.Spec.SchedulingGates)) @@ -60,6 +57,6 @@ func (pl *SchedulingGates) EventsToRegister() []framework.ClusterEventWithHint { } // New initializes a new plugin and returns it. -func New(_ context.Context, _ runtime.Object, _ framework.Handle, fts feature.Features) (framework.Plugin, error) { - return &SchedulingGates{EnablePodSchedulingReadiness: fts.EnablePodSchedulingReadiness}, nil +func New(_ context.Context, _ runtime.Object, _ framework.Handle) (framework.Plugin, error) { + return &SchedulingGates{}, nil } diff --git a/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates_test.go b/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates_test.go index b4bbc2a72f479..3c6ceea470f53 100644 --- a/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates_test.go +++ b/pkg/scheduler/framework/plugins/schedulinggates/scheduling_gates_test.go @@ -23,48 +23,32 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/kubernetes/pkg/scheduler/framework" - "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature" st "k8s.io/kubernetes/pkg/scheduler/testing" "k8s.io/kubernetes/test/utils/ktesting" ) func TestPreEnqueue(t *testing.T) { tests := []struct { - name string - pod *v1.Pod - enablePodSchedulingReadiness bool - want *framework.Status + name string + pod *v1.Pod + want *framework.Status }{ { - name: "pod does not carry scheduling gates, feature disabled", - pod: st.MakePod().Name("p").Obj(), - enablePodSchedulingReadiness: false, - want: nil, + name: "pod does not carry scheduling gates", + pod: st.MakePod().Name("p").Obj(), + want: nil, }, { - name: "pod does not carry scheduling gates, feature enabled", - pod: st.MakePod().Name("p").Obj(), - enablePodSchedulingReadiness: true, - want: nil, - }, - { - name: "pod carries scheduling gates, feature disabled", - pod: st.MakePod().Name("p").SchedulingGates([]string{"foo", "bar"}).Obj(), - enablePodSchedulingReadiness: false, - want: nil, - }, - { - name: "pod carries scheduling gates, feature enabled", - pod: st.MakePod().Name("p").SchedulingGates([]string{"foo", "bar"}).Obj(), - enablePodSchedulingReadiness: true, - want: framework.NewStatus(framework.UnschedulableAndUnresolvable, "waiting for scheduling gates: [foo bar]"), + name: "pod carries scheduling gates", + pod: st.MakePod().Name("p").SchedulingGates([]string{"foo", "bar"}).Obj(), + want: framework.NewStatus(framework.UnschedulableAndUnresolvable, "waiting for scheduling gates: [foo bar]"), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, ctx := ktesting.NewTestContext(t) - p, err := New(ctx, nil, nil, feature.Features{EnablePodSchedulingReadiness: tt.enablePodSchedulingReadiness}) + p, err := New(ctx, nil, nil) if err != nil { t.Fatalf("Creating plugin: %v", err) } diff --git a/staging/src/k8s.io/api/core/v1/generated.proto b/staging/src/k8s.io/api/core/v1/generated.proto index b5334a2dab107..7d1873fc75b64 100644 --- a/staging/src/k8s.io/api/core/v1/generated.proto +++ b/staging/src/k8s.io/api/core/v1/generated.proto @@ -4194,13 +4194,10 @@ message PodSpec { // // SchedulingGates can only be set at pod creation time, and be removed only afterwards. // - // This is a beta feature enabled by the PodSchedulingReadiness feature gate. - // // +patchMergeKey=name // +patchStrategy=merge // +listType=map // +listMapKey=name - // +featureGate=PodSchedulingReadiness // +optional repeated PodSchedulingGate schedulingGates = 38; diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go index d84b031b9ff9a..976c79979b77e 100644 --- a/staging/src/k8s.io/api/core/v1/types.go +++ b/staging/src/k8s.io/api/core/v1/types.go @@ -3797,13 +3797,10 @@ type PodSpec struct { // // SchedulingGates can only be set at pod creation time, and be removed only afterwards. // - // This is a beta feature enabled by the PodSchedulingReadiness feature gate. - // // +patchMergeKey=name // +patchStrategy=merge // +listType=map // +listMapKey=name - // +featureGate=PodSchedulingReadiness // +optional SchedulingGates []PodSchedulingGate `json:"schedulingGates,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,38,opt,name=schedulingGates"` // ResourceClaims defines which ResourceClaims must be allocated diff --git a/staging/src/k8s.io/api/core/v1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/core/v1/types_swagger_doc_generated.go index be8f0dfe07e43..d3e2997970689 100644 --- a/staging/src/k8s.io/api/core/v1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/core/v1/types_swagger_doc_generated.go @@ -1759,7 +1759,7 @@ var map_PodSpec = map[string]string{ "setHostnameAsFQDN": "If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. If a pod does not have FQDN, this has no effect. Default to false.", "os": "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup", "hostUsers": "Use the host's user namespace. Optional: Default to true. If set to true or not present, the pod will be run in the host user namespace, useful for when the pod needs a feature only available to the host user namespace, such as loading a kernel module with CAP_SYS_MODULE. When set to false, a new userns is created for the pod. Setting false is useful for mitigating container breakout vulnerabilities even allowing users to run their containers as root without actually having root privileges on the host. This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature.", - "schedulingGates": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.\n\nThis is a beta feature enabled by the PodSchedulingReadiness feature gate.", + "schedulingGates": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.", "resourceClaims": "ResourceClaims defines which ResourceClaims must be allocated and reserved before the Pod is allowed to start. The resources will be made available to those containers which consume them by name.\n\nThis is an alpha field and requires enabling the DynamicResourceAllocation feature gate.\n\nThis field is immutable.", } diff --git a/test/integration/pods/pods_test.go b/test/integration/pods/pods_test.go index 52ee551c3cdb6..18eeace6ea814 100644 --- a/test/integration/pods/pods_test.go +++ b/test/integration/pods/pods_test.go @@ -25,12 +25,9 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - utilfeature "k8s.io/apiserver/pkg/util/feature" clientset "k8s.io/client-go/kubernetes" typedv1 "k8s.io/client-go/kubernetes/typed/core/v1" - featuregatetesting "k8s.io/component-base/featuregate/testing" kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing" - "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/test/integration" "k8s.io/kubernetes/test/integration/framework" ) @@ -689,47 +686,11 @@ func TestMutablePodSchedulingDirectives(t *testing.T) { defer framework.DeleteNamespaceOrDie(client, ns, t) cases := []struct { - name string - create *v1.Pod - update *v1.Pod - enableSchedulingGates bool - err string + name string + create *v1.Pod + update *v1.Pod + err string }{ - { - name: "node selector is immutable when AllowMutableNodeSelector is false", - create: &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - { - Name: "fake-name", - Image: "fakeimage", - }, - }, - SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}}, - }, - }, - update: &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-pod", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - { - Name: "fake-name", - Image: "fakeimage", - }, - }, - NodeSelector: map[string]string{ - "foo": "bar", - }, - SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}}, - }, - }, - err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image", - }, { name: "adding node selector is allowed for gated pods", create: &v1.Pod{ @@ -763,7 +724,6 @@ func TestMutablePodSchedulingDirectives(t *testing.T) { SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}}, }, }, - enableSchedulingGates: true, }, { name: "addition to nodeAffinity is allowed for gated pods", @@ -842,7 +802,6 @@ func TestMutablePodSchedulingDirectives(t *testing.T) { SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}}, }, }, - enableSchedulingGates: true, }, { name: "addition to nodeAffinity is allowed for gated pods with nil affinity", @@ -899,12 +858,9 @@ func TestMutablePodSchedulingDirectives(t *testing.T) { SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}}, }, }, - enableSchedulingGates: true, }, } for _, tc := range cases { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, tc.enableSchedulingGates)() - if _, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), tc.create, metav1.CreateOptions{}); err != nil { t.Errorf("Failed to create pod: %v", err) } diff --git a/test/integration/scheduler/plugins/plugins_test.go b/test/integration/scheduler/plugins/plugins_test.go index c8900164649c9..63df54ecee1ba 100644 --- a/test/integration/scheduler/plugins/plugins_test.go +++ b/test/integration/scheduler/plugins/plugins_test.go @@ -33,12 +33,9 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/apiserver/pkg/util/feature" clientset "k8s.io/client-go/kubernetes" listersv1 "k8s.io/client-go/listers/core/v1" - featuregatetesting "k8s.io/component-base/featuregate/testing" configv1 "k8s.io/kube-scheduler/config/v1" - "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/scheduler" schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config" configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing" @@ -2199,8 +2196,6 @@ func TestPreScorePlugin(t *testing.T) { // TestPreEnqueuePlugin tests invocation of enqueue plugins. func TestPreEnqueuePlugin(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.PodSchedulingReadiness, true)() - testContext := testutils.InitTestAPIServer(t, "enqueue-plugin", nil) tests := []struct { @@ -2636,8 +2631,6 @@ func (pl *SchedulingGatesPluginWOEvents) EventsToRegister() []framework.ClusterE // This test helps to verify registering nil events for schedulingGates plugin works as expected. func TestSchedulingGatesPluginEventsToRegister(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.PodSchedulingReadiness, true)() - testContext := testutils.InitTestAPIServer(t, "preenqueue-plugin", nil) num := func(pl framework.Plugin) int { @@ -2659,12 +2652,12 @@ func TestSchedulingGatesPluginEventsToRegister(t *testing.T) { }{ { name: "preEnqueue plugin without event registered", - enqueuePlugin: &SchedulingGatesPluginWOEvents{SchedulingGates: schedulinggates.SchedulingGates{EnablePodSchedulingReadiness: true}}, + enqueuePlugin: &SchedulingGatesPluginWOEvents{SchedulingGates: schedulinggates.SchedulingGates{}}, count: 2, }, { name: "preEnqueue plugin with event registered", - enqueuePlugin: &SchedulingGatesPluginWithEvents{SchedulingGates: schedulinggates.SchedulingGates{EnablePodSchedulingReadiness: true}}, + enqueuePlugin: &SchedulingGatesPluginWithEvents{SchedulingGates: schedulinggates.SchedulingGates{}}, count: 3, }, } diff --git a/test/integration/scheduler/queue_test.go b/test/integration/scheduler/queue_test.go index 42535552916a9..6dfc1f714d8df 100644 --- a/test/integration/scheduler/queue_test.go +++ b/test/integration/scheduler/queue_test.go @@ -58,55 +58,33 @@ func TestSchedulingGates(t *testing.T) { tests := []struct { name string pods []*v1.Pod - featureEnabled bool want []string rmPodsSchedulingGates []int wantPostGatesRemoval []string }{ { - name: "feature disabled, regular pods", + name: "regular pods", pods: []*v1.Pod{ st.MakePod().Name("p1").Container("pause").Obj(), st.MakePod().Name("p2").Container("pause").Obj(), }, - featureEnabled: false, - want: []string{"p1", "p2"}, + want: []string{"p1", "p2"}, }, { - name: "feature enabled, regular pods", - pods: []*v1.Pod{ - st.MakePod().Name("p1").Container("pause").Obj(), - st.MakePod().Name("p2").Container("pause").Obj(), - }, - featureEnabled: true, - want: []string{"p1", "p2"}, - }, - { - name: "feature disabled, one pod carrying scheduling gates", + name: "one pod carrying scheduling gates", pods: []*v1.Pod{ st.MakePod().Name("p1").SchedulingGates([]string{"foo"}).Container("pause").Obj(), st.MakePod().Name("p2").Container("pause").Obj(), }, - featureEnabled: false, - want: []string{"p1", "p2"}, + want: []string{"p2"}, }, { - name: "feature enabled, one pod carrying scheduling gates", - pods: []*v1.Pod{ - st.MakePod().Name("p1").SchedulingGates([]string{"foo"}).Container("pause").Obj(), - st.MakePod().Name("p2").Container("pause").Obj(), - }, - featureEnabled: true, - want: []string{"p2"}, - }, - { - name: "feature enabled, two pod carrying scheduling gates, and remove gates of one pod", + name: "two pod carrying scheduling gates, and remove gates of one pod", pods: []*v1.Pod{ st.MakePod().Name("p1").SchedulingGates([]string{"foo"}).Container("pause").Obj(), st.MakePod().Name("p2").SchedulingGates([]string{"bar"}).Container("pause").Obj(), st.MakePod().Name("p3").Container("pause").Obj(), }, - featureEnabled: true, want: []string{"p3"}, rmPodsSchedulingGates: []int{1}, // remove gates of 'p2' wantPostGatesRemoval: []string{"p2"}, @@ -115,8 +93,6 @@ func TestSchedulingGates(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, tt.featureEnabled)() - // Use zero backoff seconds to bypass backoffQ. // It's intended to not start the scheduler's queue, and hence to // not start any flushing logic. We will pop and schedule the Pods manually later.