diff --git a/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/pod_antiaffinity_test.go b/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/pod_antiaffinity_test.go index 1b6affa2d..2dbc0a7d4 100644 --- a/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/pod_antiaffinity_test.go +++ b/pkg/framework/plugins/removepodsviolatinginterpodantiaffinity/pod_antiaffinity_test.go @@ -33,84 +33,75 @@ import ( "sigs.k8s.io/descheduler/test" ) -func TestPodAntiAffinity(t *testing.T) { - node1 := test.BuildTestNode("n1", 2000, 3000, 10, func(node *v1.Node) { - node.ObjectMeta.Labels = map[string]string{ - "region": "main-region", - } - }) - node2 := test.BuildTestNode("n2", 2000, 3000, 10, func(node *v1.Node) { - node.ObjectMeta.Labels = map[string]string{ - "datacenter": "east", - } - }) - node3 := test.BuildTestNode("n3", 2000, 3000, 10, func(node *v1.Node) { - node.Spec = v1.NodeSpec{ - Unschedulable: true, - } - }) - node4 := test.BuildTestNode("n4", 2, 2, 1, nil) - node5 := test.BuildTestNode("n5", 200, 3000, 10, func(node *v1.Node) { - node.ObjectMeta.Labels = map[string]string{ - "region": "main-region", - } - }) +const ( + nodeName1 = "n1" + nodeName2 = "n2" + nodeName3 = "n3" + nodeName4 = "n4" + nodeName5 = "n5" +) - p1 := test.BuildTestPod("p1", 100, 0, node1.Name, nil) - p2 := test.BuildTestPod("p2", 100, 0, node1.Name, nil) - p3 := test.BuildTestPod("p3", 100, 0, node1.Name, nil) - p4 := test.BuildTestPod("p4", 100, 0, node1.Name, nil) - p5 := test.BuildTestPod("p5", 100, 0, node1.Name, nil) - p6 := test.BuildTestPod("p6", 100, 0, node1.Name, nil) - p7 := test.BuildTestPod("p7", 100, 0, node1.Name, nil) - p8 := test.BuildTestPod("p8", 100, 0, node1.Name, nil) - p9 := test.BuildTestPod("p9", 100, 0, node1.Name, nil) - p10 := test.BuildTestPod("p10", 100, 0, node1.Name, nil) - p11 := test.BuildTestPod("p11", 100, 0, node5.Name, nil) - p9.DeletionTimestamp = &metav1.Time{} - p10.DeletionTimestamp = &metav1.Time{} +func buildTestNode(name string, apply func(*v1.Node)) *v1.Node { + return test.BuildTestNode(name, 2000, 3000, 10, apply) +} - criticalPriority := utils.SystemCriticalPriority - nonEvictablePod := test.BuildTestPod("non-evict", 100, 0, node1.Name, func(pod *v1.Pod) { - pod.Spec.Priority = &criticalPriority - }) - p2.Labels = map[string]string{"foo": "bar"} - p5.Labels = map[string]string{"foo": "bar"} - p6.Labels = map[string]string{"foo": "bar"} - p7.Labels = map[string]string{"foo1": "bar1"} - p11.Labels = map[string]string{"foo": "bar"} - nonEvictablePod.Labels = map[string]string{"foo": "bar"} - test.SetNormalOwnerRef(p1) - test.SetNormalOwnerRef(p2) - test.SetNormalOwnerRef(p3) - test.SetNormalOwnerRef(p4) - test.SetNormalOwnerRef(p5) - test.SetNormalOwnerRef(p6) - test.SetNormalOwnerRef(p7) - test.SetNormalOwnerRef(p9) - test.SetNormalOwnerRef(p10) - test.SetNormalOwnerRef(p11) - - // set pod anti affinity - test.SetPodAntiAffinity(p1, "foo", "bar") - test.SetPodAntiAffinity(p3, "foo", "bar") - test.SetPodAntiAffinity(p4, "foo", "bar") - test.SetPodAntiAffinity(p5, "foo1", "bar1") - test.SetPodAntiAffinity(p6, "foo1", "bar1") - test.SetPodAntiAffinity(p7, "foo", "bar") - test.SetPodAntiAffinity(p9, "foo", "bar") - test.SetPodAntiAffinity(p10, "foo", "bar") - - // set pod priority - test.SetPodPriority(p5, 100) - test.SetPodPriority(p6, 50) - test.SetPodPriority(p7, 0) - - // Set pod node selectors - p8.Spec.NodeSelector = map[string]string{ - "datacenter": "west", +func setNodeMainRegionLabel(node *v1.Node) { + node.ObjectMeta.Labels = map[string]string{ + "region": "main-region", } +} +func buildTestNode1() *v1.Node { + return buildTestNode(nodeName1, setNodeMainRegionLabel) +} + +func buildTestPod(name, nodeName string, apply func(*v1.Pod)) *v1.Pod { + return test.BuildTestPod(name, 100, 0, nodeName, apply) +} + +func buildTestPodForNode1(name string, apply func(*v1.Pod)) *v1.Pod { + return buildTestPod(name, nodeName1, apply) +} + +func setPodAntiAffinityFooBar(pod *v1.Pod) { + test.SetPodAntiAffinity(pod, "foo", "bar") +} + +func setPodAntiAffinityFoo1Bar1(pod *v1.Pod) { + test.SetPodAntiAffinity(pod, "foo1", "bar1") +} + +func setLabelsFooBar(pod *v1.Pod) { + pod.Labels = map[string]string{"foo": "bar"} +} + +func setLabelsFoo1Bar1(pod *v1.Pod) { + pod.Labels = map[string]string{"foo1": "bar1"} +} + +func buildTestPodWithAntiAffinityForNode1(name string) *v1.Pod { + return buildTestPodForNode1(name, func(pod *v1.Pod) { + test.SetNormalOwnerRef(pod) + setPodAntiAffinityFooBar(pod) + }) +} + +func buildTestPodP2ForNode1() *v1.Pod { + return buildTestPodForNode1("p2", func(pod *v1.Pod) { + test.SetNormalOwnerRef(pod) + setLabelsFooBar(pod) + }) +} + +func buildTestPodNonEvictableForNode1() *v1.Pod { + criticalPriority := utils.SystemCriticalPriority + return buildTestPodForNode1("non-evict", func(pod *v1.Pod) { + pod.Spec.Priority = &criticalPriority + setLabelsFooBar(pod) + }) +} + +func TestPodAntiAffinity(t *testing.T) { var uint1 uint = 1 var uint3 uint = 3 @@ -125,87 +116,204 @@ func TestPodAntiAffinity(t *testing.T) { nodes []*v1.Node }{ { - description: "Maximum pods to evict - 0", - pods: []*v1.Pod{p1, p2, p3, p4}, - nodes: []*v1.Node{node1}, + description: "Maximum pods to evict - 0", + pods: []*v1.Pod{ + buildTestPodWithAntiAffinityForNode1("p1"), + buildTestPodP2ForNode1(), + buildTestPodWithAntiAffinityForNode1("p3"), + buildTestPodWithAntiAffinityForNode1("p4"), + }, + nodes: []*v1.Node{ + buildTestNode1(), + }, expectedEvictedPodCount: 3, }, { - description: "Maximum pods to evict - 3", - maxPodsToEvictPerNode: &uint3, - pods: []*v1.Pod{p1, p2, p3, p4}, - nodes: []*v1.Node{node1}, + description: "Maximum pods to evict - 3", + maxPodsToEvictPerNode: &uint3, + pods: []*v1.Pod{ + buildTestPodWithAntiAffinityForNode1("p1"), + buildTestPodP2ForNode1(), + buildTestPodWithAntiAffinityForNode1("p3"), + buildTestPodWithAntiAffinityForNode1("p4"), + }, + nodes: []*v1.Node{ + buildTestNode1(), + }, expectedEvictedPodCount: 3, }, { description: "Maximum pods to evict (maxPodsToEvictPerNamespace=3) - 3", maxNoOfPodsToEvictPerNamespace: &uint3, - pods: []*v1.Pod{p1, p2, p3, p4}, - nodes: []*v1.Node{node1}, - expectedEvictedPodCount: 3, + pods: []*v1.Pod{ + buildTestPodWithAntiAffinityForNode1("p1"), + buildTestPodP2ForNode1(), + buildTestPodWithAntiAffinityForNode1("p3"), + buildTestPodWithAntiAffinityForNode1("p4"), + }, + nodes: []*v1.Node{ + buildTestNode1(), + }, + expectedEvictedPodCount: 3, }, { description: "Maximum pods to evict (maxNoOfPodsToEvictTotal)", maxNoOfPodsToEvictPerNamespace: &uint3, maxNoOfPodsToEvictTotal: &uint1, - pods: []*v1.Pod{p1, p2, p3, p4}, - nodes: []*v1.Node{node1}, - expectedEvictedPodCount: 1, - }, - { - description: "Evict only 1 pod after sorting", - pods: []*v1.Pod{p5, p6, p7}, - nodes: []*v1.Node{node1}, + pods: []*v1.Pod{ + buildTestPodWithAntiAffinityForNode1("p1"), + buildTestPodP2ForNode1(), + buildTestPodWithAntiAffinityForNode1("p3"), + buildTestPodWithAntiAffinityForNode1("p4"), + }, + nodes: []*v1.Node{ + buildTestNode1(), + }, expectedEvictedPodCount: 1, }, { - description: "Evicts pod that conflicts with critical pod (but does not evict critical pod)", - maxPodsToEvictPerNode: &uint1, - pods: []*v1.Pod{p1, nonEvictablePod}, - nodes: []*v1.Node{node1}, + description: "Evict only 1 pod after sorting", + pods: []*v1.Pod{ + buildTestPodForNode1("p5", func(pod *v1.Pod) { + test.SetNormalOwnerRef(pod) + setLabelsFooBar(pod) + setPodAntiAffinityFoo1Bar1(pod) + test.SetPodPriority(pod, 100) + }), + buildTestPodForNode1("p6", func(pod *v1.Pod) { + test.SetNormalOwnerRef(pod) + setLabelsFooBar(pod) + setPodAntiAffinityFoo1Bar1(pod) + test.SetPodPriority(pod, 50) + }), + buildTestPodForNode1("p7", func(pod *v1.Pod) { + test.SetNormalOwnerRef(pod) + setLabelsFoo1Bar1(pod) + setPodAntiAffinityFooBar(pod) + test.SetPodPriority(pod, 0) + }), + }, + nodes: []*v1.Node{ + buildTestNode1(), + }, expectedEvictedPodCount: 1, }, { - description: "Evicts pod that conflicts with critical pod (but does not evict critical pod)", - maxPodsToEvictPerNode: &uint1, - pods: []*v1.Pod{p1, nonEvictablePod}, - nodes: []*v1.Node{node1}, + description: "Evicts pod that conflicts with critical pod (but does not evict critical pod)", + maxPodsToEvictPerNode: &uint1, + pods: []*v1.Pod{ + buildTestPodWithAntiAffinityForNode1("p1"), + buildTestPodNonEvictableForNode1(), + }, + nodes: []*v1.Node{ + buildTestNode1(), + }, expectedEvictedPodCount: 1, }, { - description: "Won't evict pods because node selectors don't match available nodes", - maxPodsToEvictPerNode: &uint1, - pods: []*v1.Pod{p8, nonEvictablePod}, - nodes: []*v1.Node{node1, node2}, + description: "Evicts pod that conflicts with critical pod (but does not evict critical pod)", + maxPodsToEvictPerNode: &uint1, + pods: []*v1.Pod{ + buildTestPodWithAntiAffinityForNode1("p1"), + buildTestPodNonEvictableForNode1(), + }, + nodes: []*v1.Node{ + buildTestNode1(), + }, + expectedEvictedPodCount: 1, + }, + { + description: "Won't evict pods because node selectors don't match available nodes", + maxPodsToEvictPerNode: &uint1, + pods: []*v1.Pod{ + buildTestPodForNode1("p8", func(pod *v1.Pod) { + pod.Spec.NodeSelector = map[string]string{ + "datacenter": "west", + } + }), + buildTestPodNonEvictableForNode1(), + }, + nodes: []*v1.Node{ + buildTestNode1(), + buildTestNode(nodeName2, func(node *v1.Node) { + node.ObjectMeta.Labels = map[string]string{ + "datacenter": "east", + } + }), + }, expectedEvictedPodCount: 0, nodeFit: true, }, { - description: "Won't evict pods because only other node is not schedulable", - maxPodsToEvictPerNode: &uint1, - pods: []*v1.Pod{p8, nonEvictablePod}, - nodes: []*v1.Node{node1, node3}, + description: "Won't evict pods because only other node is not schedulable", + maxPodsToEvictPerNode: &uint1, + pods: []*v1.Pod{ + buildTestPodForNode1("p8", func(pod *v1.Pod) { + pod.Spec.NodeSelector = map[string]string{ + "datacenter": "west", + } + }), + buildTestPodNonEvictableForNode1(), + }, + nodes: []*v1.Node{ + buildTestNode1(), + buildTestNode(nodeName3, func(node *v1.Node) { + node.Spec = v1.NodeSpec{ + Unschedulable: true, + } + }), + }, expectedEvictedPodCount: 0, nodeFit: true, }, { - description: "No pod to evicted since all pod terminating", - pods: []*v1.Pod{p9, p10}, - nodes: []*v1.Node{node1}, + description: "No pod to evicted since all pod terminating", + pods: []*v1.Pod{ + buildTestPodForNode1("p9", func(pod *v1.Pod) { + test.SetNormalOwnerRef(pod) + setPodAntiAffinityFooBar(pod) + pod.DeletionTimestamp = &metav1.Time{} + }), + buildTestPodForNode1("p10", func(pod *v1.Pod) { + test.SetNormalOwnerRef(pod) + setPodAntiAffinityFooBar(pod) + pod.DeletionTimestamp = &metav1.Time{} + }), + }, + nodes: []*v1.Node{ + buildTestNode1(), + }, expectedEvictedPodCount: 0, }, { - description: "Won't evict pods because only other node doesn't have enough resources", - maxPodsToEvictPerNode: &uint3, - pods: []*v1.Pod{p1, p2, p3, p4}, - nodes: []*v1.Node{node1, node4}, + description: "Won't evict pods because only other node doesn't have enough resources", + maxPodsToEvictPerNode: &uint3, + pods: []*v1.Pod{ + buildTestPodWithAntiAffinityForNode1("p1"), + buildTestPodP2ForNode1(), + buildTestPodWithAntiAffinityForNode1("p3"), + buildTestPodWithAntiAffinityForNode1("p4"), + }, + nodes: []*v1.Node{ + buildTestNode1(), + test.BuildTestNode(nodeName4, 2, 2, 1, nil), + }, expectedEvictedPodCount: 0, nodeFit: true, }, { - description: "Evict pod violating anti-affinity among different node (all pods have anti-affinity)", - pods: []*v1.Pod{p1, p11}, - nodes: []*v1.Node{node1, node5}, + description: "Evict pod violating anti-affinity among different node (all pods have anti-affinity)", + pods: []*v1.Pod{ + buildTestPodWithAntiAffinityForNode1("p1"), + buildTestPod("p11", nodeName5, func(pod *v1.Pod) { + test.SetNormalOwnerRef(pod) + setLabelsFooBar(pod) + }), + }, + nodes: []*v1.Node{ + buildTestNode1(), + test.BuildTestNode(nodeName5, 200, 3000, 10, setNodeMainRegionLabel), + }, expectedEvictedPodCount: 1, nodeFit: false, },