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
|
||||
case mungedPodSpec.Affinity == nil && oldNodeAffinity != nil:
|
||||
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:
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
@ -12836,6 +12836,117 @@ func TestValidatePodUpdate(t *testing.T) {
|
||||
},
|
||||
err: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0]: Invalid value:",
|
||||
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 {
|
||||
|
@ -844,6 +844,63 @@ func TestMutablePodSchedulingDirectives(t *testing.T) {
|
||||
},
|
||||
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 {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodSchedulingReadiness, tc.enableSchedulingGates)()
|
||||
|
Loading…
Reference in New Issue
Block a user