123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794 |
- /*
- Copyright 2017 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package predicates
- import (
- "fmt"
- "reflect"
- "sort"
- "testing"
- "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- schedulernodeinfo "k8s.io/kubernetes/pkg/scheduler/nodeinfo"
- schedulertesting "k8s.io/kubernetes/pkg/scheduler/testing"
- )
- // sortablePods lets us to sort pods.
- type sortablePods []*v1.Pod
- func (s sortablePods) Less(i, j int) bool {
- return s[i].Namespace < s[j].Namespace ||
- (s[i].Namespace == s[j].Namespace && s[i].Name < s[j].Name)
- }
- func (s sortablePods) Len() int { return len(s) }
- func (s sortablePods) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
- var _ = sort.Interface(&sortablePods{})
- // sortableServices allows us to sort services.
- type sortableServices []*v1.Service
- func (s sortableServices) Less(i, j int) bool {
- return s[i].Namespace < s[j].Namespace ||
- (s[i].Namespace == s[j].Namespace && s[i].Name < s[j].Name)
- }
- func (s sortableServices) Len() int { return len(s) }
- func (s sortableServices) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
- var _ = sort.Interface(&sortableServices{})
- // predicateMetadataEquivalent returns true if the two metadata are equivalent.
- // Note: this function does not compare podRequest.
- func predicateMetadataEquivalent(meta1, meta2 *predicateMetadata) error {
- if !reflect.DeepEqual(meta1.pod, meta2.pod) {
- return fmt.Errorf("pods are not the same")
- }
- if meta1.podBestEffort != meta2.podBestEffort {
- return fmt.Errorf("podBestEfforts are not equal")
- }
- if meta1.serviceAffinityInUse != meta1.serviceAffinityInUse {
- return fmt.Errorf("serviceAffinityInUses are not equal")
- }
- if len(meta1.podPorts) != len(meta2.podPorts) {
- return fmt.Errorf("podPorts are not equal")
- }
- for !reflect.DeepEqual(meta1.podPorts, meta2.podPorts) {
- return fmt.Errorf("podPorts are not equal")
- }
- if !reflect.DeepEqual(meta1.topologyPairsPotentialAffinityPods, meta2.topologyPairsPotentialAffinityPods) {
- return fmt.Errorf("topologyPairsPotentialAffinityPods are not equal")
- }
- if !reflect.DeepEqual(meta1.topologyPairsPotentialAntiAffinityPods, meta2.topologyPairsPotentialAntiAffinityPods) {
- return fmt.Errorf("topologyPairsPotentialAntiAffinityPods are not equal")
- }
- if !reflect.DeepEqual(meta1.topologyPairsAntiAffinityPodsMap.podToTopologyPairs,
- meta2.topologyPairsAntiAffinityPodsMap.podToTopologyPairs) {
- return fmt.Errorf("topologyPairsAntiAffinityPodsMap.podToTopologyPairs are not equal")
- }
- if !reflect.DeepEqual(meta1.topologyPairsAntiAffinityPodsMap.topologyPairToPods,
- meta2.topologyPairsAntiAffinityPodsMap.topologyPairToPods) {
- return fmt.Errorf("topologyPairsAntiAffinityPodsMap.topologyPairToPods are not equal")
- }
- if meta1.serviceAffinityInUse {
- sortablePods1 := sortablePods(meta1.serviceAffinityMatchingPodList)
- sort.Sort(sortablePods1)
- sortablePods2 := sortablePods(meta2.serviceAffinityMatchingPodList)
- sort.Sort(sortablePods2)
- if !reflect.DeepEqual(sortablePods1, sortablePods2) {
- return fmt.Errorf("serviceAffinityMatchingPodLists are not euqal")
- }
- sortableServices1 := sortableServices(meta1.serviceAffinityMatchingPodServices)
- sort.Sort(sortableServices1)
- sortableServices2 := sortableServices(meta2.serviceAffinityMatchingPodServices)
- sort.Sort(sortableServices2)
- if !reflect.DeepEqual(sortableServices1, sortableServices2) {
- return fmt.Errorf("serviceAffinityMatchingPodServices are not euqal")
- }
- }
- return nil
- }
- func TestPredicateMetadata_AddRemovePod(t *testing.T) {
- var label1 = map[string]string{
- "region": "r1",
- "zone": "z11",
- }
- var label2 = map[string]string{
- "region": "r1",
- "zone": "z12",
- }
- var label3 = map[string]string{
- "region": "r2",
- "zone": "z21",
- }
- selector1 := map[string]string{"foo": "bar"}
- antiAffinityFooBar := &v1.PodAntiAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
- {
- LabelSelector: &metav1.LabelSelector{
- MatchExpressions: []metav1.LabelSelectorRequirement{
- {
- Key: "foo",
- Operator: metav1.LabelSelectorOpIn,
- Values: []string{"bar"},
- },
- },
- },
- TopologyKey: "region",
- },
- },
- }
- antiAffinityComplex := &v1.PodAntiAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
- {
- LabelSelector: &metav1.LabelSelector{
- MatchExpressions: []metav1.LabelSelectorRequirement{
- {
- Key: "foo",
- Operator: metav1.LabelSelectorOpIn,
- Values: []string{"bar", "buzz"},
- },
- },
- },
- TopologyKey: "region",
- },
- {
- LabelSelector: &metav1.LabelSelector{
- MatchExpressions: []metav1.LabelSelectorRequirement{
- {
- Key: "service",
- Operator: metav1.LabelSelectorOpNotIn,
- Values: []string{"bar", "security", "test"},
- },
- },
- },
- TopologyKey: "zone",
- },
- },
- }
- affinityComplex := &v1.PodAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
- {
- LabelSelector: &metav1.LabelSelector{
- MatchExpressions: []metav1.LabelSelectorRequirement{
- {
- Key: "foo",
- Operator: metav1.LabelSelectorOpIn,
- Values: []string{"bar", "buzz"},
- },
- },
- },
- TopologyKey: "region",
- },
- {
- LabelSelector: &metav1.LabelSelector{
- MatchExpressions: []metav1.LabelSelectorRequirement{
- {
- Key: "service",
- Operator: metav1.LabelSelectorOpNotIn,
- Values: []string{"bar", "security", "test"},
- },
- },
- },
- TopologyKey: "zone",
- },
- },
- }
- tests := []struct {
- name string
- pendingPod *v1.Pod
- addedPod *v1.Pod
- existingPods []*v1.Pod
- nodes []*v1.Node
- services []*v1.Service
- }{
- {
- name: "no anti-affinity or service affinity exist",
- pendingPod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "pending", Labels: selector1},
- },
- existingPods: []*v1.Pod{
- {ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeA"},
- },
- {ObjectMeta: metav1.ObjectMeta{Name: "p2"},
- Spec: v1.PodSpec{NodeName: "nodeC"},
- },
- },
- addedPod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "addedPod", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeB"},
- },
- nodes: []*v1.Node{
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: label1}},
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: label2}},
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: label3}},
- },
- },
- {
- name: "metadata anti-affinity terms are updated correctly after adding and removing a pod",
- pendingPod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "pending", Labels: selector1},
- },
- existingPods: []*v1.Pod{
- {ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeA"},
- },
- {ObjectMeta: metav1.ObjectMeta{Name: "p2"},
- Spec: v1.PodSpec{
- NodeName: "nodeC",
- Affinity: &v1.Affinity{
- PodAntiAffinity: antiAffinityFooBar,
- },
- },
- },
- },
- addedPod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "addedPod", Labels: selector1},
- Spec: v1.PodSpec{
- NodeName: "nodeB",
- Affinity: &v1.Affinity{
- PodAntiAffinity: antiAffinityFooBar,
- },
- },
- },
- nodes: []*v1.Node{
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: label1}},
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: label2}},
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: label3}},
- },
- },
- {
- name: "metadata service-affinity data are updated correctly after adding and removing a pod",
- pendingPod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "pending", Labels: selector1},
- },
- existingPods: []*v1.Pod{
- {ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeA"},
- },
- {ObjectMeta: metav1.ObjectMeta{Name: "p2"},
- Spec: v1.PodSpec{NodeName: "nodeC"},
- },
- },
- addedPod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "addedPod", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeB"},
- },
- services: []*v1.Service{{Spec: v1.ServiceSpec{Selector: selector1}}},
- nodes: []*v1.Node{
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: label1}},
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: label2}},
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: label3}},
- },
- },
- {
- name: "metadata anti-affinity terms and service affinity data are updated correctly after adding and removing a pod",
- pendingPod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "pending", Labels: selector1},
- },
- existingPods: []*v1.Pod{
- {ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeA"},
- },
- {ObjectMeta: metav1.ObjectMeta{Name: "p2"},
- Spec: v1.PodSpec{
- NodeName: "nodeC",
- Affinity: &v1.Affinity{
- PodAntiAffinity: antiAffinityFooBar,
- },
- },
- },
- },
- addedPod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "addedPod", Labels: selector1},
- Spec: v1.PodSpec{
- NodeName: "nodeA",
- Affinity: &v1.Affinity{
- PodAntiAffinity: antiAffinityComplex,
- },
- },
- },
- services: []*v1.Service{{Spec: v1.ServiceSpec{Selector: selector1}}},
- nodes: []*v1.Node{
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: label1}},
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: label2}},
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: label3}},
- },
- },
- {
- name: "metadata matching pod affinity and anti-affinity are updated correctly after adding and removing a pod",
- pendingPod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "pending", Labels: selector1},
- },
- existingPods: []*v1.Pod{
- {ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeA"},
- },
- {ObjectMeta: metav1.ObjectMeta{Name: "p2"},
- Spec: v1.PodSpec{
- NodeName: "nodeC",
- Affinity: &v1.Affinity{
- PodAntiAffinity: antiAffinityFooBar,
- PodAffinity: affinityComplex,
- },
- },
- },
- },
- addedPod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "addedPod", Labels: selector1},
- Spec: v1.PodSpec{
- NodeName: "nodeA",
- Affinity: &v1.Affinity{
- PodAntiAffinity: antiAffinityComplex,
- },
- },
- },
- services: []*v1.Service{{Spec: v1.ServiceSpec{Selector: selector1}}},
- nodes: []*v1.Node{
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: label1}},
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeB", Labels: label2}},
- {ObjectMeta: metav1.ObjectMeta{Name: "nodeC", Labels: label3}},
- },
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- allPodLister := schedulertesting.FakePodLister(append(test.existingPods, test.addedPod))
- // getMeta creates predicate meta data given the list of pods.
- getMeta := func(lister schedulertesting.FakePodLister) (*predicateMetadata, map[string]*schedulernodeinfo.NodeInfo) {
- nodeInfoMap := schedulernodeinfo.CreateNodeNameToInfoMap(lister, test.nodes)
- // nodeList is a list of non-pointer nodes to feed to FakeNodeListInfo.
- nodeList := []v1.Node{}
- for _, n := range test.nodes {
- nodeList = append(nodeList, *n)
- }
- _, precompute := NewServiceAffinityPredicate(lister, schedulertesting.FakeServiceLister(test.services), FakeNodeListInfo(nodeList), nil)
- RegisterPredicateMetadataProducer("ServiceAffinityMetaProducer", precompute)
- pmf := PredicateMetadataFactory{lister}
- meta := pmf.GetMetadata(test.pendingPod, nodeInfoMap)
- return meta.(*predicateMetadata), nodeInfoMap
- }
- // allPodsMeta is meta data produced when all pods, including test.addedPod
- // are given to the metadata producer.
- allPodsMeta, _ := getMeta(allPodLister)
- // existingPodsMeta1 is meta data produced for test.existingPods (without test.addedPod).
- existingPodsMeta1, nodeInfoMap := getMeta(schedulertesting.FakePodLister(test.existingPods))
- // Add test.addedPod to existingPodsMeta1 and make sure meta is equal to allPodsMeta
- nodeInfo := nodeInfoMap[test.addedPod.Spec.NodeName]
- if err := existingPodsMeta1.AddPod(test.addedPod, nodeInfo); err != nil {
- t.Errorf("error adding pod to meta: %v", err)
- }
- if err := predicateMetadataEquivalent(allPodsMeta, existingPodsMeta1); err != nil {
- t.Errorf("meta data are not equivalent: %v", err)
- }
- // Remove the added pod and from existingPodsMeta1 an make sure it is equal
- // to meta generated for existing pods.
- existingPodsMeta2, _ := getMeta(schedulertesting.FakePodLister(test.existingPods))
- if err := existingPodsMeta1.RemovePod(test.addedPod); err != nil {
- t.Errorf("error removing pod from meta: %v", err)
- }
- if err := predicateMetadataEquivalent(existingPodsMeta1, existingPodsMeta2); err != nil {
- t.Errorf("meta data are not equivalent: %v", err)
- }
- })
- }
- }
- // TestPredicateMetadata_ShallowCopy tests the ShallowCopy function. It is based
- // on the idea that shallow-copy should produce an object that is deep-equal to the original
- // object.
- func TestPredicateMetadata_ShallowCopy(t *testing.T) {
- selector1 := map[string]string{"foo": "bar"}
- source := predicateMetadata{
- pod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test",
- Namespace: "testns",
- },
- },
- podBestEffort: true,
- podRequest: &schedulernodeinfo.Resource{
- MilliCPU: 1000,
- Memory: 300,
- AllowedPodNumber: 4,
- },
- podPorts: []*v1.ContainerPort{
- {
- Name: "name",
- HostPort: 10,
- ContainerPort: 20,
- Protocol: "TCP",
- HostIP: "1.2.3.4",
- },
- },
- topologyPairsAntiAffinityPodsMap: &topologyPairsMaps{
- topologyPairToPods: map[topologyPair]podSet{
- {key: "name", value: "machine1"}: {
- &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p2", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeC"},
- }: struct{}{},
- },
- {key: "name", value: "machine2"}: {
- &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeA"},
- }: struct{}{},
- },
- },
- podToTopologyPairs: map[string]topologyPairSet{
- "p2_": {
- topologyPair{key: "name", value: "machine1"}: struct{}{},
- },
- "p1_": {
- topologyPair{key: "name", value: "machine2"}: struct{}{},
- },
- },
- },
- topologyPairsPotentialAffinityPods: &topologyPairsMaps{
- topologyPairToPods: map[topologyPair]podSet{
- {key: "name", value: "nodeA"}: {
- &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeA"},
- }: struct{}{},
- },
- {key: "name", value: "nodeC"}: {
- &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p2"},
- Spec: v1.PodSpec{
- NodeName: "nodeC",
- },
- }: struct{}{},
- &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p6", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeC"},
- }: struct{}{},
- },
- },
- podToTopologyPairs: map[string]topologyPairSet{
- "p1_": {
- topologyPair{key: "name", value: "nodeA"}: struct{}{},
- },
- "p2_": {
- topologyPair{key: "name", value: "nodeC"}: struct{}{},
- },
- "p6_": {
- topologyPair{key: "name", value: "nodeC"}: struct{}{},
- },
- },
- },
- topologyPairsPotentialAntiAffinityPods: &topologyPairsMaps{
- topologyPairToPods: map[topologyPair]podSet{
- {key: "name", value: "nodeN"}: {
- &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p1", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeN"},
- }: struct{}{},
- &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p2"},
- Spec: v1.PodSpec{
- NodeName: "nodeM",
- },
- }: struct{}{},
- &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p3"},
- Spec: v1.PodSpec{
- NodeName: "nodeM",
- },
- }: struct{}{},
- },
- {key: "name", value: "nodeM"}: {
- &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "p6", Labels: selector1},
- Spec: v1.PodSpec{NodeName: "nodeM"},
- }: struct{}{},
- },
- },
- podToTopologyPairs: map[string]topologyPairSet{
- "p1_": {
- topologyPair{key: "name", value: "nodeN"}: struct{}{},
- },
- "p2_": {
- topologyPair{key: "name", value: "nodeN"}: struct{}{},
- },
- "p3_": {
- topologyPair{key: "name", value: "nodeN"}: struct{}{},
- },
- "p6_": {
- topologyPair{key: "name", value: "nodeM"}: struct{}{},
- },
- },
- },
- serviceAffinityInUse: true,
- serviceAffinityMatchingPodList: []*v1.Pod{
- {ObjectMeta: metav1.ObjectMeta{Name: "pod1"}},
- {ObjectMeta: metav1.ObjectMeta{Name: "pod2"}},
- },
- serviceAffinityMatchingPodServices: []*v1.Service{
- {ObjectMeta: metav1.ObjectMeta{Name: "service1"}},
- },
- }
- if !reflect.DeepEqual(source.ShallowCopy().(*predicateMetadata), &source) {
- t.Errorf("Copy is not equal to source!")
- }
- }
- // TestGetTPMapMatchingIncomingAffinityAntiAffinity tests against method getTPMapMatchingIncomingAffinityAntiAffinity
- // on Anti Affinity cases
- func TestGetTPMapMatchingIncomingAffinityAntiAffinity(t *testing.T) {
- newPodAffinityTerms := func(keys ...string) []v1.PodAffinityTerm {
- var terms []v1.PodAffinityTerm
- for _, key := range keys {
- terms = append(terms, v1.PodAffinityTerm{
- LabelSelector: &metav1.LabelSelector{
- MatchExpressions: []metav1.LabelSelectorRequirement{
- {
- Key: key,
- Operator: metav1.LabelSelectorOpExists,
- },
- },
- },
- TopologyKey: "hostname",
- })
- }
- return terms
- }
- newPod := func(labels ...string) *v1.Pod {
- labelMap := make(map[string]string)
- for _, l := range labels {
- labelMap[l] = ""
- }
- return &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "normal", Labels: labelMap},
- Spec: v1.PodSpec{NodeName: "nodeA"},
- }
- }
- normalPodA := newPod("aaa")
- normalPodB := newPod("bbb")
- normalPodAB := newPod("aaa", "bbb")
- nodeA := &v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "nodeA", Labels: map[string]string{"hostname": "nodeA"}}}
- tests := []struct {
- name string
- existingPods []*v1.Pod
- nodes []*v1.Node
- pod *v1.Pod
- wantAffinityPodsMaps *topologyPairsMaps
- wantAntiAffinityPodsMaps *topologyPairsMaps
- wantErr bool
- }{
- {
- name: "nil test",
- nodes: []*v1.Node{nodeA},
- pod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "aaa-normal"},
- },
- wantAffinityPodsMaps: newTopologyPairsMaps(),
- wantAntiAffinityPodsMaps: newTopologyPairsMaps(),
- },
- {
- name: "incoming pod without affinity/anti-affinity causes a no-op",
- existingPods: []*v1.Pod{normalPodA},
- nodes: []*v1.Node{nodeA},
- pod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "aaa-normal"},
- },
- wantAffinityPodsMaps: newTopologyPairsMaps(),
- wantAntiAffinityPodsMaps: newTopologyPairsMaps(),
- },
- {
- name: "no pod has label that violates incoming pod's affinity and anti-affinity",
- existingPods: []*v1.Pod{normalPodB},
- nodes: []*v1.Node{nodeA},
- pod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "aaa-anti"},
- Spec: v1.PodSpec{
- Affinity: &v1.Affinity{
- PodAffinity: &v1.PodAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa"),
- },
- PodAntiAffinity: &v1.PodAntiAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa"),
- },
- },
- },
- },
- wantAffinityPodsMaps: newTopologyPairsMaps(),
- wantAntiAffinityPodsMaps: newTopologyPairsMaps(),
- },
- {
- name: "existing pod matches incoming pod's affinity and anti-affinity - single term case",
- existingPods: []*v1.Pod{normalPodA},
- nodes: []*v1.Node{nodeA},
- pod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "affi-antiaffi"},
- Spec: v1.PodSpec{
- Affinity: &v1.Affinity{
- PodAffinity: &v1.PodAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa"),
- },
- PodAntiAffinity: &v1.PodAntiAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa"),
- },
- },
- },
- },
- wantAffinityPodsMaps: &topologyPairsMaps{
- topologyPairToPods: map[topologyPair]podSet{
- {key: "hostname", value: "nodeA"}: {normalPodA: struct{}{}},
- },
- podToTopologyPairs: map[string]topologyPairSet{
- "normal_": {
- topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
- },
- },
- },
- wantAntiAffinityPodsMaps: &topologyPairsMaps{
- topologyPairToPods: map[topologyPair]podSet{
- {key: "hostname", value: "nodeA"}: {normalPodA: struct{}{}},
- },
- podToTopologyPairs: map[string]topologyPairSet{
- "normal_": {
- topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
- },
- },
- },
- },
- {
- name: "existing pod matches incoming pod's affinity and anti-affinity - mutiple terms case",
- existingPods: []*v1.Pod{normalPodAB},
- nodes: []*v1.Node{nodeA},
- pod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "affi-antiaffi"},
- Spec: v1.PodSpec{
- Affinity: &v1.Affinity{
- PodAffinity: &v1.PodAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa", "bbb"),
- },
- PodAntiAffinity: &v1.PodAntiAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa"),
- },
- },
- },
- },
- wantAffinityPodsMaps: &topologyPairsMaps{
- topologyPairToPods: map[topologyPair]podSet{
- {key: "hostname", value: "nodeA"}: {normalPodAB: struct{}{}},
- },
- podToTopologyPairs: map[string]topologyPairSet{
- "normal_": {
- topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
- },
- },
- },
- wantAntiAffinityPodsMaps: &topologyPairsMaps{
- topologyPairToPods: map[topologyPair]podSet{
- {key: "hostname", value: "nodeA"}: {normalPodAB: struct{}{}},
- },
- podToTopologyPairs: map[string]topologyPairSet{
- "normal_": {
- topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
- },
- },
- },
- },
- {
- name: "existing pod not match incoming pod's affinity but matches anti-affinity",
- existingPods: []*v1.Pod{normalPodA},
- nodes: []*v1.Node{nodeA},
- pod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "affi-antiaffi"},
- Spec: v1.PodSpec{
- Affinity: &v1.Affinity{
- PodAffinity: &v1.PodAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa", "bbb"),
- },
- PodAntiAffinity: &v1.PodAntiAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa", "bbb"),
- },
- },
- },
- },
- wantAffinityPodsMaps: newTopologyPairsMaps(),
- wantAntiAffinityPodsMaps: &topologyPairsMaps{
- topologyPairToPods: map[topologyPair]podSet{
- {key: "hostname", value: "nodeA"}: {normalPodA: struct{}{}},
- },
- podToTopologyPairs: map[string]topologyPairSet{
- "normal_": {
- topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
- },
- },
- },
- },
- {
- name: "incoming pod's anti-affinity has more than one term - existing pod violates partial term - case 1",
- existingPods: []*v1.Pod{normalPodAB},
- nodes: []*v1.Node{nodeA},
- pod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "anaffi-antiaffiti"},
- Spec: v1.PodSpec{
- Affinity: &v1.Affinity{
- PodAffinity: &v1.PodAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa", "ccc"),
- },
- PodAntiAffinity: &v1.PodAntiAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa", "ccc"),
- },
- },
- },
- },
- wantAffinityPodsMaps: newTopologyPairsMaps(),
- wantAntiAffinityPodsMaps: &topologyPairsMaps{
- topologyPairToPods: map[topologyPair]podSet{
- {key: "hostname", value: "nodeA"}: {normalPodAB: struct{}{}},
- },
- podToTopologyPairs: map[string]topologyPairSet{
- "normal_": {
- topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
- },
- },
- },
- },
- {
- name: "incoming pod's anti-affinity has more than one term - existing pod violates partial term - case 2",
- existingPods: []*v1.Pod{normalPodB},
- nodes: []*v1.Node{nodeA},
- pod: &v1.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: "affi-antiaffi"},
- Spec: v1.PodSpec{
- Affinity: &v1.Affinity{
- PodAffinity: &v1.PodAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa", "bbb"),
- },
- PodAntiAffinity: &v1.PodAntiAffinity{
- RequiredDuringSchedulingIgnoredDuringExecution: newPodAffinityTerms("aaa", "bbb"),
- },
- },
- },
- },
- wantAffinityPodsMaps: newTopologyPairsMaps(),
- wantAntiAffinityPodsMaps: &topologyPairsMaps{
- topologyPairToPods: map[topologyPair]podSet{
- {key: "hostname", value: "nodeA"}: {normalPodB: struct{}{}},
- },
- podToTopologyPairs: map[string]topologyPairSet{
- "normal_": {
- topologyPair{key: "hostname", value: "nodeA"}: struct{}{},
- },
- },
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- nodeInfoMap := schedulernodeinfo.CreateNodeNameToInfoMap(tt.existingPods, tt.nodes)
- gotAffinityPodsMaps, gotAntiAffinityPodsMaps, err := getTPMapMatchingIncomingAffinityAntiAffinity(tt.pod, nodeInfoMap)
- if (err != nil) != tt.wantErr {
- t.Errorf("getTPMapMatchingIncomingAffinityAntiAffinity() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if !reflect.DeepEqual(gotAffinityPodsMaps, tt.wantAffinityPodsMaps) {
- t.Errorf("getTPMapMatchingIncomingAffinityAntiAffinity() gotAffinityPodsMaps = %#v, want %#v", gotAffinityPodsMaps, tt.wantAffinityPodsMaps)
- }
- if !reflect.DeepEqual(gotAntiAffinityPodsMaps, tt.wantAntiAffinityPodsMaps) {
- t.Errorf("getTPMapMatchingIncomingAffinityAntiAffinity() gotAntiAffinityPodsMaps = %#v, want %#v", gotAntiAffinityPodsMaps, tt.wantAntiAffinityPodsMaps)
- }
- })
- }
- }
|