feature(scheduler): implement matchLabelKeys in PodAffinity and PodAntiAffinity
This commit is contained in:
@@ -10198,7 +10198,206 @@ func TestValidatePod(t *testing.T) {
|
||||
DNSPolicy: core.DNSClusterFirst,
|
||||
},
|
||||
},
|
||||
"MatchLabelKeys/MismatchLabelKeys in required PodAffinity": {
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
|
||||
Spec: core.PodSpec{
|
||||
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: core.RestartPolicyAlways,
|
||||
DNSPolicy: core.DNSClusterFirst,
|
||||
Affinity: &core.Affinity{
|
||||
PodAffinity: &core.PodAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||
{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
{
|
||||
Key: "key2",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
{
|
||||
Key: "key3",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"key2"},
|
||||
MismatchLabelKeys: []string{"key3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"MatchLabelKeys/MismatchLabelKeys in preferred PodAffinity": {
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
|
||||
Spec: core.PodSpec{
|
||||
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: core.RestartPolicyAlways,
|
||||
DNSPolicy: core.DNSClusterFirst,
|
||||
Affinity: &core.Affinity{
|
||||
PodAffinity: &core.PodAffinity{
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{
|
||||
{
|
||||
Weight: 10,
|
||||
PodAffinityTerm: core.PodAffinityTerm{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
{
|
||||
Key: "key2",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
{
|
||||
Key: "key3",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"key2"},
|
||||
MismatchLabelKeys: []string{"key3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"MatchLabelKeys/MismatchLabelKeys in required PodAntiAffinity": {
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
|
||||
Spec: core.PodSpec{
|
||||
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: core.RestartPolicyAlways,
|
||||
DNSPolicy: core.DNSClusterFirst,
|
||||
Affinity: &core.Affinity{
|
||||
PodAntiAffinity: &core.PodAntiAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||
{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
{
|
||||
Key: "key2",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
{
|
||||
Key: "key3",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"key2"},
|
||||
MismatchLabelKeys: []string{"key3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"MatchLabelKeys/MismatchLabelKeys in preferred PodAntiAffinity": {
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
|
||||
Spec: core.PodSpec{
|
||||
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: core.RestartPolicyAlways,
|
||||
DNSPolicy: core.DNSClusterFirst,
|
||||
Affinity: &core.Affinity{
|
||||
PodAntiAffinity: &core.PodAntiAffinity{
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{
|
||||
{
|
||||
Weight: 10,
|
||||
PodAffinityTerm: core.PodAffinityTerm{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
{
|
||||
Key: "key2",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
{
|
||||
Key: "key3",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"key2"},
|
||||
MismatchLabelKeys: []string{"key3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"LabelSelector can have the same key as MismatchLabelKeys": {
|
||||
// Note: On the contrary, in case of matchLabelKeys, keys in matchLabelKeys are not allowed to be specified in labelSelector by users.
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
|
||||
Spec: core.PodSpec{
|
||||
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: core.RestartPolicyAlways,
|
||||
DNSPolicy: core.DNSClusterFirst,
|
||||
Affinity: &core.Affinity{
|
||||
PodAffinity: &core.PodAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||
{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
{
|
||||
// This is the same key as in MismatchLabelKeys
|
||||
// but it's allowed.
|
||||
Key: "key2",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
{
|
||||
Key: "key2",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MismatchLabelKeys: []string{"key2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for k, v := range successCases {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
if errs := ValidatePodCreate(&v, PodValidationOptions{}); len(errs) != 0 {
|
||||
@@ -10657,6 +10856,510 @@ func TestValidatePod(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid soft pod affinity, key in MatchLabelKeys isn't correctly defined": {
|
||||
expectedError: "prefix part must be non-empty",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAffinity: &core.PodAffinity{
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{
|
||||
{
|
||||
Weight: 10,
|
||||
PodAffinityTerm: core.PodAffinityTerm{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"/simple"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid hard pod affinity, key in MatchLabelKeys isn't correctly defined": {
|
||||
expectedError: "prefix part must be non-empty",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAffinity: &core.PodAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||
{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"/simple"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid soft pod anti-affinity, key in MatchLabelKeys isn't correctly defined": {
|
||||
expectedError: "prefix part must be non-empty",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAntiAffinity: &core.PodAntiAffinity{
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{
|
||||
{
|
||||
Weight: 10,
|
||||
PodAffinityTerm: core.PodAffinityTerm{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"/simple"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid hard pod anti-affinity, key in MatchLabelKeys isn't correctly defined": {
|
||||
expectedError: "prefix part must be non-empty",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAntiAffinity: &core.PodAntiAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||
{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"/simple"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid soft pod affinity, key in MismatchLabelKeys isn't correctly defined": {
|
||||
expectedError: "prefix part must be non-empty",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAffinity: &core.PodAffinity{
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{
|
||||
{
|
||||
Weight: 10,
|
||||
PodAffinityTerm: core.PodAffinityTerm{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MismatchLabelKeys: []string{"/simple"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid hard pod affinity, key in MismatchLabelKeys isn't correctly defined": {
|
||||
expectedError: "prefix part must be non-empty",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAffinity: &core.PodAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||
{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MismatchLabelKeys: []string{"/simple"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid soft pod anti-affinity, key in MismatchLabelKeys isn't correctly defined": {
|
||||
expectedError: "prefix part must be non-empty",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAntiAffinity: &core.PodAntiAffinity{
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{
|
||||
{
|
||||
Weight: 10,
|
||||
PodAffinityTerm: core.PodAffinityTerm{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MismatchLabelKeys: []string{"/simple"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid hard pod anti-affinity, key in MismatchLabelKeys isn't correctly defined": {
|
||||
expectedError: "prefix part must be non-empty",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAntiAffinity: &core.PodAntiAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||
{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MismatchLabelKeys: []string{"/simple"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid soft pod affinity, key exists in both matchLabelKeys and labelSelector": {
|
||||
expectedError: "exists in both matchLabelKeys and labelSelector",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Labels: map[string]string{"key": "value1"},
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAffinity: &core.PodAffinity{
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{
|
||||
{
|
||||
Weight: 10,
|
||||
PodAffinityTerm: core.PodAffinityTerm{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
// This one should be created from MatchLabelKeys.
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"key"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid hard pod affinity, key exists in both matchLabelKeys and labelSelector": {
|
||||
expectedError: "exists in both matchLabelKeys and labelSelector",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Labels: map[string]string{"key": "value1"},
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAffinity: &core.PodAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||
{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
// This one should be created from MatchLabelKeys.
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"key"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid soft pod anti-affinity, key exists in both matchLabelKeys and labelSelector": {
|
||||
expectedError: "exists in both matchLabelKeys and labelSelector",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Labels: map[string]string{"key": "value1"},
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAntiAffinity: &core.PodAntiAffinity{
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{
|
||||
{
|
||||
Weight: 10,
|
||||
PodAffinityTerm: core.PodAffinityTerm{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
// This one should be created from MatchLabelKeys.
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"key"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid hard pod anti-affinity, key exists in both matchLabelKeys and labelSelector": {
|
||||
expectedError: "exists in both matchLabelKeys and labelSelector",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
Labels: map[string]string{"key": "value1"},
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAntiAffinity: &core.PodAntiAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||
{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
// This one should be created from MatchLabelKeys.
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{"value1"},
|
||||
},
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"key"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid soft pod affinity, key exists in both MatchLabelKeys and MismatchLabelKeys": {
|
||||
expectedError: "exists in both matchLabelKeys and mismatchLabelKeys",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAffinity: &core.PodAffinity{
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{
|
||||
{
|
||||
Weight: 10,
|
||||
PodAffinityTerm: core.PodAffinityTerm{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"samekey"},
|
||||
MismatchLabelKeys: []string{"samekey"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid hard pod affinity, key exists in both MatchLabelKeys and MismatchLabelKeys": {
|
||||
expectedError: "exists in both matchLabelKeys and mismatchLabelKeys",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAffinity: &core.PodAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||
{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"samekey"},
|
||||
MismatchLabelKeys: []string{"samekey"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid soft pod anti-affinity, key exists in both MatchLabelKeys and MismatchLabelKeys": {
|
||||
expectedError: "exists in both matchLabelKeys and mismatchLabelKeys",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAntiAffinity: &core.PodAntiAffinity{
|
||||
PreferredDuringSchedulingIgnoredDuringExecution: []core.WeightedPodAffinityTerm{
|
||||
{
|
||||
Weight: 10,
|
||||
PodAffinityTerm: core.PodAffinityTerm{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"samekey"},
|
||||
MismatchLabelKeys: []string{"samekey"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid hard pod anti-affinity, key exists in both MatchLabelKeys and MismatchLabelKeys": {
|
||||
expectedError: "exists in both matchLabelKeys and mismatchLabelKeys",
|
||||
spec: core.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "123",
|
||||
Namespace: "ns",
|
||||
},
|
||||
Spec: validPodSpec(&core.Affinity{
|
||||
PodAntiAffinity: &core.PodAntiAffinity{
|
||||
RequiredDuringSchedulingIgnoredDuringExecution: []core.PodAffinityTerm{
|
||||
{
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "key",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
TopologyKey: "k8s.io/zone",
|
||||
MatchLabelKeys: []string{"samekey"},
|
||||
MismatchLabelKeys: []string{"samekey"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
"invalid toleration key": {
|
||||
expectedError: "spec.tolerations[0].key",
|
||||
spec: core.Pod{
|
||||
@@ -11143,7 +11846,7 @@ func TestValidatePod(t *testing.T) {
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
if errs := ValidatePodCreate(&v.spec, PodValidationOptions{AllowInvalidPodDeletionCost: false}); len(errs) == 0 {
|
||||
if errs := ValidatePodCreate(&v.spec, PodValidationOptions{}); len(errs) == 0 {
|
||||
t.Errorf("expected failure")
|
||||
} else if v.expectedError == "" {
|
||||
t.Errorf("missing expectedError, got %q", errs.ToAggregate().Error())
|
||||
@@ -21756,11 +22459,13 @@ func TestValidateTopologySpreadConstraints(t *testing.T) {
|
||||
WhenUnsatisfiable: core.DoNotSchedule,
|
||||
MatchLabelKeys: []string{"foo"},
|
||||
LabelSelector: &metav1.LabelSelector{
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{{
|
||||
Key: "foo",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
}},
|
||||
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "foo",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{"value1", "value2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
wantFieldErrors: field.ErrorList{field.Invalid(fieldPathMatchLabelKeys.Index(0), "foo", "exists in both matchLabelKeys and labelSelector")},
|
||||
|
Reference in New Issue
Block a user