mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Updating the nodeAffinity of gated pods having nil affinity should be allowed
This commit is contained in:
		@@ -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)()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user