You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2017/12/13 20:32:19 UTC

mesos git commit: Added tests for quota enforcement with unallocated reservations.

Repository: mesos
Updated Branches:
  refs/heads/master 0277a0015 -> da9ca553f


Added tests for quota enforcement with unallocated reservations.

Previously, it was possible for roles to exceed their quota limit
via reservations (see MESOS-4527). This introduces tests to ensure
that roles cannot exceed their limit due to reservations.

Review: https://reviews.apache.org/r/64493/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/da9ca553
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/da9ca553
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/da9ca553

Branch: refs/heads/master
Commit: da9ca553f989a7e704c91bed7582d58655605631
Parents: 0277a00
Author: Meng Zhu <mz...@mesosphere.io>
Authored: Wed Dec 13 12:11:43 2017 -0800
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Wed Dec 13 12:30:59 2017 -0800

----------------------------------------------------------------------
 src/tests/hierarchical_allocator_tests.cpp | 182 ++++++++++++++++++++++++
 1 file changed, 182 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/da9ca553/src/tests/hierarchical_allocator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/hierarchical_allocator_tests.cpp b/src/tests/hierarchical_allocator_tests.cpp
index 862f468..f5fb47e 100644
--- a/src/tests/hierarchical_allocator_tests.cpp
+++ b/src/tests/hierarchical_allocator_tests.cpp
@@ -1266,6 +1266,188 @@ TEST_F(HierarchicalAllocatorTest, SameShareFairness)
 }
 
 
+class HierarchicalAllocatorTestWithReservations
+  : public HierarchicalAllocatorTestBase,
+    public WithParamInterface<Resource::ReservationInfo::Type> {};
+
+
+INSTANTIATE_TEST_CASE_P(
+    ReservationTypeSwitch,
+    HierarchicalAllocatorTestWithReservations,
+    testing::Values(
+        Resource::ReservationInfo::DYNAMIC,
+        Resource::ReservationInfo::STATIC));
+
+
+// This test verifies that the reservations should be
+// accounted towards the quota guarantee/limit even if
+// they are currently unallocated.
+TEST_P(HierarchicalAllocatorTestWithReservations, ReservationUnallocated)
+{
+  Clock::pause();
+
+  const string QUOTA_ROLE{"quota-role"};
+
+  initialize();
+
+  Resource::ReservationInfo reservation;
+  reservation.set_type(GetParam());
+  reservation.set_role(QUOTA_ROLE);
+
+  Resources resources = Resources::parse("cpus:1;mem:1024").get();
+  resources = resources.pushReservation(reservation);
+
+  SlaveInfo agent1 = createSlaveInfo(resources);
+  allocator->addSlave(
+      agent1.id(),
+      agent1,
+      AGENT_CAPABILITIES(),
+      None(),
+      agent1.resources(),
+      {});
+
+  Resources reserved = Resources(agent1.resources()).reserved(QUOTA_ROLE);
+
+  // Set a quota for 1x agent resources.
+  const Quota quota = createQuota(QUOTA_ROLE, "cpus:1;mem:1024");
+  allocator->setQuota(QUOTA_ROLE, quota);
+
+  // Create `framework1` and set quota for its role.
+  FrameworkInfo framework1 = createFrameworkInfo({QUOTA_ROLE});
+  allocator->addFramework(framework1.id(), framework1, {}, true, {});
+
+  // Process all triggered allocation events.
+  Clock::settle();
+
+  // `framework1` will be offered the reserved resources at `agent1`
+  // because those resources are reserved for its role.
+  Allocation expected = Allocation(
+      framework1.id(),
+      {{QUOTA_ROLE, {{agent1.id(), reserved}}}});
+
+  AWAIT_EXPECT_EQ(expected, allocations.get());
+
+  // Decline the reservations for the rest of the test.
+  Filters filter1day;
+  filter1day.set_refuse_seconds(Days(1).secs());
+  allocator->recoverResources(
+      framework1.id(),
+      agent1.id(),
+      allocatedResources(reserved, QUOTA_ROLE),
+      filter1day);
+
+  // Add another agent with unreserved resources.
+  // This will trigger a batch allocation.
+  SlaveInfo agent2 = createSlaveInfo("cpus:1;mem:1024");
+  allocator->addSlave(
+      agent2.id(),
+      agent2,
+      AGENT_CAPABILITIES(),
+      None(),
+      agent2.resources(),
+      {});
+
+  Clock::settle();
+
+  // Agent2's resources should not be allocated to `framework1` under
+  // `QUOTA_ROLE` because the reserved resources should be accounted
+  // towards the quota and allocating this agent will exceed the
+  // quota limit.
+  Future<Allocation> allocation = allocations.get();
+  EXPECT_TRUE(allocation.isPending());
+}
+
+
+// This test verifies that the reservations should be
+// accounted towards the quota guarantee/limit if they
+// are currently allocated.
+TEST_P(HierarchicalAllocatorTestWithReservations, ReservationAllocated)
+{
+  Clock::pause();
+
+  const string QUOTA_ROLE{"quota-role"};
+
+  initialize();
+
+  Resource::ReservationInfo reservation;
+  reservation.set_type(GetParam());
+  reservation.set_role(QUOTA_ROLE);
+
+  Resources resources = Resources::parse("cpus:1;mem:1024").get();
+  resources = resources.pushReservation(reservation);
+
+  SlaveInfo agent1 = createSlaveInfo(resources);
+  allocator->addSlave(
+      agent1.id(),
+      agent1,
+      AGENT_CAPABILITIES(),
+      None(),
+      agent1.resources(),
+      {});
+
+  Resources reserved = Resources(agent1.resources()).reserved(QUOTA_ROLE);
+
+  // Set a quota for 2x agent resources.
+  const Quota quota = createQuota(QUOTA_ROLE, "cpus:2;mem:2048");
+  allocator->setQuota(QUOTA_ROLE, quota);
+
+  // Create `framework1` and set quota for its role.
+  FrameworkInfo framework1 = createFrameworkInfo({QUOTA_ROLE});
+  allocator->addFramework(framework1.id(), framework1, {}, true, {});
+
+  // Process all triggered allocation events.
+  Clock::settle();
+
+  // `framework1` will be offered the reserved resources at `agent1`
+  // because those resources are reserved for its role.
+  Allocation expected = Allocation(
+      framework1.id(),
+      {{QUOTA_ROLE, {{agent1.id(), reserved}}}});
+
+  AWAIT_EXPECT_EQ(expected, allocations.get());
+
+  // Add another agent with unreserved resources.
+  // This will trigger a batch allocation.
+  SlaveInfo agent2 = createSlaveInfo("cpus:1;mem:1024");
+  allocator->addSlave(
+      agent2.id(),
+      agent2,
+      AGENT_CAPABILITIES(),
+      None(),
+      agent2.resources(),
+      {});
+
+  Clock::settle();
+
+  expected = Allocation(
+      framework1.id(),
+      {{QUOTA_ROLE, {{agent2.id(), agent2.resources()}}}});
+
+  // Agent2's resources should be allocated to framework1
+  // to meet its remaining quota.
+  AWAIT_EXPECT_EQ(expected, allocations.get());
+
+  // Add a third agent with unreserved resources.
+  // This will trigger a batch allocation.
+  SlaveInfo agent3 = createSlaveInfo("cpus:1;mem:1024");
+  allocator->addSlave(
+      agent3.id(),
+      agent3,
+      AGENT_CAPABILITIES(),
+      None(),
+      agent3.resources(),
+      {});
+
+  Clock::settle();
+
+  // Agent3's resources should not be allocated to `framework1` under
+  // `QUOTA_ROLE` because the role is already allocated its quota.
+  // Some of this quota is satisfied via an allocated reservation.
+  Future<Allocation> allocation = allocations.get();
+  EXPECT_TRUE(allocation.isPending());
+}
+
+
 // Checks that resources on a slave that are statically reserved to
 // a role are only offered to frameworks in that role.
 TEST_F(HierarchicalAllocatorTest, Reservations)