mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 04:06:03 +00:00
[scheduling] Moved pod affinity and anti-affinity from annotations to api
fields. #25319
This commit is contained in:
parent
1854d48238
commit
6a3ad93d6c
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,6 @@ func DeepEqualSafePodSpec() api.PodSpec {
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
TerminationGracePeriodSeconds: &grace,
|
||||
SecurityContext: &api.PodSecurityContext{},
|
||||
Affinity: &api.Affinity{},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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{}
|
||||
|
@ -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"},
|
||||
|
@ -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 {
|
||||
|
@ -132,7 +132,6 @@ func TestMerge(t *testing.T) {
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
TerminationGracePeriodSeconds: &grace,
|
||||
SecurityContext: &api.PodSecurityContext{},
|
||||
Affinity: &api.Affinity{},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -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{
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
],
|
||||
)
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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",
|
||||
],
|
||||
)
|
||||
|
@ -904,10 +904,7 @@ func (c *PodAffinityChecker) InterPodAffinityMatches(pod *v1.Pod, meta interface
|
||||
}
|
||||
|
||||
// Now check if <pod> 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 {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
|
@ -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}},
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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 + `"
|
||||
}]
|
||||
}
|
||||
}`,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user