Merge pull request #123575 from Huang-Wei/pod-scheduling-readiness-stable

Graduate PodSchedulingReadiness to stable
This commit is contained in:
Kubernetes Prow Robot 2024-03-03 22:29:38 -08:00 committed by GitHub
commit e4a14fe0f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 97 additions and 521 deletions

View File

@ -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"
},

View File

@ -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": [
{

View File

@ -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": [
{

View File

@ -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": [
{

View File

@ -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{

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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)...)

View File

@ -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)

View File

@ -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},

View File

@ -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{

View File

@ -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) {
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()
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)
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)
}
_, 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)
}
if flipFeatureGateBeforeBinding {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, !tt.featureEnabled)()
} 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)
}
_, 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)
}
}
})
}
}
})
}
}

View File

@ -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
}

View File

@ -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",
name: "pod with .spec.schedulingGates",
pod: &api.Pod{
Spec: api.PodSpec{
SchedulingGates: []api.PodSchedulingGate{{Name: "foo"}},
},
},
featureEnabled: false,
want: api.PodCondition{},
},
{
name: "pod with .spec.schedulingGates, feature enabled",
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 {

View File

@ -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},
},
},
}

View File

@ -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

View File

@ -37,66 +37,34 @@ 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,
features.DynamicResourceAllocation: 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,
},
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: names.SchedulingGates},
{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},
},
},
},
@ -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},
},
},
},

View File

@ -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{

View File

@ -25,7 +25,6 @@ type Features struct {
EnableMinDomainsInPodTopologySpread bool
EnableNodeInclusionPolicyInPodTopologySpread bool
EnableMatchLabelKeysInPodTopologySpread bool
EnablePodSchedulingReadiness bool
EnablePodDisruptionConditions bool
EnableInPlacePodVerticalScaling bool
EnableSidecarContainers bool

View File

@ -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

View File

@ -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
}

View File

@ -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)
}

View File

@ -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;

View File

@ -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

View File

@ -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.",
}

View File

@ -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)
}

View File

@ -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,
},
}

View File

@ -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.