Added a test for quota allocation including non-quota resources.
This test verifies the behavior of allocating a resource to quota
roles that have no quota set for that particular resource (e.g.
allocating memory to a role with only quota set for CPU). If a
role has no quota set for a resource, it will get that resource
only when two conditions are both met:
(1) It is tentatively being allocated some other resources on the
same agent to meet its quota, or some reservations (which may
or may not involve quota resources); and
(2) After allocating those resources, quota headroom is still
above the required amount.
Review: https://reviews.apache.org/r/64794/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/9abb48fb
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/9abb48fb
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/9abb48fb
Branch: refs/heads/master
Commit: 9abb48fb0cba1be179de148555b5a48dc86408f7
Parents: 0c416d5
Author: Meng Zhu <[email protected]>
Authored: Fri Dec 22 15:05:57 2017 -0800
Committer: Benjamin Mahler <[email protected]>
Committed: Fri Dec 22 15:05:57 2017 -0800
----------------------------------------------------------------------
src/tests/hierarchical_allocator_tests.cpp | 105 ++++++++++++++++++++++++
1 file changed, 105 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/9abb48fb/src/tests/hierarchical_allocator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/hierarchical_allocator_tests.cpp
b/src/tests/hierarchical_allocator_tests.cpp
index ad9d556..9bc939d 100644
--- a/src/tests/hierarchical_allocator_tests.cpp
+++ b/src/tests/hierarchical_allocator_tests.cpp
@@ -3492,6 +3492,111 @@ TEST_F(HierarchicalAllocatorTest,
QuotaAllocationGranularityUnchoppableResource)
}
+// This test verifies the behavior of allocating a resource to quota roles
+// that has no quota set for that particular resource (e.g. allocating
+// memory to a role with only quota set for CPU). If a role has no quota
+// set for a resource, it will get that resource only when two conditions
+// are both met:
+//
+// - It was allocated quota resources on the agent;
+//
+// - It can be allocated without violating the quota headroom.
+TEST_F(HierarchicalAllocatorTest, QuotaRoleAllocateNonQuotaResource)
+{
+ Clock::pause();
+ initialize();
+
+ const string QUOTA_ROLE_1{"quota-role-1"};
+
+ const Quota quota1 = createQuota(QUOTA_ROLE_1, "cpus:2");
+ allocator->setQuota(QUOTA_ROLE_1, quota1);
+
+ SlaveInfo agent1 = createSlaveInfo("cpus:1;mem:1024;ports:[31000-32000]");
+ allocator->addSlave(
+ agent1.id(),
+ agent1,
+ AGENT_CAPABILITIES(),
+ None(),
+ agent1.resources(),
+ {});
+
+ // Create `framework` under `QUOTA_ROLE_1`.
+ // This will tigger an event-driven allocation loop.
+ FrameworkInfo framework = createFrameworkInfo({QUOTA_ROLE_1});
+ allocator->addFramework(framework.id(), framework, {}, true, {});
+
+ Clock::settle();
+
+ // `framework` will get all resources of `agent1`. Memory resource is
+ // allocated because `QUOTA_ROLE_1` does not have any memory quota limit
+ // and there is no need to set aside memory for other quota roles. Port
+ // resource is allocated due to the same reason (this is further due to
+ // the fact that ports are non-scalar resources that no roles can set
+ // quota for).
+ Allocation expected = Allocation(
+ framework.id(),
+ {{QUOTA_ROLE_1, {{agent1.id(), agent1.resources()}}}});
+
+ AWAIT_EXPECT_EQ(expected, allocations.get());
+
+ // QUOTA_ROLE_1:
+ // quota: "cpus:2"
+ // allocated: "cpus:1;mem:1024;ports:[31000-32000]" (agent1)
+
+ const string QUOTA_ROLE_2{"quota-role-2"};
+
+ const Quota quota2 = createQuota(QUOTA_ROLE_2, "mem:1024");
+ allocator->setQuota(QUOTA_ROLE_2, quota2);
+
+ // Add `agent2` with identical resources.
+ // This will trigger an event-driven allocation on `agent2`.
+ SlaveInfo agent2 = createSlaveInfo("cpus:1;mem:1024;ports:[31000-32000]");
+ allocator->addSlave(
+ agent2.id(),
+ agent2,
+ AGENT_CAPABILITIES(),
+ None(),
+ agent2.resources(),
+ {});
+
+ // `framework` will only get cpu and port resources. CPU resource is
+ // allocated because `QUOTA_ROLE_1` still needs one more CPU to meet its
+ // quota. Memory is NOT allocated even though `QUOTA_ROLE_1` has no memory
+ // quota limit because the memory needs to be set aside for `QUOTA_ROLE_2`.
+ // Port resource is allocated because `QUOTA_ROLE_1` does not have any port
+ // quota limit and there is no need to set aside the port resource for other
+ // quota roles ((this is further due to the fact that ports are non-scalar
+ // resources that no roles can set quota for).
+ expected = Allocation(
+ framework.id(),
+ {{QUOTA_ROLE_1, {{agent2.id(),
+ agent2.resources() - Resources(quota2.info.guarantee())}}}});
+
+ AWAIT_EXPECT_EQ(expected, allocations.get());
+
+ // QUOTA_ROLE_1:
+ // quota: "cpus:2"
+ // allocated: "cpus:1;mem:1024;ports:[31000-32000]" (agent1)
+ // "cpus:1;ports:[31000-32000]" (agent2)
+ //
+ // QUOTA_ROLE_1's quota has been met.
+
+ // Add `agent3` with identical resources.
+ // This will trigger an event-driven allocation on `agent3`.
+ SlaveInfo agent3 = createSlaveInfo("cpus:1;mem:1024;ports:[31000-32000]");
+ allocator->addSlave(
+ agent3.id(),
+ agent3,
+ AGENT_CAPABILITIES(),
+ None(),
+ agent3.resources(),
+ {});
+
+ // No allocation will happen because QUOTA_ROLE_1's quota has been met.
+ EXPECT_TRUE(allocations.get().isPending());
+}
+
+
// This test verifies, that the free pool (what is left after all quotas
// are satisfied) is allocated according to the DRF algorithm across the roles
// which do not have quota set.