mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-13 13:55:41 +00:00
Graduate PodSchedulingReadiness to stable
This commit is contained in:
parent
a67973a45c
commit
01db4ae9e7
@ -239,23 +239,6 @@ leaderElection:
|
|||||||
"simplified-scheduler": defaults.ExpandedPluginsV1,
|
"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",
|
name: "default config",
|
||||||
flags: []string{
|
flags: []string{
|
||||||
|
@ -382,7 +382,6 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po
|
|||||||
AllowIndivisibleHugePagesValues: false,
|
AllowIndivisibleHugePagesValues: false,
|
||||||
AllowInvalidLabelValueInSelector: false,
|
AllowInvalidLabelValueInSelector: false,
|
||||||
AllowInvalidTopologySpreadConstraintLabelSelector: false,
|
AllowInvalidTopologySpreadConstraintLabelSelector: false,
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: utilfeature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness),
|
|
||||||
AllowNamespacedSysctlsForHostNetAndHostIPC: false,
|
AllowNamespacedSysctlsForHostNetAndHostIPC: false,
|
||||||
AllowNonLocalProjectedTokenPath: 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)
|
dropDisabledProcMountField(podSpec, oldPodSpec)
|
||||||
|
|
||||||
dropDisabledTopologySpreadConstraintsFields(podSpec, oldPodSpec)
|
dropDisabledTopologySpreadConstraintsFields(podSpec, oldPodSpec)
|
||||||
@ -983,14 +977,6 @@ func appArmorInUse(podAnnotations map[string]string) bool {
|
|||||||
return false
|
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
|
// restartableInitContainersInUse returns true if the pod spec is non-nil and
|
||||||
// it has any init container with ContainerRestartPolicyAlways.
|
// it has any init container with ContainerRestartPolicyAlways.
|
||||||
func restartableInitContainersInUse(podSpec *api.PodSpec) bool {
|
func restartableInitContainersInUse(podSpec *api.PodSpec) bool {
|
||||||
|
@ -2602,88 +2602,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) {
|
func TestValidateTopologySpreadConstraintLabelSelectorOption(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -3352,9 +3352,6 @@ type PodSpec struct {
|
|||||||
//
|
//
|
||||||
// SchedulingGates can only be set at pod creation time, and be removed only afterwards.
|
// 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
|
// +optional
|
||||||
SchedulingGates []PodSchedulingGate
|
SchedulingGates []PodSchedulingGate
|
||||||
// ResourceClaims defines which ResourceClaims must be allocated
|
// ResourceClaims defines which ResourceClaims must be allocated
|
||||||
|
@ -3974,8 +3974,6 @@ type PodValidationOptions struct {
|
|||||||
AllowHostIPsField bool
|
AllowHostIPsField bool
|
||||||
// Allow invalid topologySpreadConstraint labelSelector for backward compatibility
|
// Allow invalid topologySpreadConstraint labelSelector for backward compatibility
|
||||||
AllowInvalidTopologySpreadConstraintLabelSelector bool
|
AllowInvalidTopologySpreadConstraintLabelSelector bool
|
||||||
// Allow node selector additions for gated pods.
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity bool
|
|
||||||
// Allow projected token volumes with non-local paths
|
// Allow projected token volumes with non-local paths
|
||||||
AllowNonLocalProjectedTokenPath bool
|
AllowNonLocalProjectedTokenPath bool
|
||||||
// Allow namespaced sysctls in hostNet and hostIPC pods
|
// 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.
|
// Handle validations specific to gated pods.
|
||||||
podIsGated := len(oldPod.Spec.SchedulingGates) > 0
|
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.
|
// Additions to spec.nodeSelector are allowed (no deletions or mutations) for gated pods.
|
||||||
if !apiequality.Semantic.DeepEqual(mungedPodSpec.NodeSelector, oldPod.Spec.NodeSelector) {
|
if !apiequality.Semantic.DeepEqual(mungedPodSpec.NodeSelector, oldPod.Spec.NodeSelector) {
|
||||||
allErrs = append(allErrs, validateNodeSelectorMutation(specPath.Child("nodeSelector"), mungedPodSpec.NodeSelector, oldPod.Spec.NodeSelector)...)
|
allErrs = append(allErrs, validateNodeSelectorMutation(specPath.Child("nodeSelector"), mungedPodSpec.NodeSelector, oldPod.Spec.NodeSelector)...)
|
||||||
|
@ -12298,22 +12298,8 @@ func TestValidatePodCreateWithSchedulingGates(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
pod *core.Pod
|
pod *core.Pod
|
||||||
featureEnabled bool
|
|
||||||
wantFieldErrors field.ErrorList
|
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",
|
name: "create a Pod with nodeName and schedulingGates, feature enabled",
|
||||||
pod: &core.Pod{
|
pod: &core.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "pod", Namespace: "ns"},
|
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")},
|
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",
|
name: "create a Pod with schedulingGates, feature enabled",
|
||||||
pod: &core.Pod{
|
pod: &core.Pod{
|
||||||
@ -12348,15 +12321,12 @@ func TestValidatePodCreateWithSchedulingGates(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
featureEnabled: true,
|
|
||||||
wantFieldErrors: nil,
|
wantFieldErrors: nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, tt.featureEnabled)()
|
|
||||||
|
|
||||||
applyEssentials(tt.pod)
|
applyEssentials(tt.pod)
|
||||||
errs := ValidatePodCreate(tt.pod, PodValidationOptions{})
|
errs := ValidatePodCreate(tt.pod, PodValidationOptions{})
|
||||||
if diff := cmp.Diff(tt.wantFieldErrors, errs); diff != "" {
|
if diff := cmp.Diff(tt.wantFieldErrors, errs); diff != "" {
|
||||||
@ -12383,7 +12353,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
new core.Pod
|
new core.Pod
|
||||||
old core.Pod
|
old core.Pod
|
||||||
opts PodValidationOptions
|
|
||||||
err string
|
err string
|
||||||
test string
|
test string
|
||||||
}{
|
}{
|
||||||
@ -13716,25 +13685,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
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",
|
test: "adding node selector is allowed for gated pods",
|
||||||
}, {
|
}, {
|
||||||
old: core.Pod{
|
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",
|
err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image",
|
||||||
test: "adding node selector is not allowed for non-gated pods",
|
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"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "spec.nodeSelector: Invalid value:",
|
err: "spec.nodeSelector: Invalid value:",
|
||||||
test: "removing node selector is not allowed for gated pods",
|
test: "removing node selector is not allowed for gated pods",
|
||||||
}, {
|
}, {
|
||||||
@ -13785,9 +13729,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
new: core.Pod{},
|
new: core.Pod{},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image",
|
err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image",
|
||||||
test: "removing node selector is not allowed for non-gated pods",
|
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",
|
test: "old pod spec has scheduling gate, new pod spec does not, and node selector is added",
|
||||||
}, {
|
}, {
|
||||||
old: core.Pod{
|
old: core.Pod{
|
||||||
@ -13828,9 +13766,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "spec.nodeSelector: Invalid value:",
|
err: "spec.nodeSelector: Invalid value:",
|
||||||
test: "modifying value of existing node selector is not allowed",
|
test: "modifying value of existing node selector is not allowed",
|
||||||
}, {
|
}, {
|
||||||
@ -13880,9 +13815,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
test: "addition to nodeAffinity is allowed for gated pods",
|
test: "addition to nodeAffinity is allowed for gated pods",
|
||||||
}, {
|
}, {
|
||||||
old: core.Pod{
|
old: core.Pod{
|
||||||
@ -13911,9 +13843,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:",
|
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:",
|
||||||
test: "old RequiredDuringSchedulingIgnoredDuringExecution is non-nil, new RequiredDuringSchedulingIgnoredDuringExecution is nil, pod is gated",
|
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",
|
err: "Forbidden: pod updates may not change fields other than `spec.containers[*].image",
|
||||||
test: "addition to nodeAffinity is not allowed for non-gated pods",
|
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",
|
test: "old pod spec has scheduling gate, new pod spec does not, and node affinity addition occurs",
|
||||||
}, {
|
}, {
|
||||||
old: core.Pod{
|
old: core.Pod{
|
||||||
@ -14053,9 +13976,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:",
|
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:",
|
||||||
test: "nodeAffinity deletion from MatchExpressions not allowed",
|
test: "nodeAffinity deletion from MatchExpressions not allowed",
|
||||||
}, {
|
}, {
|
||||||
@ -14101,9 +14021,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:",
|
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:",
|
||||||
test: "nodeAffinity deletion from MatchFields not allowed",
|
test: "nodeAffinity deletion from MatchFields not allowed",
|
||||||
}, {
|
}, {
|
||||||
@ -14154,9 +14071,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:",
|
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:",
|
||||||
test: "nodeAffinity modification of item in MatchExpressions not allowed",
|
test: "nodeAffinity modification of item in MatchExpressions not allowed",
|
||||||
}, {
|
}, {
|
||||||
@ -14206,9 +14120,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:",
|
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:",
|
||||||
test: "nodeAffinity modification of item in MatchFields not allowed",
|
test: "nodeAffinity modification of item in MatchFields not allowed",
|
||||||
}, {
|
}, {
|
||||||
@ -14269,9 +14180,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:",
|
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:",
|
||||||
test: "nodeSelectorTerms addition on gated pod should fail",
|
test: "nodeSelectorTerms addition on gated pod should fail",
|
||||||
}, {
|
}, {
|
||||||
@ -14313,9 +14221,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
test: "preferredDuringSchedulingIgnoredDuringExecution can modified for gated pods",
|
test: "preferredDuringSchedulingIgnoredDuringExecution can modified for gated pods",
|
||||||
}, {
|
}, {
|
||||||
old: core.Pod{
|
old: core.Pod{
|
||||||
@ -14365,9 +14270,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
test: "preferredDuringSchedulingIgnoredDuringExecution can have additions for gated pods",
|
test: "preferredDuringSchedulingIgnoredDuringExecution can have additions for gated pods",
|
||||||
}, {
|
}, {
|
||||||
old: core.Pod{
|
old: core.Pod{
|
||||||
@ -14394,9 +14296,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
test: "preferredDuringSchedulingIgnoredDuringExecution can have removals for gated pods",
|
test: "preferredDuringSchedulingIgnoredDuringExecution can have removals for gated pods",
|
||||||
}, {
|
}, {
|
||||||
old: core.Pod{
|
old: core.Pod{
|
||||||
@ -14423,9 +14322,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:",
|
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms: Invalid value:",
|
||||||
test: "new node affinity is nil",
|
test: "new node affinity is nil",
|
||||||
}, {
|
}, {
|
||||||
@ -14453,9 +14349,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
test: "preferredDuringSchedulingIgnoredDuringExecution can have removals for gated pods",
|
test: "preferredDuringSchedulingIgnoredDuringExecution can have removals for gated pods",
|
||||||
}, {
|
}, {
|
||||||
old: core.Pod{
|
old: core.Pod{
|
||||||
@ -14490,9 +14383,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:",
|
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:",
|
||||||
test: "empty NodeSelectorTerm (selects nothing) cannot become populated (selects something)",
|
test: "empty NodeSelectorTerm (selects nothing) cannot become populated (selects something)",
|
||||||
}, {
|
}, {
|
||||||
@ -14520,9 +14410,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
test: "nil affinity can be mutated for gated pods",
|
test: "nil affinity can be mutated for gated pods",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -14560,9 +14447,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "pod updates may not change fields other than",
|
err: "pod updates may not change fields other than",
|
||||||
test: "the podAffinity cannot be updated on gated pods",
|
test: "the podAffinity cannot be updated on gated pods",
|
||||||
},
|
},
|
||||||
@ -14601,9 +14485,6 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opts: PodValidationOptions{
|
|
||||||
AllowMutableNodeSelectorAndNodeAffinity: true,
|
|
||||||
},
|
|
||||||
err: "pod updates may not change fields other than",
|
err: "pod updates may not change fields other than",
|
||||||
test: "the podAntiAffinity cannot be updated on gated pods",
|
test: "the podAntiAffinity cannot be updated on gated pods",
|
||||||
},
|
},
|
||||||
@ -14634,7 +14515,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
test.old.Spec.RestartPolicy = "Always"
|
test.old.Spec.RestartPolicy = "Always"
|
||||||
}
|
}
|
||||||
|
|
||||||
errs := ValidatePodUpdate(&test.new, &test.old, test.opts)
|
errs := ValidatePodUpdate(&test.new, &test.old, PodValidationOptions{})
|
||||||
if test.err == "" {
|
if test.err == "" {
|
||||||
if len(errs) != 0 {
|
if len(errs) != 0 {
|
||||||
t.Errorf("unexpected invalid: %s (%+v)\nA: %+v\nB: %+v", test.test, errs, test.new, test.old)
|
t.Errorf("unexpected invalid: %s (%+v)\nA: %+v\nB: %+v", test.test, errs, test.new, test.old)
|
||||||
|
@ -612,6 +612,7 @@ const (
|
|||||||
// kep: https://kep.k8s.io/3521
|
// kep: https://kep.k8s.io/3521
|
||||||
// alpha: v1.26
|
// alpha: v1.26
|
||||||
// beta: v1.27
|
// beta: v1.27
|
||||||
|
// stable: v1.30
|
||||||
//
|
//
|
||||||
// Enable users to specify when a Pod is ready for scheduling.
|
// Enable users to specify when a Pod is ready for scheduling.
|
||||||
PodSchedulingReadiness featuregate.Feature = "PodSchedulingReadiness"
|
PodSchedulingReadiness featuregate.Feature = "PodSchedulingReadiness"
|
||||||
@ -1092,7 +1093,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||||||
|
|
||||||
PodLifecycleSleepAction: {Default: true, PreRelease: featuregate.Beta},
|
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},
|
ProcMountType: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
|
|
||||||
|
@ -42,10 +42,7 @@ import (
|
|||||||
apiserverstorage "k8s.io/apiserver/pkg/storage"
|
apiserverstorage "k8s.io/apiserver/pkg/storage"
|
||||||
storeerr "k8s.io/apiserver/pkg/storage/errors"
|
storeerr "k8s.io/apiserver/pkg/storage/errors"
|
||||||
etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing"
|
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"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||||
"k8s.io/kubernetes/pkg/securitycontext"
|
"k8s.io/kubernetes/pkg/securitycontext"
|
||||||
)
|
)
|
||||||
@ -752,22 +749,11 @@ func TestEtcdCreateWithConflict(t *testing.T) {
|
|||||||
func TestEtcdCreateWithSchedulingGates(t *testing.T) {
|
func TestEtcdCreateWithSchedulingGates(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
featureEnabled bool
|
|
||||||
schedulingGates []api.PodSchedulingGate
|
schedulingGates []api.PodSchedulingGate
|
||||||
wantErr error
|
wantErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "pod with non-nil schedulingGates, feature disabled",
|
name: "pod with non-nil schedulingGates",
|
||||||
featureEnabled: false,
|
|
||||||
schedulingGates: []api.PodSchedulingGate{
|
|
||||||
{Name: "foo"},
|
|
||||||
{Name: "bar"},
|
|
||||||
},
|
|
||||||
wantErr: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "pod with non-nil schedulingGates, feature enabled",
|
|
||||||
featureEnabled: true,
|
|
||||||
schedulingGates: []api.PodSchedulingGate{
|
schedulingGates: []api.PodSchedulingGate{
|
||||||
{Name: "foo"},
|
{Name: "foo"},
|
||||||
{Name: "bar"},
|
{Name: "bar"},
|
||||||
@ -775,26 +761,14 @@ func TestEtcdCreateWithSchedulingGates(t *testing.T) {
|
|||||||
wantErr: goerrors.New(`Operation cannot be fulfilled on pods/binding "foo": pod foo has non-empty .spec.schedulingGates`),
|
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",
|
name: "pod with nil schedulingGates",
|
||||||
featureEnabled: false,
|
|
||||||
schedulingGates: nil,
|
|
||||||
wantErr: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "pod with nil schedulingGates, feature enabled",
|
|
||||||
featureEnabled: true,
|
|
||||||
schedulingGates: nil,
|
schedulingGates: nil,
|
||||||
wantErr: nil,
|
wantErr: nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
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) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, tt.featureEnabled)()
|
|
||||||
storage, bindingStorage, _, server := newStorage(t)
|
storage, bindingStorage, _, server := newStorage(t)
|
||||||
defer server.Terminate(t)
|
defer server.Terminate(t)
|
||||||
defer storage.Store.DestroyFunc()
|
defer storage.Store.DestroyFunc()
|
||||||
@ -805,9 +779,6 @@ func TestEtcdCreateWithSchedulingGates(t *testing.T) {
|
|||||||
if _, err := storage.Create(ctx, pod, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}); err != nil {
|
if _, err := storage.Create(ctx, pod, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}); err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
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{
|
_, err := bindingStorage.Create(ctx, "foo", &api.Binding{
|
||||||
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "foo"},
|
ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "foo"},
|
||||||
Target: api.ObjectReference{Name: "machine"},
|
Target: api.ObjectReference{Name: "machine"},
|
||||||
@ -825,7 +796,6 @@ func TestEtcdCreateWithSchedulingGates(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validNewBinding() *api.Binding {
|
func validNewBinding() *api.Binding {
|
||||||
|
@ -740,8 +740,7 @@ func mutatePodAffinity(pod *api.Pod) {
|
|||||||
// applySchedulingGatedCondition adds a {type:PodScheduled, reason:SchedulingGated} condition
|
// applySchedulingGatedCondition adds a {type:PodScheduled, reason:SchedulingGated} condition
|
||||||
// to a new-created Pod if necessary.
|
// to a new-created Pod if necessary.
|
||||||
func applySchedulingGatedCondition(pod *api.Pod) {
|
func applySchedulingGatedCondition(pod *api.Pod) {
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness) ||
|
if len(pod.Spec.SchedulingGates) == 0 {
|
||||||
len(pod.Spec.SchedulingGates) == 0 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,39 +316,20 @@ func TestSchedulingGatedCondition(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
pod *api.Pod
|
pod *api.Pod
|
||||||
featureEnabled bool
|
|
||||||
want api.PodCondition
|
want api.PodCondition
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "pod without .spec.schedulingGates, feature disabled",
|
name: "pod without .spec.schedulingGates",
|
||||||
pod: &api.Pod{},
|
pod: &api.Pod{},
|
||||||
featureEnabled: false,
|
|
||||||
want: api.PodCondition{},
|
want: api.PodCondition{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pod without .spec.schedulingGates, feature enabled",
|
name: "pod with .spec.schedulingGates",
|
||||||
pod: &api.Pod{},
|
|
||||||
featureEnabled: true,
|
|
||||||
want: api.PodCondition{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "pod with .spec.schedulingGates, feature disabled",
|
|
||||||
pod: &api.Pod{
|
pod: &api.Pod{
|
||||||
Spec: api.PodSpec{
|
Spec: api.PodSpec{
|
||||||
SchedulingGates: []api.PodSchedulingGate{{Name: "foo"}},
|
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{
|
want: api.PodCondition{
|
||||||
Type: api.PodScheduled,
|
Type: api.PodScheduled,
|
||||||
Status: api.ConditionFalse,
|
Status: api.ConditionFalse,
|
||||||
@ -360,8 +341,6 @@ func TestSchedulingGatedCondition(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, tt.featureEnabled)()
|
|
||||||
|
|
||||||
Strategy.PrepareForCreate(genericapirequest.NewContext(), tt.pod)
|
Strategy.PrepareForCreate(genericapirequest.NewContext(), tt.pod)
|
||||||
var got api.PodCondition
|
var got api.PodCondition
|
||||||
for _, condition := range tt.pod.Status.Conditions {
|
for _, condition := range tt.pod.Status.Conditions {
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
var PluginsV1 = &config.Plugins{
|
var PluginsV1 = &config.Plugins{
|
||||||
MultiPoint: config.PluginSet{
|
MultiPoint: config.PluginSet{
|
||||||
Enabled: []config.Plugin{
|
Enabled: []config.Plugin{
|
||||||
|
{Name: names.SchedulingGates},
|
||||||
{Name: names.PrioritySort},
|
{Name: names.PrioritySort},
|
||||||
{Name: names.NodeUnschedulable},
|
{Name: names.NodeUnschedulable},
|
||||||
{Name: names.NodeName},
|
{Name: names.NodeName},
|
||||||
@ -45,7 +46,6 @@ var PluginsV1 = &config.Plugins{
|
|||||||
{Name: names.NodeResourcesBalancedAllocation, Weight: 1},
|
{Name: names.NodeResourcesBalancedAllocation, Weight: 1},
|
||||||
{Name: names.ImageLocality, Weight: 1},
|
{Name: names.ImageLocality, Weight: 1},
|
||||||
{Name: names.DefaultBinder},
|
{Name: names.DefaultBinder},
|
||||||
{Name: names.SchedulingGates},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ func getDefaultPlugins() *v1.Plugins {
|
|||||||
plugins := &v1.Plugins{
|
plugins := &v1.Plugins{
|
||||||
MultiPoint: v1.PluginSet{
|
MultiPoint: v1.PluginSet{
|
||||||
Enabled: []v1.Plugin{
|
Enabled: []v1.Plugin{
|
||||||
|
{Name: names.SchedulingGates},
|
||||||
{Name: names.PrioritySort},
|
{Name: names.PrioritySort},
|
||||||
{Name: names.NodeUnschedulable},
|
{Name: names.NodeUnschedulable},
|
||||||
{Name: names.NodeName},
|
{Name: names.NodeName},
|
||||||
@ -60,9 +61,6 @@ func getDefaultPlugins() *v1.Plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func applyFeatureGates(config *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) {
|
if utilfeature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation) {
|
||||||
// This plugin should come before DefaultPreemption because if
|
// This plugin should come before DefaultPreemption because if
|
||||||
// there is a problem with a Pod and PostFilter gets called to
|
// there is a problem with a Pod and PostFilter gets called to
|
||||||
|
@ -37,66 +37,34 @@ func TestApplyFeatureGates(t *testing.T) {
|
|||||||
wantConfig *v1.Plugins
|
wantConfig *v1.Plugins
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Feature gates disabled",
|
name: "Feature gate DynamicResourceAllocation disabled",
|
||||||
features: map[featuregate.Feature]bool{
|
features: map[featuregate.Feature]bool{
|
||||||
features.PodSchedulingReadiness: false,
|
features.DynamicResourceAllocation: false,
|
||||||
},
|
},
|
||||||
wantConfig: &v1.Plugins{
|
wantConfig: &v1.Plugins{
|
||||||
MultiPoint: v1.PluginSet{
|
MultiPoint: v1.PluginSet{
|
||||||
Enabled: []v1.Plugin{
|
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.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{
|
wantConfig: &v1.Plugins{
|
||||||
MultiPoint: v1.PluginSet{
|
MultiPoint: v1.PluginSet{
|
||||||
Enabled: []v1.Plugin{
|
Enabled: []v1.Plugin{
|
||||||
|
{Name: names.SchedulingGates},
|
||||||
{Name: names.PrioritySort},
|
{Name: names.PrioritySort},
|
||||||
{Name: names.NodeUnschedulable},
|
{Name: names.NodeUnschedulable},
|
||||||
{Name: names.NodeName},
|
{Name: names.NodeName},
|
||||||
@ -130,7 +99,6 @@ func TestApplyFeatureGates(t *testing.T) {
|
|||||||
{Name: names.NodeResourcesBalancedAllocation, Weight: ptr.To[int32](1)},
|
{Name: names.NodeResourcesBalancedAllocation, Weight: ptr.To[int32](1)},
|
||||||
{Name: names.ImageLocality, Weight: ptr.To[int32](1)},
|
{Name: names.ImageLocality, Weight: ptr.To[int32](1)},
|
||||||
{Name: names.DefaultBinder},
|
{Name: names.DefaultBinder},
|
||||||
{Name: names.SchedulingGates},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -331,6 +331,7 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
Plugins: &configv1.Plugins{
|
Plugins: &configv1.Plugins{
|
||||||
MultiPoint: configv1.PluginSet{
|
MultiPoint: configv1.PluginSet{
|
||||||
Enabled: []configv1.Plugin{
|
Enabled: []configv1.Plugin{
|
||||||
|
{Name: names.SchedulingGates},
|
||||||
{Name: names.PrioritySort},
|
{Name: names.PrioritySort},
|
||||||
{Name: names.NodeUnschedulable},
|
{Name: names.NodeUnschedulable},
|
||||||
{Name: names.NodeName},
|
{Name: names.NodeName},
|
||||||
@ -351,7 +352,6 @@ func TestSchedulerDefaults(t *testing.T) {
|
|||||||
{Name: names.NodeResourcesBalancedAllocation, Weight: ptr.To[int32](1)},
|
{Name: names.NodeResourcesBalancedAllocation, Weight: ptr.To[int32](1)},
|
||||||
{Name: names.ImageLocality, Weight: ptr.To[int32](1)},
|
{Name: names.ImageLocality, Weight: ptr.To[int32](1)},
|
||||||
{Name: names.DefaultBinder},
|
{Name: names.DefaultBinder},
|
||||||
{Name: names.SchedulingGates},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Bind: configv1.PluginSet{
|
Bind: configv1.PluginSet{
|
||||||
|
@ -25,7 +25,6 @@ type Features struct {
|
|||||||
EnableMinDomainsInPodTopologySpread bool
|
EnableMinDomainsInPodTopologySpread bool
|
||||||
EnableNodeInclusionPolicyInPodTopologySpread bool
|
EnableNodeInclusionPolicyInPodTopologySpread bool
|
||||||
EnableMatchLabelKeysInPodTopologySpread bool
|
EnableMatchLabelKeysInPodTopologySpread bool
|
||||||
EnablePodSchedulingReadiness bool
|
|
||||||
EnablePodDisruptionConditions bool
|
EnablePodDisruptionConditions bool
|
||||||
EnableInPlacePodVerticalScaling bool
|
EnableInPlacePodVerticalScaling bool
|
||||||
EnableSidecarContainers bool
|
EnableSidecarContainers bool
|
||||||
|
@ -51,7 +51,6 @@ func NewInTreeRegistry() runtime.Registry {
|
|||||||
EnableMinDomainsInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MinDomainsInPodTopologySpread),
|
EnableMinDomainsInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MinDomainsInPodTopologySpread),
|
||||||
EnableNodeInclusionPolicyInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.NodeInclusionPolicyInPodTopologySpread),
|
EnableNodeInclusionPolicyInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.NodeInclusionPolicyInPodTopologySpread),
|
||||||
EnableMatchLabelKeysInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MatchLabelKeysInPodTopologySpread),
|
EnableMatchLabelKeysInPodTopologySpread: feature.DefaultFeatureGate.Enabled(features.MatchLabelKeysInPodTopologySpread),
|
||||||
EnablePodSchedulingReadiness: feature.DefaultFeatureGate.Enabled(features.PodSchedulingReadiness),
|
|
||||||
EnablePodDisruptionConditions: feature.DefaultFeatureGate.Enabled(features.PodDisruptionConditions),
|
EnablePodDisruptionConditions: feature.DefaultFeatureGate.Enabled(features.PodDisruptionConditions),
|
||||||
EnableInPlacePodVerticalScaling: feature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling),
|
EnableInPlacePodVerticalScaling: feature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling),
|
||||||
EnableSidecarContainers: feature.DefaultFeatureGate.Enabled(features.SidecarContainers),
|
EnableSidecarContainers: feature.DefaultFeatureGate.Enabled(features.SidecarContainers),
|
||||||
@ -80,7 +79,7 @@ func NewInTreeRegistry() runtime.Registry {
|
|||||||
queuesort.Name: queuesort.New,
|
queuesort.Name: queuesort.New,
|
||||||
defaultbinder.Name: defaultbinder.New,
|
defaultbinder.Name: defaultbinder.New,
|
||||||
defaultpreemption.Name: runtime.FactoryAdapter(fts, defaultpreemption.New),
|
defaultpreemption.Name: runtime.FactoryAdapter(fts, defaultpreemption.New),
|
||||||
schedulinggates.Name: runtime.FactoryAdapter(fts, schedulinggates.New),
|
schedulinggates.Name: schedulinggates.New,
|
||||||
}
|
}
|
||||||
|
|
||||||
return registry
|
return registry
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework"
|
"k8s.io/kubernetes/pkg/scheduler/framework"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
|
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,9 +30,7 @@ import (
|
|||||||
const Name = names.SchedulingGates
|
const Name = names.SchedulingGates
|
||||||
|
|
||||||
// SchedulingGates checks if a Pod carries .spec.schedulingGates.
|
// SchedulingGates checks if a Pod carries .spec.schedulingGates.
|
||||||
type SchedulingGates struct {
|
type SchedulingGates struct{}
|
||||||
EnablePodSchedulingReadiness bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ framework.PreEnqueuePlugin = &SchedulingGates{}
|
var _ framework.PreEnqueuePlugin = &SchedulingGates{}
|
||||||
var _ framework.EnqueueExtensions = &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 {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
gates := make([]string, 0, len(p.Spec.SchedulingGates))
|
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.
|
// New initializes a new plugin and returns it.
|
||||||
func New(_ context.Context, _ runtime.Object, _ framework.Handle, fts feature.Features) (framework.Plugin, error) {
|
func New(_ context.Context, _ runtime.Object, _ framework.Handle) (framework.Plugin, error) {
|
||||||
return &SchedulingGates{EnablePodSchedulingReadiness: fts.EnablePodSchedulingReadiness}, nil
|
return &SchedulingGates{}, nil
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework"
|
"k8s.io/kubernetes/pkg/scheduler/framework"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature"
|
|
||||||
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
st "k8s.io/kubernetes/pkg/scheduler/testing"
|
||||||
"k8s.io/kubernetes/test/utils/ktesting"
|
"k8s.io/kubernetes/test/utils/ktesting"
|
||||||
)
|
)
|
||||||
@ -32,31 +31,16 @@ func TestPreEnqueue(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
pod *v1.Pod
|
pod *v1.Pod
|
||||||
enablePodSchedulingReadiness bool
|
|
||||||
want *framework.Status
|
want *framework.Status
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "pod does not carry scheduling gates, feature disabled",
|
name: "pod does not carry scheduling gates",
|
||||||
pod: st.MakePod().Name("p").Obj(),
|
pod: st.MakePod().Name("p").Obj(),
|
||||||
enablePodSchedulingReadiness: false,
|
|
||||||
want: nil,
|
want: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pod does not carry scheduling gates, feature enabled",
|
name: "pod carries scheduling gates",
|
||||||
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(),
|
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]"),
|
want: framework.NewStatus(framework.UnschedulableAndUnresolvable, "waiting for scheduling gates: [foo bar]"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -64,7 +48,7 @@ func TestPreEnqueue(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
_, ctx := ktesting.NewTestContext(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 {
|
if err != nil {
|
||||||
t.Fatalf("Creating plugin: %v", err)
|
t.Fatalf("Creating plugin: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -3797,13 +3797,10 @@ type PodSpec struct {
|
|||||||
//
|
//
|
||||||
// SchedulingGates can only be set at pod creation time, and be removed only afterwards.
|
// 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
|
// +patchMergeKey=name
|
||||||
// +patchStrategy=merge
|
// +patchStrategy=merge
|
||||||
// +listType=map
|
// +listType=map
|
||||||
// +listMapKey=name
|
// +listMapKey=name
|
||||||
// +featureGate=PodSchedulingReadiness
|
|
||||||
// +optional
|
// +optional
|
||||||
SchedulingGates []PodSchedulingGate `json:"schedulingGates,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,38,opt,name=schedulingGates"`
|
SchedulingGates []PodSchedulingGate `json:"schedulingGates,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,38,opt,name=schedulingGates"`
|
||||||
// ResourceClaims defines which ResourceClaims must be allocated
|
// ResourceClaims defines which ResourceClaims must be allocated
|
||||||
|
@ -25,12 +25,9 @@ import (
|
|||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
typedv1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
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"
|
kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
"k8s.io/kubernetes/test/integration"
|
"k8s.io/kubernetes/test/integration"
|
||||||
"k8s.io/kubernetes/test/integration/framework"
|
"k8s.io/kubernetes/test/integration/framework"
|
||||||
)
|
)
|
||||||
@ -692,44 +689,8 @@ func TestMutablePodSchedulingDirectives(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
create *v1.Pod
|
create *v1.Pod
|
||||||
update *v1.Pod
|
update *v1.Pod
|
||||||
enableSchedulingGates bool
|
|
||||||
err string
|
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",
|
name: "adding node selector is allowed for gated pods",
|
||||||
create: &v1.Pod{
|
create: &v1.Pod{
|
||||||
@ -763,7 +724,6 @@ func TestMutablePodSchedulingDirectives(t *testing.T) {
|
|||||||
SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
enableSchedulingGates: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "addition to nodeAffinity is allowed for gated pods",
|
name: "addition to nodeAffinity is allowed for gated pods",
|
||||||
@ -842,7 +802,6 @@ func TestMutablePodSchedulingDirectives(t *testing.T) {
|
|||||||
SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}},
|
SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
enableSchedulingGates: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "addition to nodeAffinity is allowed for gated pods with nil affinity",
|
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"}},
|
SchedulingGates: []v1.PodSchedulingGate{{Name: "baz"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
enableSchedulingGates: true,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
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 {
|
if _, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), tc.create, metav1.CreateOptions{}); err != nil {
|
||||||
t.Errorf("Failed to create pod: %v", err)
|
t.Errorf("Failed to create pod: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,9 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apiserver/pkg/util/feature"
|
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
listersv1 "k8s.io/client-go/listers/core/v1"
|
listersv1 "k8s.io/client-go/listers/core/v1"
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
|
||||||
configv1 "k8s.io/kube-scheduler/config/v1"
|
configv1 "k8s.io/kube-scheduler/config/v1"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
"k8s.io/kubernetes/pkg/scheduler"
|
"k8s.io/kubernetes/pkg/scheduler"
|
||||||
schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
schedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing"
|
configtesting "k8s.io/kubernetes/pkg/scheduler/apis/config/testing"
|
||||||
@ -2199,8 +2196,6 @@ func TestPreScorePlugin(t *testing.T) {
|
|||||||
|
|
||||||
// TestPreEnqueuePlugin tests invocation of enqueue plugins.
|
// TestPreEnqueuePlugin tests invocation of enqueue plugins.
|
||||||
func TestPreEnqueuePlugin(t *testing.T) {
|
func TestPreEnqueuePlugin(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.PodSchedulingReadiness, true)()
|
|
||||||
|
|
||||||
testContext := testutils.InitTestAPIServer(t, "enqueue-plugin", nil)
|
testContext := testutils.InitTestAPIServer(t, "enqueue-plugin", nil)
|
||||||
|
|
||||||
tests := []struct {
|
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.
|
// This test helps to verify registering nil events for schedulingGates plugin works as expected.
|
||||||
func TestSchedulingGatesPluginEventsToRegister(t *testing.T) {
|
func TestSchedulingGatesPluginEventsToRegister(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.PodSchedulingReadiness, true)()
|
|
||||||
|
|
||||||
testContext := testutils.InitTestAPIServer(t, "preenqueue-plugin", nil)
|
testContext := testutils.InitTestAPIServer(t, "preenqueue-plugin", nil)
|
||||||
|
|
||||||
num := func(pl framework.Plugin) int {
|
num := func(pl framework.Plugin) int {
|
||||||
@ -2659,12 +2652,12 @@ func TestSchedulingGatesPluginEventsToRegister(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "preEnqueue plugin without event registered",
|
name: "preEnqueue plugin without event registered",
|
||||||
enqueuePlugin: &SchedulingGatesPluginWOEvents{SchedulingGates: schedulinggates.SchedulingGates{EnablePodSchedulingReadiness: true}},
|
enqueuePlugin: &SchedulingGatesPluginWOEvents{SchedulingGates: schedulinggates.SchedulingGates{}},
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "preEnqueue plugin with event registered",
|
name: "preEnqueue plugin with event registered",
|
||||||
enqueuePlugin: &SchedulingGatesPluginWithEvents{SchedulingGates: schedulinggates.SchedulingGates{EnablePodSchedulingReadiness: true}},
|
enqueuePlugin: &SchedulingGatesPluginWithEvents{SchedulingGates: schedulinggates.SchedulingGates{}},
|
||||||
count: 3,
|
count: 3,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -58,55 +58,33 @@ func TestSchedulingGates(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
pods []*v1.Pod
|
pods []*v1.Pod
|
||||||
featureEnabled bool
|
|
||||||
want []string
|
want []string
|
||||||
rmPodsSchedulingGates []int
|
rmPodsSchedulingGates []int
|
||||||
wantPostGatesRemoval []string
|
wantPostGatesRemoval []string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "feature disabled, regular pods",
|
name: "regular pods",
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
st.MakePod().Name("p1").Container("pause").Obj(),
|
st.MakePod().Name("p1").Container("pause").Obj(),
|
||||||
st.MakePod().Name("p2").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",
|
name: "one pod carrying scheduling gates",
|
||||||
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",
|
|
||||||
pods: []*v1.Pod{
|
pods: []*v1.Pod{
|
||||||
st.MakePod().Name("p1").SchedulingGates([]string{"foo"}).Container("pause").Obj(),
|
st.MakePod().Name("p1").SchedulingGates([]string{"foo"}).Container("pause").Obj(),
|
||||||
st.MakePod().Name("p2").Container("pause").Obj(),
|
st.MakePod().Name("p2").Container("pause").Obj(),
|
||||||
},
|
},
|
||||||
featureEnabled: false,
|
|
||||||
want: []string{"p1", "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"},
|
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{
|
pods: []*v1.Pod{
|
||||||
st.MakePod().Name("p1").SchedulingGates([]string{"foo"}).Container("pause").Obj(),
|
st.MakePod().Name("p1").SchedulingGates([]string{"foo"}).Container("pause").Obj(),
|
||||||
st.MakePod().Name("p2").SchedulingGates([]string{"bar"}).Container("pause").Obj(),
|
st.MakePod().Name("p2").SchedulingGates([]string{"bar"}).Container("pause").Obj(),
|
||||||
st.MakePod().Name("p3").Container("pause").Obj(),
|
st.MakePod().Name("p3").Container("pause").Obj(),
|
||||||
},
|
},
|
||||||
featureEnabled: true,
|
|
||||||
want: []string{"p3"},
|
want: []string{"p3"},
|
||||||
rmPodsSchedulingGates: []int{1}, // remove gates of 'p2'
|
rmPodsSchedulingGates: []int{1}, // remove gates of 'p2'
|
||||||
wantPostGatesRemoval: []string{"p2"},
|
wantPostGatesRemoval: []string{"p2"},
|
||||||
@ -115,8 +93,6 @@ func TestSchedulingGates(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
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.
|
// Use zero backoff seconds to bypass backoffQ.
|
||||||
// It's intended to not start the scheduler's queue, and hence to
|
// 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.
|
// not start any flushing logic. We will pop and schedule the Pods manually later.
|
||||||
|
Loading…
Reference in New Issue
Block a user