diff --git a/pkg/api/helpers.go b/pkg/api/helpers.go index 8a47c67241b..775866ce149 100644 --- a/pkg/api/helpers.go +++ b/pkg/api/helpers.go @@ -486,20 +486,6 @@ const ( UnsafeSysctlsPodAnnotationKey string = "security.alpha.kubernetes.io/unsafe-sysctls" ) -// GetAffinityFromPod gets the json serialized affinity data from Pod.Annotations -// and converts it to the Affinity type in api. -func GetAffinityFromPodAnnotations(annotations map[string]string) (*Affinity, error) { - if len(annotations) > 0 && annotations[AffinityAnnotationKey] != "" { - var affinity Affinity - err := json.Unmarshal([]byte(annotations[AffinityAnnotationKey]), &affinity) - if err != nil { - return nil, err - } - return &affinity, nil - } - return nil, nil -} - // GetTolerationsFromPodAnnotations gets the json serialized tolerations data from Pod.Annotations // and converts it to the []Toleration type in api. func GetTolerationsFromPodAnnotations(annotations map[string]string) ([]Toleration, error) { diff --git a/pkg/api/helpers_test.go b/pkg/api/helpers_test.go index 50571577f2d..68a977700b6 100644 --- a/pkg/api/helpers_test.go +++ b/pkg/api/helpers_test.go @@ -241,62 +241,6 @@ func TestNodeSelectorRequirementsAsSelector(t *testing.T) { } } -func TestGetAffinityFromPod(t *testing.T) { - testCases := []struct { - pod *Pod - expectErr bool - }{ - { - pod: &Pod{}, - expectErr: false, - }, - { - pod: &Pod{ - ObjectMeta: ObjectMeta{ - Annotations: map[string]string{ - AffinityAnnotationKey: ` - {"nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": { - "nodeSelectorTerms": [{ - "matchExpressions": [{ - "key": "foo", - "operator": "In", - "values": ["value1", "value2"] - }] - }] - }}}`, - }, - }, - }, - expectErr: false, - }, - { - pod: &Pod{ - ObjectMeta: ObjectMeta{ - Annotations: map[string]string{ - AffinityAnnotationKey: ` - {"nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": { - "nodeSelectorTerms": [{ - "matchExpressions": [{ - "key": "foo", - `, - }, - }, - }, - expectErr: true, - }, - } - - for i, tc := range testCases { - _, err := GetAffinityFromPodAnnotations(tc.pod.Annotations) - if err == nil && tc.expectErr { - t.Errorf("[%v]expected error but got none.", i) - } - if err != nil && !tc.expectErr { - t.Errorf("[%v]did not expect error but got: %v", i, err) - } - } -} - func TestTaintToString(t *testing.T) { testCases := []struct { taint *Taint diff --git a/pkg/api/serialization_test.go b/pkg/api/serialization_test.go index ae66a98e628..e6a39e9f374 100644 --- a/pkg/api/serialization_test.go +++ b/pkg/api/serialization_test.go @@ -331,7 +331,6 @@ func TestEncode_Ptr(t *testing.T) { TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, - Affinity: &api.Affinity{}, }, } obj := runtime.Object(pod) @@ -345,7 +344,6 @@ func TestEncode_Ptr(t *testing.T) { } if !api.Semantic.DeepEqual(obj2, pod) { t.Errorf("\nExpected:\n\n %#v,\n\nGot:\n\n %#vDiff: %v\n\n", pod, obj2, diff.ObjectDiff(obj2, pod)) - } } diff --git a/pkg/api/testing/pod_specs.go b/pkg/api/testing/pod_specs.go index a50e992c793..87300a3da73 100644 --- a/pkg/api/testing/pod_specs.go +++ b/pkg/api/testing/pod_specs.go @@ -29,7 +29,6 @@ func DeepEqualSafePodSpec() api.PodSpec { DNSPolicy: api.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, - Affinity: &api.Affinity{}, } } diff --git a/pkg/api/v1/defaults.go b/pkg/api/v1/defaults.go index acc0744db87..50950837721 100644 --- a/pkg/api/v1/defaults.go +++ b/pkg/api/v1/defaults.go @@ -174,9 +174,6 @@ func SetDefaults_PodSpec(obj *PodSpec) { period := int64(DefaultTerminationGracePeriodSeconds) obj.TerminationGracePeriodSeconds = &period } - if obj.Affinity == nil { - obj.Affinity = &Affinity{} - } } func SetDefaults_Probe(obj *Probe) { if obj.TimeoutSeconds == 0 { diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 2665b95e11e..7af6742aa58 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -101,10 +101,6 @@ func ValidateDNS1123Subdomain(value string, fldPath *field.Path) field.ErrorList func ValidatePodSpecificAnnotations(annotations map[string]string, spec *api.PodSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} - if annotations[api.AffinityAnnotationKey] != "" { - allErrs = append(allErrs, ValidateAffinityInPodAnnotations(annotations, fldPath)...) - } - if annotations[api.TolerationsAnnotationKey] != "" { allErrs = append(allErrs, ValidateTolerationsInPodAnnotations(annotations, fldPath)...) } @@ -1672,7 +1668,14 @@ func validateAffinity(affinity *api.Affinity, fldPath *field.Path) field.ErrorLi allErrs = append(allErrs, ValidatePreferredSchedulingTerms(na.PreferredDuringSchedulingIgnoredDuringExecution, fldPath.Child("preferredDuringSchedulingIgnoredDuringExecution"))...) } } + if affinity.PodAffinity != nil { + allErrs = append(allErrs, validatePodAffinity(affinity.PodAffinity, fldPath.Child("podAffinity"))...) + } + if affinity.PodAntiAffinity != nil { + allErrs = append(allErrs, validatePodAntiAffinity(affinity.PodAntiAffinity, fldPath.Child("podAntiAffinity"))...) + } } + return allErrs } @@ -1968,30 +1971,6 @@ func validatePodAffinity(podAffinity *api.PodAffinity, fldPath *field.Path) fiel return allErrs } -// ValidateAffinityInPodAnnotations tests that the serialized Affinity in Pod.Annotations has valid data -func ValidateAffinityInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - - affinity, err := api.GetAffinityFromPodAnnotations(annotations) - if err != nil { - allErrs = append(allErrs, field.Invalid(fldPath, api.AffinityAnnotationKey, err.Error())) - return allErrs - } - if affinity == nil { - return allErrs - } - - affinityFldPath := fldPath.Child(api.AffinityAnnotationKey) - if affinity.PodAffinity != nil { - allErrs = append(allErrs, validatePodAffinity(affinity.PodAffinity, affinityFldPath.Child("podAffinity"))...) - } - if affinity.PodAntiAffinity != nil { - allErrs = append(allErrs, validatePodAntiAffinity(affinity.PodAntiAffinity, affinityFldPath.Child("podAntiAffinity"))...) - } - - return allErrs -} - // ValidateTolerationsInPodAnnotations tests that the serialized tolerations in Pod.Annotations has valid data func ValidateTolerationsInPodAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index fc05356cd70..7224d862b53 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -3076,11 +3076,18 @@ func TestValidatePodSpec(t *testing.T) { } func TestValidatePod(t *testing.T) { - validPodSpec := api.PodSpec{ - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, + validPodSpec := func(affinity *api.Affinity) api.PodSpec { + spec := api.PodSpec{ + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + RestartPolicy: api.RestartPolicyAlways, + DNSPolicy: api.DNSClusterFirst, + } + if affinity != nil { + spec.Affinity = affinity + } + return spec } + successCases := []api.Pod{ { // Basic fields. ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"}, @@ -3111,10 +3118,7 @@ func TestValidatePod(t *testing.T) { Name: "123", Namespace: "ns", }, - Spec: api.PodSpec{ - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, + Spec: validPodSpec( // TODO: Uncomment and move this block and move inside NodeAffinity once // RequiredDuringSchedulingRequiredDuringExecution is implemented // RequiredDuringSchedulingRequiredDuringExecution: &api.NodeSelector{ @@ -3129,7 +3133,7 @@ func TestValidatePod(t *testing.T) { // }, // }, // }, - Affinity: &api.Affinity{ + &api.Affinity{ NodeAffinity: &api.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{ NodeSelectorTerms: []api.NodeSelectorTerm{ @@ -3160,7 +3164,7 @@ func TestValidatePod(t *testing.T) { }, }, }, - }, + ), }, { // Serialized pod affinity in affinity requirements in annotations. ObjectMeta: api.ObjectMeta{ @@ -3179,38 +3183,44 @@ func TestValidatePod(t *testing.T) { // "namespaces":["ns"], // "topologyKey": "zone" // }] - Annotations: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "key2", - "operator": "In", - "values": ["value1", "value2"] - }] - }, - "topologyKey": "zone", - "namespaces": ["ns"] - }], - "preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 10, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "key2", - "operator": "NotIn", - "values": ["value1", "value2"] - }] - }, - "namespaces": ["ns"], - "topologyKey": "region" - } - }] - }}`, - }, }, - Spec: validPodSpec, + Spec: validPodSpec(&api.Affinity{ + PodAffinity: &api.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "key2", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"value1", "value2"}, + }, + }, + }, + TopologyKey: "zone", + Namespaces: []string{"ns"}, + }, + }, + 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"}, + TopologyKey: "region", + }, + }, + }, + }, + }), }, { // Serialized pod anti affinity with different Label Operators in affinity requirements in annotations. ObjectMeta: api.ObjectMeta{ @@ -3229,36 +3239,42 @@ func TestValidatePod(t *testing.T) { // "namespaces":["ns"], // "topologyKey": "zone" // }] - Annotations: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "key2", - "operator": "Exists" - }] - }, - "topologyKey": "zone", - "namespaces": ["ns"] - }], - "preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 10, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "key2", - "operator": "DoesNotExist" - }] - }, - "namespaces": ["ns"], - "topologyKey": "region" - } - }] - }}`, - }, }, - Spec: validPodSpec, + Spec: validPodSpec(&api.Affinity{ + PodAntiAffinity: &api.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "key2", + Operator: metav1.LabelSelectorOpExists, + }, + }, + }, + TopologyKey: "zone", + Namespaces: []string{"ns"}, + }, + }, + PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{ + { + Weight: 10, + PodAffinityTerm: api.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "key2", + Operator: metav1.LabelSelectorOpDoesNotExist, + }, + }, + }, + Namespaces: []string{"ns"}, + TopologyKey: "region", + }, + }, + }, + }, + }), }, { // populate tolerations equal operator in annotations. ObjectMeta: api.ObjectMeta{ @@ -3274,7 +3290,7 @@ func TestValidatePod(t *testing.T) { }]`, }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, { // populate tolerations exists operator in annotations. ObjectMeta: api.ObjectMeta{ @@ -3289,7 +3305,7 @@ func TestValidatePod(t *testing.T) { }]`, }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, { // empty operator is ok for toleration ObjectMeta: api.ObjectMeta{ @@ -3304,7 +3320,7 @@ func TestValidatePod(t *testing.T) { }]`, }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, { // empty efffect is ok for toleration ObjectMeta: api.ObjectMeta{ @@ -3319,7 +3335,7 @@ func TestValidatePod(t *testing.T) { }]`, }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, { // docker default seccomp profile ObjectMeta: api.ObjectMeta{ @@ -3329,7 +3345,7 @@ func TestValidatePod(t *testing.T) { api.SeccompPodAnnotationKey: "docker/default", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, { // unconfined seccomp profile ObjectMeta: api.ObjectMeta{ @@ -3339,7 +3355,7 @@ func TestValidatePod(t *testing.T) { api.SeccompPodAnnotationKey: "unconfined", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, { // localhost seccomp profile ObjectMeta: api.ObjectMeta{ @@ -3349,7 +3365,7 @@ func TestValidatePod(t *testing.T) { api.SeccompPodAnnotationKey: "localhost/foo", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, { // localhost seccomp profile for a container ObjectMeta: api.ObjectMeta{ @@ -3359,7 +3375,7 @@ func TestValidatePod(t *testing.T) { api.SeccompContainerAnnotationKeyPrefix + "foo": "localhost/foo", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, { // default AppArmor profile for a container ObjectMeta: api.ObjectMeta{ @@ -3369,7 +3385,7 @@ func TestValidatePod(t *testing.T) { apparmor.ContainerAnnotationKeyPrefix + "ctr": apparmor.ProfileRuntimeDefault, }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, { // default AppArmor profile for an init container ObjectMeta: api.ObjectMeta{ @@ -3394,7 +3410,7 @@ func TestValidatePod(t *testing.T) { apparmor.ContainerAnnotationKeyPrefix + "ctr": apparmor.ProfileNamePrefix + "foo", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, { // syntactically valid sysctls ObjectMeta: api.ObjectMeta{ @@ -3405,7 +3421,7 @@ func TestValidatePod(t *testing.T) { api.UnsafeSysctlsPodAnnotationKey: "knet.ipv4.route.min_pmtu=1000", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, { // valid opaque integer resources for init container ObjectMeta: api.ObjectMeta{Name: "valid-opaque-int", Namespace: "ns"}, @@ -3502,271 +3518,234 @@ func TestValidatePod(t *testing.T) { Name: "123", Namespace: "ns", }, - Spec: api.PodSpec{ - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Affinity: &api.Affinity{ - NodeAffinity: &api.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{ - NodeSelectorTerms: []api.NodeSelectorTerm{ - { - MatchExpressions: []api.NodeSelectorRequirement{ - { + Spec: validPodSpec(&api.Affinity{ + NodeAffinity: &api.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{ + NodeSelectorTerms: []api.NodeSelectorTerm{ + { + MatchExpressions: []api.NodeSelectorRequirement{ + { - Key: "key1", - }, + Key: "key1", }, }, }, }, }, }, - }, + }), }, "invalid preferredSchedulingTerm in node affinity, weight should be in range 1-100": { ObjectMeta: api.ObjectMeta{ Name: "123", Namespace: "ns", }, - Spec: api.PodSpec{ - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Affinity: &api.Affinity{ - NodeAffinity: &api.NodeAffinity{ - PreferredDuringSchedulingIgnoredDuringExecution: []api.PreferredSchedulingTerm{ - { - Weight: 199, - Preference: api.NodeSelectorTerm{ - MatchExpressions: []api.NodeSelectorRequirement{ - { - Key: "foo", - Operator: api.NodeSelectorOpIn, - Values: []string{"bar"}, - }, + Spec: validPodSpec(&api.Affinity{ + NodeAffinity: &api.NodeAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []api.PreferredSchedulingTerm{ + { + Weight: 199, + Preference: api.NodeSelectorTerm{ + MatchExpressions: []api.NodeSelectorRequirement{ + { + Key: "foo", + Operator: api.NodeSelectorOpIn, + Values: []string{"bar"}, }, }, }, }, }, }, - }, + }), }, "invalid requiredDuringSchedulingIgnoredDuringExecution node selector, nodeSelectorTerms must have at least one term": { ObjectMeta: api.ObjectMeta{ Name: "123", Namespace: "ns", }, - Spec: api.PodSpec{ - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Affinity: &api.Affinity{ - NodeAffinity: &api.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{ - NodeSelectorTerms: []api.NodeSelectorTerm{}, - }, + Spec: validPodSpec(&api.Affinity{ + NodeAffinity: &api.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{ + NodeSelectorTerms: []api.NodeSelectorTerm{}, }, }, - }, + }), }, "invalid requiredDuringSchedulingIgnoredDuringExecution node selector term, matchExpressions must have at least one node selector requirement": { ObjectMeta: api.ObjectMeta{ Name: "123", Namespace: "ns", }, - Spec: api.PodSpec{ - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - RestartPolicy: api.RestartPolicyAlways, - DNSPolicy: api.DNSClusterFirst, - Affinity: &api.Affinity{ - NodeAffinity: &api.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{ - NodeSelectorTerms: []api.NodeSelectorTerm{ - { - MatchExpressions: []api.NodeSelectorRequirement{}, - }, + Spec: validPodSpec(&api.Affinity{ + NodeAffinity: &api.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &api.NodeSelector{ + NodeSelectorTerms: []api.NodeSelectorTerm{ + { + MatchExpressions: []api.NodeSelectorRequirement{}, }, }, }, }, - }, + }), }, "invalid weight in preferredDuringSchedulingIgnoredDuringExecution in pod affinity annotations, weight should be in range 1-100": { ObjectMeta: api.ObjectMeta{ Name: "123", Namespace: "ns", - Annotations: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 109, - "podAffinityTerm": - { - "labelSelector": { - "matchExpressions": [{ - "key": "key2", - "operator": "NotIn", - "values": ["value1", "value2"] - }] - }, - "namespaces": ["ns"], - "topologyKey": "region" - } - }]}}`, - }, }, - Spec: validPodSpec, + Spec: validPodSpec(&api.Affinity{ + PodAffinity: &api.PodAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{ + { + Weight: 109, + PodAffinityTerm: api.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "key2", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"value1", "value2"}, + }, + }, + }, + Namespaces: []string{"ns"}, + TopologyKey: "region", + }, + }, + }, + }, + }), }, "invalid labelSelector in preferredDuringSchedulingIgnoredDuringExecution in podaffinity annotations, values should be empty if the operator is Exists": { ObjectMeta: api.ObjectMeta{ Name: "123", Namespace: "ns", - Annotations: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 10, - "podAffinityTerm": - { - "labelSelector": { - "matchExpressions": [{ - "key": "key2", - "operator": "Exists", - "values": ["value1", "value2"] - }] - }, - "namespaces": ["ns"], - "topologyKey": "region" - } - }]}}`, - }, }, - Spec: validPodSpec, + 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.LabelSelectorOpExists, + Values: []string{"value1", "value2"}, + }, + }, + }, + Namespaces: []string{"ns"}, + TopologyKey: "region", + }, + }, + }, + }, + }), }, "invalid name space in preferredDuringSchedulingIgnoredDuringExecution in podaffinity annotations, name space shouldbe valid": { ObjectMeta: api.ObjectMeta{ Name: "123", Namespace: "ns", - Annotations: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 10, - "podAffinityTerm": - { - "labelSelector": { - "matchExpressions": [{ - "key": "key2", - "operator": "Exists", - "values": ["value1", "value2"] - }] - }, - "namespaces": ["INVALID_NAMESPACE"], - "topologyKey": "region" - } - }]}}`, - }, }, - Spec: validPodSpec, - }, - "invalid labelOperator in preferredDuringSchedulingIgnoredDuringExecution in podantiaffinity annotations, labelOperator should be proper": { - ObjectMeta: api.ObjectMeta{ - Name: "123", - Namespace: "ns", - Annotations: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAntiAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 10, - "podAffinityTerm": + Spec: validPodSpec(&api.Affinity{ + PodAffinity: &api.PodAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{ { - "labelSelector": { - "matchExpressions": [{ - "key": "key2", - "operator": "WrongOp", - "values": ["value1", "value2"] - }] + Weight: 10, + PodAffinityTerm: api.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "key2", + Operator: metav1.LabelSelectorOpExists, + }, + }, + }, + Namespaces: []string{"INVALID_NAMESPACE"}, + TopologyKey: "region", }, - "namespaces": ["ns"], - "topologyKey": "region" - } - }]}}`, + }, + }, }, - }, - Spec: validPodSpec, + }), }, "invalid pod affinity, empty topologyKey is not allowed for hard pod affinity": { ObjectMeta: api.ObjectMeta{ Name: "123", Namespace: "ns", - Annotations: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAffinity": {"requiredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 10, - "podAffinityTerm": - { - "labelSelector": { - "matchExpressions": [{ - "key": "key2", - "operator": "In", - "values": ["value1", "value2"] - }] - }, - "namespaces": ["ns"], - "topologyKey": "" - } - }]}}`, - }, }, - Spec: validPodSpec, + Spec: validPodSpec(&api.Affinity{ + PodAffinity: &api.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "key2", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"value1", "value2"}, + }, + }, + }, + Namespaces: []string{"ns"}, + }, + }, + }, + }), }, "invalid pod anti-affinity, empty topologyKey is not allowed for hard pod anti-affinity": { ObjectMeta: api.ObjectMeta{ Name: "123", Namespace: "ns", - Annotations: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAntiAffinity": {"requiredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 10, - "podAffinityTerm": - { - "labelSelector": { - "matchExpressions": [{ - "key": "key2", - "operator": "In", - "values": ["value1", "value2"] - }] - }, - "namespaces": ["ns"], - "topologyKey": "" - } - }]}}`, - }, }, - Spec: validPodSpec, + Spec: validPodSpec(&api.Affinity{ + PodAntiAffinity: &api.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "key2", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"value1", "value2"}, + }, + }, + }, + Namespaces: []string{"ns"}, + }, + }, + }, + }), }, "invalid pod anti-affinity, empty topologyKey is not allowed for soft pod affinity": { ObjectMeta: api.ObjectMeta{ Name: "123", Namespace: "ns", - Annotations: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAffinity": {"preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 10, - "podAffinityTerm": - { - "labelSelector": { - "matchExpressions": [{ - "key": "key2", - "operator": "In", - "values": ["value1", "value2"] - }] - }, - "namespaces": ["ns"], - "topologyKey": "" - } - }]}}`, - }, }, - Spec: validPodSpec, + Spec: validPodSpec(&api.Affinity{ + PodAffinity: &api.PodAffinity{ + 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": { ObjectMeta: api.ObjectMeta{ @@ -3782,7 +3761,7 @@ func TestValidatePod(t *testing.T) { }]`, }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "invalid toleration operator": { ObjectMeta: api.ObjectMeta{ @@ -3798,7 +3777,7 @@ func TestValidatePod(t *testing.T) { }]`, }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "value must be empty when `operator` is 'Exists'": { ObjectMeta: api.ObjectMeta{ @@ -3814,7 +3793,7 @@ func TestValidatePod(t *testing.T) { }]`, }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "must be a valid pod seccomp profile": { ObjectMeta: api.ObjectMeta{ @@ -3824,7 +3803,7 @@ func TestValidatePod(t *testing.T) { api.SeccompPodAnnotationKey: "foo", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "must be a valid container seccomp profile": { ObjectMeta: api.ObjectMeta{ @@ -3834,7 +3813,7 @@ func TestValidatePod(t *testing.T) { api.SeccompContainerAnnotationKeyPrefix + "foo": "foo", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "must be a non-empty container name in seccomp annotation": { ObjectMeta: api.ObjectMeta{ @@ -3844,7 +3823,7 @@ func TestValidatePod(t *testing.T) { api.SeccompContainerAnnotationKeyPrefix: "foo", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "must be a non-empty container profile in seccomp annotation": { ObjectMeta: api.ObjectMeta{ @@ -3854,7 +3833,7 @@ func TestValidatePod(t *testing.T) { api.SeccompContainerAnnotationKeyPrefix + "foo": "", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "must be a relative path in a node-local seccomp profile annotation": { ObjectMeta: api.ObjectMeta{ @@ -3864,7 +3843,7 @@ func TestValidatePod(t *testing.T) { api.SeccompPodAnnotationKey: "localhost//foo", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "must not start with '../'": { ObjectMeta: api.ObjectMeta{ @@ -3874,7 +3853,7 @@ func TestValidatePod(t *testing.T) { api.SeccompPodAnnotationKey: "localhost/../foo", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "AppArmor profile must apply to a container": { ObjectMeta: api.ObjectMeta{ @@ -3901,7 +3880,7 @@ func TestValidatePod(t *testing.T) { apparmor.ContainerAnnotationKeyPrefix + "ctr": "bad-name", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "only default AppArmor profile may start with runtime/": { ObjectMeta: api.ObjectMeta{ @@ -3911,7 +3890,7 @@ func TestValidatePod(t *testing.T) { apparmor.ContainerAnnotationKeyPrefix + "ctr": "runtime/foo", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "invalid sysctl annotation": { ObjectMeta: api.ObjectMeta{ @@ -3921,7 +3900,7 @@ func TestValidatePod(t *testing.T) { api.SysctlsPodAnnotationKey: "foo:", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "invalid comma-separated sysctl annotation": { ObjectMeta: api.ObjectMeta{ @@ -3931,7 +3910,7 @@ func TestValidatePod(t *testing.T) { api.SysctlsPodAnnotationKey: "kernel.msgmax,", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "invalid unsafe sysctl annotation": { ObjectMeta: api.ObjectMeta{ @@ -3941,7 +3920,7 @@ func TestValidatePod(t *testing.T) { api.SysctlsPodAnnotationKey: "foo:", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "intersecting safe sysctls and unsafe sysctls annotations": { ObjectMeta: api.ObjectMeta{ @@ -3952,7 +3931,7 @@ func TestValidatePod(t *testing.T) { api.UnsafeSysctlsPodAnnotationKey: "kernel.shmmax=10000000", }, }, - Spec: validPodSpec, + Spec: validPodSpec(nil), }, "invalid opaque integer resource requirement: request must be <= limit": { ObjectMeta: api.ObjectMeta{Name: "123", Namespace: "ns"}, diff --git a/pkg/apis/extensions/v1beta1/defaults_test.go b/pkg/apis/extensions/v1beta1/defaults_test.go index a76e0e7755d..a47d33d6c01 100644 --- a/pkg/apis/extensions/v1beta1/defaults_test.go +++ b/pkg/apis/extensions/v1beta1/defaults_test.go @@ -40,7 +40,6 @@ func TestSetDefaultDaemonSet(t *testing.T) { RestartPolicy: v1.RestartPolicyAlways, SecurityContext: &v1.PodSecurityContext{}, TerminationGracePeriodSeconds: &period, - Affinity: &v1.Affinity{}, }, ObjectMeta: v1.ObjectMeta{ Labels: defaultLabels, @@ -52,7 +51,6 @@ func TestSetDefaultDaemonSet(t *testing.T) { RestartPolicy: v1.RestartPolicyAlways, SecurityContext: &v1.PodSecurityContext{}, TerminationGracePeriodSeconds: &period, - Affinity: &v1.Affinity{}, }, } tests := []struct { @@ -157,7 +155,6 @@ func TestSetDefaultDeployment(t *testing.T) { RestartPolicy: v1.RestartPolicyAlways, SecurityContext: &v1.PodSecurityContext{}, TerminationGracePeriodSeconds: &period, - Affinity: &v1.Affinity{}, }, } tests := []struct { diff --git a/pkg/kubectl/cmd/util/helpers_test.go b/pkg/kubectl/cmd/util/helpers_test.go index 89ba8a3b038..501945e1836 100644 --- a/pkg/kubectl/cmd/util/helpers_test.go +++ b/pkg/kubectl/cmd/util/helpers_test.go @@ -132,7 +132,6 @@ func TestMerge(t *testing.T) { DNSPolicy: api.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, - Affinity: &api.Affinity{}, }, }, }, diff --git a/pkg/kubelet/config/common_test.go b/pkg/kubelet/config/common_test.go index bc1b7ad1e99..7019d943519 100644 --- a/pkg/kubelet/config/common_test.go +++ b/pkg/kubelet/config/common_test.go @@ -54,7 +54,6 @@ func TestDecodeSinglePod(t *testing.T) { SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), }}, SecurityContext: &v1.PodSecurityContext{}, - Affinity: &v1.Affinity{}, }, } json, err := runtime.Encode(testapi.Default.Codec(), pod) @@ -115,7 +114,6 @@ func TestDecodePodList(t *testing.T) { SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults(), }}, SecurityContext: &v1.PodSecurityContext{}, - Affinity: &v1.Affinity{}, }, } podList := &v1.PodList{ diff --git a/pkg/kubelet/config/file_linux_test.go b/pkg/kubelet/config/file_linux_test.go index dc169fefc16..95bda1c7000 100644 --- a/pkg/kubelet/config/file_linux_test.go +++ b/pkg/kubelet/config/file_linux_test.go @@ -188,7 +188,6 @@ func getTestCases(hostname types.NodeName) []*testCase { Spec: v1.PodSpec{ Containers: []v1.Container{{Name: "image", Image: "test/image", SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, SecurityContext: &v1.PodSecurityContext{}, - Affinity: &v1.Affinity{}, }, Status: v1.PodStatus{ Phase: v1.PodPending, @@ -214,7 +213,6 @@ func getTestCases(hostname types.NodeName) []*testCase { ImagePullPolicy: "Always", SecurityContext: securitycontext.ValidSecurityContextWithContainerDefaults()}}, SecurityContext: &v1.PodSecurityContext{}, - Affinity: &v1.Affinity{}, }, Status: v1.PodStatus{ Phase: v1.PodPending, diff --git a/pkg/kubelet/config/http_test.go b/pkg/kubelet/config/http_test.go index df668f27c30..c27a137e708 100644 --- a/pkg/kubelet/config/http_test.go +++ b/pkg/kubelet/config/http_test.go @@ -148,7 +148,6 @@ func TestExtractPodsFromHTTP(t *testing.T) { NodeName: string(nodeName), Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways}}, SecurityContext: &v1.PodSecurityContext{}, - Affinity: &v1.Affinity{}, }, Status: v1.PodStatus{ Phase: v1.PodPending, @@ -170,7 +169,6 @@ func TestExtractPodsFromHTTP(t *testing.T) { DNSPolicy: v1.DNSClusterFirst, SecurityContext: &v1.PodSecurityContext{}, TerminationGracePeriodSeconds: &grace, - Affinity: &v1.Affinity{}, Containers: []v1.Container{{ Name: "1", @@ -201,7 +199,6 @@ func TestExtractPodsFromHTTP(t *testing.T) { NodeName: nodeName, Containers: []v1.Container{{Name: "1", Image: "foo", ImagePullPolicy: v1.PullAlways}}, SecurityContext: &v1.PodSecurityContext{}, - Affinity: &v1.Affinity{}, }, Status: v1.PodStatus{ Phase: v1.PodPending, @@ -216,7 +213,6 @@ func TestExtractPodsFromHTTP(t *testing.T) { NodeName: nodeName, Containers: []v1.Container{{Name: "2", Image: "bar:bartag", ImagePullPolicy: ""}}, SecurityContext: &v1.PodSecurityContext{}, - Affinity: &v1.Affinity{}, }, Status: v1.PodStatus{ Phase: v1.PodPending, @@ -240,7 +236,6 @@ func TestExtractPodsFromHTTP(t *testing.T) { DNSPolicy: v1.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &v1.PodSecurityContext{}, - Affinity: &v1.Affinity{}, Containers: []v1.Container{{ Name: "1", @@ -267,7 +262,6 @@ func TestExtractPodsFromHTTP(t *testing.T) { DNSPolicy: v1.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &v1.PodSecurityContext{}, - Affinity: &v1.Affinity{}, Containers: []v1.Container{{ Name: "2", diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index ade676de57a..cc243d4da21 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -484,7 +484,8 @@ func TestCriticalPrioritySorting(t *testing.T) { Requests: v1.ResourceList{ "memory": resource.MustParse("90"), }, - }}}} + }}}, + } pods := []*v1.Pod{ podWithUidNameNsSpec("000000000", "newpod", "foo", spec), podWithUidNameNsSpec("987654321", "oldpod", "foo", spec), @@ -637,7 +638,8 @@ func TestHandleMemExceeded(t *testing.T) { Requests: v1.ResourceList{ "memory": resource.MustParse("90"), }, - }}}} + }}}, + } pods := []*v1.Pod{ podWithUidNameNsSpec("123456789", "newpod", "foo", spec), podWithUidNameNsSpec("987654321", "oldpod", "foo", spec), diff --git a/pkg/registry/core/pod/storage/storage_test.go b/pkg/registry/core/pod/storage/storage_test.go index ff94c6b518e..9cf3a213acb 100644 --- a/pkg/registry/core/pod/storage/storage_test.go +++ b/pkg/registry/core/pod/storage/storage_test.go @@ -73,7 +73,6 @@ func validNewPod() *api.Pod { }, }, SecurityContext: &api.PodSecurityContext{}, - Affinity: &api.Affinity{}, }, } } @@ -660,7 +659,6 @@ func TestEtcdUpdateScheduled(t *testing.T) { }, }, SecurityContext: &api.PodSecurityContext{}, - Affinity: &api.Affinity{}, }, }, nil, 1) if err != nil { @@ -689,7 +687,6 @@ func TestEtcdUpdateScheduled(t *testing.T) { TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, - Affinity: &api.Affinity{}, }, } _, _, err = storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(&podIn, api.Scheme)) @@ -730,7 +727,6 @@ func TestEtcdUpdateStatus(t *testing.T) { }, }, SecurityContext: &api.PodSecurityContext{}, - Affinity: &api.Affinity{}, }, } err := storage.Storage.Create(ctx, key, &podStart, nil, 0) @@ -755,7 +751,6 @@ func TestEtcdUpdateStatus(t *testing.T) { }, }, SecurityContext: &api.PodSecurityContext{}, - Affinity: &api.Affinity{}, }, Status: api.PodStatus{ Phase: api.PodRunning, diff --git a/plugin/pkg/admission/antiaffinity/BUILD b/plugin/pkg/admission/antiaffinity/BUILD index 2e40dc0d0e5..11803455cc3 100644 --- a/plugin/pkg/admission/antiaffinity/BUILD +++ b/plugin/pkg/admission/antiaffinity/BUILD @@ -19,7 +19,6 @@ go_library( "//pkg/admission:go_default_library", "//pkg/api:go_default_library", "//pkg/api/errors:go_default_library", - "//vendor:github.com/golang/glog", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", ], ) diff --git a/plugin/pkg/admission/antiaffinity/admission.go b/plugin/pkg/admission/antiaffinity/admission.go index 6c687a36f62..e3a7837c514 100644 --- a/plugin/pkg/admission/antiaffinity/admission.go +++ b/plugin/pkg/admission/antiaffinity/admission.go @@ -20,7 +20,6 @@ import ( "fmt" "io" - "github.com/golang/glog" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/admission" "k8s.io/kubernetes/pkg/api" @@ -56,11 +55,7 @@ func (p *plugin) Admit(attributes admission.Attributes) (err error) { if !ok { return apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted") } - affinity, err := api.GetAffinityFromPodAnnotations(pod.Annotations) - if err != nil { - glog.V(5).Infof("Invalid Affinity detected, but we will leave handling of this to validation phase") - return nil - } + affinity := pod.Spec.Affinity if affinity != nil && affinity.PodAntiAffinity != nil { var podAntiAffinityTerms []api.PodAffinityTerm if len(affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 { diff --git a/plugin/pkg/admission/antiaffinity/admission_test.go b/plugin/pkg/admission/antiaffinity/admission_test.go index 62b50bb7a68..4834b44b143 100644 --- a/plugin/pkg/admission/antiaffinity/admission_test.go +++ b/plugin/pkg/admission/antiaffinity/admission_test.go @@ -32,109 +32,120 @@ func TestInterPodAffinityAdmission(t *testing.T) { Spec: api.PodSpec{}, } tests := []struct { - affinity map[string]string + affinity *api.Affinity errorExpected bool }{ // empty affinity its success. { - affinity: map[string]string{}, + affinity: &api.Affinity{}, errorExpected: false, }, // what ever topologyKey in preferredDuringSchedulingIgnoredDuringExecution, the admission should success. { - affinity: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAntiAffinity": { - "preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 5, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] + affinity: &api.Affinity{ + PodAntiAffinity: &api.PodAntiAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{ + { + Weight: 5, + PodAffinityTerm: api.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, }, - "namespaces": [], - "topologyKey": "az" - } - }] - }}`, + }, + TopologyKey: "az", + }, + }, + }, + }, }, errorExpected: false, }, // valid topologyKey in requiredDuringSchedulingIgnoredDuringExecution, // plus any topologyKey in preferredDuringSchedulingIgnoredDuringExecution, then admission success. { - affinity: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAntiAffinity": { - "preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 5, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] + affinity: &api.Affinity{ + PodAntiAffinity: &api.PodAntiAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []api.WeightedPodAffinityTerm{ + { + Weight: 5, + PodAffinityTerm: api.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, }, - "namespaces": [], - "topologyKey": "az" - } - }], - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] + TopologyKey: "az", }, - "namespaces": [], - "topologyKey": "` + metav1.LabelHostname + `" - }] - }}`, + }, + }, + RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, + }, + TopologyKey: metav1.LabelHostname, + }, + }, + }, }, errorExpected: false, }, // valid topologyKey in requiredDuringSchedulingIgnoredDuringExecution then admission success. { - affinity: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] + affinity: &api.Affinity{ + PodAntiAffinity: &api.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, }, - "namespaces":[], - "topologyKey": "` + metav1.LabelHostname + `" - }] - }}`, + TopologyKey: metav1.LabelHostname, + }, + }, + }, }, errorExpected: false, }, // invalid topologyKey in requiredDuringSchedulingIgnoredDuringExecution then admission fails. { - affinity: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] + affinity: &api.Affinity{ + PodAntiAffinity: &api.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, }, - "namespaces":[], - "topologyKey": " zone " - }] - }}`, + TopologyKey: " zone ", + }, + }, + }, }, errorExpected: true, }, @@ -161,59 +172,51 @@ func TestInterPodAffinityAdmission(t *testing.T) { // } // list of requiredDuringSchedulingIgnoredDuringExecution middle element topologyKey is not valid. { - affinity: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] - }, - "namespaces":[], - "topologyKey": "` + metav1.LabelHostname + `" - }, + affinity: &api.Affinity{ + PodAntiAffinity: &api.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []api.PodAffinityTerm{ { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, }, - "namespaces":[], - "topologyKey": " zone " + TopologyKey: metav1.LabelHostname, + }, { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, + }, + TopologyKey: " zone ", + }, { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, + }, + TopologyKey: metav1.LabelHostname, }, - { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] - }, - "namespaces": [], - "topologyKey": "` + metav1.LabelHostname + `" - }] - }}`, + }, + }, }, errorExpected: true, }, - { - affinity: map[string]string{ - api.AffinityAnnotationKey: ` - {"podAntiAffinity": { - "thisIsAInvalidAffinity": [{} - }}`, - }, - // however, we should not get error here - errorExpected: false, - }, } for _, test := range tests { - pod.ObjectMeta.Annotations = test.affinity + pod.Spec.Affinity = test.affinity err := handler.Admit(admission.NewAttributesRecord(&pod, nil, api.Kind("Pod").WithVersion("version"), "foo", "name", api.Resource("pods").WithVersion("version"), "", "ignored", nil)) if test.errorExpected && err == nil { diff --git a/plugin/pkg/scheduler/algorithm/predicates/BUILD b/plugin/pkg/scheduler/algorithm/predicates/BUILD index d2b64291358..4326afd2f2e 100644 --- a/plugin/pkg/scheduler/algorithm/predicates/BUILD +++ b/plugin/pkg/scheduler/algorithm/predicates/BUILD @@ -46,6 +46,7 @@ go_test( "//plugin/pkg/scheduler/algorithm:go_default_library", "//plugin/pkg/scheduler/algorithm/priorities/util:go_default_library", "//plugin/pkg/scheduler/schedulercache:go_default_library", + "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/labels", ], ) diff --git a/plugin/pkg/scheduler/algorithm/predicates/predicates.go b/plugin/pkg/scheduler/algorithm/predicates/predicates.go index aeacf0101ce..138ff64f892 100644 --- a/plugin/pkg/scheduler/algorithm/predicates/predicates.go +++ b/plugin/pkg/scheduler/algorithm/predicates/predicates.go @@ -904,10 +904,7 @@ func (c *PodAffinityChecker) InterPodAffinityMatches(pod *v1.Pod, meta interface } // Now check if requirements will be satisfied on this node. - affinity, err := v1.GetAffinityFromPodAnnotations(pod.Annotations) - if err != nil { - return false, nil, err - } + affinity := pod.Spec.Affinity if affinity == nil || (affinity.PodAffinity == nil && affinity.PodAntiAffinity == nil) { return true, nil, nil } @@ -1008,11 +1005,7 @@ func getMatchingAntiAffinityTerms(pod *v1.Pod, nodeInfoMap map[string]*scheduler } var nodeResult []matchingPodAntiAffinityTerm for _, existingPod := range nodeInfo.PodsWithAffinity() { - affinity, err := v1.GetAffinityFromPodAnnotations(existingPod.Annotations) - if err != nil { - catchError(err) - return - } + affinity := existingPod.Spec.Affinity if affinity == nil { continue } @@ -1040,10 +1033,7 @@ func getMatchingAntiAffinityTerms(pod *v1.Pod, nodeInfoMap map[string]*scheduler func (c *PodAffinityChecker) getMatchingAntiAffinityTerms(pod *v1.Pod, allPods []*v1.Pod) ([]matchingPodAntiAffinityTerm, error) { var result []matchingPodAntiAffinityTerm for _, existingPod := range allPods { - affinity, err := v1.GetAffinityFromPodAnnotations(existingPod.Annotations) - if err != nil { - return nil, err - } + affinity := pod.Spec.Affinity if affinity != nil && affinity.PodAntiAffinity != nil { existingPodNode, err := c.info.GetNodeInfo(existingPod.Spec.NodeName) if err != nil { diff --git a/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go b/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go index 7f60b773640..7f84ce9794f 100644 --- a/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go +++ b/plugin/pkg/scheduler/algorithm/predicates/predicates_test.go @@ -22,6 +22,7 @@ import ( "strings" "testing" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/plugin/pkg/scheduler/algorithm" @@ -1035,41 +1036,6 @@ func TestPodFitsSelector(t *testing.T) { fits: false, test: "Pod with an empty []NodeSelectorTerm in affinity, can't match the node's labels and won't schedule onto the node", }, - /* - { - pod: &v1.Pod{ - ObjectMeta: v1.ObjectMeta{ - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": { - "nodeSelectorTerms": [{}, {}] - }}}`, - }, - }, - Spec: v1.PodSpec{ - Affinity: &v1.Affinity{ - NodeAffinity: &v1.NodeAffinity{ - RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{ - NodeSelectorTerms: []v1.NodeSelectorTerm{ - { - MatchExpressions: {}, - }, - { - MatchExpressions: {}, - }, - }, - }, - }, - }, - }, - }, - labels: map[string]string{ - "foo": "bar", - }, - fits: false, - test: "Pod with invalid NodeSelectTerms in affinity will match no objects and won't schedule onto the node", - }, - */ { pod: &v1.Pod{ Spec: v1.PodSpec{ @@ -1995,20 +1961,25 @@ func TestInterPodAffinity(t *testing.T) { pod: &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: podLabel2, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan", "value2"] - }] + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan", "value2"}, + }, + }, }, - "topologyKey": "region" - }] - }}`, + TopologyKey: "region", + }, + }, + }, }, }, }, @@ -2021,19 +1992,25 @@ func TestInterPodAffinity(t *testing.T) { pod: &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: podLabel2, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: `{"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "NotIn", - "values": ["securityscan3", "value3"] - }] + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"securityscan3", "value3"}, + }, + }, + }, + TopologyKey: "region", }, - "topologyKey": "region" - }] - }}`, + }, + }, }, }, }, @@ -2046,20 +2023,25 @@ func TestInterPodAffinity(t *testing.T) { pod: &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: podLabel2, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan", "value2"] - }] + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan", "value2"}, + }, + }, + }, + Namespaces: []string{"DiffNameSpace"}, }, - "namespaces":["DiffNameSpace"] - }] - }}`, + }, + }, }, }, }, @@ -2072,19 +2054,24 @@ func TestInterPodAffinity(t *testing.T) { pod: &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: podLabel, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["antivirusscan", "value2"] - }] - } - }] - }}`, + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"antivirusscan", "value2"}, + }, + }, + }, + }, + }, + }, }, }, }, @@ -2097,37 +2084,42 @@ func TestInterPodAffinity(t *testing.T) { pod: &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: podLabel2, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [ + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ { - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "Exists" - }, { - "key": "wrongkey", - "operator": "DoesNotExist" - }] + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpExists, + }, { + Key: "wrongkey", + Operator: metav1.LabelSelectorOpDoesNotExist, + }, + }, }, - "topologyKey": "region" + TopologyKey: "region", }, { - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan"] - }, { - "key": "service", - "operator": "NotIn", - "values": ["WrongValue"] - }] + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan"}, + }, { + Key: "service", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"WrongValue"}, + }, + }, }, - "topologyKey": "region" - } - ] - }}`, + TopologyKey: "region", + }, + }, + }, }, }, }, @@ -2140,37 +2132,42 @@ func TestInterPodAffinity(t *testing.T) { pod: &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: podLabel2, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [ + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ { - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "Exists" - }, { - "key": "wrongkey", - "operator": "DoesNotExist" - }] + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpExists, + }, { + Key: "wrongkey", + Operator: metav1.LabelSelectorOpDoesNotExist, + }, + }, }, - "topologyKey": "region" + TopologyKey: "region", }, { - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan2"] - }, { - "key": "service", - "operator": "NotIn", - "values": ["WrongValue"] - }] + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan2"}, + }, { + Key: "service", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"WrongValue"}, + }, + }, }, - "topologyKey": "region" - } - ] - }}`, + TopologyKey: "region", + }, + }, + }, }, }, }, @@ -2183,32 +2180,41 @@ func TestInterPodAffinity(t *testing.T) { pod: &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: podLabel2, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan", "value2"] - }] + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan", "value2"}, + }, + }, + }, + TopologyKey: "region", }, - "topologyKey": "region" - }] + }, }, - "podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["antivirusscan", "value2"] - }] + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"antivirusscan", "value2"}, + }, + }, + }, + TopologyKey: "node", }, - "topologyKey": "node" - }] - }}`, + }, + }, }, }, }, @@ -2265,53 +2271,70 @@ func TestInterPodAffinity(t *testing.T) { pod: &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: podLabel2, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan", "value2"] - }] + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan", "value2"}, + }, + }, + }, + TopologyKey: "region", }, - "topologyKey": "region" - }] + }, }, - "podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["antivirusscan", "value2"] - }] + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"antivirusscan", "value2"}, + }, + }, + }, + TopologyKey: "node", }, - "topologyKey": "node" - }] - }}`, + }, + }, }, }, }, - pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, - ObjectMeta: v1.ObjectMeta{Labels: podLabel, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"PodAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["antivirusscan", "value2"] - }] + pods: []*v1.Pod{ + { + Spec: v1.PodSpec{ + NodeName: "machine1", + Affinity: &v1.Affinity{ + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"antivirusscan", "value2"}, + }, + }, + }, + TopologyKey: "node", + }, }, - "topologyKey": "node" - }] - }}`, - }}, - }}, + }, + }, + }, + ObjectMeta: v1.ObjectMeta{Labels: podLabel}, + }, + }, node: &node1, fits: true, test: "satisfies the PodAffinity and PodAntiAffinity and PodAntiAffinity symmetry with the existing pod", @@ -2320,32 +2343,41 @@ func TestInterPodAffinity(t *testing.T) { pod: &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: podLabel2, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan", "value2"] - }] + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan", "value2"}, + }, + }, + }, + TopologyKey: "region", }, - "topologyKey": "region" - }] + }, }, - "podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan", "value2"] - }] + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan", "value2"}, + }, + }, + }, + TopologyKey: "zone", }, - "topologyKey": "zone" - }] - }}`, + }, + }, }, }, }, @@ -2358,53 +2390,70 @@ func TestInterPodAffinity(t *testing.T) { pod: &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: podLabel, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan", "value2"] - }] + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan", "value2"}, + }, + }, + }, + TopologyKey: "region", }, - "topologyKey": "region" - }] + }, }, - "podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["antivirusscan", "value2"] - }] + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"antivirusscan", "value2"}, + }, + }, + }, + TopologyKey: "node", }, - "topologyKey": "node" - }] - }}`, + }, + }, }, }, }, - pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, - ObjectMeta: v1.ObjectMeta{Labels: podLabel, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"PodAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan", "value2"] - }] + pods: []*v1.Pod{ + { + Spec: v1.PodSpec{ + NodeName: "machine1", + Affinity: &v1.Affinity{ + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan", "value2"}, + }, + }, + }, + TopologyKey: "zone", + }, }, - "topologyKey": "zone" - }] - }}`, - }}, - }}, + }, + }, + }, + ObjectMeta: v1.ObjectMeta{Labels: podLabel}, + }, + }, node: &node1, fits: false, test: "satisfies the PodAffinity and PodAntiAffinity but doesn't satisfies PodAntiAffinity symmetry with the existing pod", @@ -2413,20 +2462,25 @@ func TestInterPodAffinity(t *testing.T) { pod: &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: podLabel, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "NotIn", - "values": ["securityscan", "value2"] - }] + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"securityscan", "value2"}, + }, + }, + }, + TopologyKey: "region", }, - "topologyKey": "region" - }] - }}`, + }, + }, }, }, }, @@ -2441,24 +2495,31 @@ func TestInterPodAffinity(t *testing.T) { Labels: podLabel, }, }, - pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, - ObjectMeta: v1.ObjectMeta{Labels: podLabel, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"PodAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan", "value2"] - }] + pods: []*v1.Pod{ + { + Spec: v1.PodSpec{NodeName: "machine1", + Affinity: &v1.Affinity{ + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan", "value2"}, + }, + }, + }, + TopologyKey: "zone", + }, }, - "topologyKey": "zone" - }] - }}`, - }}, - }}, + }, + }, + }, + ObjectMeta: v1.ObjectMeta{Labels: podLabel}, + }, + }, node: &node1, fits: false, test: "verify that PodAntiAffinity from existing pod is respected when pod has no AntiAffinity constraints. doesn't satisfy PodAntiAffinity symmetry with the existing pod", @@ -2469,24 +2530,31 @@ func TestInterPodAffinity(t *testing.T) { Labels: podLabel, }, }, - pods: []*v1.Pod{{Spec: v1.PodSpec{NodeName: "machine1"}, - ObjectMeta: v1.ObjectMeta{Labels: podLabel, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"PodAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "NotIn", - "values": ["securityscan", "value2"] - }] - }, - "topologyKey": "zone" - }] - }}`, - }}, - }}, + pods: []*v1.Pod{ + { + Spec: v1.PodSpec{NodeName: "machine1", + Affinity: &v1.Affinity{ + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"securityscan", "value2"}, + }, + }, + }, + TopologyKey: "zone", + }, + }, + }, + }, + }, + ObjectMeta: v1.ObjectMeta{Labels: podLabel}, + }, + }, node: &node1, fits: true, test: "verify that PodAntiAffinity from existing pod is respected when pod has no AntiAffinity constraints. satisfy PodAntiAffinity symmetry with the existing pod", @@ -2547,21 +2615,24 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { }{ { pod: &v1.Pod{ - ObjectMeta: v1.ObjectMeta{ - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "foo", - "operator": "In", - "values": ["bar"] - }] + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "foo", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"bar"}, + }, + }, + }, + TopologyKey: "region", }, - "topologyKey": "region" - }] - }}`, + }, + }, }, }, }, @@ -2582,25 +2653,6 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { }, { pod: &v1.Pod{ - ObjectMeta: v1.ObjectMeta{ - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - { - "podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "foo", - "operator": "In", - "values": ["abc"] - }] - }, - "topologyKey": "region" - }] - } - }`, - }, - }, Spec: v1.PodSpec{ Affinity: &v1.Affinity{ NodeAffinity: &v1.NodeAffinity{ @@ -2618,6 +2670,22 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { }, }, }, + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "foo", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"abc"}, + }, + }, + }, + TopologyKey: "region", + }, + }, + }, }, }, }, @@ -2641,20 +2709,25 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { Labels: map[string]string{ "foo": "bar", }, - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "foo", - "operator": "In", - "values": ["bar"] - }] + }, + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "foo", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"bar"}, + }, + }, + }, + TopologyKey: "zone", }, - "topologyKey": "zone" - }] - }}`, + }, + }, }, }, }, @@ -2672,23 +2745,24 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { }, { pod: &v1.Pod{ - ObjectMeta: v1.ObjectMeta{ - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - { - "podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "foo", - "operator": "In", - "values": ["abc"] - }] + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "foo", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"abc"}, + }, + }, }, - "topologyKey": "region" - }] - } - }`, + TopologyKey: "region", + }, + }, + }, }, }, }, @@ -2707,23 +2781,24 @@ func TestInterPodAffinityWithMultipleNodes(t *testing.T) { }, { pod: &v1.Pod{ - ObjectMeta: v1.ObjectMeta{ - Annotations: map[string]string{ - v1.AffinityAnnotationKey: ` - { - "podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "foo", - "operator": "In", - "values": ["abc"] - }] + Spec: v1.PodSpec{ + Affinity: &v1.Affinity{ + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "foo", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"abc"}, + }, + }, }, - "topologyKey": "region" - }] - } - }`, + TopologyKey: "region", + }, + }, + }, }, }, }, diff --git a/plugin/pkg/scheduler/algorithm/priorities/interpod_affinity.go b/plugin/pkg/scheduler/algorithm/priorities/interpod_affinity.go index 738bafb3a4d..4fb806961de 100644 --- a/plugin/pkg/scheduler/algorithm/priorities/interpod_affinity.go +++ b/plugin/pkg/scheduler/algorithm/priorities/interpod_affinity.go @@ -118,10 +118,7 @@ func (p *podAffinityPriorityMap) processTerms(terms []v1.WeightedPodAffinityTerm // Symmetry need to be considered for preferredDuringSchedulingIgnoredDuringExecution from podAffinity & podAntiAffinity, // symmetry need to be considered for hard requirements from podAffinity func (ipa *InterPodAffinity) CalculateInterPodAffinityPriority(pod *v1.Pod, nodeNameToInfo map[string]*schedulercache.NodeInfo, nodes []*v1.Node) (schedulerapi.HostPriorityList, error) { - affinity, err := v1.GetAffinityFromPodAnnotations(pod.Annotations) - if err != nil { - return nil, err - } + affinity := pod.Spec.Affinity hasAffinityConstraints := affinity != nil && affinity.PodAffinity != nil hasAntiAffinityConstraints := affinity != nil && affinity.PodAntiAffinity != nil @@ -142,10 +139,7 @@ func (ipa *InterPodAffinity) CalculateInterPodAffinityPriority(pod *v1.Pod, node if err != nil { return err } - existingPodAffinity, err := v1.GetAffinityFromPodAnnotations(existingPod.Annotations) - if err != nil { - return err - } + existingPodAffinity := existingPod.Spec.Affinity existingHasAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAffinity != nil existingHasAntiAffinityConstraints := existingPodAffinity != nil && existingPodAffinity.PodAntiAffinity != nil diff --git a/plugin/pkg/scheduler/algorithm/priorities/interpod_affinity_test.go b/plugin/pkg/scheduler/algorithm/priorities/interpod_affinity_test.go index 98192af073b..e61b54f664b 100644 --- a/plugin/pkg/scheduler/algorithm/priorities/interpod_affinity_test.go +++ b/plugin/pkg/scheduler/algorithm/priorities/interpod_affinity_test.go @@ -65,188 +65,203 @@ func TestInterPodAffinityPriority(t *testing.T) { "security": "S2", } // considered only preferredDuringSchedulingIgnoredDuringExecution in pod affinity - stayWithS1InRegion := map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 5, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S1"] - }] - }, - "namespaces": [], - "topologyKey": "region" - } - }] - }}`, - } - stayWithS2InRegion := map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 6, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] - }, - "namespaces": [], - "topologyKey": "region" - } - }] - }}`, - } - affinity3 := map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "preferredDuringSchedulingIgnoredDuringExecution": [ + stayWithS1InRegion := &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{ { - "weight": 8, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "NotIn", - "values":["S1"] - }, { - "key": "security", - "operator": "In", - "values":["S2"] - }] + Weight: 5, + PodAffinityTerm: v1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S1"}, + }, + }, }, - "namespaces": [], - "topologyKey": "region" - } - }, { - "weight": 2, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "Exists" - }, { - "key": "wrongkey", - "operator": "DoesNotExist" - }] - }, - "namespaces": [], - "topologyKey": "region" - } - } - ] - }}`, + TopologyKey: "region", + }, + }, + }, + }, } - hardAffinity := map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [ + stayWithS2InRegion := &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{ { - "labelSelector":{ - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values": ["S1", "value2"] - }] + Weight: 6, + PodAffinityTerm: v1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, + }, + TopologyKey: "region", }, - "namespaces": [], - "topologyKey": "region" - }, { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "Exists" - }, { - "key": "wrongkey", - "operator": "DoesNotExist" - }] - }, - "namespaces": [], - "topologyKey": "region" - } - ] - }}`, + }, + }, + }, } - awayFromS1InAz := map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAntiAffinity": { - "preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 5, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S1"] - }] + affinity3 := &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{ + { + Weight: 8, + PodAffinityTerm: v1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"S1"}, + }, { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, + }, + TopologyKey: "region", }, - "namespaces": [], - "topologyKey": "az" - } - }] - }}`, + }, { + Weight: 2, + PodAffinityTerm: v1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpExists, + }, { + Key: "wrongkey", + Operator: metav1.LabelSelectorOpDoesNotExist, + }, + }, + }, + TopologyKey: "region", + }, + }, + }, + }, + } + hardAffinity := &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S1", "value2"}, + }, + }, + }, + TopologyKey: "region", + }, { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpExists, + }, { + Key: "wrongkey", + Operator: metav1.LabelSelectorOpDoesNotExist, + }, + }, + }, + TopologyKey: "region", + }, + }, + }, + } + awayFromS1InAz := &v1.Affinity{ + PodAntiAffinity: &v1.PodAntiAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{ + { + Weight: 5, + PodAffinityTerm: v1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S1"}, + }, + }, + }, + TopologyKey: "az", + }, + }, + }, + }, } // to stay away from security S2 in any az. - awayFromS2InAz := map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAntiAffinity": { - "preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 5, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] + awayFromS2InAz := &v1.Affinity{ + PodAntiAffinity: &v1.PodAntiAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{ + { + Weight: 5, + PodAffinityTerm: v1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, + }, + TopologyKey: "az", }, - "namespaces": [], - "topologyKey": "az" - } - }] - }}`, + }, + }, + }, } // to stay with security S1 in same region, stay away from security S2 in any az. - stayWithS1InRegionAwayFromS2InAz := map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 8, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S1"] - }] + stayWithS1InRegionAwayFromS2InAz := &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{ + { + Weight: 8, + PodAffinityTerm: v1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S1"}, + }, + }, + }, + TopologyKey: "region", }, - "namespaces": [], - "topologyKey": "region" - } - }] + }, + }, }, - "podAntiAffinity": { - "preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 5, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] + PodAntiAffinity: &v1.PodAntiAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{ + { + Weight: 5, + PodAffinityTerm: v1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, + }, + TopologyKey: "az", }, - "namespaces": [], - "topologyKey": "az" - } - }] - }}`, + }, + }, + }, } tests := []struct { @@ -257,7 +272,7 @@ func TestInterPodAffinityPriority(t *testing.T) { test string }{ { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: map[string]string{}}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, nodes: []*v1.Node{ {ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}}, {ObjectMeta: v1.ObjectMeta{Name: "machine2", Labels: labelRgIndia}}, @@ -270,7 +285,7 @@ func TestInterPodAffinityPriority(t *testing.T) { // the node(machine3) that don't have the label {"region": "whatever the value is"} (mismatch the topology key) but that have existing pods that match the labelSelector get low score // the node(machine2) that have the label {"region": "China"} (match the topology key) but that have existing pods that mismatch the labelSelector get low score { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS1InRegion}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS1InRegion}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}}, @@ -290,7 +305,7 @@ func TestInterPodAffinityPriority(t *testing.T) { // the node3(machine3) that have the label {"region": "India"}, match the topology key but have a different label value, don't have existing pods that match the labelSelector, // get a low score. { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Annotations: stayWithS1InRegion}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS1InRegion}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, }, @@ -307,7 +322,7 @@ func TestInterPodAffinityPriority(t *testing.T) { // Then, nodes in regionChina get higher score than nodes in regionIndia, and all the nodes in regionChina should get a same score(high score), // while all the nodes in regionIndia should get another same score(low score). { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS2InRegion}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS2InRegion}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}}, {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}}, @@ -328,7 +343,7 @@ func TestInterPodAffinityPriority(t *testing.T) { }, // Test with the different operators and values for pod affinity scheduling preference, including some match failures. { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: affinity3}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: affinity3}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}}, @@ -347,8 +362,8 @@ func TestInterPodAffinityPriority(t *testing.T) { { pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}}, pods: []*v1.Pod{ - {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS1InRegion}}, - {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2, Annotations: stayWithS2InRegion}}, + {Spec: v1.PodSpec{NodeName: "machine1", Affinity: stayWithS1InRegion}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, + {Spec: v1.PodSpec{NodeName: "machine2", Affinity: stayWithS2InRegion}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}}, }, nodes: []*v1.Node{ {ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}}, @@ -361,8 +376,8 @@ func TestInterPodAffinityPriority(t *testing.T) { { pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, pods: []*v1.Pod{ - {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: hardAffinity}}, - {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2, Annotations: hardAffinity}}, + {Spec: v1.PodSpec{NodeName: "machine1", Affinity: hardAffinity}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, + {Spec: v1.PodSpec{NodeName: "machine2", Affinity: hardAffinity}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}}, }, nodes: []*v1.Node{ {ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}}, @@ -380,7 +395,7 @@ func TestInterPodAffinityPriority(t *testing.T) { // there are 2 nodes, say node1 and node2, both nodes have pods that match the labelSelector and have topology-key in node.Labels. // But there are more pods on node1 that match the preference than node2. Then, node1 get a lower score than node2. { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: awayFromS1InAz}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: awayFromS1InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}}, @@ -393,7 +408,7 @@ func TestInterPodAffinityPriority(t *testing.T) { test: "Anti Affinity: pod that doesnot match existing pods in node will get high score ", }, { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: awayFromS1InAz}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: awayFromS1InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, @@ -406,7 +421,7 @@ func TestInterPodAffinityPriority(t *testing.T) { test: "Anti Affinity: pod that does not matches topology key & matches the pods in nodes will get higher score comparing to others ", }, { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: awayFromS1InAz}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: awayFromS1InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, @@ -423,8 +438,8 @@ func TestInterPodAffinityPriority(t *testing.T) { { pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}}, pods: []*v1.Pod{ - {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: awayFromS2InAz}}, - {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2, Annotations: awayFromS1InAz}}, + {Spec: v1.PodSpec{NodeName: "machine1", Affinity: awayFromS2InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, + {Spec: v1.PodSpec{NodeName: "machine2", Affinity: awayFromS1InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}}, }, nodes: []*v1.Node{ {ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelAzAz1}}, @@ -435,7 +450,7 @@ func TestInterPodAffinityPriority(t *testing.T) { }, // Test both affinity and anti-affinity { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS1InRegionAwayFromS2InAz}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS1InRegionAwayFromS2InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, @@ -452,7 +467,7 @@ func TestInterPodAffinityPriority(t *testing.T) { // so that all the pods of a RC/service can stay in a same region but trying to separate with each other // machine-1,machine-3,machine-4 are in ChinaRegion others machin-2,machine-5 are in IndiaRegion { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS1InRegionAwayFromS2InAz}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS1InRegionAwayFromS2InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, @@ -478,12 +493,12 @@ func TestInterPodAffinityPriority(t *testing.T) { // for Affinity symmetry, the weights are: 0, 0, 8, 0 // for Anti Affinity symmetry, the weights are: 0, 0, 0, -5 { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1, Annotations: stayWithS1InRegionAwayFromS2InAz}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: stayWithS1InRegionAwayFromS2InAz}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS1}}, {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabelSecurityS2}}, - {Spec: v1.PodSpec{NodeName: "machine3"}, ObjectMeta: v1.ObjectMeta{Annotations: stayWithS1InRegionAwayFromS2InAz}}, - {Spec: v1.PodSpec{NodeName: "machine4"}, ObjectMeta: v1.ObjectMeta{Annotations: awayFromS1InAz}}, + {Spec: v1.PodSpec{NodeName: "machine3", Affinity: stayWithS1InRegionAwayFromS2InAz}}, + {Spec: v1.PodSpec{NodeName: "machine4", Affinity: awayFromS1InAz}}, }, nodes: []*v1.Node{ {ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}}, @@ -527,23 +542,23 @@ func TestHardPodAffinitySymmetricWeight(t *testing.T) { labelAzAz1 := map[string]string{ "az": "az1", } - hardPodAffinity := map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [ + hardPodAffinity := &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ { - "labelSelector":{ - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["S1"] - }] + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S1"}, + }, + }, }, - "namespaces": [], - "topologyKey": "region" - } - ] - }}`, + TopologyKey: "region", + }, + }, + }, } tests := []struct { pod *v1.Pod @@ -556,8 +571,8 @@ func TestHardPodAffinitySymmetricWeight(t *testing.T) { { pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelServiceS1}}, pods: []*v1.Pod{ - {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Annotations: hardPodAffinity}}, - {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Annotations: hardPodAffinity}}, + {Spec: v1.PodSpec{NodeName: "machine1", Affinity: hardPodAffinity}}, + {Spec: v1.PodSpec{NodeName: "machine2", Affinity: hardPodAffinity}}, }, nodes: []*v1.Node{ {ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}}, @@ -571,8 +586,8 @@ func TestHardPodAffinitySymmetricWeight(t *testing.T) { { pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabelServiceS1}}, pods: []*v1.Pod{ - {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Annotations: hardPodAffinity}}, - {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Annotations: hardPodAffinity}}, + {Spec: v1.PodSpec{NodeName: "machine1", Affinity: hardPodAffinity}}, + {Spec: v1.PodSpec{NodeName: "machine2", Affinity: hardPodAffinity}}, }, nodes: []*v1.Node{ {ObjectMeta: v1.ObjectMeta{Name: "machine1", Labels: labelRgChina}}, @@ -612,24 +627,26 @@ func TestSoftPodAntiAffinityWithFailureDomains(t *testing.T) { podLabel1 := map[string]string{ "security": "S1", } - antiAffinity1 := map[string]string{ - v1.AffinityAnnotationKey: ` - {"podAntiAffinity": { - "preferredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 5, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S1"] - }] + antiAffinity1 := &v1.Affinity{ + PodAntiAffinity: &v1.PodAntiAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{ + { + Weight: 5, + PodAffinityTerm: v1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S1"}, + }, + }, + }, + TopologyKey: "", }, - "namespaces": [], - "topologyKey": "" - } - }] - }}`, + }, + }, + }, } tests := []struct { pod *v1.Pod @@ -640,7 +657,7 @@ func TestSoftPodAntiAffinityWithFailureDomains(t *testing.T) { test string }{ { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1, Annotations: antiAffinity1}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: antiAffinity1}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}}, {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}}, @@ -654,7 +671,7 @@ func TestSoftPodAntiAffinityWithFailureDomains(t *testing.T) { test: "Soft Pod Anti Affinity: when the topologyKey is emtpy, match among topologyKeys indicated by failure domains.", }, { - pod: &v1.Pod{Spec: v1.PodSpec{NodeName: ""}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1, Annotations: antiAffinity1}}, + pod: &v1.Pod{Spec: v1.PodSpec{NodeName: "", Affinity: antiAffinity1}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}}, pods: []*v1.Pod{ {Spec: v1.PodSpec{NodeName: "machine1"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}}, {Spec: v1.PodSpec{NodeName: "machine2"}, ObjectMeta: v1.ObjectMeta{Labels: podLabel1}}, diff --git a/plugin/pkg/scheduler/algorithm/priorities/metadata.go b/plugin/pkg/scheduler/algorithm/priorities/metadata.go index eb3e65f3f45..ef8143e68e3 100644 --- a/plugin/pkg/scheduler/algorithm/priorities/metadata.go +++ b/plugin/pkg/scheduler/algorithm/priorities/metadata.go @@ -38,18 +38,9 @@ func PriorityMetadata(pod *v1.Pod, nodeNameToInfo map[string]*schedulercache.Nod if err != nil { return nil } - affinity := pod.Spec.Affinity - annotationAffinity, err := v1.GetAffinityFromPodAnnotations(pod.Annotations) - if err != nil { - return nil - } - if annotationAffinity != nil { - affinity.PodAffinity = annotationAffinity.PodAffinity - affinity.PodAntiAffinity = annotationAffinity.PodAntiAffinity - } return &priorityMetadata{ nonZeroRequest: getNonZeroRequests(pod), podTolerations: tolerations, - affinity: affinity, + affinity: pod.Spec.Affinity, } } diff --git a/plugin/pkg/scheduler/schedulercache/node_info.go b/plugin/pkg/scheduler/schedulercache/node_info.go index a3e816ae715..94f07900163 100644 --- a/plugin/pkg/scheduler/schedulercache/node_info.go +++ b/plugin/pkg/scheduler/schedulercache/node_info.go @@ -209,11 +209,8 @@ func (n *NodeInfo) String() string { } func hasPodAffinityConstraints(pod *v1.Pod) bool { - affinity, err := v1.GetAffinityFromPodAnnotations(pod.Annotations) - if err != nil || affinity == nil { - return false - } - return affinity.PodAffinity != nil || affinity.PodAntiAffinity != nil + affinity := pod.Spec.Affinity + return affinity != nil && (affinity.PodAffinity != nil || affinity.PodAntiAffinity != nil) } // addPod adds pod information to this NodeInfo. diff --git a/staging/src/k8s.io/client-go/pkg/api/v1/defaults.go b/staging/src/k8s.io/client-go/pkg/api/v1/defaults.go index 1476b9d88b4..92ddd384486 100644 --- a/staging/src/k8s.io/client-go/pkg/api/v1/defaults.go +++ b/staging/src/k8s.io/client-go/pkg/api/v1/defaults.go @@ -175,9 +175,6 @@ func SetDefaults_PodSpec(obj *PodSpec) { period := int64(DefaultTerminationGracePeriodSeconds) obj.TerminationGracePeriodSeconds = &period } - if obj.Affinity == nil { - obj.Affinity = &Affinity{} - } } func SetDefaults_Probe(obj *Probe) { if obj.TimeoutSeconds == 0 { diff --git a/test/e2e/scheduler_predicates.go b/test/e2e/scheduler_predicates.go index 748a0ed774d..cdb2eb9a9d0 100644 --- a/test/e2e/scheduler_predicates.go +++ b/test/e2e/scheduler_predicates.go @@ -44,8 +44,7 @@ var masterNodes sets.String type pausePodConfig struct { Name string - Affinity string - NodeAffinity *v1.Affinity + Affinity *v1.Affinity Annotations, Labels, NodeSelector map[string]string Resources *v1.ResourceRequirements } @@ -241,7 +240,7 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() { podName := "without-label" _, err := cs.Core().Pods(ns).Create(initPausePod(f, pausePodConfig{ Name: podName, - NodeAffinity: &v1.Affinity{ + Affinity: &v1.Affinity{ NodeAffinity: &v1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{ NodeSelectorTerms: []v1.NodeSelectorTerm{ @@ -303,7 +302,7 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() { createPausePod(f, pausePodConfig{ Name: podName, - NodeAffinity: &v1.Affinity{ + Affinity: &v1.Affinity{ NodeAffinity: &v1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{ NodeSelectorTerms: []v1.NodeSelectorTerm{ @@ -350,7 +349,7 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() { labelPodName := "with-labels" pod := createPausePod(f, pausePodConfig{ Name: labelPodName, - NodeAffinity: &v1.Affinity{ + Affinity: &v1.Affinity{ NodeAffinity: &v1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{ NodeSelectorTerms: []v1.NodeSelectorTerm{ @@ -392,24 +391,24 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() { _, err := cs.Core().Pods(ns).Create(initPausePod(f, pausePodConfig{ Name: podName, Labels: map[string]string{"name": "without-label"}, - Affinity: `{ - "podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "weight": 0, - "podAffinityTerm": { - "labelSelector": { - "matchExpressions": [{ - "key": "service", - "operator": "DoesNotExist", - "values":["securityscan"] - }] + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpDoesNotExist, + Values: []string{"securityscan"}, + }, + }, }, - "namespaces": [], - "topologyKey": "kubernetes.io/hostname" - } - }] - } - }`, + TopologyKey: "kubernetes.io/hostname", + }, + }, + }, + }, })) if err == nil || !errors.IsInvalid(err) { @@ -427,20 +426,24 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() { podName := "without-label-" + string(uuid.NewUUID()) createPausePod(f, pausePodConfig{ Name: podName, - Affinity: `{ - "podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector":{ - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["securityscan", "value2"] - }] + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "service", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"securityscan", "value2"}, + }, + }, + }, + TopologyKey: "kubernetes.io/hostname", }, - "topologyKey": "kubernetes.io/hostname" - }] - } - }`, + }, + }, + }, }) waitForScheduler() @@ -462,21 +465,25 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() { labelPodName := "with-podaffinity-" + string(uuid.NewUUID()) pod := createPausePod(f, pausePodConfig{ Name: labelPodName, - Affinity: `{ - "podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values": ["S1", "value2"] - }] + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S1", "value2"}, + }, + }, + }, + TopologyKey: k, + Namespaces: []string{ns}, }, - "topologyKey": "` + k + `", - "namespaces":["` + ns + `"] - }] - } - }`, + }, + }, + }, }) // check that pod got scheduled. We intentionally DO NOT check that the @@ -529,21 +536,25 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() { Name: labelPodName, Labels: map[string]string{"service": "Diff"}, NodeSelector: map[string]string{k: v}, // only launch on our two nodes, contradicting the podAntiAffinity - Affinity: `{ - "podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector":{ - "matchExpressions": [{ - "key": "service", - "operator": "In", - "values": ["S1", "value2"] - }] + Affinity: &v1.Affinity{ + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S1", "value2"}, + }, + }, + }, + TopologyKey: k, + Namespaces: []string{ns}, }, - "topologyKey": "` + k + `", - "namespaces": ["` + ns + `"] - }] - } - }`, + }, + }, + }, }) waitForScheduler() @@ -565,29 +576,31 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() { labelPodName := "with-podaffinity-" + string(uuid.NewUUID()) pod := createPausePod(f, pausePodConfig{ Name: labelPodName, - Affinity: `{ - "podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector":{ - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values": ["S1", "value2"] + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S1", "value2"}, + }, { + Key: "security", + Operator: metav1.LabelSelectorOpNotIn, + Values: []string{"S2"}, + }, { + Key: "security", + Operator: metav1.LabelSelectorOpExists, + }, + }, }, - { - "key": "security", - "operator": "NotIn", - "values": ["S2"] - }, - { - "key": "security", - "operator":"Exists" - }] + TopologyKey: k, }, - "topologyKey": "` + k + `" - }] - } - }`, + }, + }, + }, }) // check that pod got scheduled. We intentionally DO NOT check that the @@ -745,15 +758,6 @@ var _ = framework.KubeDescribe("SchedulerPredicates [Serial]", func() { }) func initPausePod(f *framework.Framework, conf pausePodConfig) *v1.Pod { - if conf.Affinity != "" { - if conf.Annotations == nil { - conf.Annotations = map[string]string{ - v1.AffinityAnnotationKey: conf.Affinity, - } - } else { - conf.Annotations[v1.AffinityAnnotationKey] = conf.Affinity - } - } pod := &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Name: conf.Name, @@ -762,7 +766,7 @@ func initPausePod(f *framework.Framework, conf pausePodConfig) *v1.Pod { }, Spec: v1.PodSpec{ NodeSelector: conf.NodeSelector, - Affinity: conf.NodeAffinity, + Affinity: conf.Affinity, Containers: []v1.Container{ { Name: podName, @@ -808,7 +812,7 @@ func runPodAndGetNodeName(f *framework.Framework, conf pausePodConfig) string { func createPodWithNodeAffinity(f *framework.Framework) *v1.Pod { return createPausePod(f, pausePodConfig{ Name: "with-nodeaffinity-" + string(uuid.NewUUID()), - NodeAffinity: &v1.Affinity{ + Affinity: &v1.Affinity{ NodeAffinity: &v1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{ NodeSelectorTerms: []v1.NodeSelectorTerm{ @@ -831,32 +835,40 @@ func createPodWithNodeAffinity(f *framework.Framework) *v1.Pod { func createPodWithPodAffinity(f *framework.Framework, topologyKey string) *v1.Pod { return createPausePod(f, pausePodConfig{ Name: "with-podantiaffinity-" + string(uuid.NewUUID()), - Affinity: `{ - "podAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S1"] - }] + Affinity: &v1.Affinity{ + PodAffinity: &v1.PodAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S1"}, + }, + }, + }, + TopologyKey: topologyKey, + }, }, - "topologyKey": "` + topologyKey + `" - }] }, - "podAntiAffinity": { - "requiredDuringSchedulingIgnoredDuringExecution": [{ - "labelSelector": { - "matchExpressions": [{ - "key": "security", - "operator": "In", - "values":["S2"] - }] + PodAntiAffinity: &v1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Key: "security", + Operator: metav1.LabelSelectorOpIn, + Values: []string{"S2"}, + }, + }, + }, + TopologyKey: topologyKey, + }, }, - "topologyKey": "` + topologyKey + `" - }] - } - }`, + }, + }, }) }