diff --git a/pkg/api/types.go b/pkg/api/types.go index 4d626b5d095..0fe9f605b17 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -2034,9 +2034,7 @@ type PodAffinityTerm struct { // the labelSelector in the specified namespaces, where co-located is defined as running on a node // whose value of the label with key topologyKey matches that of any node on which any of the // selected pods is running. - // For PreferredDuringScheduling pod anti-affinity, empty topologyKey is interpreted as "all topologies" - // ("all topologies" here means all the topologyKeys indicated by scheduler command-line argument --failure-domains); - // for affinity and for RequiredDuringScheduling pod anti-affinity, empty topologyKey is not allowed. + // Empty topologyKey is not allowed. // +optional TopologyKey string } diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 85b6b82e167..c3affacecb9 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -2435,7 +2435,7 @@ func ValidatePreferredSchedulingTerms(terms []api.PreferredSchedulingTerm, fldPa } // validatePodAffinityTerm tests that the specified podAffinityTerm fields have valid data -func validatePodAffinityTerm(podAffinityTerm api.PodAffinityTerm, allowEmptyTopologyKey bool, fldPath *field.Path) field.ErrorList { +func validatePodAffinityTerm(podAffinityTerm api.PodAffinityTerm, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(podAffinityTerm.LabelSelector, fldPath.Child("matchExpressions"))...) @@ -2444,32 +2444,29 @@ func validatePodAffinityTerm(podAffinityTerm api.PodAffinityTerm, allowEmptyTopo allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), name, msg)) } } - if !allowEmptyTopologyKey && len(podAffinityTerm.TopologyKey) == 0 { - allErrs = append(allErrs, field.Required(fldPath.Child("topologyKey"), "can only be empty for PreferredDuringScheduling pod anti affinity")) + if len(podAffinityTerm.TopologyKey) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("topologyKey"), "can not be empty")) } - if len(podAffinityTerm.TopologyKey) != 0 { - allErrs = append(allErrs, unversionedvalidation.ValidateLabelName(podAffinityTerm.TopologyKey, fldPath.Child("topologyKey"))...) - } - return allErrs + return append(allErrs, unversionedvalidation.ValidateLabelName(podAffinityTerm.TopologyKey, fldPath.Child("topologyKey"))...) } // validatePodAffinityTerms tests that the specified podAffinityTerms fields have valid data -func validatePodAffinityTerms(podAffinityTerms []api.PodAffinityTerm, allowEmptyTopologyKey bool, fldPath *field.Path) field.ErrorList { +func validatePodAffinityTerms(podAffinityTerms []api.PodAffinityTerm, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for i, podAffinityTerm := range podAffinityTerms { - allErrs = append(allErrs, validatePodAffinityTerm(podAffinityTerm, allowEmptyTopologyKey, fldPath.Index(i))...) + allErrs = append(allErrs, validatePodAffinityTerm(podAffinityTerm, fldPath.Index(i))...) } return allErrs } // validateWeightedPodAffinityTerms tests that the specified weightedPodAffinityTerms fields have valid data -func validateWeightedPodAffinityTerms(weightedPodAffinityTerms []api.WeightedPodAffinityTerm, allowEmptyTopologyKey bool, fldPath *field.Path) field.ErrorList { +func validateWeightedPodAffinityTerms(weightedPodAffinityTerms []api.WeightedPodAffinityTerm, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for j, weightedTerm := range weightedPodAffinityTerms { if weightedTerm.Weight <= 0 || weightedTerm.Weight > 100 { allErrs = append(allErrs, field.Invalid(fldPath.Index(j).Child("weight"), weightedTerm.Weight, "must be in the range 1-100")) } - allErrs = append(allErrs, validatePodAffinityTerm(weightedTerm.PodAffinityTerm, allowEmptyTopologyKey, fldPath.Index(j).Child("podAffinityTerm"))...) + allErrs = append(allErrs, validatePodAffinityTerm(weightedTerm.PodAffinityTerm, fldPath.Index(j).Child("podAffinityTerm"))...) } return allErrs } @@ -2483,13 +2480,11 @@ func validatePodAntiAffinity(podAntiAffinity *api.PodAntiAffinity, fldPath *fiel // fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...) //} if podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil { - // empty topologyKey is not allowed for hard pod anti-affinity - allErrs = append(allErrs, validatePodAffinityTerms(podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution, false, + allErrs = append(allErrs, validatePodAffinityTerms(podAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution, fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...) } if podAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution != nil { - // empty topologyKey is allowed for soft pod anti-affinity - allErrs = append(allErrs, validateWeightedPodAffinityTerms(podAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution, true, + allErrs = append(allErrs, validateWeightedPodAffinityTerms(podAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution, fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...) } return allErrs @@ -2504,13 +2499,11 @@ func validatePodAffinity(podAffinity *api.PodAffinity, fldPath *field.Path) fiel // fldPath.Child("requiredDuringSchedulingRequiredDuringExecution"))...) //} if podAffinity.RequiredDuringSchedulingIgnoredDuringExecution != nil { - // empty topologyKey is not allowed for hard pod affinity - allErrs = append(allErrs, validatePodAffinityTerms(podAffinity.RequiredDuringSchedulingIgnoredDuringExecution, false, + allErrs = append(allErrs, validatePodAffinityTerms(podAffinity.RequiredDuringSchedulingIgnoredDuringExecution, fldPath.Child("requiredDuringSchedulingIgnoredDuringExecution"))...) } if podAffinity.PreferredDuringSchedulingIgnoredDuringExecution != nil { - // empty topologyKey is not allowed for soft pod affinity - allErrs = append(allErrs, validateWeightedPodAffinityTerms(podAffinity.PreferredDuringSchedulingIgnoredDuringExecution, false, + allErrs = append(allErrs, validateWeightedPodAffinityTerms(podAffinity.PreferredDuringSchedulingIgnoredDuringExecution, fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...) } return allErrs diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index 400dc4a84e0..97087e1e8da 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -4747,8 +4747,8 @@ func TestValidatePod(t *testing.T) { }), }, }, - "invalid pod affinity, empty topologyKey is not allowed for hard pod affinity": { - expectedError: "can only be empty for PreferredDuringScheduling pod anti affinity", + "invalid hard pod affinity, empty topologyKey is not allowed for hard pod affinity": { + expectedError: "can not be empty", spec: api.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "123", @@ -4774,8 +4774,8 @@ func TestValidatePod(t *testing.T) { }), }, }, - "invalid pod anti-affinity, empty topologyKey is not allowed for hard pod anti-affinity": { - expectedError: "can only be empty for PreferredDuringScheduling pod anti affinity", + "invalid hard pod anti-affinity, empty topologyKey is not allowed for hard pod anti-affinity": { + expectedError: "can not be empty", spec: api.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "123", @@ -4801,8 +4801,8 @@ func TestValidatePod(t *testing.T) { }), }, }, - "invalid pod anti-affinity, empty topologyKey is not allowed for soft pod affinity": { - expectedError: "can only be empty for PreferredDuringScheduling pod anti affinity", + "invalid soft pod affinity, empty topologyKey is not allowed for soft pod affinity": { + expectedError: "can not be empty", spec: api.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "123", @@ -4831,6 +4831,36 @@ func TestValidatePod(t *testing.T) { }), }, }, + "invalid soft pod anti-affinity, empty topologyKey is not allowed for soft pod anti-affinity": { + expectedError: "can not be empty", + spec: api.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "123", + Namespace: "ns", + }, + Spec: validPodSpec(&api.Affinity{ + PodAntiAffinity: &api.PodAntiAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{ + { + Weight: 10, + PodAffinityTerm: api.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "key2", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"value1", "value2"}, + }, + }, + }, + Namespaces: []string{"ns"}, + }, + }, + }, + }, + }), + }, + }, "invalid toleration key": { expectedError: "spec.tolerations[0].key", spec: api.Pod{ diff --git a/plugin/pkg/scheduler/algorithm/priorities/util/topologies.go b/plugin/pkg/scheduler/algorithm/priorities/util/topologies.go index 2764d9a0acb..511ffc13706 100644 --- a/plugin/pkg/scheduler/algorithm/priorities/util/topologies.go +++ b/plugin/pkg/scheduler/algorithm/priorities/util/topologies.go @@ -75,7 +75,6 @@ type Topologies struct { } // NodesHaveSameTopologyKey checks if nodeA and nodeB have same label value with given topologyKey as label key. -// If the topologyKey is empty, check if the two nodes have any of the default topologyKeys, and have same corresponding label value. func (tps *Topologies) NodesHaveSameTopologyKey(nodeA, nodeB *v1.Node, topologyKey string) bool { return NodesHaveSameTopologyKey(nodeA, nodeB, topologyKey) }