mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 12:07:47 +00:00
Updating the nodeAffinity of gated pods having nil affinity should be allowed
This commit is contained in:
parent
54d2ced4d6
commit
4c9887e3eb
@ -4753,7 +4753,14 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel
|
|||||||
// already effectively nil, no change needed
|
// already effectively nil, no change needed
|
||||||
case mungedPodSpec.Affinity == nil && oldNodeAffinity != nil:
|
case mungedPodSpec.Affinity == nil && oldNodeAffinity != nil:
|
||||||
mungedPodSpec.Affinity = &core.Affinity{NodeAffinity: oldNodeAffinity} // +k8s:verify-mutation:reason=clone
|
mungedPodSpec.Affinity = &core.Affinity{NodeAffinity: oldNodeAffinity} // +k8s:verify-mutation:reason=clone
|
||||||
|
case mungedPodSpec.Affinity != nil && oldPod.Spec.Affinity == nil &&
|
||||||
|
mungedPodSpec.Affinity.PodAntiAffinity == nil && mungedPodSpec.Affinity.PodAffinity == nil:
|
||||||
|
// We ensure no other fields are being changed, but the NodeAffinity. If that's the case, and the
|
||||||
|
// old pod's affinity is nil, we set the mungedPodSpec's affinity to nil.
|
||||||
|
mungedPodSpec.Affinity = nil // +k8s:verify-mutation:reason=clone
|
||||||
default:
|
default:
|
||||||
|
// The node affinity is being updated and the old pod Affinity is not nil.
|
||||||
|
// We set the mungedPodSpec's node affinity to the old pod's node affinity.
|
||||||
mungedPodSpec.Affinity.NodeAffinity = oldNodeAffinity // +k8s:verify-mutation:reason=clone
|
mungedPodSpec.Affinity.NodeAffinity = oldNodeAffinity // +k8s:verify-mutation:reason=clone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12836,6 +12836,117 @@ func TestValidatePodUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
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)",
|
||||||
|
}, {
|
||||||
|
old: core.Pod{
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Affinity: nil,
|
||||||
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new: core.Pod{
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Affinity: &core.Affinity{
|
||||||
|
NodeAffinity: &core.NodeAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{
|
||||||
|
NodeSelectorTerms: []core.NodeSelectorTerm{{
|
||||||
|
MatchExpressions: []core.NodeSelectorRequirement{{
|
||||||
|
Key: "expr",
|
||||||
|
Operator: core.NodeSelectorOpIn,
|
||||||
|
Values: []string{"foo"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
opts: PodValidationOptions{
|
||||||
|
AllowMutableNodeSelectorAndNodeAffinity: true,
|
||||||
|
},
|
||||||
|
test: "nil affinity can be mutated for gated pods",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: core.Pod{
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Affinity: nil,
|
||||||
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new: core.Pod{
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Affinity: &core.Affinity{
|
||||||
|
NodeAffinity: &core.NodeAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{
|
||||||
|
NodeSelectorTerms: []core.NodeSelectorTerm{{
|
||||||
|
MatchExpressions: []core.NodeSelectorRequirement{{
|
||||||
|
Key: "expr",
|
||||||
|
Operator: core.NodeSelectorOpIn,
|
||||||
|
Values: []string{"foo"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PodAffinity: &core.PodAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
TopologyKey: "foo",
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{"foo": "bar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: core.Pod{
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Affinity: nil,
|
||||||
|
SchedulingGates: []core.PodSchedulingGate{{Name: "baz"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new: core.Pod{
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Affinity: &core.Affinity{
|
||||||
|
NodeAffinity: &core.NodeAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: &core.NodeSelector{
|
||||||
|
NodeSelectorTerms: []core.NodeSelectorTerm{{
|
||||||
|
MatchExpressions: []core.NodeSelectorRequirement{{
|
||||||
|
Key: "expr",
|
||||||
|
Operator: core.NodeSelectorOpIn,
|
||||||
|
Values: []string{"foo"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PodAntiAffinity: &core.PodAntiAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||||
|
{
|
||||||
|
TopologyKey: "foo",
|
||||||
|
LabelSelector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{"foo": "bar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
@ -844,6 +844,63 @@ func TestMutablePodSchedulingDirectives(t *testing.T) {
|
|||||||
},
|
},
|
||||||
enableSchedulingGates: true,
|
enableSchedulingGates: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "addition to nodeAffinity is allowed for gated pods with nil affinity",
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Affinity: &v1.Affinity{
|
||||||
|
NodeAffinity: &v1.NodeAffinity{
|
||||||
|
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
||||||
|
// Add 1 MatchExpression and 1 MatchField.
|
||||||
|
NodeSelectorTerms: []v1.NodeSelectorTerm{
|
||||||
|
{
|
||||||
|
MatchExpressions: []v1.NodeSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "expr",
|
||||||
|
Operator: v1.NodeSelectorOpIn,
|
||||||
|
Values: []string{"foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MatchFields: []v1.NodeSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "metadata.name",
|
||||||
|
Operator: v1.NodeSelectorOpIn,
|
||||||
|
Values: []string{"foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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)()
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, tc.enableSchedulingGates)()
|
||||||
|
Loading…
Reference in New Issue
Block a user