pbacsko commented on code in PR #847:
URL: https://github.com/apache/yunikorn-core/pull/847#discussion_r1584978835
##########
pkg/scheduler/objects/preemption_test.go:
##########
@@ -226,6 +231,1194 @@ func TestTryPreemption(t *testing.T) {
assert.Check(t, !alloc2.IsPreempted(), "alloc2 not preempted")
}
+// TestTryPreemptionOnNode Test try preemption on node with simple queue
hierarchy. Since Node doesn't have enough resources to accomodate, preemption
happens because of node resource constraint.
+// Guaranteed and Max resource set on both victim queue path and preemptor
queue path in 2 levels. victim and preemptor queue are siblings.
+// Ask (Preemptor) resource type matches with all resource types of the
victim. But Guaranteed set only on specific resource type. 2 Victims are
available, but 1 should be preempted because further preemption would make
usage go below the guaranteed quota
+// Setup:
+// Nodes are Node1 and Node2. Nodes are full. No space to accommodate the ask.
+// root.parent. Guaranteed set on parent, first: 10
+// root.parent.child1. Guaranteed set, first: 5. 2 Allocations (belongs to
single app) are running. Each Allocation usage is first:5, pods: 1. Total usage
is first:10, pods: 2.
+// root.parent.child2. Guaranteed set, first: 5. Ask of first:5 is waiting for
resources.
+// 1 Allocation on root.parent.child1 should be preempted to free up resources
for ask arrived in root.parent.child2.
+func TestTryPreemptionOnNode(t *testing.T) {
+ t.SkipNow()
+ node1 := newNode("node1", map[string]resources.Quantity{"first": 5,
"pods": 1})
+ node2 := newNode("node2", map[string]resources.Quantity{"first": 5,
"pods": 1})
+ iterator := getNodeIteratorFn(node1, node2)
+ rootQ, err := createRootQueue(nil)
+ assert.NilError(t, err)
+ parentQ, err := createManagedQueueGuaranteed(rootQ, "parent", true,
map[string]string{"first": "20"}, map[string]string{"first": "10"})
+ assert.NilError(t, err)
+ childQ1, err := createManagedQueueGuaranteed(parentQ, "child1", false,
map[string]string{"first": "10"}, map[string]string{"first": "5"})
+ assert.NilError(t, err)
+ childQ2, err := createManagedQueueGuaranteed(parentQ, "child2", false,
map[string]string{"first": "10"}, map[string]string{"first": "5"})
+ assert.NilError(t, err)
+ app1 := newApplication(appID1, "default", "root.parent.child1")
+ app1.SetQueue(childQ1)
+ childQ1.applications[appID1] = app1
+ ask1 := newAllocationAsk("alloc1", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5, "pods":
1}))
+ ask1.createTime = time.Now().Add(-1 * time.Minute)
+ assert.NilError(t, app1.AddAllocationAsk(ask1))
+ ask2 := newAllocationAsk("alloc2", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5, "pods":
1}))
+ ask2.createTime = time.Now()
+ assert.NilError(t, app1.AddAllocationAsk(ask2))
+ alloc1 := NewAllocation("node1", ask1)
+ app1.AddAllocation(alloc1)
+ assert.Check(t, node1.AddAllocation(alloc1), "node alloc1 failed")
+ alloc2 := NewAllocation("node1", ask2)
+ app1.AddAllocation(alloc2)
+ assert.Check(t, node2.AddAllocation(alloc2), "node alloc2 failed")
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask1.GetAllocatedResource(), false))
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask2.GetAllocatedResource(), false))
+ app2 := newApplication(appID2, "default", "root.parent.child2")
+ app2.SetQueue(childQ2)
+ childQ2.applications[appID2] = app2
+ ask3 := newAllocationAsk("alloc3", appID2,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5, "pods":
1}))
+ assert.NilError(t, app2.AddAllocationAsk(ask3))
+ headRoom :=
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10, "pods":
3})
+ preemptor := NewPreemptor(app2, headRoom, 30*time.Second, ask3,
iterator(), false)
+
+ alloc, ok := preemptor.TryPreemption()
+ assert.Assert(t, ok, "no victims found")
+ assert.Equal(t, "alloc3", alloc.allocationKey, "wrong alloc")
+ assert.Check(t, !alloc1.IsPreempted(), "alloc1 preempted")
+ assert.Check(t, alloc2.IsPreempted(), "alloc2 not preempted")
+}
+
+// TestTryPreemptionOnQueue Test try preemption on queue with simple queue
hierarchy. Since Node has enough resources to accomodate, preemption happens
because of queue resource constraint.
+// Guaranteed and Max resource set on both victim queue path and preemptor
queue path in 2 levels. victim and preemptor queue are siblings.
+// Ask (Preemptor) resource type matches with all resource types of the
victim. But Guaranteed set only on specific resource type. 2 Victims are
available, but 1 should be preempted because further preemption would make
usage go below the guaranteed quota
+// Setup:
+// Nodes are Node1 and Node2. Node has enough space to accommodate the new ask.
+// root.parent. Guaranteed set on parent, first: 10
+// root.parent.child1. Guaranteed set, first: 5. 2 Allocations (belongs to
single app) are running. Each Allocation usage is first:5, pods: 1. Total usage
is first:10, pods: 2.
+// root.parent.child2. Guaranteed set, first: 5. Ask of first:5 is waiting for
resources.
+// 1 Allocation on root.parent.child1 should be preempted to free up resources
for ask arrived in root.parent.child2.
+func TestTryPreemptionOnQueue(t *testing.T) {
+ t.SkipNow()
+ node1 := newNode("node1", map[string]resources.Quantity{"first": 10,
"pods": 2})
+ node2 := newNode("node2", map[string]resources.Quantity{"first": 10,
"pods": 2})
+ iterator := getNodeIteratorFn(node1, node2)
+ rootQ, err := createRootQueue(nil)
+ assert.NilError(t, err)
+ parentQ, err := createManagedQueueGuaranteed(rootQ, "parent", true,
map[string]string{"first": "10"}, nil)
+ assert.NilError(t, err)
+ childQ1, err := createManagedQueueGuaranteed(parentQ, "child1", false,
nil, map[string]string{"first": "5"})
+ assert.NilError(t, err)
+ childQ2, err := createManagedQueueGuaranteed(parentQ, "child2", false,
nil, map[string]string{"first": "5"})
+ assert.NilError(t, err)
+ app1 := newApplication(appID1, "default", "root.parent.child1")
+ app1.SetQueue(childQ1)
+ childQ1.applications[appID1] = app1
+ ask1 := newAllocationAsk("alloc1", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5, "pods":
1}))
+ ask1.createTime = time.Now().Add(-1 * time.Minute)
+ assert.NilError(t, app1.AddAllocationAsk(ask1))
+ ask2 := newAllocationAsk("alloc2", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5, "pods":
1}))
+ ask2.createTime = time.Now()
+ assert.NilError(t, app1.AddAllocationAsk(ask2))
+ alloc1 := NewAllocation("node1", ask1)
+ app1.AddAllocation(alloc1)
+ assert.Check(t, node1.AddAllocation(alloc1), "node alloc1 failed")
+ alloc2 := NewAllocation("node1", ask2)
+ app1.AddAllocation(alloc2)
+ assert.Check(t, node2.AddAllocation(alloc2), "node alloc2 failed")
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask1.GetAllocatedResource(), false))
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask2.GetAllocatedResource(), false))
+ app2 := newApplication(appID2, "default", "root.parent.child2")
+ app2.SetQueue(childQ2)
+ childQ2.applications[appID2] = app2
+ ask3 := newAllocationAsk("alloc3", appID2,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5, "pods":
1}))
+ assert.NilError(t, app2.AddAllocationAsk(ask3))
+ headRoom :=
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10, "pods":
3})
+ preemptor := NewPreemptor(app2, headRoom, 30*time.Second, ask3,
iterator(), false)
+
+ alloc, ok := preemptor.TryPreemption()
+ assert.Assert(t, ok, "no victims found")
+ assert.Equal(t, "alloc3", alloc.allocationKey, "wrong alloc")
+ assert.Check(t, !alloc1.IsPreempted(), "alloc1 preempted")
+ assert.Check(t, alloc2.IsPreempted(), "alloc2 not preempted")
+}
+
+// TestTryPreemptionWithVictimsAvailableButInsufficientResource Test try
preemption on queue with simple queue hierarchy. Since Node has enough
resources to accomodate, preemption happens because of queue resource
constraint.
+// Guaranteed and Max resource set on both victim queue path and preemptor
queue path. victim and preemptor queue are siblings.
+// Ask (Preemptor) resource type matches with 1 resource type of the victim.
Guaranteed also set on specific resource type. 2 Victims are available, but
total resource usage is lesser than ask requirement.
+// Setup:
+// Nodes are Node1 and Node2. Node has enough space to accommodate the new ask.
+// root.parent.Max set on parent, first: 8
+// root.parent.child1. Guaranteed not set. 2 Allocations (belongs to single
app) are running. Each Allocation usage is first:2, pods: 1. Total usage is
first:4, pods: 2.
+// root.parent.child2. Guaranteed set, first: 5. Ask of first:5 is waiting for
resources.
+// 2 Allocation on root.parent.child1 has been found and considered as
victims. Since victims total resource usage (first: 4) is lesser than ask
requirment (first: 5), preemption won't help. Hence, victims are dropped.
+func TestTryPreemptionWithVictimsAvailableButInsufficientResource(t
*testing.T) {
+ t.SkipNow()
+ node1 := newNode(node1, map[string]resources.Quantity{"first": 10,
"pods": 2})
+ node2 := newNode("node2", map[string]resources.Quantity{"first": 10,
"pods": 2})
+ iterator := getNodeIteratorFn(node1, node2)
+ rootQ, err := createRootQueue(map[string]string{"first": "20", "pods":
"5"})
+ assert.NilError(t, err)
+ parentQ, err := createManagedQueueGuaranteed(rootQ, "parent", true,
map[string]string{"first": "8"}, nil)
+ assert.NilError(t, err)
+ childQ1, err := createManagedQueueGuaranteed(parentQ, "child1", false,
nil, nil)
+ assert.NilError(t, err)
+ childQ2, err := createManagedQueueGuaranteed(parentQ, "child2", false,
nil, map[string]string{"first": "5"})
+ assert.NilError(t, err)
+ app1 := newApplication(appID1, "default", "root.parent.child1")
+ app1.SetQueue(childQ1)
+ childQ1.applications[appID1] = app1
+ ask1 := newAllocationAsk("alloc1", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 2, "pods":
1}))
+ ask1.createTime = time.Now().Add(-1 * time.Minute)
+ assert.NilError(t, app1.AddAllocationAsk(ask1))
+ ask2 := newAllocationAsk("alloc2", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 2, "pods":
1}))
+ ask2.createTime = time.Now()
+ assert.NilError(t, app1.AddAllocationAsk(ask2))
+ alloc1 := NewAllocation("node1", ask1)
+ app1.AddAllocation(alloc1)
+ assert.Check(t, node1.AddAllocation(alloc1), "node alloc1 failed")
+ alloc2 := NewAllocation("node1", ask2)
+ app1.AddAllocation(alloc2)
+ assert.Check(t, node2.AddAllocation(alloc2), "node alloc2 failed")
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask1.GetAllocatedResource(), false))
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask2.GetAllocatedResource(), false))
+ app2 := newApplication(appID2, "default", "root.parent.child2")
+ app2.SetQueue(childQ2)
+ childQ2.applications[appID2] = app2
+ ask3 := newAllocationAsk("alloc3", appID2,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5}))
+ assert.NilError(t, app2.AddAllocationAsk(ask3))
+ headRoom :=
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10, "pods":
3})
+ preemptor := NewPreemptor(app2, headRoom, 30*time.Second, ask3,
iterator(), false)
+
+ alloc, ok := preemptor.TryPreemption()
+ var expectedAlloc *Allocation
+ assert.Equal(t, ok, false, "no victims found")
+ assert.Equal(t, alloc, expectedAlloc, "wrong alloc")
+ assert.Check(t, !alloc1.IsPreempted(), "alloc1 preempted")
+ assert.Check(t, !alloc2.IsPreempted(), "alloc2 not preempted")
+}
+
+//
TestTryPreemptionWithVictimsAvailableOnDifferentNodesButInsufficientResource
Test try preemption on queue with simple queue hierarchy. Since Node doesn't
have enough resources to accomodate, preemption happens because of node
resource constraint.
+// Guaranteed and Max resource set on both victim queue path and preemptor
queue path. victim and preemptor queue are siblings.
+// Ask (Preemptor) resource type matches with 1 resource type of the victim.
Guaranteed also set on specific resource type. 2 Victims are available, but
total resource usage is lesser than ask requirement.
+// Setup:
+// Nodes are Node1 and Node2. Both Nodes are almost full. No space to
accommodate the ask.
+// root.parent.Max set on parent, first: 6
+// root.parent.child1. Guaranteed not set. 2 Allocations (belongs to single
app) are running. Each Allocation usage is first:2, pods: 1. Total usage is
first:4, pods: 2.
+// root.parent.child2. Guaranteed set, first: 5. Ask of first:5 is waiting for
resources.
+// 2 Allocation on root.parent.child1 has been found and considered as
victims. Since victims total resource usage (first: 4) is lesser than ask
requirment (first: 5), preemption won't help. Hence, victims are dropped.
+func
TestTryPreemptionWithVictimsAvailableOnDifferentNodesButInsufficientResource(t
*testing.T) {
+ t.SkipNow()
+ node1 := newNode(node1, map[string]resources.Quantity{"first": 5,
"pods": 1})
+ node2 := newNode("node2", map[string]resources.Quantity{"first": 5,
"pods": 1})
+ iterator := getNodeIteratorFn(node1, node2)
+ rootQ, err := createRootQueue(nil)
+ assert.NilError(t, err)
+ parentQ, err := createManagedQueueGuaranteed(rootQ, "parent", true,
map[string]string{"first": "6"}, nil)
+ assert.NilError(t, err)
+ childQ1, err := createManagedQueueGuaranteed(parentQ, "child1", false,
nil, nil)
+ assert.NilError(t, err)
+ childQ2, err := createManagedQueueGuaranteed(parentQ, "child2", false,
nil, map[string]string{"first": "5"})
+ assert.NilError(t, err)
+ app1 := newApplication(appID1, "default", "root.parent.child1")
+ app1.SetQueue(childQ1)
+ childQ1.applications[appID1] = app1
+ ask1 := newAllocationAsk("alloc1", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 2, "pods":
1}))
+ ask1.createTime = time.Now().Add(-1 * time.Minute)
+ assert.NilError(t, app1.AddAllocationAsk(ask1))
+ ask2 := newAllocationAsk("alloc2", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 2, "pods":
1}))
+ ask2.createTime = time.Now()
+ assert.NilError(t, app1.AddAllocationAsk(ask2))
+ alloc1 := NewAllocation("node1", ask1)
+ app1.AddAllocation(alloc1)
+ assert.Check(t, node1.AddAllocation(alloc1), "node alloc1 failed")
+ alloc2 := NewAllocation("node2", ask2)
+ app1.AddAllocation(alloc2)
+ assert.Check(t, node2.AddAllocation(alloc2), "node alloc2 failed")
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask1.GetAllocatedResource(), false))
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask2.GetAllocatedResource(), false))
+ app2 := newApplication(appID2, "default", "root.parent.child2")
+ app2.SetQueue(childQ2)
+ childQ2.applications[appID2] = app2
+ ask3 := newAllocationAsk("alloc3", appID2,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5}))
+ assert.NilError(t, app2.AddAllocationAsk(ask3))
+ headRoom :=
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10, "pods":
3})
+ preemptor := NewPreemptor(app2, headRoom, 30*time.Second, ask3,
iterator(), false)
+
+ // register predicate handler
+ preemptions := []mock.Preemption{
+ mock.NewPreemption(true, "alloc3", "node1", []string{"alloc1"},
0, 0),
+ mock.NewPreemption(true, "alloc3", "node2", []string{"alloc2"},
0, 0),
+ }
+
+ plugin := mock.NewPreemptionPredicatePlugin(nil, nil, preemptions)
+ plugins.RegisterSchedulerPlugin(plugin)
+ defer plugins.UnregisterSchedulerPlugins()
+
+ alloc, ok := preemptor.TryPreemption()
+ var expectedAlloc *Allocation
+ assert.Equal(t, ok, false, "no victims found")
+ assert.Equal(t, alloc, expectedAlloc, "wrong alloc")
+ assert.Check(t, !alloc1.IsPreempted(), "alloc1 preempted")
+ assert.Check(t, !alloc2.IsPreempted(), "alloc2 not preempted")
+}
+
+// TestTryPreemptionWithVictimsAvailableButOnDifferentNodes Test try
preemption on queue with simple queue hierarchy. Since Node doesn't have enough
resources to accomodate, preemption happens because of node resource constraint.
+// Guaranteed and Max resource set on both victim queue path and preemptor
queue path. victim and preemptor queue are siblings.
+// Ask (Preemptor) resource type matches with 1 resource type of the victim.
Guaranteed also set on specific resource type. 2 Victims are available, but
total resource usage is lesser than ask requirement.
+// Setup:
+// Nodes are Node1 and Node2. Both Nodes are almost full. No space to
accommodate the ask. Node 2 won't even fit because max capacity itself is
lesser than ask requirement. Hence, Node 1 only is eligible.
+// root.parent.Max set on parent, first: 6
+// root.parent.child1. Guaranteed not set. 2 Allocations (belongs to single
app) are running. 1st Allocation usage is first:4, pods: 1. 2nd Allocation
usage is first:2, pods: 1. Total usage is first:6, pods: 2.
+// root.parent.child2. Guaranteed set, first: 5. Ask of first:5 is waiting for
resources.
+// 2 Allocation on root.parent.child1 has been found and considered as victims
and preempted to free up resources for ask.
+func TestTryPreemptionWithVictimsAvailableButOnDifferentNodes(t *testing.T) {
+ t.SkipNow()
+ node1 := newNode(node1, map[string]resources.Quantity{"first": 5,
"pods": 1})
+ node2 := newNode("node2", map[string]resources.Quantity{"first": 4,
"pods": 1})
+ iterator := getNodeIteratorFn(node1, node2)
+ rootQ, err := createRootQueue(nil)
+ assert.NilError(t, err)
+ parentQ, err := createManagedQueueGuaranteed(rootQ, "parent", true,
map[string]string{"first": "6"}, nil)
+ assert.NilError(t, err)
+ childQ1, err := createManagedQueueGuaranteed(parentQ, "child1", false,
nil, nil)
+ assert.NilError(t, err)
+ childQ2, err := createManagedQueueGuaranteed(parentQ, "child2", false,
nil, map[string]string{"first": "5"})
+ assert.NilError(t, err)
+ app1 := newApplication(appID1, "default", "root.parent.child1")
+ app1.SetQueue(childQ1)
+ childQ1.applications[appID1] = app1
+ ask1 := newAllocationAsk("alloc1", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 4, "pods":
1}))
+ ask1.createTime = time.Now().Add(-1 * time.Minute)
+ assert.NilError(t, app1.AddAllocationAsk(ask1))
+ ask2 := newAllocationAsk("alloc2", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 2, "pods":
1}))
+ ask2.createTime = time.Now()
+ assert.NilError(t, app1.AddAllocationAsk(ask2))
+ alloc1 := NewAllocation("node1", ask1)
+ app1.AddAllocation(alloc1)
+ assert.Check(t, node1.AddAllocation(alloc1), "node alloc1 failed")
+ alloc2 := NewAllocation("node2", ask2)
+ app1.AddAllocation(alloc2)
+ assert.Check(t, node2.AddAllocation(alloc2), "node alloc2 failed")
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask1.GetAllocatedResource(), false))
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask2.GetAllocatedResource(), false))
+ app2 := newApplication(appID2, "default", "root.parent.child2")
+ app2.SetQueue(childQ2)
+ childQ2.applications[appID2] = app2
+ ask3 := newAllocationAsk("alloc3", appID2,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5}))
+ assert.NilError(t, app2.AddAllocationAsk(ask3))
+ headRoom :=
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10, "pods":
3})
+ preemptor := NewPreemptor(app2, headRoom, 30*time.Second, ask3,
iterator(), false)
+
+ // register predicate handler
+ preemptions := []mock.Preemption{
+ mock.NewPreemption(true, "alloc3", "node1", []string{"alloc1"},
0, 0),
+ mock.NewPreemption(true, "alloc3", "node2", []string{"alloc2"},
0, 0),
+ }
+
+ plugin := mock.NewPreemptionPredicatePlugin(nil, nil, preemptions)
+ plugins.RegisterSchedulerPlugin(plugin)
+ defer plugins.UnregisterSchedulerPlugins()
+
+ alloc, ok := preemptor.TryPreemption()
+ assert.Assert(t, ok, "no victims found")
+ assert.Equal(t, "alloc3", alloc.allocationKey, "wrong alloc")
+ assert.Check(t, alloc1.IsPreempted(), "alloc1 preempted")
+ assert.Check(t, alloc2.IsPreempted(), "alloc2 not preempted")
+}
+
+// TestTryPreemptionOnQueueWithVictimsOnDifferentNodes Test try preemption on
queue with simple queue hierarchy. Since Node has enough resources to
accomodate, preemption happens because of queue resource constraint.
+// Guaranteed and Max resource set on both victim queue path and preemptor
queue paths. victim and preemptor queue are siblings.
+// Ask (Preemptor) resource type matches with all resource types of the
victim. Guaranteed set only on that specific resource type.
+// Setup:
+// Nodes are Node1 and Node2. Node has enough space to accommodate the new ask.
+// root.parent. Max set on parent, first: 18
+// root.parent.child1. Guaranteed not set. 2 Allocations (belongs to single
app) are running on node1 and node2. Each Allocation usage is first:5. Total
usage is first:10.
+// root.parent.child2. Guaranteed set 5. Ask of first:5 is waiting for
resources.
+// root.parent.child3. Guaranteed not set. 1 Allocation is running on node2.
Total usage is first:5.
+// Preemption options are 1. 2 Alloc running on Node 2 but on child 1 and
child 3 queues. 2. 2 Alloc running on Node 2 and child 1 queue. 3. All three 3
allocs.
+// option 1 >> option 2 >> option 3. In option 3, preempting third allocation
is unnecessary, should avoid this option.
+// Either option 1 or option2 is fine, but not option 3.
+func TestTryPreemptionOnQueueWithVictimsOnDifferentNodes(t *testing.T) {
+ t.SkipNow()
+ node1 := newNode(node1, map[string]resources.Quantity{"first": 30})
+ node2 := newNode("node2", map[string]resources.Quantity{"first": 30})
+ iterator := getNodeIteratorFn(node1, node2)
+ rootQ, err := createRootQueue(nil)
+ assert.NilError(t, err)
+ parentQ, err := createManagedQueueGuaranteed(rootQ, "parent", true,
map[string]string{"first": "18"}, nil)
+ assert.NilError(t, err)
+ childQ1, err := createManagedQueueGuaranteed(parentQ, "child1", false,
nil, nil)
+ assert.NilError(t, err)
+ childQ2, err := createManagedQueueGuaranteed(parentQ, "child2", false,
nil, map[string]string{"first": "15"})
+ assert.NilError(t, err)
+ childQ3, err := createManagedQueueGuaranteed(parentQ, "child3", false,
nil, nil)
+ assert.NilError(t, err)
+ app1 := newApplication(appID1, "default", "root.parent.child1")
+ app1.SetQueue(childQ1)
+ childQ1.applications[appID1] = app1
+ ask1 := newAllocationAsk("alloc1", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5}))
+ ask1.createTime = time.Now().Add(-2 * time.Minute)
+ assert.NilError(t, app1.AddAllocationAsk(ask1))
+ ask2 := newAllocationAsk("alloc2", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5}))
+ ask2.createTime = time.Now().Add(-1 * time.Minute)
+ assert.NilError(t, app1.AddAllocationAsk(ask2))
+ alloc1 := NewAllocation("node1", ask1)
+ app1.AddAllocation(alloc1)
+ assert.Check(t, node1.AddAllocation(alloc1), "node alloc1 failed")
+ alloc2 := NewAllocation("node2", ask2)
+ app1.AddAllocation(alloc2)
+ assert.Check(t, node2.AddAllocation(alloc2), "node alloc2 failed")
+
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask1.GetAllocatedResource(), false))
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask2.GetAllocatedResource(), false))
+
+ app3 := newApplication(appID3, "default", "root.parent.child3")
+ app3.SetQueue(childQ3)
+ childQ3.applications[appID3] = app3
+
+ ask4 := newAllocationAsk("alloc4", appID3,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5}))
+ ask4.createTime = time.Now()
+ assert.NilError(t, app3.AddAllocationAsk(ask4))
+
+ alloc4 := NewAllocation("node2", ask4)
+ app3.AddAllocation(alloc4)
+ assert.Check(t, node2.AddAllocation(alloc4), "node alloc2 failed")
+ assert.NilError(t,
childQ3.IncAllocatedResource(ask4.GetAllocatedResource(), false))
+
+ app2 := newApplication(appID2, "default", "root.parent.child2")
+ app2.SetQueue(childQ2)
+ childQ2.applications[appID2] = app2
+ ask3 := newAllocationAsk("alloc3", appID2,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10}))
+ assert.NilError(t, app2.AddAllocationAsk(ask3))
+ headRoom :=
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10, "pods":
3})
+ preemptor := NewPreemptor(app2, headRoom, 30*time.Second, ask3,
iterator(), false)
+
+ allocs := map[string]string{}
+ allocs["alloc3"] = "node2"
+
+ plugin := mock.NewPreemptionPredicatePlugin(nil, allocs, nil)
+ plugins.RegisterSchedulerPlugin(plugin)
+ defer plugins.UnregisterSchedulerPlugins()
+
+ alloc, ok := preemptor.TryPreemption()
+ assert.Assert(t, ok, "no victims found")
+ assert.Equal(t, "alloc3", alloc.allocationKey, "wrong alloc")
+ assert.Equal(t, "node2", alloc.nodeID, "wrong alloc")
+ assert.Equal(t, "node1", alloc1.nodeID, "wrong alloc")
+ assert.Equal(t, "node2", alloc2.nodeID, "wrong alloc")
+ assert.Equal(t, "node2", alloc4.nodeID, "wrong alloc")
+ assert.Check(t, !alloc1.IsPreempted(), "alloc1 preempted")
+ assert.Check(t, alloc2.IsPreempted(), "alloc2 not preempted")
+ assert.Check(t, alloc4.IsPreempted(), "alloc2 not preempted")
+}
+
+// TestTryPreemptionOnQueueWithVictimsAvailableButLowerPriority Test try
preemption on queue with simple queue hierarchy. Since Node has enough
resources to accomodate, preemption happens because of queue resource
constraint.
+// Guaranteed and Max resource set on both victim queue path and preemptor
queue paths. victim and preemptor queue are siblings.
+// Ask (Preemptor) resource type matches with all resource types of the
victim. Guaranteed set only on that specific resource type.
+// Setup:
+// Nodes are Node1 and Node2. Node has enough space to accommodate the new ask.
+// root.parent. Max set on parent, first: 18
+// root.parent.child1. Guaranteed not set. 2 Allocations (belongs to single
app) are running on node1 and node2. Each Allocation usage is first:5. Total
usage is first:10.
+// root.parent.child2. Guaranteed set 5. Ask of first:5 is waiting for
resources.
+// root.parent.child3. Guaranteed not set. 1 Allocation is running on node2.
Total usage is first:5.
+// High priority ask should not be touched and remaining 2 allocs should be
preempted to free up resources
+func TestTryPreemptionOnQueueWithVictimsAvailableButLowerPriority(t
*testing.T) {
+ t.SkipNow()
+ node1 := newNode(node1, map[string]resources.Quantity{"first": 30})
+ node2 := newNode("node2", map[string]resources.Quantity{"first": 30})
+ iterator := getNodeIteratorFn(node1, node2)
+ rootQ, err := createRootQueue(nil)
+ assert.NilError(t, err)
+ parentQ, err := createManagedQueueGuaranteed(rootQ, "parent", true,
map[string]string{"first": "18"}, nil)
+ assert.NilError(t, err)
+ childQ1, err := createManagedQueueGuaranteed(parentQ, "child1", false,
nil, nil)
+ assert.NilError(t, err)
+ childQ2, err := createManagedQueueGuaranteed(parentQ, "child2", false,
nil, map[string]string{"first": "15"})
+ assert.NilError(t, err)
+ childQ3, err := createManagedQueueGuaranteed(parentQ, "child3", false,
nil, nil)
+ assert.NilError(t, err)
+ app1 := newApplication(appID1, "default", "root.parent.child1")
+ app1.SetQueue(childQ1)
+ childQ1.applications[appID1] = app1
+ ask1 := newAllocationAsk("alloc1", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5}))
+ ask1.createTime = time.Now().Add(-2 * time.Minute)
+ assert.NilError(t, app1.AddAllocationAsk(ask1))
+
+ // High priority ask, should not be considered as victim
+ ask2 := newAllocationAskPriority("alloc2", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5}), 1000)
+ ask2.createTime = time.Now().Add(-1 * time.Minute)
+ assert.NilError(t, app1.AddAllocationAsk(ask2))
+ alloc1 := NewAllocation("node1", ask1)
+ app1.AddAllocation(alloc1)
+ assert.Check(t, node1.AddAllocation(alloc1), "node alloc1 failed")
+ alloc2 := NewAllocation("node2", ask2)
+ app1.AddAllocation(alloc2)
+ assert.Check(t, node2.AddAllocation(alloc2), "node alloc2 failed")
+
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask1.GetAllocatedResource(), false))
+ assert.NilError(t,
childQ1.IncAllocatedResource(ask2.GetAllocatedResource(), false))
+
+ app3 := newApplication(appID3, "default", "root.parent.child3")
+ app3.SetQueue(childQ3)
+ childQ3.applications[appID3] = app3
+
+ ask4 := newAllocationAsk("alloc4", appID3,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5}))
+ ask4.createTime = time.Now()
+ assert.NilError(t, app3.AddAllocationAsk(ask4))
+
+ alloc4 := NewAllocation("node2", ask4)
+ app3.AddAllocation(alloc4)
+ assert.Check(t, node2.AddAllocation(alloc4), "node alloc2 failed")
+ assert.NilError(t,
childQ3.IncAllocatedResource(ask4.GetAllocatedResource(), false))
+
+ app2 := newApplication(appID2, "default", "root.parent.child2")
+ app2.SetQueue(childQ2)
+ childQ2.applications[appID2] = app2
+ ask3 := newAllocationAsk("alloc3", appID2,
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10}))
+ assert.NilError(t, app2.AddAllocationAsk(ask3))
+ headRoom :=
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10, "pods":
3})
+ preemptor := NewPreemptor(app2, headRoom, 30*time.Second, ask3,
iterator(), false)
+
+ allocs := map[string]string{}
+ allocs["alloc3"] = "node2"
+
+ plugin := mock.NewPreemptionPredicatePlugin(nil, allocs, nil)
+ plugins.RegisterSchedulerPlugin(plugin)
+ defer plugins.UnregisterSchedulerPlugins()
+
+ alloc, ok := preemptor.TryPreemption()
+ assert.Assert(t, ok, "no victims found")
+ assert.Equal(t, "alloc3", alloc.allocationKey, "wrong alloc")
+ assert.Equal(t, "node2", alloc.nodeID, "wrong alloc")
+ assert.Equal(t, "node1", alloc1.nodeID, "wrong alloc")
+ assert.Equal(t, "node2", alloc2.nodeID, "wrong alloc")
+ assert.Equal(t, "node2", alloc4.nodeID, "wrong alloc")
+ assert.Check(t, alloc1.IsPreempted(), "alloc1 preempted")
+ assert.Check(t, !alloc2.IsPreempted(), "alloc2 not preempted")
+ assert.Check(t, alloc4.IsPreempted(), "alloc2 not preempted")
+}
+
+// TestPreemptionWithAskResTypesDifferedFromGuaranteedSetOnPreemptorSide Test
try preemption with 2 level queue hierarchy.
+// Guaranteed set only on preemptor queue path, but not on the victim queue
path.
+// Ask (Preemptor) resource type matches with one of the victim's resource
types. Still, needs to be preempted because matching resource type has been
configured as guaranteed.
+// Setup:
+// Nodes are Node1. Node has enough space to accommodate the new ask.
+// root.parent.parent1.child1. Guaranteed set on root.parent.parent1, vcores:
1. Ask of vcores: 1 is waiting for resources.
+// root.parent.parent2.child2. 2 Allocations (belongs to single app) are
running. Each Allocation usage is vcores:1, mem: 200. Total usage is vcores:2,
mem: 400
+// root.parent.parent2.child3. No usage, no guaranteed set
+// 1 Allocation on root.parent.parent1.child2 should be preempted to free up
resources for ask arrived in root.parent.parent1.child1.
+func TestPreemptionWithAskResTypesDifferedFromGuaranteedSetOnPreemptorSide(t
*testing.T) {
+ t.SkipNow()
+ node := newNode(node1, map[string]resources.Quantity{"vcores": 3,
"mem": 400})
+ iterator := getNodeIteratorFn(node)
+ rootQ, err := createRootQueue(nil)
+ assert.NilError(t, err)
+ parentQ, err := createManagedQueueGuaranteed(rootQ, "parent", true,
map[string]string{"vcores": "2"}, nil)
+ assert.NilError(t, err)
+ parentQ1, err := createManagedQueueGuaranteed(parentQ, "parent1", true,
nil, map[string]string{"vcores": "1"})
+ assert.NilError(t, err)
+ parentQ2, err := createManagedQueueGuaranteed(parentQ, "parent2", true,
nil, nil)
+ assert.NilError(t, err)
+
+ childQ1, err := createManagedQueueGuaranteed(parentQ1, "child1", false,
nil, nil)
+ assert.NilError(t, err)
+ childQ2, err := createManagedQueueGuaranteed(parentQ2, "child2", false,
nil, nil)
+ assert.NilError(t, err)
+ _, err = createManagedQueueGuaranteed(parentQ2, "child3", false, nil,
nil)
+ assert.NilError(t, err)
+
+ app1 := newApplication(appID1, "default", "root.parent.parent2.child2")
+ app1.SetQueue(childQ2)
+ childQ2.applications[appID1] = app1
+ ask1 := newAllocationAsk("alloc1", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"vcores": 1, "mem":
200}))
+ ask1.createTime = time.Now().Add(-1 * time.Minute)
+ assert.NilError(t, app1.AddAllocationAsk(ask1))
+ ask2 := newAllocationAsk("alloc2", appID1,
resources.NewResourceFromMap(map[string]resources.Quantity{"vcores": 1, "mem":
200}))
+ ask2.createTime = time.Now()
+ assert.NilError(t, app1.AddAllocationAsk(ask2))
+ alloc1 := NewAllocation(node1, ask1)
+ app1.AddAllocation(alloc1)
+ assert.Check(t, node.AddAllocation(alloc1), "node alloc1 failed")
+ alloc2 := NewAllocation(node1, ask2)
+ app1.AddAllocation(alloc2)
+ assert.Check(t, node.AddAllocation(alloc2), "node alloc2 failed")
+ assert.NilError(t,
childQ2.IncAllocatedResource(ask1.GetAllocatedResource(), false))
+ assert.NilError(t,
childQ2.IncAllocatedResource(ask2.GetAllocatedResource(), false))
+ app2 := newApplication(appID2, "default", "root.parent.parent1.child1")
+ app2.SetQueue(childQ1)
+ childQ1.applications[appID2] = app2
+ ask3 := newAllocationAsk("alloc3", appID2,
resources.NewResourceFromMap(map[string]resources.Quantity{"vcores": 1}))
+ assert.NilError(t, app2.AddAllocationAsk(ask3))
+ headRoom :=
resources.NewResourceFromMap(map[string]resources.Quantity{"vcores": 2})
+ preemptor := NewPreemptor(app2, headRoom, 30*time.Second, ask3,
iterator(), false)
+
+ alloc, ok := preemptor.TryPreemption()
+ assert.Assert(t, ok, "no victims found")
+ assert.Equal(t, "alloc3", alloc.allocationKey, "wrong alloc")
+ assert.Check(t, !alloc1.IsPreempted(), "alloc1 preempted")
+ assert.Check(t, alloc2.IsPreempted(), "alloc2 not preempted")
+}
+
+// TestPreemptionOnNodeWithAskResTypesDifferedFromGuaranteedSetOnPreemptorSide
Test try preemption with 2 level queue hierarchy. Since Node doesn't have
enough resources to accomodate, preemption happens because of node resource
constraint.
+// Guaranteed set only on preemptor queue path, but not on the victim queue
path.
+// Ask (Preemptor) resource type matches with one of the victim's resource
types. Still, needs to be preempted because matching resource type has been
configured as guaranteed.
+// Setup:
+// Nodes are Node1. Node is full, doesn't enough space to accommodate the ask.
+// root.parent.parent1.child1. Guaranteed set on root.parent.parent1, vcores:
1. Ask of vcores: 1 is waiting for resources.
+// root.parent.parent2.child2. 2 Allocations (belongs to single app) are
running. Each Allocation usage is vcores:1, mem: 200. Total usage is vcores:2,
mem: 400
+// root.parent.parent2.child3. No usage, no guaranteed set
+// 1 Allocation on root.parent.parent1.child2 should be preempted to free up
resources for ask arrived in root.parent.parent1.child1.
+func
TestPreemptionOnNodeWithAskResTypesDifferedFromGuaranteedSetOnPreemptorSide(t
*testing.T) {
Review Comment:
nit: naming:
TestTryPreemptionOnNode_AskResTypesDifferent_GuaranteedOnPreemptorSide`.
EDIT: there are still tests left, but the rest should be obvious after these
examples.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]