You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by mp...@apache.org on 2017/06/20 09:46:37 UTC

[01/21] mesos git commit: Resources: Updated the comment to mention the resource format [1/20].

Repository: mesos
Updated Branches:
  refs/heads/master feac8c9b6 -> 9036c3187


Resources: Updated the comment to mention the resource format [1/20].

With reservation refinement, `Resources` always stores `Resource`
objects that are validated, and in the "post-reservation-refinement"
format. Added this precondition to the top of `Resources` declaration.

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


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

Branch: refs/heads/master
Commit: db2babf9829edbd20124c04b93910ce370d62f08
Parents: feac8c9
Author: Michael Park <mp...@apache.org>
Authored: Sun Jun 18 21:55:12 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:28:10 2017 -0700

----------------------------------------------------------------------
 include/mesos/resources.hpp    | 14 +++++++-------
 include/mesos/v1/resources.hpp | 14 +++++++-------
 2 files changed, 14 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/db2babf9/include/mesos/resources.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/resources.hpp b/include/mesos/resources.hpp
index be2e377..2efe9fb 100644
--- a/include/mesos/resources.hpp
+++ b/include/mesos/resources.hpp
@@ -53,13 +53,13 @@
 
 namespace mesos {
 
-// NOTE: Resource objects stored in the class are always valid and
-// kept combined if possible. It is the caller's responsibility to
-// validate any Resource object or repeated Resource protobufs before
-// constructing a Resources object. Otherwise, invalid Resource
-// objects will be silently stripped. Invalid Resource objects will
-// also be silently ignored when used in arithmetic operations (e.g.,
-// +=, -=, etc.).
+// NOTE: Resource objects stored in the class are always valid, are in
+// the "post-reservation-refinement" format, and kept combined if possible.
+// It is the caller's responsibility to validate any Resource object or
+// repeated Resource protobufs before constructing a Resources object.
+// Otherwise, invalid Resource objects will be silently stripped.
+// Invalid Resource objects will also be silently ignored when used in
+// arithmetic operations (e.g., +=, -=, etc.).
 class Resources
 {
 private:

http://git-wip-us.apache.org/repos/asf/mesos/blob/db2babf9/include/mesos/v1/resources.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/v1/resources.hpp b/include/mesos/v1/resources.hpp
index fe62166..07b9bb5 100644
--- a/include/mesos/v1/resources.hpp
+++ b/include/mesos/v1/resources.hpp
@@ -53,13 +53,13 @@
 namespace mesos {
 namespace v1 {
 
-// NOTE: Resource objects stored in the class are always valid and
-// kept combined if possible. It is the caller's responsibility to
-// validate any Resource object or repeated Resource protobufs before
-// constructing a Resources object. Otherwise, invalid Resource
-// objects will be silently stripped. Invalid Resource objects will
-// also be silently ignored when used in arithmetic operations (e.g.,
-// +=, -=, etc.).
+// NOTE: Resource objects stored in the class are always valid, are in
+// the "post-reservation-refinement" format, and kept combined if possible.
+// It is the caller's responsibility to validate any Resource object or
+// repeated Resource protobufs before constructing a Resources object.
+// Otherwise, invalid Resource objects will be silently stripped.
+// Invalid Resource objects will also be silently ignored when used in
+// arithmetic operations (e.g., +=, -=, etc.).
 class Resources
 {
 private:


[21/21] mesos git commit: Updated authorization tests [20/20].

Posted by mp...@apache.org.
Updated authorization tests [20/20].

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


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

Branch: refs/heads/master
Commit: 9036c31873954c59d8e03076796acf2e578c10a8
Parents: c55f44f
Author: Michael Park <mp...@apache.org>
Authored: Tue Jun 20 01:10:57 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:46:00 2017 -0700

----------------------------------------------------------------------
 src/tests/authorization_tests.cpp | 230 ++++++++++++++++++++++++++-------
 1 file changed, 185 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/9036c318/src/tests/authorization_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/authorization_tests.cpp b/src/tests/authorization_tests.cpp
index 1b5c6e2..f65bf2f 100644
--- a/src/tests/authorization_tests.cpp
+++ b/src/tests/authorization_tests.cpp
@@ -1085,7 +1085,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("foo");
-    request.mutable_object()->mutable_resource()->set_role("bar");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("bar");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1100,7 +1104,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("foo");
-    request.mutable_object()->mutable_resource()->set_role("awesome_role");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("awesome_role");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
   {
@@ -1114,7 +1122,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("bar");
-    request.mutable_object()->mutable_resource()->set_role("awesome_role");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("awesome_role");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1131,7 +1143,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("baz");
-    request.mutable_object()->mutable_resource()->set_role("ads");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("ads");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1146,7 +1162,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("baz");
-    request.mutable_object()->mutable_resource()->set_role("awesome_role");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("awesome_role");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 
@@ -1177,7 +1197,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("zelda");
-    request.mutable_object()->mutable_resource()->set_role("ads");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("ads");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 
@@ -1188,7 +1212,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("elizabeth-ii");
-    request.mutable_object()->mutable_resource()->set_role("king");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1196,7 +1224,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("elizabeth-ii");
-    request.mutable_object()->mutable_resource()->set_role("king/prince");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1204,7 +1236,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("elizabeth-ii");
-    request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince/duke");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1215,7 +1251,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("charles");
-    request.mutable_object()->mutable_resource()->set_role("king");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 
@@ -1223,7 +1263,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("charles");
-    request.mutable_object()->mutable_resource()->set_role("king/prince");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1231,7 +1275,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("charles");
-    request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince/duke");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1242,7 +1290,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("j-welby");
-    request.mutable_object()->mutable_resource()->set_role("king");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1250,7 +1302,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("j-welby");
-    request.mutable_object()->mutable_resource()->set_role("king/prince");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 
@@ -1258,7 +1314,11 @@ TYPED_TEST(AuthorizationTest, Reserve)
     authorization::Request request;
     request.set_action(authorization::RESERVE_RESOURCES);
     request.mutable_subject()->set_value("j-welby");
-    request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince/duke");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 }
@@ -1315,8 +1375,11 @@ TYPED_TEST(AuthorizationTest, Unreserve)
     authorization::Request request;
     request.set_action(authorization::UNRESERVE_RESOURCES);
     request.mutable_subject()->set_value("foo");
-    request.mutable_object()->mutable_resource()
-        ->mutable_reservation()->set_principal("foo");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_principal("foo");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1333,8 +1396,11 @@ TYPED_TEST(AuthorizationTest, Unreserve)
     authorization::Request request;
     request.set_action(authorization::UNRESERVE_RESOURCES);
     request.mutable_subject()->set_value("bar");
-    request.mutable_object()->mutable_resource()
-        ->mutable_reservation()->set_principal("foo");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_principal("foo");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 
@@ -1349,8 +1415,11 @@ TYPED_TEST(AuthorizationTest, Unreserve)
     authorization::Request request;
     request.set_action(authorization::UNRESERVE_RESOURCES);
     request.mutable_subject()->set_value("bar");
-    request.mutable_object()->mutable_resource()
-        ->mutable_reservation()->set_principal("bar");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_principal("bar");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 
@@ -1367,8 +1436,11 @@ TYPED_TEST(AuthorizationTest, Unreserve)
     authorization::Request request;
     request.set_action(authorization::UNRESERVE_RESOURCES);
     request.mutable_subject()->set_value("ops");
-    request.mutable_object()->mutable_resource()
-        ->mutable_reservation()->set_principal("foo");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_principal("foo");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1383,8 +1455,11 @@ TYPED_TEST(AuthorizationTest, Unreserve)
     authorization::Request request;
     request.set_action(authorization::UNRESERVE_RESOURCES);
     request.mutable_subject()->set_value("ops");
-    request.mutable_object()->mutable_resource()
-        ->mutable_reservation()->set_principal("foo");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_principal("foo");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
   {
@@ -1398,8 +1473,11 @@ TYPED_TEST(AuthorizationTest, Unreserve)
     authorization::Request request;
     request.set_action(authorization::UNRESERVE_RESOURCES);
     request.mutable_subject()->set_value("ops");
-    request.mutable_object()->mutable_resource()
-        ->mutable_reservation()->set_principal("bar");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_principal("bar");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
   {
@@ -1413,8 +1491,11 @@ TYPED_TEST(AuthorizationTest, Unreserve)
     authorization::Request request;
     request.set_action(authorization::UNRESERVE_RESOURCES);
     request.mutable_subject()->set_value("ops");
-    request.mutable_object()->mutable_resource()
-        ->mutable_reservation()->set_principal("ops");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_principal("ops");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1432,8 +1513,11 @@ TYPED_TEST(AuthorizationTest, Unreserve)
     authorization::Request request;
     request.set_action(authorization::UNRESERVE_RESOURCES);
     request.mutable_subject()->set_value("zelda");
-    request.mutable_object()->mutable_resource()
-        ->mutable_reservation()->set_principal("foo");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_principal("foo");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 }
@@ -1521,7 +1605,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("foo");
-    request.mutable_object()->mutable_resource()->set_role("awesome_role");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("awesome_role");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1538,7 +1626,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("bar");
-    request.mutable_object()->mutable_resource()->set_role("panda");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("panda");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1555,7 +1647,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("bar");
-    request.mutable_object()->mutable_resource()->set_role("giraffe");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("giraffe");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 
@@ -1572,7 +1668,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("baz");
-    request.mutable_object()->mutable_resource()->set_role("panda");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("panda");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 
@@ -1590,7 +1690,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("zelda");
-    request.mutable_object()->mutable_resource()->set_role("panda");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("panda");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 
@@ -1601,7 +1705,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("elizabeth-ii");
-    request.mutable_object()->mutable_resource()->set_role("king");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1609,7 +1717,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("elizabeth-ii");
-    request.mutable_object()->mutable_resource()->set_role("king/prince");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1617,7 +1729,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("elizabeth-ii");
-    request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince/duke");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1628,7 +1744,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("charles");
-    request.mutable_object()->mutable_resource()->set_role("king");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 
@@ -1636,7 +1756,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("charles");
-    request.mutable_object()->mutable_resource()->set_role("king/prince");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1644,7 +1768,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("charles");
-    request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince/duke");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1655,7 +1783,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("j-welby");
-    request.mutable_object()->mutable_resource()->set_role("king");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king");
     AWAIT_EXPECT_TRUE(authorizer.get()->authorized(request));
   }
 
@@ -1663,7 +1795,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("j-welby");
-    request.mutable_object()->mutable_resource()->set_role("king/prince");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 
@@ -1671,7 +1807,11 @@ TYPED_TEST(AuthorizationTest, CreateVolume)
     authorization::Request request;
     request.set_action(authorization::CREATE_VOLUME);
     request.mutable_subject()->set_value("j-welby");
-    request.mutable_object()->mutable_resource()->set_role("king/prince/duke");
+    request.mutable_object()
+      ->mutable_resource()
+      ->mutable_reservations()
+      ->Add()
+      ->set_role("king/prince/duke");
     AWAIT_EXPECT_FALSE(authorizer.get()->authorized(request));
   }
 }


[11/21] mesos git commit: Adjusted the agent to the new resources format [11/20].

Posted by mp...@apache.org.
Adjusted the agent to the new resources format [11/20].

The agent uses `convertResourceFormat` to convert the in-bound
resources to the "post-reseration-refinement" format, and
the out-bound resources are converted back to "pre-" or
"endpoint" format as necessary.

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


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

Branch: refs/heads/master
Commit: 0d5792d8ff62bd6415ad605c215fce3a7f9da229
Parents: 0322de5
Author: Michael Park <mp...@apache.org>
Authored: Mon Jun 19 14:30:19 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:35:06 2017 -0700

----------------------------------------------------------------------
 src/common/resources_utils.hpp |  4 ++--
 src/slave/paths.cpp            | 12 ++++++----
 src/slave/slave.cpp            | 48 +++++++++++++++++++++++++++++++------
 src/slave/slave.hpp            |  2 +-
 src/slave/state.cpp            | 23 ++++++++++++++----
 src/slave/state.hpp            | 15 +++++++++---
 6 files changed, 83 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0d5792d8/src/common/resources_utils.hpp
----------------------------------------------------------------------
diff --git a/src/common/resources_utils.hpp b/src/common/resources_utils.hpp
index d7d439a..4b03368 100644
--- a/src/common/resources_utils.hpp
+++ b/src/common/resources_utils.hpp
@@ -137,8 +137,8 @@ void convertResourceFormat(Offer::Operation* operation, ResourceFormat format);
 
 // Convert the given resources to the "pre-reservation-refinement" format
 // if none of the resources have refined reservations. Returns an `Error`
-// if there are any refined reservations present, and the resources are
-// left in the "post-reservation-refinement" format.
+// if there are any refined reservations present; in this case, the resources
+// are left in the "post-reservation-refinement" format.
 Try<Nothing> downgradeResources(
     google::protobuf::RepeatedPtrField<Resource>* resources);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/0d5792d8/src/slave/paths.cpp
----------------------------------------------------------------------
diff --git a/src/slave/paths.cpp b/src/slave/paths.cpp
index b2709ad..c08e83c 100644
--- a/src/slave/paths.cpp
+++ b/src/slave/paths.cpp
@@ -19,6 +19,7 @@
 #include <vector>
 
 #include <mesos/mesos.hpp>
+#include <mesos/resources.hpp>
 #include <mesos/roles.hpp>
 #include <mesos/type_utils.hpp>
 
@@ -475,21 +476,24 @@ string getPersistentVolumePath(
     const string& rootDir,
     const Resource& volume)
 {
-  CHECK(volume.has_role());
+  CHECK_GT(volume.reservations_size(), 0);
   CHECK(volume.has_disk());
   CHECK(volume.disk().has_persistence());
 
+  const string& role = Resources::reservationRole(volume);
+
   // Additionally check that the role and the persistent ID are valid
   // before using them to construct a directory path.
-  CHECK_NONE(roles::validate(volume.role()));
+  CHECK_NONE(roles::validate(role));
   CHECK_NONE(common::validation::validateID(volume.disk().persistence().id()));
 
+
   // If no `source` is provided in `DiskInfo` volumes are mapped into
   // the `rootDir`.
   if (!volume.disk().has_source()) {
     return getPersistentVolumePath(
         rootDir,
-        volume.role(),
+        role,
         volume.disk().persistence().id());
   }
 
@@ -503,7 +507,7 @@ string getPersistentVolumePath(
       CHECK(volume.disk().source().path().has_root());
       return getPersistentVolumePath(
           volume.disk().source().path().root(),
-          volume.role(),
+          role,
           volume.disk().persistence().id());
     }
     case Resource::DiskInfo::Source::MOUNT: {

http://git-wip-us.apache.org/repos/asf/mesos/blob/0d5792d8/src/slave/slave.cpp
----------------------------------------------------------------------
diff --git a/src/slave/slave.cpp b/src/slave/slave.cpp
index 91a1bf3..f808458 100644
--- a/src/slave/slave.cpp
+++ b/src/slave/slave.cpp
@@ -1391,17 +1391,33 @@ void Slave::doReliableRegistration(Duration maxBackoff)
   // See MESOS-5330.
   link(master.get());
 
-  if (!info.has_id()) {
+  SlaveInfo slaveInfo = info;
+
+  // We ignore the `Try` from `downgradeResources` here because for now,
+  // we send the result either way.
+  // TODO(mpark): Do something smarter with the result once something like
+  // a master capability is introduced.
+  downgradeResources(slaveInfo.mutable_resources());
+
+  RepeatedPtrField<Resource> checkpointedResources_ = checkpointedResources;
+
+  // We ignore the `Try` from `downgradeResources` here because for now,
+  // we send the result either way.
+  // TODO(mpark): Do something smarter with the result once something like
+  // a master capability is introduced.
+  downgradeResources(&checkpointedResources_);
+
+  if (!slaveInfo.has_id()) {
     // Registering for the first time.
     RegisterSlaveMessage message;
     message.set_version(MESOS_VERSION);
-    message.mutable_slave()->CopyFrom(info);
+    message.mutable_slave()->CopyFrom(slaveInfo);
     foreach (const SlaveInfo::Capability& capability, AGENT_CAPABILITIES()) {
       message.add_agent_capabilities()->CopyFrom(capability);
     }
 
     // Include checkpointed resources.
-    message.mutable_checkpointed_resources()->CopyFrom(checkpointedResources);
+    message.mutable_checkpointed_resources()->CopyFrom(checkpointedResources_);
 
     send(master.get(), message);
   } else {
@@ -1413,9 +1429,9 @@ void Slave::doReliableRegistration(Duration maxBackoff)
     }
 
     // Include checkpointed resources.
-    message.mutable_checkpointed_resources()->CopyFrom(checkpointedResources);
+    message.mutable_checkpointed_resources()->CopyFrom(checkpointedResources_);
 
-    message.mutable_slave()->CopyFrom(info);
+    message.mutable_slave()->CopyFrom(slaveInfo);
 
     foreachvalue (Framework* framework, frameworks) {
       message.add_frameworks()->CopyFrom(framework->info);
@@ -1596,25 +1612,40 @@ void Slave::run(
   };
 
   injectAllocationInfo(executorInfo.mutable_resources(), frameworkInfo);
+  convertResourceFormat(
+      executorInfo.mutable_resources(),
+      POST_RESERVATION_REFINEMENT);
 
   if (task.isSome()) {
     injectAllocationInfo(task->mutable_resources(), frameworkInfo);
+    convertResourceFormat(
+        task->mutable_resources(),
+        POST_RESERVATION_REFINEMENT);
 
     if (task->has_executor()) {
       injectAllocationInfo(
           task->mutable_executor()->mutable_resources(),
           frameworkInfo);
+      convertResourceFormat(
+          task->mutable_executor()->mutable_resources(),
+          POST_RESERVATION_REFINEMENT);
     }
   }
 
   if (taskGroup.isSome()) {
     foreach (TaskInfo& task, *taskGroup->mutable_tasks()) {
       injectAllocationInfo(task.mutable_resources(), frameworkInfo);
+      convertResourceFormat(
+          task.mutable_resources(),
+          POST_RESERVATION_REFINEMENT);
 
       if (task.has_executor()) {
         injectAllocationInfo(
             task.mutable_executor()->mutable_resources(),
             frameworkInfo);
+        convertResourceFormat(
+            task.mutable_executor()->mutable_resources(),
+            POST_RESERVATION_REFINEMENT);
       }
     }
   }
@@ -3302,7 +3333,7 @@ void Slave::updateFramework(
 }
 
 
-void Slave::checkpointResources(const vector<Resource>& _checkpointedResources)
+void Slave::checkpointResources(vector<Resource> _checkpointedResources)
 {
   // TODO(jieyu): Here we assume that CheckpointResourcesMessages are
   // ordered (i.e., slave receives them in the same order master sends
@@ -3325,6 +3356,9 @@ void Slave::checkpointResources(const vector<Resource>& _checkpointedResources)
   //      master about the incorrect checkpointed resources. When that
   //      happens, we expect framework to reconcile based on the
   //      offers they get.
+
+  convertResourceFormat(&_checkpointedResources, POST_RESERVATION_REFINEMENT);
+
   Resources newCheckpointedResources = _checkpointedResources;
 
   if (newCheckpointedResources == checkpointedResources) {
@@ -3405,7 +3439,7 @@ Try<Nothing> Slave::syncCheckpointedResources(
   // directory, or LVM volumes from a given device.
   foreach (const Resource& volume, newVolumes) {
     // This is validated in master.
-    CHECK_NE(volume.role(), "*");
+    CHECK(Resources::isReserved(volume));
 
     if (oldVolumes.contains(volume)) {
       continue;

http://git-wip-us.apache.org/repos/asf/mesos/blob/0d5792d8/src/slave/slave.hpp
----------------------------------------------------------------------
diff --git a/src/slave/slave.hpp b/src/slave/slave.hpp
index 7ffaed1..ebc0ea0 100644
--- a/src/slave/slave.hpp
+++ b/src/slave/slave.hpp
@@ -194,7 +194,7 @@ public:
   void updateFramework(
       const UpdateFrameworkMessage& message);
 
-  void checkpointResources(const std::vector<Resource>& checkpointedResources);
+  void checkpointResources(std::vector<Resource> checkpointedResources);
 
   void subscribe(
       HttpConnection http,

http://git-wip-us.apache.org/repos/asf/mesos/blob/0d5792d8/src/slave/state.cpp
----------------------------------------------------------------------
diff --git a/src/slave/state.cpp b/src/slave/state.cpp
index 18b790d..5dd8b1c 100644
--- a/src/slave/state.cpp
+++ b/src/slave/state.cpp
@@ -42,6 +42,8 @@
 #include <stout/os/realpath.hpp>
 #include <stout/os/stat.hpp>
 
+#include "common/resources_utils.hpp"
+
 #include "messages/messages.hpp"
 
 #include "slave/paths.hpp"
@@ -148,7 +150,7 @@ Try<SlaveState> SlaveState::recover(
     return state;
   }
 
-  const Result<SlaveInfo>& slaveInfo = ::protobuf::read<SlaveInfo>(path);
+  Result<SlaveInfo> slaveInfo = ::protobuf::read<SlaveInfo>(path);
 
   if (slaveInfo.isError()) {
     const string& message = "Failed to read agent info from '" + path + "': " +
@@ -169,6 +171,10 @@ Try<SlaveState> SlaveState::recover(
     return state;
   }
 
+  convertResourceFormat(
+      slaveInfo.get().mutable_resources(),
+      POST_RESERVATION_REFINEMENT);
+
   state.info = slaveInfo.get();
 
   // Find the frameworks.
@@ -387,8 +393,7 @@ Try<ExecutorState> ExecutorState::recover(
     return state;
   }
 
-  const Result<ExecutorInfo>& executorInfo =
-    ::protobuf::read<ExecutorInfo>(path);
+  Result<ExecutorInfo> executorInfo = ::protobuf::read<ExecutorInfo>(path);
 
   if (executorInfo.isError()) {
     message = "Failed to read executor info from '" + path + "': " +
@@ -410,6 +415,10 @@ Try<ExecutorState> ExecutorState::recover(
     return state;
   }
 
+  convertResourceFormat(
+      executorInfo.get().mutable_resources(),
+      POST_RESERVATION_REFINEMENT);
+
   state.info = executorInfo.get();
 
   return state;
@@ -585,7 +594,7 @@ Try<TaskState> TaskState::recover(
     return state;
   }
 
-  const Result<Task>& task = ::protobuf::read<Task>(path);
+  Result<Task> task = ::protobuf::read<Task>(path);
 
   if (task.isError()) {
     message = "Failed to read task info from '" + path + "': " + task.error();
@@ -606,6 +615,10 @@ Try<TaskState> TaskState::recover(
     return state;
   }
 
+  convertResourceFormat(
+      task.get().mutable_resources(),
+      POST_RESERVATION_REFINEMENT);
+
   state.info = task.get();
 
   // Read the status updates.
@@ -770,6 +783,8 @@ Try<Resources> ResourcesState::recoverResources(
       break;
     }
 
+    convertResourceFormat(&resource.get(), POST_RESERVATION_REFINEMENT);
+
     resources += resource.get();
   }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/0d5792d8/src/slave/state.hpp
----------------------------------------------------------------------
diff --git a/src/slave/state.hpp b/src/slave/state.hpp
index a497ce1..537358c 100644
--- a/src/slave/state.hpp
+++ b/src/slave/state.hpp
@@ -42,6 +42,8 @@
 #include <stout/os/rm.hpp>
 #include <stout/os/write.hpp>
 
+#include "common/resources_utils.hpp"
+
 #include "messages/messages.hpp"
 
 namespace mesos {
@@ -101,10 +103,17 @@ Try<Nothing> checkpoint(
 
 inline Try<Nothing> checkpoint(
     const std::string& path,
-    const Resources& resources)
+    const Resources& resources_)
 {
-  const google::protobuf::RepeatedPtrField<Resource>& messages = resources;
-  return checkpoint(path, messages);
+  google::protobuf::RepeatedPtrField<Resource> resources = resources_;
+
+  // We ignore the `Try` from `downgradeResources` here because for now,
+  // we checkpoint the result either way.
+  // TODO(mpark): Do something smarter with the result once something like
+  // an agent recovery capability is introduced.
+  downgradeResources(&resources);
+
+  return checkpoint(path, resources);
 }
 
 }  // namespace internal {


[12/21] mesos git commit: Adjusted the authorizer to the new resource format [12/20].

Posted by mp...@apache.org.
Adjusted the authorizer to the new resource format [12/20].

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


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

Branch: refs/heads/master
Commit: 6be854ada23dc2da21c11516f0ec51e24090001a
Parents: 0d5792d
Author: Michael Park <mc...@gmail.com>
Authored: Wed May 31 18:39:06 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:35:06 2017 -0700

----------------------------------------------------------------------
 src/authorizer/local/authorizer.cpp | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/6be854ad/src/authorizer/local/authorizer.cpp
----------------------------------------------------------------------
diff --git a/src/authorizer/local/authorizer.cpp b/src/authorizer/local/authorizer.cpp
index 810566a..82ae846 100644
--- a/src/authorizer/local/authorizer.cpp
+++ b/src/authorizer/local/authorizer.cpp
@@ -233,7 +233,15 @@ public:
         case authorization::UNRESERVE_RESOURCES:
           aclObject.set_type(mesos::ACL::Entity::SOME);
           if (object->resource) {
-            aclObject.add_values(object->resource->reservation().principal());
+            if (object->resource->reservations_size() > 0) {
+              // Check for principal in "post-reservation-refinement" format.
+              aclObject.add_values(
+                  object->resource->reservations().rbegin()->principal());
+            } else {
+              // Check for principal in "pre-reservation-refinement" format.
+              aclObject.add_values(
+                  object->resource->reservation().principal());
+            }
           } else if (object->value) {
             aclObject.add_values(*(object->value));
           } else {
@@ -557,7 +565,14 @@ public:
         case authorization::RESERVE_RESOURCES: {
           entityObject.set_type(ACL::Entity::SOME);
           if (object->resource) {
-            entityObject.add_values(object->resource->role());
+            if (object->resource->reservations_size() > 0) {
+              // Check for role in "post-reservation-refinement" format.
+              entityObject.add_values(
+                  object->resource->reservations().rbegin()->role());
+            } else {
+              // Check for role in "pre-reservation-refinement" format.
+              entityObject.add_values(object->resource->role());
+            }
           } else if (object->value) {
             entityObject.add_values(*(object->value));
           } else {


[15/21] mesos git commit: Marked `Resource.role` as deprecated [15/20].

Posted by mp...@apache.org.
Marked `Resource.role` as deprecated [15/20].

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


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

Branch: refs/heads/master
Commit: b71fe0313173bb72490ec4b63b384297ded6b1d7
Parents: 9374529
Author: Michael Park <mp...@apache.org>
Authored: Tue Jun 20 01:09:19 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:44:35 2017 -0700

----------------------------------------------------------------------
 include/mesos/mesos.proto    | 2 +-
 include/mesos/v1/mesos.proto | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/b71fe031/include/mesos/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/mesos.proto b/include/mesos/mesos.proto
index e2502ac..38449da 100644
--- a/include/mesos/mesos.proto
+++ b/include/mesos/mesos.proto
@@ -987,7 +987,7 @@ message Resource {
   //       See the 'Resource Format' section for more details.
   //
   // TODO(mpark): Deprecate once `reservations` is no longer experimental.
-  optional string role = 6 [default = "*"];
+  optional string role = 6 [default = "*", deprecated=true];
 
   // This was initially introduced to support MULTI_ROLE capable
   // frameworks. Frameworks that are not MULTI_ROLE capable can

http://git-wip-us.apache.org/repos/asf/mesos/blob/b71fe031/include/mesos/v1/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/v1/mesos.proto b/include/mesos/v1/mesos.proto
index b9a9cc3..81eca47 100644
--- a/include/mesos/v1/mesos.proto
+++ b/include/mesos/v1/mesos.proto
@@ -981,7 +981,7 @@ message Resource {
   //       See the 'Resource Format' section for more details.
   //
   // TODO(mpark): Deprecate once `reservations` is no longer experimental.
-  optional string role = 6 [default = "*"];
+  optional string role = 6 [default = "*", deprecated=true];
 
   // This was initially introduced to support MULTI_ROLE capable
   // frameworks. Frameworks that are not MULTI_ROLE capable can


[03/21] mesos git commit: Resources: Adjusted the comparators to new resource format [3/20].

Posted by mp...@apache.org.
Resources: Adjusted the comparators to new resource format [3/20].

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


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

Branch: refs/heads/master
Commit: 2d78e5aec75bdd2b6115d9a822a93e8b5fa70283
Parents: 1e22003
Author: Michael Park <mp...@apache.org>
Authored: Thu May 25 17:20:37 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:30:08 2017 -0700

----------------------------------------------------------------------
 src/common/resources.cpp | 50 +++++++++++++++++++++++++------------------
 src/v1/resources.cpp     | 50 +++++++++++++++++++++++++------------------
 2 files changed, 58 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/2d78e5ae/src/common/resources.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources.cpp b/src/common/resources.cpp
index 8cfe6ff..79c4d7d 100644
--- a/src/common/resources.cpp
+++ b/src/common/resources.cpp
@@ -80,6 +80,14 @@ bool operator==(
     const Resource::ReservationInfo& left,
     const Resource::ReservationInfo& right)
 {
+  if (left.type() != right.type()) {
+    return false;
+  }
+
+  if (left.role() != right.role()) {
+    return false;
+  }
+
   if (left.has_principal() != right.has_principal()) {
     return false;
   }
@@ -220,9 +228,7 @@ bool operator!=(const Resource::DiskInfo& left, const Resource::DiskInfo& right)
 
 bool operator==(const Resource& left, const Resource& right)
 {
-  if (left.name() != right.name() ||
-      left.type() != right.type() ||
-      left.role() != right.role()) {
+  if (left.name() != right.name() || left.type() != right.type()) {
     return false;
   }
 
@@ -236,13 +242,15 @@ bool operator==(const Resource& left, const Resource& right)
     return false;
   }
 
-  // Check ReservationInfo.
-  if (left.has_reservation() != right.has_reservation()) {
+  // Check the stack of ReservationInfo.
+  if (left.reservations_size() != right.reservations_size()) {
     return false;
   }
 
-  if (left.has_reservation() && left.reservation() != right.reservation()) {
-    return false;
+  for (int i = 0; i < left.reservations_size(); ++i) {
+    if (left.reservations(i) != right.reservations(i)) {
+      return false;
+    }
   }
 
   // Check DiskInfo.
@@ -309,9 +317,7 @@ static bool addable(const Resource& left, const Resource& right)
   }
 
   // Now, we verify if the two non-shared resources can be added.
-  if (left.name() != right.name() ||
-      left.type() != right.type() ||
-      left.role() != right.role()) {
+  if (left.name() != right.name() || left.type() != right.type()) {
     return false;
   }
 
@@ -325,13 +331,15 @@ static bool addable(const Resource& left, const Resource& right)
     return false;
   }
 
-  // Check ReservationInfo.
-  if (left.has_reservation() != right.has_reservation()) {
+  // Check the stack of ReservationInfo.
+  if (left.reservations_size() != right.reservations_size()) {
     return false;
   }
 
-  if (left.has_reservation() && left.reservation() != right.reservation()) {
-    return false;
+  for (int i = 0; i < left.reservations_size(); ++i) {
+    if (left.reservations(i) != right.reservations(i)) {
+      return false;
+    }
   }
 
   // Check DiskInfo.
@@ -396,9 +404,7 @@ static bool subtractable(const Resource& left, const Resource& right)
   }
 
   // Now, we verify if the two non-shared resources can be subtracted.
-  if (left.name() != right.name() ||
-      left.type() != right.type() ||
-      left.role() != right.role()) {
+  if (left.name() != right.name() || left.type() != right.type()) {
     return false;
   }
 
@@ -412,13 +418,15 @@ static bool subtractable(const Resource& left, const Resource& right)
     return false;
   }
 
-  // Check ReservationInfo.
-  if (left.has_reservation() != right.has_reservation()) {
+  // Check the stack of ReservationInfo.
+  if (left.reservations_size() != right.reservations_size()) {
     return false;
   }
 
-  if (left.has_reservation() && left.reservation() != right.reservation()) {
-    return false;
+  for (int i = 0; i < left.reservations_size(); ++i) {
+    if (left.reservations(i) != right.reservations(i)) {
+      return false;
+    }
   }
 
   // Check DiskInfo.

http://git-wip-us.apache.org/repos/asf/mesos/blob/2d78e5ae/src/v1/resources.cpp
----------------------------------------------------------------------
diff --git a/src/v1/resources.cpp b/src/v1/resources.cpp
index bf054b9..0a4f4b2 100644
--- a/src/v1/resources.cpp
+++ b/src/v1/resources.cpp
@@ -82,6 +82,14 @@ bool operator==(
     const Resource::ReservationInfo& left,
     const Resource::ReservationInfo& right)
 {
+  if (left.type() != right.type()) {
+    return false;
+  }
+
+  if (left.role() != right.role()) {
+    return false;
+  }
+
   if (left.has_principal() != right.has_principal()) {
     return false;
   }
@@ -222,9 +230,7 @@ bool operator!=(const Resource::DiskInfo& left, const Resource::DiskInfo& right)
 
 bool operator==(const Resource& left, const Resource& right)
 {
-  if (left.name() != right.name() ||
-      left.type() != right.type() ||
-      left.role() != right.role()) {
+  if (left.name() != right.name() || left.type() != right.type()) {
     return false;
   }
 
@@ -238,13 +244,15 @@ bool operator==(const Resource& left, const Resource& right)
     return false;
   }
 
-  // Check ReservationInfo.
-  if (left.has_reservation() != right.has_reservation()) {
+  // Check the stack of ReservationInfo.
+  if (left.reservations_size() != right.reservations_size()) {
     return false;
   }
 
-  if (left.has_reservation() && left.reservation() != right.reservation()) {
-    return false;
+  for (int i = 0; i < left.reservations_size(); ++i) {
+    if (left.reservations(i) != right.reservations(i)) {
+      return false;
+    }
   }
 
   // Check DiskInfo.
@@ -311,9 +319,7 @@ static bool addable(const Resource& left, const Resource& right)
   }
 
   // Now, we verify if the two non-shared resources can be added.
-  if (left.name() != right.name() ||
-      left.type() != right.type() ||
-      left.role() != right.role()) {
+  if (left.name() != right.name() || left.type() != right.type()) {
     return false;
   }
 
@@ -327,13 +333,15 @@ static bool addable(const Resource& left, const Resource& right)
     return false;
   }
 
-  // Check ReservationInfo.
-  if (left.has_reservation() != right.has_reservation()) {
+  // Check the stack of ReservationInfo.
+  if (left.reservations_size() != right.reservations_size()) {
     return false;
   }
 
-  if (left.has_reservation() && left.reservation() != right.reservation()) {
-    return false;
+  for (int i = 0; i < left.reservations_size(); ++i) {
+    if (left.reservations(i) != right.reservations(i)) {
+      return false;
+    }
   }
 
   // Check DiskInfo.
@@ -398,9 +406,7 @@ static bool subtractable(const Resource& left, const Resource& right)
   }
 
   // Now, we verify if the two non-shared resources can be subtracted.
-  if (left.name() != right.name() ||
-      left.type() != right.type() ||
-      left.role() != right.role()) {
+  if (left.name() != right.name() || left.type() != right.type()) {
     return false;
   }
 
@@ -414,13 +420,15 @@ static bool subtractable(const Resource& left, const Resource& right)
     return false;
   }
 
-  // Check ReservationInfo.
-  if (left.has_reservation() != right.has_reservation()) {
+  // Check the stack of ReservationInfo.
+  if (left.reservations_size() != right.reservations_size()) {
     return false;
   }
 
-  if (left.has_reservation() && left.reservation() != right.reservation()) {
-    return false;
+  for (int i = 0; i < left.reservations_size(); ++i) {
+    if (left.reservations(i) != right.reservations(i)) {
+      return false;
+    }
   }
 
   // Check DiskInfo.


[10/21] mesos git commit: Adjusted the master to the new resources format [10/20].

Posted by mp...@apache.org.
Adjusted the master to the new resources format [10/20].

The master uses `convertResourceFormat` to convert the in-bound
resources to the "post-reservation-refinement" format, and
the out-bound resources are converted back the "pre-", or
"endpoint" format as necessary.

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


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

Branch: refs/heads/master
Commit: 0322de5971a72fa0750f07703994be206967158d
Parents: 3e8311e
Author: Michael Park <mp...@apache.org>
Authored: Sat Jun 17 15:38:58 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:34:52 2017 -0700

----------------------------------------------------------------------
 src/master/http.cpp          |   8 ++
 src/master/master.cpp        | 223 +++++++++++++++++++++++++++++++-------
 src/master/master.hpp        |   4 +-
 src/master/quota.cpp         |  21 +---
 src/master/quota_handler.cpp |  11 ++
 5 files changed, 208 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0322de59/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index a9ed358..d594d67 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -1129,6 +1129,8 @@ Future<Response> Master::Http::_createVolumes(
         validate.get().message);
   }
 
+  convertResourceFormat(&operation, POST_RESERVATION_REFINEMENT);
+
   return master->authorizeCreateVolume(operation.create(), principal)
     .then(defer(master->self(), [=](bool authorized) -> Future<Response> {
       if (!authorized) {
@@ -1302,6 +1304,8 @@ Future<Response> Master::Http::_destroyVolumes(
     return BadRequest("Invalid DESTROY operation: " + validate.get().message);
   }
 
+  convertResourceFormat(&operation, POST_RESERVATION_REFINEMENT);
+
   return master->authorizeDestroyVolume(operation.destroy(), principal)
     .then(defer(master->self(), [=](bool authorized) -> Future<Response> {
       if (!authorized) {
@@ -2265,6 +2269,8 @@ Future<Response> Master::Http::_reserve(
         error.get().message);
   }
 
+  convertResourceFormat(&operation, POST_RESERVATION_REFINEMENT);
+
   return master->authorizeReserveResources(operation.reserve(), principal)
     .then(defer(master->self(), [=](bool authorized) -> Future<Response> {
       if (!authorized) {
@@ -5019,6 +5025,8 @@ Future<Response> Master::Http::_unreserve(
         "Invalid UNRESERVE operation: " + error.get().message);
   }
 
+  convertResourceFormat(&operation, POST_RESERVATION_REFINEMENT);
+
   return master->authorizeUnreserveResources(operation.unreserve(), principal)
     .then(defer(master->self(), [=](bool authorized) -> Future<Response> {
       if (!authorized) {

http://git-wip-us.apache.org/repos/asf/mesos/blob/0322de59/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 287a5b7..ec594a8 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -3497,11 +3497,29 @@ Future<bool> Master::authorizeReserveResources(
   hashset<string> roles;
   list<Future<bool>> authorizations;
   foreach (const Resource& resource, reserve.resources()) {
-    if (!roles.contains(resource.role())) {
-      roles.insert(resource.role());
+    // NOTE: Since authorization happens __before__ validation and resource
+    // format conversion, we must look for roles that may appear in both
+    // "pre" and "post" reservation-refinement formats. This may not even be
+    // valid, but we rely on validation being performed aftewards.
+    string role;
+    if (resource.reservations_size() > 0) {
+      // Check for the role in the "post-reservation-refinement" format.
+      //
+      // If there is a stack of reservations, we only perform authorization
+      // for the most refined reservation, since we only support "pushing"
+      // one reservation at a time. That is, all of the previous reservations
+      // must have already been authorized.
+      role = resource.reservations().rbegin()->role();
+    } else {
+      // Check for the role in the "pre-reservation-refinement" format.
+      role = resource.role();
+    }
+
+    if (!roles.contains(role)) {
+      roles.insert(role);
 
       request.mutable_object()->mutable_resource()->CopyFrom(resource);
-      request.mutable_object()->set_value(resource.role());
+      request.mutable_object()->set_value(role);
       authorizations.push_back(authorizer.get()->authorized(request));
     }
   }
@@ -3551,16 +3569,24 @@ Future<bool> Master::authorizeUnreserveResources(
 
   list<Future<bool>> authorizations;
   foreach (const Resource& resource, unreserve.resources()) {
-    // NOTE: Since validation of this operation is performed after
-    // authorization, we must check here that this resource is
-    // dynamically reserved. If it isn't, the error will be caught
-    // during validation.
-    if (Resources::isDynamicallyReserved(resource) &&
-        resource.reservation().has_principal()) {
+    // NOTE: Since authorization happens __before__ validation and resource
+    // format conversion, we must look for the principal that may appear in
+    // both "pre" and "post" reservation-refinement formats. This may not be
+    // valid, but we rely on validation being performed later.
+    Option<string> principal;
+    if (resource.reservations_size() > 0 &&
+        resource.reservations().rbegin()->has_principal()) {
+      // Check for roles in the "post-reservation-refinement" format.
+      principal = resource.reservations().rbegin()->principal();
+    } else if (
+        resource.has_reservation() && resource.reservation().has_principal()) {
+      // Check for roles in the "pre-reservation-refinement" format.
+      principal = resource.reservation().principal();
+    }
+
+    if (principal.isSome()) {
       request.mutable_object()->mutable_resource()->CopyFrom(resource);
-
-      request.mutable_object()->set_value(
-          resource.reservation().principal());
+      request.mutable_object()->set_value(principal.get());
 
       authorizations.push_back(authorizer.get()->authorized(request));
     }
@@ -3610,11 +3636,25 @@ Future<bool> Master::authorizeCreateVolume(
   hashset<string> roles;
   list<Future<bool>> authorizations;
   foreach (const Resource& volume, create.volumes()) {
-    if (!roles.contains(volume.role())) {
-      roles.insert(volume.role());
+    string role;
+    if (volume.reservations_size() > 0) {
+      // Check for role in the "post-reservation-refinement" format.
+      //
+      // If there is a stack of reservations, we only perform authorization
+      // for the most refined reservation, since we only support "pushing"
+      // one reservation at a time. That is, all of the previous reservations
+      // must have already been authorized.
+      role = volume.reservations().rbegin()->role();
+    } else {
+      // Check for role in the "pre-reservation-refinement" format.
+      role = volume.role();
+    }
+
+    if (!roles.contains(role)) {
+      roles.insert(role);
 
       request.mutable_object()->mutable_resource()->CopyFrom(volume);
-      request.mutable_object()->set_value(volume.role());
+      request.mutable_object()->set_value(role);
       authorizations.push_back(authorizer.get()->authorized(request));
     }
   }
@@ -3662,7 +3702,7 @@ Future<bool> Master::authorizeDestroyVolume(
     // NOTE: Since validation of this operation may be performed after
     // authorization, we must check here that this resource is a persistent
     // volume. If it isn't, the error will be caught during validation.
-    if (Resources::isPersistentVolume(volume)) {
+    if (volume.has_disk() && volume.disk().has_persistence()) {
       request.mutable_object()->mutable_resource()->CopyFrom(volume);
       request.mutable_object()->set_value(
           volume.disk().persistence().principal());
@@ -4162,7 +4202,9 @@ void Master::_accept(
   CHECK_READY(_authorizations);
   list<Future<bool>> authorizations = _authorizations.get();
 
-  foreach (const Offer::Operation& operation, accept.operations()) {
+  // We iterate by copy here since we call `convertResourceFormat` on it
+  // after validation which modifies the `Operation`.
+  foreach (Offer::Operation operation, accept.operations()) {
     switch (operation.type()) {
       // The RESERVE operation allows a principal to reserve resources.
       case Offer::Operation::RESERVE: {
@@ -4208,6 +4250,8 @@ void Master::_accept(
           continue;
         }
 
+        convertResourceFormat(&operation, POST_RESERVATION_REFINEMENT);
+
         // Test the given operation on the included resources.
         Try<Resources> resources = _offeredResources.apply(operation);
         if (resources.isError()) {
@@ -4263,6 +4307,8 @@ void Master::_accept(
           continue;
         }
 
+        convertResourceFormat(&operation, POST_RESERVATION_REFINEMENT);
+
         // Test the given operation on the included resources.
         Try<Resources> resources = _offeredResources.apply(operation);
         if (resources.isError()) {
@@ -4328,6 +4374,8 @@ void Master::_accept(
           continue;
         }
 
+        convertResourceFormat(&operation, POST_RESERVATION_REFINEMENT);
+
         Try<Resources> resources = _offeredResources.apply(operation);
         if (resources.isError()) {
           drop(framework, operation, resources.error());
@@ -4385,6 +4433,8 @@ void Master::_accept(
           continue;
         }
 
+        convertResourceFormat(&operation, POST_RESERVATION_REFINEMENT);
+
         // If any offer from this slave contains a volume that needs
         // to be destroyed, we should process it, but we should also
         // rescind those offers.
@@ -4577,13 +4627,6 @@ void Master::_accept(
 
             _offeredResources -= consumed;
 
-            // TODO(bmahler): Consider updating this log message to
-            // indicate when the executor is also being launched.
-            LOG(INFO) << "Launching task " << task_.task_id()
-                      << " of framework " << *framework
-                      << " with resources " << task_.resources()
-                      << " on agent " << *slave;
-
             RunTaskMessage message;
             message.mutable_framework()->MergeFrom(framework->info);
 
@@ -4602,7 +4645,34 @@ void Master::_accept(
                       slave->info));
             }
 
-            send(slave->pid, message);
+            Try<Nothing> sendRunTaskMessage = Nothing();
+
+            if (!slave->capabilities.reservationRefinement) {
+              sendRunTaskMessage =
+                downgradeResources(message.mutable_task()->mutable_resources());
+
+              if (!sendRunTaskMessage.isError() &&
+                  message.mutable_task()->has_executor()) {
+                sendRunTaskMessage =
+                  downgradeResources(message.mutable_task()
+                                       ->mutable_executor()
+                                       ->mutable_resources());
+              }
+            }
+
+            if (sendRunTaskMessage.isError()) {
+              LOG(WARNING) << "Not launching task containing resources with"
+                           << " refined reservations, since agent " << *slave
+                           << " is not RESERVATION_REFINEMENT-capable";
+            } else {
+              // TODO(bmahler): Consider updating this log message to
+              // indicate when the executor is also being launched.
+              LOG(INFO) << "Launching task " << task_.task_id()
+                        << " of framework " << *framework << " with resources "
+                        << task_.resources() << " on agent " << *slave;
+
+              send(slave->pid, message);
+            }
           }
 
           _operation.mutable_launch()->add_task_infos()->CopyFrom(task);
@@ -4784,12 +4854,36 @@ void Master::_accept(
           }
         }
 
-        LOG(INFO) << "Launching task group " << stringify(taskIds)
-                  << " of framework " << *framework
-                  << " with resources " << totalResources
-                  << " on agent " << *slave;
+        Try<Nothing> sendRunTaskGroupMessage = Nothing();
+
+        if (!slave->capabilities.reservationRefinement) {
+          sendRunTaskGroupMessage =
+            downgradeResources(message.mutable_executor()->mutable_resources());
+
+          foreach (
+              TaskInfo& task, *message.mutable_task_group()->mutable_tasks()) {
+            if (sendRunTaskGroupMessage.isError()) {
+              break;
+            }
+
+            sendRunTaskGroupMessage =
+              downgradeResources(task.mutable_resources());
+          }
+        }
+
+        if (sendRunTaskGroupMessage.isError()) {
+          LOG(WARNING) << "Not launching task group containing resources with"
+                       << " refined reservations, since agent " << *slave
+                       << " is not RESERVATION_REFINEMENT-capable: "
+                       << sendRunTaskGroupMessage.error();
+        } else {
+          LOG(INFO) << "Launching task group " << stringify(taskIds)
+                    << " of framework " << *framework << " with resources "
+                    << totalResources << " on agent " << *slave;
+
+          send(slave->pid, message);
+        }
 
-        send(slave->pid, message);
         break;
       }
 
@@ -6051,6 +6145,9 @@ void Master::__reregisterSlave(
       injectAllocationInfo(
           task.mutable_resources(),
           frameworks_.at(task.framework_id()));
+
+      convertResourceFormat(
+          task.mutable_resources(), POST_RESERVATION_REFINEMENT);
     }
 
     foreach (ExecutorInfo& executor, adjustedExecutorInfos) {
@@ -6059,6 +6156,9 @@ void Master::__reregisterSlave(
       injectAllocationInfo(
           executor.mutable_resources(),
           frameworks_.at(executor.framework_id()));
+
+      convertResourceFormat(
+          executor.mutable_resources(), POST_RESERVATION_REFINEMENT);
     }
   }
 
@@ -6256,13 +6356,26 @@ void Master::___reregisterSlave(
     }
   }
 
+  CheckpointResourcesMessage message;
+
+  message.mutable_resources()->CopyFrom(slave->checkpointedResources);
+
+  if (!slave->capabilities.reservationRefinement) {
+    Try<Nothing> result = downgradeResources(message.mutable_resources());
+    if (result.isError()) {
+      LOG(WARNING) << "Not sending updated checkpointed resouces "
+                   << slave->checkpointedResources
+                   << " with refined reservations, since agent " << *slave
+                   << " is not RESERVATION_REFINEMENT-capable.";
+
+      return;
+    }
+  }
+
   LOG(INFO) << "Sending updated checkpointed resources "
             << slave->checkpointedResources
             << " to agent " << *slave;
 
-  CheckpointResourcesMessage message;
-  message.mutable_resources()->CopyFrom(slave->checkpointedResources);
-
   send(slave->pid, message);
 }
 
@@ -7295,6 +7408,11 @@ void Master::offer(
         }
       }
 
+      if (!framework->capabilities.reservationRefinement) {
+        convertResourceFormat(
+            offer_.mutable_resources(), PRE_RESERVATION_REFINEMENT);
+      }
+
       // Add the offer *AND* the corresponding slave's PID.
       message.add_offers()->MergeFrom(offer_);
       message.add_pids(slave->pid);
@@ -8719,13 +8837,26 @@ void Master::_apply(Slave* slave, const Offer::Operation& operation) {
 
   slave->apply(operation);
 
-  LOG(INFO) << "Sending checkpointed resources "
-            << slave->checkpointedResources
-            << " to agent " << *slave;
-
   CheckpointResourcesMessage message;
+
   message.mutable_resources()->CopyFrom(slave->checkpointedResources);
 
+  if (!slave->capabilities.reservationRefinement) {
+    Try<Nothing> result = downgradeResources(message.mutable_resources());
+    if (result.isError()) {
+      LOG(WARNING) << "Not sending updated checkpointed resouces "
+                   << slave->checkpointedResources
+                   << " with refined reservations, since agent " << *slave
+                   << " is not RESERVATION_REFINEMENT-capable.";
+
+      return;
+    }
+  }
+
+  LOG(INFO) << "Sending updated checkpointed resources "
+            << slave->checkpointedResources
+            << " to agent " << *slave;
+
   send(slave->pid, message);
 }
 
@@ -9240,18 +9371,22 @@ void Master::subscribe(const HttpConnection& http)
 
 Slave::Slave(
     Master* const _master,
-    const SlaveInfo& _info,
+    SlaveInfo _info,
     const UPID& _pid,
     const MachineID& _machineId,
     const string& _version,
     const vector<SlaveInfo::Capability>& _capabilites,
     const Time& _registeredTime,
-    const Resources& _checkpointedResources,
+    vector<Resource> _checkpointedResources,
     const vector<ExecutorInfo>& executorInfos,
     const vector<Task>& tasks)
   : master(_master),
     id(_info.id()),
-    info(_info),
+    info([&_info]() {
+      convertResourceFormat(
+          _info.mutable_resources(), POST_RESERVATION_REFINEMENT);
+      return _info;
+    }()),
     machineId(_machineId),
     pid(_pid),
     version(_version),
@@ -9259,14 +9394,18 @@ Slave::Slave(
     registeredTime(_registeredTime),
     connected(true),
     active(true),
-    checkpointedResources(_checkpointedResources),
+    checkpointedResources([&_checkpointedResources]() {
+      convertResourceFormat(
+          &_checkpointedResources, POST_RESERVATION_REFINEMENT);
+      return _checkpointedResources;
+    }()),
     observer(nullptr)
 {
   CHECK(_info.has_id());
 
   Try<Resources> resources = applyCheckpointedResources(
       info.resources(),
-      _checkpointedResources);
+      checkpointedResources);
 
   // NOTE: This should be validated during slave recovery.
   CHECK_SOME(resources);

http://git-wip-us.apache.org/repos/asf/mesos/blob/0322de59/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 9c1e95c..4f50dce 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -116,13 +116,13 @@ struct Role;
 struct Slave
 {
   Slave(Master* const _master,
-        const SlaveInfo& _info,
+        SlaveInfo _info,
         const process::UPID& _pid,
         const MachineID& _machineId,
         const std::string& _version,
         const std::vector<SlaveInfo::Capability>& _capabilites,
         const process::Time& _registeredTime,
-        const Resources& _checkpointedResources,
+        std::vector<Resource> _checkpointedResources,
         const std::vector<ExecutorInfo>& executorInfos =
           std::vector<ExecutorInfo>(),
         const std::vector<Task>& tasks =

http://git-wip-us.apache.org/repos/asf/mesos/blob/0322de59/src/master/quota.cpp
----------------------------------------------------------------------
diff --git a/src/master/quota.cpp b/src/master/quota.cpp
index 3e0d280..79e4ad8 100644
--- a/src/master/quota.cpp
+++ b/src/master/quota.cpp
@@ -25,6 +25,8 @@
 #include <stout/error.hpp>
 #include <stout/option.hpp>
 
+#include "common/resources_utils.hpp"
+
 using google::protobuf::RepeatedPtrField;
 
 using mesos::quota::QuotaInfo;
@@ -132,22 +134,16 @@ Option<Error> quotaInfo(const QuotaInfo& quotaInfo)
   }
 
   foreach (const Resource& resource, quotaInfo.guarantee()) {
-    // Check that each guarantee/resource is valid.
-    Option<Error> resourceError = Resources::validate(resource);
-    if (resourceError.isSome()) {
-      return Error(
-          "QuotaInfo with invalid resource: " + resourceError->message);
-    }
-
     // Check that `resource` does not contain fields that are
     // irrelevant for quota.
-
-    if (resource.has_reservation()) {
-      return Error("QuotaInfo must not contain ReservationInfo");
+    if (resource.reservations_size() > 0) {
+      return Error("QuotaInfo must not contain any ReservationInfo");
     }
+
     if (resource.has_disk()) {
       return Error("QuotaInfo must not contain DiskInfo");
     }
+
     if (resource.has_revocable()) {
       return Error("QuotaInfo must not contain RevocableInfo");
     }
@@ -155,11 +151,6 @@ Option<Error> quotaInfo(const QuotaInfo& quotaInfo)
     if (resource.type() != Value::SCALAR) {
       return Error("QuotaInfo must not include non-scalar resources");
     }
-
-    // Check that the role is either unset or default.
-    if (resource.has_role() && resource.role() != "*") {
-      return Error("QuotaInfo resources must not specify a role");
-    }
   }
 
   return None();

http://git-wip-us.apache.org/repos/asf/mesos/blob/0322de59/src/master/quota_handler.cpp
----------------------------------------------------------------------
diff --git a/src/master/quota_handler.cpp b/src/master/quota_handler.cpp
index 7fe5580..26b2dc8 100644
--- a/src/master/quota_handler.cpp
+++ b/src/master/quota_handler.cpp
@@ -472,6 +472,17 @@ Future<http::Response> Master::QuotaHandler::_set(
 
   QuotaInfo quotaInfo = create.get();
 
+  // Check that each guarantee/resource is valid.
+  Option<Error> validate = Resources::validate(quotaInfo.guarantee());
+  if (validate.isSome()) {
+    return BadRequest(
+        "Failed to validate set quota request:"
+        " QuotaInfo with invalid resource: " + validate->message);
+  }
+
+  convertResourceFormat(
+      quotaInfo.mutable_guarantee(), POST_RESERVATION_REFINEMENT);
+
   // Check that the `QuotaInfo` is a valid quota request.
   {
     Option<Error> error = quota::validation::quotaInfo(quotaInfo);


[04/21] mesos git commit: Resources: Adjusted `operator<<` to the new resource format [4/20].

Posted by mp...@apache.org.
Resources: Adjusted `operator<<` to the new resource format [4/20].

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


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

Branch: refs/heads/master
Commit: 9ac264bf533b96629dbb742e42c93b537a88ef6e
Parents: 2d78e5a
Author: Michael Park <mp...@apache.org>
Authored: Sun Jun 18 22:05:10 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:30:21 2017 -0700

----------------------------------------------------------------------
 src/common/resources.cpp | 80 ++++++++++++++++++++++++++-----------------
 src/v1/resources.cpp     | 80 ++++++++++++++++++++++++++-----------------
 2 files changed, 96 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/9ac264bf/src/common/resources.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources.cpp b/src/common/resources.cpp
index 79c4d7d..22bc24e 100644
--- a/src/common/resources.cpp
+++ b/src/common/resources.cpp
@@ -2182,27 +2182,6 @@ ostream& operator<<(ostream& stream, const Volume& volume)
 }
 
 
-ostream& operator<<(ostream& stream, const Resource::DiskInfo& disk)
-{
-  if (disk.has_source()) {
-    stream << disk.source();
-  }
-
-  if (disk.has_persistence()) {
-    if (disk.has_source()) {
-      stream << ",";
-    }
-    stream << disk.persistence().id();
-  }
-
-  if (disk.has_volume()) {
-    stream << ":" << disk.volume();
-  }
-
-  return stream;
-}
-
-
 ostream& operator<<(ostream& stream, const Labels& labels)
 {
   stream << "{";
@@ -2227,30 +2206,67 @@ ostream& operator<<(ostream& stream, const Labels& labels)
 }
 
 
-ostream& operator<<(ostream& stream, const Resource& resource)
+ostream& operator<<(
+    ostream& stream,
+    const Resource::ReservationInfo& reservation)
 {
-  stream << resource.name();
+  stream << Resource::ReservationInfo::Type_Name(reservation.type()) << ","
+         << reservation.role();
 
-  stream << "(" << resource.role();
+  if (reservation.has_principal()) {
+    stream << "," << reservation.principal();
+  }
 
-  if (resource.has_reservation()) {
-    const Resource::ReservationInfo& reservation = resource.reservation();
+  if (reservation.has_labels()) {
+    stream << "," << reservation.labels();
+  }
 
-    if (reservation.has_principal()) {
-      stream << ", " << reservation.principal();
-    }
+  return stream;
+}
+
+
+ostream& operator<<(ostream& stream, const Resource::DiskInfo& disk)
+{
+  if (disk.has_source()) {
+    stream << disk.source();
+  }
 
-    if (reservation.has_labels()) {
-      stream << ", " << reservation.labels();
+  if (disk.has_persistence()) {
+    if (disk.has_source()) {
+      stream << ",";
     }
+    stream << disk.persistence().id();
   }
 
-  stream << ")";
+  if (disk.has_volume()) {
+    stream << ":" << disk.volume();
+  }
+
+  return stream;
+}
+
+
+ostream& operator<<(ostream& stream, const Resource& resource)
+{
+  stream << resource.name();
 
   if (resource.has_allocation_info()) {
     stream << "(allocated: " << resource.allocation_info().role() << ")";
   }
 
+  if (resource.reservations_size() > 0) {
+    stream << "(reservations: [";
+
+    for (int i = 0; i < resource.reservations_size(); ++i) {
+      if (i > 0) {
+        stream << ",";
+      }
+      stream << "(" << resource.reservations(i) << ")";
+    }
+
+    stream << "])";
+  }
+
   if (resource.has_disk()) {
     stream << "[" << resource.disk() << "]";
   }

http://git-wip-us.apache.org/repos/asf/mesos/blob/9ac264bf/src/v1/resources.cpp
----------------------------------------------------------------------
diff --git a/src/v1/resources.cpp b/src/v1/resources.cpp
index 0a4f4b2..d03577f 100644
--- a/src/v1/resources.cpp
+++ b/src/v1/resources.cpp
@@ -2184,27 +2184,6 @@ ostream& operator<<(ostream& stream, const Volume& volume)
 }
 
 
-ostream& operator<<(ostream& stream, const Resource::DiskInfo& disk)
-{
-  if (disk.has_source()) {
-    stream << disk.source();
-  }
-
-  if (disk.has_persistence()) {
-    if (disk.has_source()) {
-      stream << ",";
-    }
-    stream << disk.persistence().id();
-  }
-
-  if (disk.has_volume()) {
-    stream << ":" << disk.volume();
-  }
-
-  return stream;
-}
-
-
 ostream& operator<<(ostream& stream, const Labels& labels)
 {
   stream << "{";
@@ -2229,30 +2208,67 @@ ostream& operator<<(ostream& stream, const Labels& labels)
 }
 
 
-ostream& operator<<(ostream& stream, const Resource& resource)
+ostream& operator<<(
+    ostream& stream,
+    const Resource::ReservationInfo& reservation)
 {
-  stream << resource.name();
+  stream << Resource::ReservationInfo::Type_Name(reservation.type()) << ","
+         << reservation.role();
 
-  stream << "(" << resource.role();
+  if (reservation.has_principal()) {
+    stream << "," << reservation.principal();
+  }
 
-  if (resource.has_reservation()) {
-    const Resource::ReservationInfo& reservation = resource.reservation();
+  if (reservation.has_labels()) {
+    stream << "," << reservation.labels();
+  }
 
-    if (reservation.has_principal()) {
-      stream << ", " << reservation.principal();
-    }
+  return stream;
+}
+
+
+ostream& operator<<(ostream& stream, const Resource::DiskInfo& disk)
+{
+  if (disk.has_source()) {
+    stream << disk.source();
+  }
 
-    if (reservation.has_labels()) {
-      stream << ", " << reservation.labels();
+  if (disk.has_persistence()) {
+    if (disk.has_source()) {
+      stream << ",";
     }
+    stream << disk.persistence().id();
   }
 
-  stream << ")";
+  if (disk.has_volume()) {
+    stream << ":" << disk.volume();
+  }
+
+  return stream;
+}
+
+
+ostream& operator<<(ostream& stream, const Resource& resource)
+{
+  stream << resource.name();
 
   if (resource.has_allocation_info()) {
     stream << "(allocated: " << resource.allocation_info().role() << ")";
   }
 
+  if (resource.reservations_size() > 0) {
+    stream << "(reservations: [";
+
+    for (int i = 0; i < resource.reservations_size(); ++i) {
+      if (i > 0) {
+        stream << ", ";
+      }
+      stream << "(" << resource.reservations(i) << ")";
+    }
+
+    stream << "])";
+  }
+
   if (resource.has_disk()) {
     stream << "[" << resource.disk() << "]";
   }


[07/21] mesos git commit: Introduced a utility function `Resources::reservationRole` [7/20].

Posted by mp...@apache.org.
Introduced a utility function `Resources::reservationRole` [7/20].

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


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

Branch: refs/heads/master
Commit: 7877b46f74730b61daf5179121139b40df26c2a6
Parents: 76b0f4e
Author: Michael Park <mp...@apache.org>
Authored: Sun Jun 18 21:15:14 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:30:33 2017 -0700

----------------------------------------------------------------------
 include/mesos/resources.hpp    |  4 ++++
 include/mesos/v1/resources.hpp |  4 ++++
 src/common/resources.cpp       | 34 +++++++++++++++++++++-------------
 src/v1/resources.cpp           | 34 +++++++++++++++++++++-------------
 4 files changed, 50 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/7877b46f/include/mesos/resources.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/resources.hpp b/include/mesos/resources.hpp
index b6264e2..513b4c3 100644
--- a/include/mesos/resources.hpp
+++ b/include/mesos/resources.hpp
@@ -306,6 +306,10 @@ public:
   // Tests if the given Resource object has refined reservations.
   static bool hasRefinedReservations(const Resource& resource);
 
+  // Returns the role to which the given Resource object is reserved for.
+  // This must be called only when the resource is reserved!
+  static const std::string& reservationRole(const Resource& resource);
+
   // Returns the summed up Resources given a hashmap<Key, Resources>.
   //
   // NOTE: While scalar resources such as "cpus" sum correctly,

http://git-wip-us.apache.org/repos/asf/mesos/blob/7877b46f/include/mesos/v1/resources.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/v1/resources.hpp b/include/mesos/v1/resources.hpp
index b7e390c..eb7d70c 100644
--- a/include/mesos/v1/resources.hpp
+++ b/include/mesos/v1/resources.hpp
@@ -306,6 +306,10 @@ public:
   // Tests if the given Resource object has refined reservations.
   static bool hasRefinedReservations(const Resource& resource);
 
+  // Returns the role to which the given Resource object is reserved for.
+  // This must be called only when the resource is reserved!
+  static const std::string& reservationRole(const Resource& resource);
+
   // Returns the summed up Resources given a hashmap<Key, Resources>.
   //
   // NOTE: While scalar resources such as "cpus" sum correctly,

http://git-wip-us.apache.org/repos/asf/mesos/blob/7877b46f/src/common/resources.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources.cpp b/src/common/resources.cpp
index d1b9a9e..1dd058f 100644
--- a/src/common/resources.cpp
+++ b/src/common/resources.cpp
@@ -1080,11 +1080,8 @@ bool Resources::isReserved(
   CHECK(!resource.has_role());
   CHECK(!resource.has_reservation());
 
-  if (role.isSome()) {
-    return !isUnreserved(resource) && role.get() == resource.role();
-  } else {
-    return !isUnreserved(resource);
-  }
+  return !isUnreserved(resource) &&
+         (role.isNone() || role.get() == reservationRole(resource));
 }
 
 
@@ -1096,8 +1093,8 @@ bool Resources::isAllocatableTo(
   CHECK(!resource.has_reservation());
 
   return isUnreserved(resource) ||
-         role == resource.role() ||
-         roles::isStrictSubroleOf(role, resource.role());
+         role == reservationRole(resource) ||
+         roles::isStrictSubroleOf(role, reservationRole(resource));
 }
 
 
@@ -1146,6 +1143,13 @@ bool Resources::hasRefinedReservations(const Resource& resource)
   return resource.reservations_size() > 1;
 }
 
+
+const string& Resources::reservationRole(const Resource& resource)
+{
+  CHECK_GE(resource.reservations_size(), 0);
+  return resource.reservations().rbegin()->role();
+}
+
 /////////////////////////////////////////////////
 // Public member functions.
 /////////////////////////////////////////////////
@@ -1356,7 +1360,7 @@ hashmap<string, Resources> Resources::reservations() const
 
   foreach (const Resource_& resource_, resources) {
     if (isReserved(resource_.resource)) {
-      result[resource_.resource.role()].add(resource_);
+      result[reservationRole(resource_.resource)].add(resource_);
     }
   }
 
@@ -1935,11 +1939,15 @@ Option<Resources> Resources::find(const Resource& target) const
   Resources remaining = Resources(target).flatten();
 
   // First look in the target role, then unreserved, then any remaining role.
-  vector<lambda::function<bool(const Resource&)>> predicates = {
-    lambda::bind(isReserved, lambda::_1, target.role()),
-    isUnreserved,
-    [](const Resource&) { return true; }
-  };
+  vector<lambda::function<bool(const Resource&)>> predicates;
+
+  if (isReserved(target)) {
+    predicates.push_back(
+        lambda::bind(isReserved, lambda::_1, reservationRole(target)));
+  }
+
+  predicates.push_back(isUnreserved);
+  predicates.push_back([](const Resource&) { return true; });
 
   foreach (const auto& predicate, predicates) {
     foreach (const Resource_& resource_, total.filter(predicate)) {

http://git-wip-us.apache.org/repos/asf/mesos/blob/7877b46f/src/v1/resources.cpp
----------------------------------------------------------------------
diff --git a/src/v1/resources.cpp b/src/v1/resources.cpp
index a853f80..a9b0233 100644
--- a/src/v1/resources.cpp
+++ b/src/v1/resources.cpp
@@ -1111,11 +1111,8 @@ bool Resources::isReserved(
   CHECK(!resource.has_role());
   CHECK(!resource.has_reservation());
 
-  if (role.isSome()) {
-    return !isUnreserved(resource) && role.get() == resource.role();
-  } else {
-    return !isUnreserved(resource);
-  }
+  return !isUnreserved(resource) &&
+         (role.isNone() || role.get() == reservationRole(resource));
 }
 
 
@@ -1127,8 +1124,8 @@ bool Resources::isAllocatableTo(
   CHECK(!resource.has_reservation());
 
   return isUnreserved(resource) ||
-         role == resource.role() ||
-         roles::isStrictSubroleOf(role, resource.role());
+         role == reservationRole(resource) ||
+         roles::isStrictSubroleOf(role, reservationRole(resource));
 }
 
 
@@ -1177,6 +1174,13 @@ bool Resources::hasRefinedReservations(const Resource& resource)
   return resource.reservations_size() > 1;
 }
 
+
+const string& Resources::reservationRole(const Resource& resource)
+{
+  CHECK_GE(resource.reservations_size(), 0);
+  return resource.reservations().rbegin()->role();
+}
+
 /////////////////////////////////////////////////
 // Public member functions.
 /////////////////////////////////////////////////
@@ -1387,7 +1391,7 @@ hashmap<string, Resources> Resources::reservations() const
 
   foreach (const Resource_& resource_, resources) {
     if (isReserved(resource_.resource)) {
-      result[resource_.resource.role()].add(resource_);
+      result[reservationRole(resource_.resource)].add(resource_);
     }
   }
 
@@ -1966,11 +1970,15 @@ Option<Resources> Resources::find(const Resource& target) const
   Resources remaining = Resources(target).flatten();
 
   // First look in the target role, then unreserved, then any remaining role.
-  vector<lambda::function<bool(const Resource&)>> predicates = {
-    lambda::bind(isReserved, lambda::_1, target.role()),
-    isUnreserved,
-    [](const Resource&) { return true; }
-  };
+  vector<lambda::function<bool(const Resource&)>> predicates;
+
+  if (isReserved(target)) {
+    predicates.push_back(
+        lambda::bind(isReserved, lambda::_1, reservationRole(target)));
+  }
+
+  predicates.push_back(isUnreserved);
+  predicates.push_back([](const Resource&) { return true; });
 
   foreach (const auto& predicate, predicates) {
     foreach (const Resource_& resource_, total.filter(predicate)) {


[19/21] mesos git commit: Adjusted tests to the new resource format [19/20].

Posted by mp...@apache.org.
http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/resources_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/resources_tests.cpp b/src/tests/resources_tests.cpp
index f19f5f1..1d7cf99 100644
--- a/src/tests/resources_tests.cpp
+++ b/src/tests/resources_tests.cpp
@@ -99,20 +99,19 @@ TEST(ResourcesTest, ParsingWithRoles)
   cpus.set_name("cpus");
   cpus.set_type(Value::SCALAR);
   cpus.mutable_scalar()->set_value(2);
-  cpus.set_role("role1");
+  cpus.add_reservations()->CopyFrom(createStaticReservationInfo("role1"));
 
   Resource mem;
   mem.set_name("mem");
   mem.set_type(Value::SCALAR);
   mem.mutable_scalar()->set_value(3);
-  mem.set_role("role1");
+  mem.add_reservations()->CopyFrom(createStaticReservationInfo("role1"));
 
   Resources resources1;
   resources1 += cpus;
   resources1 += mem;
 
   EXPECT_EQ(parse1, resources1);
-  EXPECT_EQ(resources1, Resources::parse(stringify(resources1)).get());
 
   Resources parse2 = Resources::parse(
       "cpus(role1):2.5;ports(role2):[0-100]").get();
@@ -121,7 +120,7 @@ TEST(ResourcesTest, ParsingWithRoles)
   cpus2.set_name("cpus");
   cpus2.set_type(Value::SCALAR);
   cpus2.mutable_scalar()->set_value(2.5);
-  cpus2.set_role("role1");
+  cpus2.add_reservations()->CopyFrom(createStaticReservationInfo("role1"));
 
   Resource ports;
   ports.set_name("ports");
@@ -129,14 +128,13 @@ TEST(ResourcesTest, ParsingWithRoles)
   Value::Range* range = ports.mutable_ranges()->add_range();
   range->set_begin(0);
   range->set_end(100);
-  ports.set_role("role2");
+  ports.add_reservations()->CopyFrom(createStaticReservationInfo("role2"));
 
   Resources resources2;
   resources2 += ports;
   resources2 += cpus2;
 
   EXPECT_EQ(parse2, resources2);
-  EXPECT_EQ(resources2, Resources::parse(stringify(resources2)).get());
 
   Resources parse3 = Resources::parse(
       "cpus:2.5;ports(role2):[0-100]", "role1").get();
@@ -328,7 +326,12 @@ TEST(ResourcesTest, ParsingFromJSONWithRoles)
     "    \"scalar\": {\n"
     "      \"value\": 45.55\n"
     "    },\n"
-    "    \"role\": \"role1\"\n"
+    "    \"reservations\": [\n"
+    "      {\n"
+    "        \"type\": \"STATIC\",\n"
+    "        \"role\": \"role1\"\n"
+    "      }\n"
+    "    ]\n"
     "  }\n"
     "]";
 
@@ -340,7 +343,7 @@ TEST(ResourcesTest, ParsingFromJSONWithRoles)
 
   ASSERT_EQ(Value::SCALAR, cpus.type());
   EXPECT_EQ(45.55, cpus.scalar().value());
-  EXPECT_EQ("role1", cpus.role());
+  EXPECT_EQ("role1", Resources::reservationRole(cpus));
 
   jsonString =
     "[\n"
@@ -350,7 +353,12 @@ TEST(ResourcesTest, ParsingFromJSONWithRoles)
     "    \"scalar\": {\n"
     "      \"value\": 54.44\n"
     "    },\n"
-    "    \"role\": \"role2\"\n"
+    "    \"reservations\": [\n"
+    "      {\n"
+    "        \"type\": \"STATIC\",\n"
+    "        \"role\": \"role2\"\n"
+    "      }\n"
+    "    ]\n"
     "  }\n"
     "]";
 
@@ -369,7 +377,7 @@ TEST(ResourcesTest, ParsingFromJSONWithRoles)
   EXPECT_EQ(145.54, resources.cpus().get());
 
   foreach (const Resource& resource, resources) {
-    if (resource.role() == "role1") {
+    if (Resources::reservationRole(resource) == "role1") {
       EXPECT_EQ(91.1, resource.scalar().value());
     } else {
       EXPECT_EQ(54.44, resource.scalar().value());
@@ -393,7 +401,12 @@ TEST(ResourcesTest, ParsingFromJSONWithRoles)
     "        }"
     "      ]"
     "    },"
-    "    \"role\": \"role1\""
+    "    \"reservations\": [\n"
+    "      {\n"
+    "        \"type\": \"STATIC\",\n"
+    "        \"role\": \"role1\"\n"
+    "      }\n"
+    "    ]\n"
     "  },"
     "  {"
     "    \"name\": \"pandas\","
@@ -404,7 +417,12 @@ TEST(ResourcesTest, ParsingFromJSONWithRoles)
     "        \"yang_yang\""
     "      ]"
     "    },"
-    "    \"role\": \"panda_liason\""
+    "    \"reservations\": [\n"
+    "      {\n"
+    "        \"type\": \"STATIC\",\n"
+    "        \"role\": \"panda_liason\"\n"
+    "      }\n"
+    "    ]\n"
     "  }"
     "]";
 
@@ -414,7 +432,7 @@ TEST(ResourcesTest, ParsingFromJSONWithRoles)
   resources = resourcesTry.get();
 
   foreach (const Resource& resource, resources) {
-    if (resource.role() == "role1") {
+    if (Resources::reservationRole(resource) == "role1") {
       EXPECT_EQ(Value::RANGES, resource.type());
       EXPECT_EQ(2, resource.ranges().range_size());
     } else {
@@ -722,10 +740,11 @@ TEST(ResourcesTest, ParsingFromJSONError)
     "    \"scalar\" : {"
     "      \"value\" : 2048"
     "    },"
-    "    \"reservation\" : {"
+    "    \"reservations\" : [{"
+    "      \"role\": \"new_role\""
     "      \"principal\" : \"default_principal\""
-    "    },"
-    "    \"role\": \"new_role\""
+    "    }],"
+    "    \"role\": \"*\""
     "  }"
     "]";
 
@@ -782,7 +801,7 @@ TEST(ResourcesTest, Printing)
       "cpus:45.55;ports:[10000-20000, 30000-50000];disks:{sda1}").get();
 
   string output =
-    "cpus(*):45.55; ports(*):[10000-20000, 30000-50000]; disks(*):{sda1}";
+    "cpus:45.55; ports:[10000-20000, 30000-50000]; disks:{sda1}";
 
   ostringstream oss;
   oss << r;
@@ -806,26 +825,27 @@ TEST(ResourcesTest, PrintingExtendedAttributes)
   // Standard resource.
   ostringstream stream;
   stream << disk;
-  EXPECT_EQ("disk(*):1", stream.str());
+  EXPECT_EQ("disk:1", stream.str());
 
   // Standard resource with role (statically reserved).
   stream.str("");
-  disk.set_role("alice");
+  disk.add_reservations()->CopyFrom(createStaticReservationInfo("alice"));
   stream << disk;
-  EXPECT_EQ("disk(alice):1", stream.str());
+  EXPECT_EQ("disk(reservations: [(STATIC,alice)]):1", stream.str());
 
   // Allocated resource.
   stream.str("");
   disk.mutable_allocation_info()->set_role("role");
   stream << disk;
-  EXPECT_EQ("disk(alice)(allocated: role):1", stream.str());
+  EXPECT_EQ(
+      "disk(allocated: role)(reservations: [(STATIC,alice)]):1", stream.str());
   disk.clear_allocation_info();
 
   // Standard revocable resource.
   stream.str("");
   disk.mutable_revocable();
   stream << disk;
-  EXPECT_EQ("disk(alice){REV}:1", stream.str());
+  EXPECT_EQ("disk(reservations: [(STATIC,alice)]){REV}:1", stream.str());
   disk.clear_revocable();
 
   // Disk resource with persistent volume.
@@ -833,13 +853,16 @@ TEST(ResourcesTest, PrintingExtendedAttributes)
   disk.mutable_disk()->mutable_persistence()->set_id("hadoop");
   disk.mutable_disk()->mutable_volume()->set_container_path("/data");
   stream << disk;
-  EXPECT_EQ("disk(alice)[hadoop:/data]:1", stream.str());
+  EXPECT_EQ(
+      "disk(reservations: [(STATIC,alice)])[hadoop:/data]:1", stream.str());
 
   // Ensure {REV} comes after [disk].
   stream.str("");
   disk.mutable_revocable();
   stream << disk;
-  EXPECT_EQ("disk(alice)[hadoop:/data]{REV}:1", stream.str());
+  EXPECT_EQ(
+      "disk(reservations: [(STATIC,alice)])[hadoop:/data]{REV}:1",
+      stream.str());
   disk.clear_revocable();
 
   // Disk resource with host path.
@@ -847,7 +870,9 @@ TEST(ResourcesTest, PrintingExtendedAttributes)
   disk.mutable_disk()->mutable_volume()->set_host_path("/hdfs");
   disk.mutable_disk()->mutable_volume()->set_mode(Volume::RW);
   stream << disk;
-  EXPECT_EQ("disk(alice)[hadoop:/hdfs:/data:rw]:1", stream.str());
+  EXPECT_EQ(
+      "disk(reservations: [(STATIC,alice)])[hadoop:/hdfs:/data:rw]:1",
+      stream.str());
 
   // Disk resource with MOUNT type.
   stream.str("");
@@ -855,7 +880,10 @@ TEST(ResourcesTest, PrintingExtendedAttributes)
       Resource::DiskInfo::Source::MOUNT);
   disk.mutable_disk()->mutable_source()->mutable_mount()->set_root("/mnt1");
   stream << disk;
-  EXPECT_EQ("disk(alice)[MOUNT:/mnt1,hadoop:/hdfs:/data:rw]:1", stream.str());
+  EXPECT_EQ(
+      "disk(reservations: "
+      "[(STATIC,alice)])[MOUNT:/mnt1,hadoop:/hdfs:/data:rw]:1",
+      stream.str());
   disk.mutable_disk()->clear_source();
 
   // Disk resource with PATH type.
@@ -864,23 +892,33 @@ TEST(ResourcesTest, PrintingExtendedAttributes)
       Resource::DiskInfo::Source::PATH);
   disk.mutable_disk()->mutable_source()->mutable_path()->set_root("/mnt2");
   stream << disk;
-  EXPECT_EQ("disk(alice)[PATH:/mnt2,hadoop:/hdfs:/data:rw]:1", stream.str());
+  EXPECT_EQ(
+      "disk(reservations: "
+      "[(STATIC,alice)])[PATH:/mnt2,hadoop:/hdfs:/data:rw]:1",
+      stream.str());
   disk.mutable_disk()->clear_source();
 
   // Disk resource with host path and dynamic reservation without labels.
   stream.str("");
-  disk.mutable_reservation()->set_principal("hdfs-p");
+  Resource::ReservationInfo* reservation = disk.add_reservations();
+  reservation->CopyFrom(
+      createDynamicReservationInfo("alice/refined", "hdfs-p"));
   stream << disk;
-  EXPECT_EQ("disk(alice, hdfs-p)[hadoop:/hdfs:/data:rw]:1", stream.str());
+  EXPECT_EQ(
+      "disk(reservations: [(STATIC,alice),(DYNAMIC,alice/refined,hdfs-p)])"
+      "[hadoop:/hdfs:/data:rw]:1",
+      stream.str());
 
   // Disk resource with host path and dynamic reservation with labels.
   stream.str("");
-  Labels* labels = disk.mutable_reservation()->mutable_labels();
+  Labels* labels = reservation->mutable_labels();
   labels->add_labels()->CopyFrom(createLabel("foo", "bar"));
   labels->add_labels()->CopyFrom(createLabel("foo"));
   stream << disk;
-  EXPECT_EQ("disk(alice, hdfs-p, {foo: bar, foo})[hadoop:/hdfs:/data:rw]:1",
-            stream.str());
+  EXPECT_EQ(
+      "disk(reservations: [(STATIC,alice),(DYNAMIC,alice/refined,hdfs-p,"
+      "{foo: bar, foo})])[hadoop:/hdfs:/data:rw]:1",
+      stream.str());
 }
 
 
@@ -894,37 +932,37 @@ TEST(ResourcesTest, PrintingScalarPrecision)
   // Three decimal digits of precision are supported.
   ostringstream stream;
   stream << scalar;
-  EXPECT_EQ("cpus(*):1.234", stream.str());
+  EXPECT_EQ("cpus:1.234", stream.str());
 
   // Additional precision is discarded via rounding.
   scalar.mutable_scalar()->set_value(1.2345);
   stream.str("");
   stream << scalar;
-  EXPECT_EQ("cpus(*):1.235", stream.str());
+  EXPECT_EQ("cpus:1.235", stream.str());
 
   scalar.mutable_scalar()->set_value(1.2344);
   stream.str("");
   stream << scalar;
-  EXPECT_EQ("cpus(*):1.234", stream.str());
+  EXPECT_EQ("cpus:1.234", stream.str());
 
   // Trailing zeroes are not printed.
   scalar.mutable_scalar()->set_value(1.1);
   stream.str("");
   stream << scalar;
-  EXPECT_EQ("cpus(*):1.1", stream.str());
+  EXPECT_EQ("cpus:1.1", stream.str());
 
   // Large integers are printed with all digits.
   scalar.mutable_scalar()->set_value(1000001);
   stream.str("");
   stream << scalar;
-  EXPECT_EQ("cpus(*):1000001", stream.str());
+  EXPECT_EQ("cpus:1000001", stream.str());
 
   // Even larger value with precision in the fractional part limited
   // to 3 digits but full precision in the integral part preserved.
   scalar.mutable_scalar()->set_value(99999999999.9994);
   stream.str("");
   stream << scalar;
-  EXPECT_EQ("cpus(*):99999999999.999", stream.str());
+  EXPECT_EQ("cpus:99999999999.999", stream.str());
 }
 
 
@@ -1903,30 +1941,23 @@ TEST(ResourcesTest, PrecisionVerySmallValue)
 TEST(ReservedResourcesTest, Validation)
 {
   // Unreserved.
-  EXPECT_NONE(Resources::validate(createReservedResource(
-      "cpus", "8", "*", None())));
+  EXPECT_NONE(Resources::validate(createReservedResource("cpus", "8")));
 
-  // Statically role reserved.
+  // Statically reserved to "role".
   EXPECT_NONE(Resources::validate(createReservedResource(
-      "cpus", "8", "role", None())));
-
-  // Invalid.
-  EXPECT_SOME(Resources::validate(createReservedResource(
-      "cpus", "8", "*", createReservationInfo("principal1"))));
-
-  // Invalid role name.
-  EXPECT_SOME(Resources::validate(createReservedResource(
-      "cpus", "8", ".", createReservationInfo("principal1"))));
+      "cpus", "8", createStaticReservationInfo("role"))));
 
   // Dynamically reserved without labels.
   EXPECT_NONE(Resources::validate(createReservedResource(
-      "cpus", "8", "role", createReservationInfo("principal2"))));
+      "cpus", "8", createDynamicReservationInfo("role", "principal2"))));
 
   // Dynamically reserved with labels.
   Labels labels;
   labels.add_labels()->CopyFrom(createLabel("foo", "bar"));
   EXPECT_NONE(Resources::validate(createReservedResource(
-      "cpus", "8", "role", createReservationInfo("principal2", labels))));
+      "cpus",
+      "8",
+      createDynamicReservationInfo("role", "principal2", labels))));
 }
 
 
@@ -1940,28 +1971,28 @@ TEST(ReservedResourcesTest, Equals)
 
   vector<Resources> unique = {
     // Unreserved.
-    createReservedResource(
-        "cpus", "8", "*", None()),
+    createReservedResource("cpus", "8"),
     // Statically reserved for role.
-    createReservedResource(
-        "cpus", "8", "role1", None()),
-    createReservedResource(
-        "cpus", "8", "role2", None()),
+    createReservedResource("cpus", "8", createStaticReservationInfo("role1")),
+    createReservedResource("cpus", "8", createStaticReservationInfo("role2")),
     // Dynamically reserved for role.
     createReservedResource(
-        "cpus", "8", "role1", createReservationInfo("principal1")),
+        "cpus", "8", createDynamicReservationInfo("role1", "principal1")),
     createReservedResource(
-        "cpus", "8", "role1", createReservationInfo("principal2")),
+        "cpus", "8", createDynamicReservationInfo("role1", "principal2")),
     createReservedResource(
-        "cpus", "8", "role2", createReservationInfo("principal1")),
+        "cpus", "8", createDynamicReservationInfo("role2", "principal1")),
     createReservedResource(
-        "cpus", "8", "role2", createReservationInfo("principal2")),
+        "cpus", "8", createDynamicReservationInfo("role2", "principal2")),
     // Dynamically reserved with labels.
     createReservedResource(
-        "cpus", "8", "role1", createReservationInfo("principal2", labels1)),
+        "cpus",
+        "8",
+        createDynamicReservationInfo("role1", "principal2", labels1)),
     createReservedResource(
-        "cpus", "8", "role1", createReservationInfo("principal2", labels2))
-  };
+        "cpus",
+        "8",
+        createDynamicReservationInfo("role1", "principal2", labels2))};
 
   // Test that all resources in 'unique' are considered different.
   foreach (const Resources& left, unique) {
@@ -1977,9 +2008,12 @@ TEST(ReservedResourcesTest, Equals)
 
 TEST(ReservedResourcesTest, AdditionStaticallyReserved)
 {
-  Resources left = createReservedResource("cpus", "8", "role", None());
-  Resources right = createReservedResource("cpus", "4", "role", None());
-  Resources expected = createReservedResource("cpus", "12", "role", None());
+  Resources left =
+    createReservedResource("cpus", "8", createStaticReservationInfo("role"));
+  Resources right =
+    createReservedResource("cpus", "4", createStaticReservationInfo("role"));
+  Resources expected =
+    createReservedResource("cpus", "12", createStaticReservationInfo("role"));
 
   EXPECT_EQ(expected, left + right);
 }
@@ -1987,15 +2021,12 @@ TEST(ReservedResourcesTest, AdditionStaticallyReserved)
 
 TEST(ReservedResourcesTest, AdditionDynamicallyReservedWithoutLabels)
 {
-  Resource::ReservationInfo reservationInfo =
-    createReservationInfo("principal");
+  Resource::ReservationInfo reservation =
+    createDynamicReservationInfo("role", "principal");
 
-  Resources left =
-    createReservedResource("cpus", "8", "role", reservationInfo);
-  Resources right =
-    createReservedResource("cpus", "4", "role", reservationInfo);
-  Resources expected =
-    createReservedResource("cpus", "12", "role", reservationInfo);
+  Resources left = createReservedResource("cpus", "8", reservation);
+  Resources right = createReservedResource("cpus", "4", reservation);
+  Resources expected = createReservedResource("cpus", "12", reservation);
 
   EXPECT_EQ(expected, left + right);
 }
@@ -2006,15 +2037,12 @@ TEST(ReservedResourcesTest, AdditionDynamicallyReservedWithSameLabels)
   Labels labels;
   labels.add_labels()->CopyFrom(createLabel("foo", "bar"));
 
-  Resource::ReservationInfo reservationInfo =
-    createReservationInfo("principal", labels);
+  Resource::ReservationInfo reservation =
+    createDynamicReservationInfo("role", "principal", labels);
 
-  Resources left =
-    createReservedResource("cpus", "8", "role", reservationInfo);
-  Resources right =
-    createReservedResource("cpus", "4", "role", reservationInfo);
-  Resources expected =
-    createReservedResource("cpus", "12", "role", reservationInfo);
+  Resources left = createReservedResource("cpus", "8", reservation);
+  Resources right = createReservedResource("cpus", "4", reservation);
+  Resources expected = createReservedResource("cpus", "12", reservation);
 
   EXPECT_EQ(expected, left + right);
 }
@@ -2028,13 +2056,13 @@ TEST(ReservedResourcesTest, AdditionDynamicallyReservedWithDistinctLabels)
   labels1.add_labels()->CopyFrom(createLabel("foo", "bar"));
   labels2.add_labels()->CopyFrom(createLabel("foo", "baz"));
 
-  Resource::ReservationInfo reservationInfo1 =
-    createReservationInfo("principal", labels1);
-  Resource::ReservationInfo reservationInfo2 =
-    createReservationInfo("principal", labels2);
+  Resource::ReservationInfo reservation1 =
+    createDynamicReservationInfo("role", "principal", labels1);
+  Resource::ReservationInfo reservation2 =
+    createDynamicReservationInfo("role", "principal", labels2);
 
-  Resources r1 = createReservedResource("cpus", "6", "role", reservationInfo1);
-  Resources r2 = createReservedResource("cpus", "6", "role", reservationInfo2);
+  Resources r1 = createReservedResource("cpus", "6", reservation1);
+  Resources r2 = createReservedResource("cpus", "6", reservation2);
   Resources sum = r1 + r2;
 
   EXPECT_EQ(2u, sum.size());
@@ -2051,13 +2079,16 @@ TEST(ReservedResourcesTest, Subtraction)
   labels1.add_labels()->CopyFrom(createLabel("foo", "bar"));
   labels2.add_labels()->CopyFrom(createLabel("foo", "baz"));
 
-  Resource::ReservationInfo reservationInfo1 =
-    createReservationInfo("principal", labels1);
-  Resource::ReservationInfo reservationInfo2 =
-    createReservationInfo("principal", labels2);
+  Resource::ReservationInfo reservation1 =
+    createDynamicReservationInfo("role", "principal", labels1);
+
+  Resource::ReservationInfo reservation2 =
+    createDynamicReservationInfo("role", "principal", labels2);
+
+  Resources r1 =
+    createReservedResource("cpus", "8", createStaticReservationInfo("role"));
 
-  Resources r1 = createReservedResource("cpus", "8", "role", None());
-  Resources r2 = createReservedResource("cpus", "8", "role", reservationInfo1);
+  Resources r2 = createReservedResource("cpus", "8", reservation1);
 
   EXPECT_TRUE((r1 - r1).empty());
   EXPECT_TRUE((r2 - r2).empty());
@@ -2068,19 +2099,21 @@ TEST(ReservedResourcesTest, Subtraction)
 
   Resources total = r1 + r2;
 
-  Resources r3 = createReservedResource("cpus", "6", "role", None());
-  Resources r4 = createReservedResource("cpus", "4", "role", reservationInfo1);
+  Resources r3 =
+    createReservedResource("cpus", "6", createStaticReservationInfo("role"));
+  Resources r4 = createReservedResource("cpus", "4", reservation1);
 
   Resources expected = r3 + r4;
 
-  Resources r5 = createReservedResource("cpus", "2", "role", None());
-  Resources r6 = createReservedResource("cpus", "4", "role", reservationInfo1);
+  Resources r5 =
+    createReservedResource("cpus", "2", createStaticReservationInfo("role"));
+  Resources r6 = createReservedResource("cpus", "4", reservation1);
 
   EXPECT_EQ(expected, total - r5 - r6);
 
   // Distinct labels
-  Resources r7 = createReservedResource("cpus", "8", "role", reservationInfo1);
-  Resources r8 = createReservedResource("cpus", "8", "role", reservationInfo2);
+  Resources r7 = createReservedResource("cpus", "8", reservation1);
+  Resources r8 = createReservedResource("cpus", "8", reservation2);
 
   EXPECT_FALSE((r2 - r1).empty());
   EXPECT_FALSE((r1 - r2).empty());
@@ -2091,9 +2124,11 @@ TEST(ReservedResourcesTest, Subtraction)
 
 TEST(ReservedResourcesTest, Contains)
 {
-  Resources r1 = createReservedResource("cpus", "8", "role", None());
+  Resources r1 =
+    createReservedResource("cpus", "8", createStaticReservationInfo("role"));
+
   Resources r2 = createReservedResource(
-      "cpus", "12", "role", createReservationInfo("principal"));
+      "cpus", "12", createDynamicReservationInfo("role", "principal"));
 
   EXPECT_TRUE(r1.contains(r1));
   EXPECT_TRUE(r2.contains(r2));
@@ -2399,15 +2434,15 @@ TEST(ResourcesOperationTest, ReserveResources)
 
   Resources unreserved = unreservedCpus + unreservedMem;
 
-  Resources reservedCpus1 =
-    unreservedCpus.flatten("role", createReservationInfo("principal")).get();
+  Resources reservedCpus1 = unreservedCpus.pushReservation(
+      createDynamicReservationInfo("role", "principal"));
 
   EXPECT_SOME_EQ(unreservedMem + reservedCpus1,
                  unreserved.apply(RESERVE(reservedCpus1)));
 
   // Check the case of insufficient unreserved resources.
   Resources reservedCpus2 = createReservedResource(
-      "cpus", "2", "role", createReservationInfo("principal"));
+      "cpus", "2", createDynamicReservationInfo("role", "principal"));
 
   EXPECT_ERROR(unreserved.apply(RESERVE(reservedCpus2)));
 }
@@ -2416,9 +2451,10 @@ TEST(ResourcesOperationTest, ReserveResources)
 TEST(ResourcesOperationTest, UnreserveResources)
 {
   Resources reservedCpus = createReservedResource(
-      "cpus", "1", "role", createReservationInfo("principal"));
+      "cpus", "1", createDynamicReservationInfo("role", "principal"));
+
   Resources reservedMem = createReservedResource(
-      "mem", "512", "role", createReservationInfo("principal"));
+      "mem", "512", createDynamicReservationInfo("role", "principal"));
 
   Resources reserved = reservedCpus + reservedMem;
 
@@ -2429,7 +2465,7 @@ TEST(ResourcesOperationTest, UnreserveResources)
 
   // Check the case of insufficient unreserved resources.
   Resource reservedCpus2 = createReservedResource(
-      "cpus", "2", "role", createReservationInfo("principal"));
+      "cpus", "2", createDynamicReservationInfo("role", "principal"));
 
   EXPECT_ERROR(reserved.apply(UNRESERVE(reservedCpus2)));
 }
@@ -2476,9 +2512,9 @@ TEST(ResourcesOperationTest, StrippedResourcesVolume)
 
   ASSERT_EQ(Value::SCALAR, strippedVolume.type());
   EXPECT_FLOAT_EQ(200, strippedVolume.scalar().value());
-  EXPECT_EQ("role", strippedVolume.role());
+  EXPECT_EQ("role", Resources::reservationRole(strippedVolume));
   EXPECT_EQ("disk", strippedVolume.name());
-  EXPECT_FALSE(strippedVolume.has_reservation());
+  EXPECT_EQ(1u, strippedVolume.reservations_size());
   EXPECT_FALSE(strippedVolume.has_disk());
   EXPECT_FALSE(Resources::isPersistentVolume(strippedVolume));
 }
@@ -2502,18 +2538,16 @@ TEST(ResourcesOperationTest, StrippedResourcesAllocated)
 TEST(ResourcesOperationTest, StrippedResourcesReserved)
 {
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      "role", createReservationInfo("principal")).get();
+  Resources dynamicallyReserved = unreserved.pushReservation(
+      createDynamicReservationInfo("role", "principal"));
 
   Resources stripped = dynamicallyReserved.createStrippedScalarQuantity();
 
-  // After being stripped, a dynamically reserved resource
-  // effectively becomes statically reserved.
   EXPECT_FALSE(stripped.reserved("role").empty());
 
   foreach (const Resource& resource, stripped) {
-    EXPECT_EQ("role", resource.role());
-    EXPECT_FALSE(resource.has_reservation());
+    EXPECT_EQ("role", Resources::reservationRole(resource));
+    EXPECT_FALSE(resource.reservations().empty());
     EXPECT_FALSE(Resources::isDynamicallyReserved(resource));
     EXPECT_FALSE(Resources::isUnreserved(resource));
   }
@@ -2632,11 +2666,8 @@ TEST(ResourcesOperationTest, FlattenResources)
 
   Resources unreserved = unreservedCpus + unreservedMem;
 
-  EXPECT_ERROR(unreserved.flatten("*", createReservationInfo("principal")));
-  EXPECT_ERROR(unreserved.flatten("-role"));
-
-  Resources reservedCpus =
-    unreservedCpus.flatten("role", createReservationInfo("principal")).get();
+  Resources reservedCpus = unreservedCpus.pushReservation(
+      createDynamicReservationInfo("role", "principal"));
 
   EXPECT_SOME_EQ(unreservedMem + reservedCpus,
                  unreserved.apply(RESERVE(reservedCpus)));
@@ -2934,14 +2965,18 @@ TEST(SharedResourcesTest, Printing)
     ostringstream oss;
 
     oss << volume;
-    EXPECT_EQ("disk(role1)[id1:path1]<SHARED>:64<1>", oss.str());
+    EXPECT_EQ(
+        "disk(reservations: [(STATIC,role1)])[id1:path1]<SHARED>:64<1>",
+        oss.str());
   }
 
   {
     ostringstream oss;
 
     oss << volume + volume;
-    EXPECT_EQ("disk(role1)[id1:path1]<SHARED>:64<2>", oss.str());
+    EXPECT_EQ(
+        "disk(reservations: [(STATIC,role1)])[id1:path1]<SHARED>:64<2>",
+        oss.str());
   }
 }
 
@@ -3266,16 +3301,15 @@ public:
     // occur when aggregating across agents in a cluster.
     ScalarArithmeticParameter reservations;
     for (int i = 0; i < 1000; ++i) {
-      Label label;
-      label.set_key("key_" + stringify(i));
-      label.set_value("value_" + stringify(i));
+      Labels labels;
 
-      Resource::ReservationInfo reservation;
-      reservation.set_principal("principal_" + stringify(i));
-      reservation.mutable_labels()->add_labels()->CopyFrom(label);
+      Label* label = labels.add_labels();
+      label->set_key("key_" + stringify(i));
+      label->set_value("value_" + stringify(i));
 
       reservations.resources +=
-        scalars.resources.flatten(stringify(i), reservation).get();
+        scalars.resources.pushReservation(createDynamicReservationInfo(
+            stringify(i), "principal_" + stringify(i), labels));
     }
     reservations.totalOperations = 10;
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/role_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/role_tests.cpp b/src/tests/role_tests.cpp
index 850dfa7..aeef9a7 100644
--- a/src/tests/role_tests.cpp
+++ b/src/tests/role_tests.cpp
@@ -127,9 +127,9 @@ TEST_F(RoleTest, ImplicitRoleRegister)
   filters.set_refuse_seconds(0);
 
   Resources unreserved = Resources::parse("disk:1024").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from `resourceOffers`.
   Future<vector<Offer>> offers;
@@ -955,22 +955,18 @@ TEST_F_TEMP_DISABLED_ON_WINDOWS(RoleTest, VolumesInOverlappingHierarchies)
 
     // Create a reserved disk. We only create a small disk so
     // we have remaining disk to offer to other frameworks.
-    Resource unreservedDisk = Resources::parse("disk", "1", "*").get();
-    Resource reservedDisk = unreservedDisk;
-    reservedDisk.set_role(role);
-    reservedDisk.mutable_reservation()->CopyFrom(
-        createReservationInfo(DEFAULT_CREDENTIAL.principal()));
+    Resource reservedDisk = createReservedResource(
+        "disk",
+        "1",
+        createDynamicReservationInfo(role, DEFAULT_CREDENTIAL.principal()));
 
     // Create a persistent volume on the reserved disk.
     Resource volume = createPersistentVolume(
-        createDiskResource(
-            stringify(DISK_SIZE.megabytes()), role, None(), None()),
+        reservedDisk,
         id,
         PATH,
-        None(),
+        DEFAULT_CREDENTIAL.principal(),
         frameworkInfo.principal());
-    volume.mutable_reservation()->CopyFrom(reservedDisk.reservation());
-    volume.set_role(reservedDisk.role());
 
     // Create a task which uses the volume and checks that
     // it contains no files leaked from another role.
@@ -1024,12 +1020,10 @@ TEST_F_TEMP_DISABLED_ON_WINDOWS(RoleTest, VolumesInOverlappingHierarchies)
         role,
         id,
         PATH,
-        None(),
+        DEFAULT_CREDENTIAL.principal(),
         None(),
         DEFAULT_CREDENTIAL.principal());
 
-    volume.mutable_reservation()->set_principal(DEFAULT_CREDENTIAL.principal());
-
     v1::master::Call destroyVolumesCall;
     destroyVolumesCall.set_type(v1::master::Call::DESTROY_VOLUMES);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/slave_recovery_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_recovery_tests.cpp b/src/tests/slave_recovery_tests.cpp
index 3850258..d60e40e 100644
--- a/src/tests/slave_recovery_tests.cpp
+++ b/src/tests/slave_recovery_tests.cpp
@@ -146,6 +146,10 @@ TEST_F(SlaveStateTest, CheckpointRepeatedProtobufMessages)
   Result<RepeatedPtrField<Resource>> actual =
     ::protobuf::read<RepeatedPtrField<Resource>>(file);
 
+  ASSERT_SOME(actual);
+
+  convertResourceFormat(&actual.get(), POST_RESERVATION_REFINEMENT);
+
   EXPECT_SOME_EQ(expected, actual);
 }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/slave_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_tests.cpp b/src/tests/slave_tests.cpp
index b3b24b6..8a69cc2 100644
--- a/src/tests/slave_tests.cpp
+++ b/src/tests/slave_tests.cpp
@@ -4703,9 +4703,8 @@ TEST_F(SlaveTest, CheckpointedResourcesIncludedInUsage)
   // Wait for slave to be initialized.
   Clock::settle();
 
-  Resource dynamicReservation = Resources::parse("cpus", "1", "role1").get();
-  dynamicReservation.mutable_reservation()->CopyFrom(
-      createReservationInfo("principal"));
+  Resource dynamicReservation = createReservedResource(
+      "cpus", "1", createDynamicReservationInfo("role1", "principal"));
 
   Resource persistentVolume = createPersistentVolume(
       Megabytes(64),

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/upgrade_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/upgrade_tests.cpp b/src/tests/upgrade_tests.cpp
index dfe77e7..eef8101 100644
--- a/src/tests/upgrade_tests.cpp
+++ b/src/tests/upgrade_tests.cpp
@@ -195,9 +195,12 @@ TEST_F(UpgradeTest, ReregisterOldAgentWithMultiRoleMaster)
   EXPECT_TRUE(capabilities.multiRole);
 
   // Strip allocation_info and MULTI_ROLE capability.
+  capabilities.multiRole = false;
+
   ReregisterSlaveMessage strippedReregisterSlaveMessage =
     reregisterSlaveMessage.get();
-  strippedReregisterSlaveMessage.clear_agent_capabilities();
+  strippedReregisterSlaveMessage.mutable_agent_capabilities()->CopyFrom(
+      capabilities.toRepeatedPtrField());
 
   foreach (ExecutorInfo& executorInfo,
            *strippedReregisterSlaveMessage.mutable_executor_infos()) {
@@ -308,9 +311,12 @@ TEST_F(UpgradeTest, UpgradeSlaveIntoMultiRole)
   EXPECT_TRUE(capabilities.multiRole);
 
   // Strip MULTI_ROLE capability.
+  capabilities.multiRole = false;
+
   RegisterSlaveMessage strippedRegisterSlaveMessage =
     registerSlaveMessage.get();
-  strippedRegisterSlaveMessage.clear_agent_capabilities();
+  strippedRegisterSlaveMessage.mutable_agent_capabilities()->CopyFrom(
+      capabilities.toRepeatedPtrField());
 
   // Prevent this from being dropped per the DROP_PROTOBUFS above.
   FUTURE_PROTOBUF(


[05/21] mesos git commit: Resources: Adjusted the utilities to the new resource format [5/20].

Posted by mp...@apache.org.
Resources: Adjusted the utilities to the new resource format [5/20].

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


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

Branch: refs/heads/master
Commit: 0bae26707645f515317b3860b22df822dd85e718
Parents: 9ac264b
Author: Michael Park <mp...@apache.org>
Authored: Sun Jun 18 22:04:29 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:30:25 2017 -0700

----------------------------------------------------------------------
 src/common/resources.cpp       | 25 ++++++++++++++++++++-----
 src/common/resources_utils.cpp | 10 ++++++++--
 src/v1/resources.cpp           | 25 ++++++++++++++++++++-----
 3 files changed, 48 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0bae2670/src/common/resources.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources.cpp b/src/common/resources.cpp
index 22bc24e..c088ee2 100644
--- a/src/common/resources.cpp
+++ b/src/common/resources.cpp
@@ -1510,7 +1510,18 @@ Resources Resources::createStrippedScalarQuantity() const
       Resource scalar = resource;
       scalar.clear_provider_id();
       scalar.clear_allocation_info();
-      scalar.clear_reservation();
+
+      // We collapse the stack of reservations here to a single `STATIC`
+      // reservation in order to maintain existing behavior of ignoring
+      // the reservation type, and keeping the reservation role.
+      if (Resources::isReserved(scalar)) {
+        Resource::ReservationInfo collapsedReservation;
+        collapsedReservation.set_type(Resource::ReservationInfo::STATIC);
+        collapsedReservation.set_role(Resources::reservationRole(scalar));
+        scalar.clear_reservations();
+        scalar.add_reservations()->CopyFrom(collapsedReservation);
+      }
+
       scalar.clear_disk();
       scalar.clear_shared();
       stripped.add(scalar);
@@ -1562,8 +1573,10 @@ Try<Resources> Resources::apply(const Offer::Operation& operation) const
       foreach (const Resource& reserved, operation.reserve().resources()) {
         if (!Resources::isReserved(reserved)) {
           return Error("Invalid RESERVE Operation: Resource must be reserved");
-        } else if (!reserved.has_reservation()) {
-          return Error("Invalid RESERVE Operation: Missing 'reservation'");
+        } else if (!Resources::isDynamicallyReserved(reserved)) {
+          return Error(
+              "Invalid RESERVE Operation: Resource must be"
+              " dynamically reserved");
         }
 
         Resources unreserved = Resources(reserved).flatten();
@@ -1588,8 +1601,10 @@ Try<Resources> Resources::apply(const Offer::Operation& operation) const
       foreach (const Resource& reserved, operation.unreserve().resources()) {
         if (!Resources::isReserved(reserved)) {
           return Error("Invalid UNRESERVE Operation: Resource is not reserved");
-        } else if (!reserved.has_reservation()) {
-          return Error("Invalid UNRESERVE Operation: Missing 'reservation'");
+        } else if (!Resources::isDynamicallyReserved(reserved)) {
+          return Error(
+              "Invalid UNRESERVE Operation: Resource is not"
+              " dynamically reserved");
         }
 
         if (!result.contains(reserved)) {

http://git-wip-us.apache.org/repos/asf/mesos/blob/0bae2670/src/common/resources_utils.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources_utils.cpp b/src/common/resources_utils.cpp
index 19c89bf..4671477 100644
--- a/src/common/resources_utils.cpp
+++ b/src/common/resources_utils.cpp
@@ -52,9 +52,15 @@ Try<Resources> applyCheckpointedResources(
 
     Resource stripped = resource;
 
+    // Since only unreserved and statically reserved resources can be specified
+    // on the agent, we strip away all of the dynamic reservations here to
+    // deduce the agent resources on which to apply the checkpointed resources.
     if (Resources::isDynamicallyReserved(resource)) {
-      stripped.set_role("*");
-      stripped.clear_reservation();
+      Resource::ReservationInfo reservation = stripped.reservations(0);
+      stripped.clear_reservations();
+      if (reservation.type() == Resource::ReservationInfo::STATIC) {
+        stripped.add_reservations()->CopyFrom(reservation);
+      }
     }
 
     // Strip persistence and volume from the disk info so that we can

http://git-wip-us.apache.org/repos/asf/mesos/blob/0bae2670/src/v1/resources.cpp
----------------------------------------------------------------------
diff --git a/src/v1/resources.cpp b/src/v1/resources.cpp
index d03577f..0fd8eac 100644
--- a/src/v1/resources.cpp
+++ b/src/v1/resources.cpp
@@ -1512,7 +1512,18 @@ Resources Resources::createStrippedScalarQuantity() const
       Resource scalar = resource;
       scalar.clear_provider_id();
       scalar.clear_allocation_info();
-      scalar.clear_reservation();
+
+      // We collapse the stack of reservations here to a single `STATIC`
+      // reservation in order to maintain existing behavior of ignoring
+      // the reservation type, and keeping the reservation role.
+      if (Resources::isReserved(scalar)) {
+        Resource::ReservationInfo collapsedReservation;
+        collapsedReservation.set_type(Resource::ReservationInfo::STATIC);
+        collapsedReservation.set_role(Resources::reservationRole(scalar));
+        scalar.clear_reservations();
+        scalar.add_reservations()->CopyFrom(collapsedReservation);
+      }
+
       scalar.clear_disk();
       scalar.clear_shared();
       stripped.add(scalar);
@@ -1564,8 +1575,10 @@ Try<Resources> Resources::apply(const Offer::Operation& operation) const
       foreach (const Resource& reserved, operation.reserve().resources()) {
         if (!Resources::isReserved(reserved)) {
           return Error("Invalid RESERVE Operation: Resource must be reserved");
-        } else if (!reserved.has_reservation()) {
-          return Error("Invalid RESERVE Operation: Missing 'reservation'");
+        } else if (!Resources::isDynamicallyReserved(reserved)) {
+          return Error(
+              "Invalid RESERVE Operation: Resource must be"
+              " dynamically reserved");
         }
 
         Resources unreserved = Resources(reserved).flatten();
@@ -1590,8 +1603,10 @@ Try<Resources> Resources::apply(const Offer::Operation& operation) const
       foreach (const Resource& reserved, operation.unreserve().resources()) {
         if (!Resources::isReserved(reserved)) {
           return Error("Invalid UNRESERVE Operation: Resource is not reserved");
-        } else if (!reserved.has_reservation()) {
-          return Error("Invalid UNRESERVE Operation: Missing 'reservation'");
+        } else if (!Resources::isDynamicallyReserved(reserved)) {
+          return Error(
+              "Invalid UNRESERVE Operation: Resource is not"
+              " dynamically reserved");
         }
 
         if (!result.contains(reserved)) {


[20/21] mesos git commit: Adjusted tests to the new resource format [19/20].

Posted by mp...@apache.org.
Adjusted tests to the new resource format [19/20].

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


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

Branch: refs/heads/master
Commit: c55f44fe1e19fbe850e62250883fcb7aac0d8057
Parents: ded150a
Author: Michael Park <mp...@apache.org>
Authored: Tue Jun 20 01:10:27 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:45:45 2017 -0700

----------------------------------------------------------------------
 src/examples/dynamic_reservation_framework.cpp  |  10 +-
 src/examples/test_framework.cpp                 |  14 +-
 src/examples/test_http_framework.cpp            |  14 +-
 src/tests/api_tests.cpp                         |  12 +-
 src/tests/default_executor_tests.cpp            |  18 +-
 src/tests/hierarchical_allocator_tests.cpp      |  24 +-
 src/tests/master_quota_tests.cpp                |  14 +-
 src/tests/master_validation_tests.cpp           | 161 +++++-----
 src/tests/persistent_volume_endpoints_tests.cpp | 192 ++++++------
 src/tests/persistent_volume_tests.cpp           |  14 +-
 src/tests/reservation_endpoints_tests.cpp       | 185 ++++++------
 src/tests/reservation_tests.cpp                 | 235 +++++----------
 src/tests/resources_tests.cpp                   | 298 +++++++++++--------
 src/tests/role_tests.cpp                        |  26 +-
 src/tests/slave_recovery_tests.cpp              |   4 +
 src/tests/slave_tests.cpp                       |   5 +-
 src/tests/upgrade_tests.cpp                     |  10 +-
 17 files changed, 629 insertions(+), 607 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/examples/dynamic_reservation_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/dynamic_reservation_framework.cpp b/src/examples/dynamic_reservation_framework.cpp
index 14b9c40..f3b1c8c 100644
--- a/src/examples/dynamic_reservation_framework.cpp
+++ b/src/examples/dynamic_reservation_framework.cpp
@@ -60,18 +60,18 @@ public:
       totalTasks(5),
       principal(_principal)
   {
-    reservationInfo.set_principal(principal);
-
     taskResources = Resources::parse(
         "cpus:" + stringify(CPUS_PER_TASK) +
         ";mem:" + stringify(MEM_PER_TASK)).get();
 
     taskResources.allocate(role);
 
+    reservationInfo.set_type(Resource::ReservationInfo::DYNAMIC);
+    reservationInfo.set_role(role);
+    reservationInfo.set_principal(principal);
+
     // The task will run on reserved resources.
-    Try<Resources> flattened = taskResources.flatten(role, reservationInfo);
-    CHECK_SOME(flattened);
-    taskResources = flattened.get();
+    taskResources = taskResources.pushReservation(reservationInfo);
   }
 
   virtual ~DynamicReservationScheduler() {}

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/examples/test_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/test_framework.cpp b/src/examples/test_framework.cpp
index 53edc6a..9dbc18b 100644
--- a/src/examples/test_framework.cpp
+++ b/src/examples/test_framework.cpp
@@ -107,9 +107,17 @@ public:
         task.mutable_slave_id()->MergeFrom(offer.slave_id());
         task.mutable_executor()->MergeFrom(executor);
 
-        Try<Resources> flattened = taskResources.flatten(role);
-        CHECK_SOME(flattened);
-        Option<Resources> resources = remaining.find(flattened.get());
+        Option<Resources> resources = [&]() {
+          if (role == "*") {
+            return remaining.find(taskResources);
+          }
+
+          Resource::ReservationInfo reservation;
+          reservation.set_type(Resource::ReservationInfo::STATIC);
+          reservation.set_role(role);
+
+          return remaining.find(taskResources.pushReservation(reservation));
+        }();
 
         CHECK_SOME(resources);
         task.mutable_resources()->MergeFrom(resources.get());

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/examples/test_http_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/test_http_framework.cpp b/src/examples/test_http_framework.cpp
index ce1a92c..a0cd84a 100644
--- a/src/examples/test_http_framework.cpp
+++ b/src/examples/test_http_framework.cpp
@@ -245,9 +245,17 @@ private:
         task.mutable_agent_id()->MergeFrom(offer.agent_id());
         task.mutable_executor()->MergeFrom(executor);
 
-        Try<Resources> flattened = taskResources.flatten(framework.role());
-        CHECK_SOME(flattened);
-        Option<Resources> resources = remaining.find(flattened.get());
+        Option<Resources> resources = [&]() {
+          if (framework.role() == "*") {
+            return remaining.find(taskResources);
+          } else {
+            Resource::ReservationInfo reservation;
+            reservation.set_type(Resource::ReservationInfo::STATIC);
+            reservation.set_role(framework.role());
+
+            return remaining.find(taskResources.pushReservation(reservation));
+          }
+        }();
 
         CHECK_SOME(resources);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/api_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/api_tests.cpp b/src/tests/api_tests.cpp
index c40f5cc..cdaa724 100644
--- a/src/tests/api_tests.cpp
+++ b/src/tests/api_tests.cpp
@@ -977,9 +977,9 @@ TEST_P(MasterAPITest, ReserveResources)
   frameworkInfo.set_role("role");
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   MockScheduler sched;
   MesosSchedulerDriver driver(
@@ -1069,9 +1069,9 @@ TEST_P(MasterAPITest, UnreserveResources)
   frameworkInfo.set_role("role");
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   v1::master::Call v1Call;
   v1Call.set_type(v1::master::Call::RESERVE_RESOURCES);

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/default_executor_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/default_executor_tests.cpp b/src/tests/default_executor_tests.cpp
index a76ece5..b977631 100644
--- a/src/tests/default_executor_tests.cpp
+++ b/src/tests/default_executor_tests.cpp
@@ -1318,9 +1318,9 @@ TEST_P(DefaultExecutorTest, ReservedResources)
     v1::Resources::parse("cpus:0.1;mem:32;disk:32").get();
 
   // Launch the executor using reserved resources.
-  v1::Resources reserved = unreserved.flatten(
-      frameworkInfo.role(),
-      v1::createReservationInfo(frameworkInfo.principal())).get();
+  v1::Resources reserved =
+    unreserved.pushReservation(v1::createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   v1::ExecutorInfo executorInfo;
   executorInfo.set_type(v1::ExecutorInfo::DEFAULT);
@@ -1472,9 +1472,9 @@ TEST_P_TEMP_DISABLED_ON_WINDOWS(
   v1::Resources unreserved =
     v1::Resources::parse("cpus:0.1;mem:32;disk:32").get();
 
-  v1::Resources reserved = unreserved.flatten(
-      frameworkInfo.role(),
-      v1::createReservationInfo(frameworkInfo.principal())).get();
+  v1::Resources reserved =
+    unreserved.pushReservation(v1::createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   v1::Resource volume = v1::createPersistentVolume(
       Megabytes(1),
@@ -1638,9 +1638,9 @@ TEST_P_TEMP_DISABLED_ON_WINDOWS(
       None(),
       frameworkInfo.principal());
 
-  v1::Resources reserved = unreserved.flatten(
-      frameworkInfo.role(),
-      v1::createReservationInfo(frameworkInfo.principal())).get();
+  v1::Resources reserved =
+    unreserved.pushReservation(v1::createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   // Launch a task that expects the persistent volume to be
   // mounted in its sandbox.

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/hierarchical_allocator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/hierarchical_allocator_tests.cpp b/src/tests/hierarchical_allocator_tests.cpp
index d6c5904..801bd12 100644
--- a/src/tests/hierarchical_allocator_tests.cpp
+++ b/src/tests/hierarchical_allocator_tests.cpp
@@ -1776,7 +1776,7 @@ TEST_F(HierarchicalAllocatorTest, UpdateAvailableSuccess)
   // Construct an offer operation for the framework's allocation.
   Resources unreserved = Resources::parse("cpus:25;mem:50").get();
   Resources dynamicallyReserved =
-    unreserved.flatten("role1", createReservationInfo("ops")).get();
+    unreserved.pushReservation(createDynamicReservationInfo("role1", "ops"));
 
   Offer::Operation reserve = RESERVE(dynamicallyReserved);
 
@@ -1829,7 +1829,7 @@ TEST_F(HierarchicalAllocatorTest, UpdateAvailableFail)
   // Construct an offer operation for the framework's allocation.
   Resources unreserved = Resources::parse("cpus:25;mem:50").get();
   Resources dynamicallyReserved =
-    unreserved.flatten("role1", createReservationInfo("ops")).get();
+    unreserved.pushReservation(createDynamicReservationInfo("role1", "ops"));
 
   Offer::Operation reserve = RESERVE(dynamicallyReserved);
 
@@ -3215,8 +3215,8 @@ TEST_F(HierarchicalAllocatorTest, QuotaSetAsideReservedResources)
 
   // Reserve 4 CPUs and 512MB of memory on `agent2` for non-quota'ed role.
   Resources unreserved = Resources::parse("cpus:4;mem:512").get();
-  Resources dynamicallyReserved =
-    unreserved.flatten(NO_QUOTA_ROLE, createReservationInfo("ops")).get();
+  Resources dynamicallyReserved = unreserved.pushReservation(
+      createDynamicReservationInfo(NO_QUOTA_ROLE, "ops"));
 
   Offer::Operation reserve = RESERVE(dynamicallyReserved);
 
@@ -5341,14 +5341,18 @@ TEST_P(HierarchicalAllocator_BENCHMARK_Test, ResourceLabels)
     labels1.add_labels()->CopyFrom(
         createLabel("unique_key_2", "value_" + stringify(i)));
 
-    Resources reserved1 =
-      createReservedResource("cpus", "8", "role1",
-                             createReservationInfo("principal1", labels1));
+    Resources reserved1 = createReservedResource(
+        "cpus",
+        "8",
+        createDynamicReservationInfo("role1", "principal1", labels1));
+
     reserved1.allocate("role1");
 
-    Resources reserved2 =
-      createReservedResource("cpus", "8", "role1",
-                             createReservationInfo("principal1", labels2));
+    Resources reserved2 = createReservedResource(
+        "cpus",
+        "8",
+        createDynamicReservationInfo("role1", "principal1", labels2));
+
     reserved2.allocate("role1");
 
     Resources _allocation = allocation + reserved1 + reserved2;

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/master_quota_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_quota_tests.cpp b/src/tests/master_quota_tests.cpp
index 6ca4570..bbdbfbe 100644
--- a/src/tests/master_quota_tests.cpp
+++ b/src/tests/master_quota_tests.cpp
@@ -35,6 +35,8 @@
 #include <stout/stringify.hpp>
 #include <stout/strings.hpp>
 
+#include "common/resources_utils.hpp"
+
 #include "master/flags.hpp"
 #include "master/master.hpp"
 
@@ -347,9 +349,10 @@ TEST_F(MasterQuotaTest, SetRequestWithInvalidData)
   {
     Resources quotaResources = Resources::parse("cpus:4;mem:512").get();
 
-    Resource reserved = Resources::parse("disk", "128", ROLE1).get();
-    reserved.mutable_reservation()->CopyFrom(
-        createReservationInfo(DEFAULT_CREDENTIAL.principal()));
+    Resource reserved = createReservedResource(
+        "disk",
+        "128",
+        createDynamicReservationInfo(ROLE1, DEFAULT_CREDENTIAL.principal()));
 
     quotaResources += reserved;
 
@@ -545,8 +548,11 @@ TEST_F(MasterQuotaTest, Status)
     const Try<QuotaStatus> status = ::protobuf::parse<QuotaStatus>(parse.get());
     ASSERT_FALSE(status.isError());
 
+    RepeatedPtrField<Resource> guarantee = status->infos(0).guarantee();
+    convertResourceFormat(&guarantee, POST_RESERVATION_REFINEMENT);
+
     ASSERT_EQ(1, status->infos().size());
-    EXPECT_EQ(quotaResources, status->infos(0).guarantee());
+    EXPECT_EQ(quotaResources, guarantee);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/master_validation_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_validation_tests.cpp b/src/tests/master_validation_tests.cpp
index e392ce4..9f3857b 100644
--- a/src/tests/master_validation_tests.cpp
+++ b/src/tests/master_validation_tests.cpp
@@ -104,8 +104,9 @@ TEST_F(ResourceValidationTest, StaticReservation)
 
 TEST_F(ResourceValidationTest, DynamicReservation)
 {
-  Resource resource = Resources::parse("cpus", "8", "role").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  Resource resource = Resources::parse("cpus", "8", "*").get();
+  resource.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role", "principal"));
 
   Option<Error> error = resource::validate(CreateResources(resource));
 
@@ -115,8 +116,9 @@ TEST_F(ResourceValidationTest, DynamicReservation)
 
 TEST_F(ResourceValidationTest, RevocableDynamicReservation)
 {
-  Resource resource = Resources::parse("cpus", "8", "role").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  Resource resource = Resources::parse("cpus", "8", "*").get();
+  resource.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role", "principal"));
   resource.mutable_revocable();
 
   Option<Error> error = resource::validate(CreateResources(resource));
@@ -128,19 +130,6 @@ TEST_F(ResourceValidationTest, RevocableDynamicReservation)
 }
 
 
-TEST_F(ResourceValidationTest, InvalidRoleReservationPair)
-{
-  Resource resource = Resources::parse("cpus", "8", "*").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
-
-  Option<Error> error = resource::validate(CreateResources(resource));
-
-  ASSERT_SOME(error);
-  EXPECT_TRUE(
-      strings::contains(error->message, "cannot be dynamically reserved"));
-}
-
-
 TEST_F(ResourceValidationTest, PersistentVolume)
 {
   Resource volume = Resources::parse("disk", "128", "role1").get();
@@ -278,15 +267,18 @@ TEST_F(ReserveOperationValidationTest, MatchingRole)
 {
   protobuf::slave::Capabilities capabilities;
 
-  Resource resource = Resources::parse("cpus", "8", "resourceRole").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  Resource resource = Resources::parse("cpus", "8", "*").get();
+  resource.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("resourceRole", "principal"));
 
   Offer::Operation::Reserve reserve;
   reserve.mutable_resources()->CopyFrom(
-      allocatedResources(resource, resource.role()));
+      allocatedResources(resource, Resources::reservationRole(resource)));
 
   FrameworkInfo frameworkInfo;
   frameworkInfo.set_role("frameworkRole");
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   Option<Error> error =
     operation::validate(reserve, "principal", capabilities, frameworkInfo);
@@ -305,6 +297,8 @@ TEST_F(ReserveOperationValidationTest, MatchingRole)
   frameworkInfo.add_roles("role2");
   frameworkInfo.add_capabilities()->set_type(
       FrameworkInfo::Capability::MULTI_ROLE);
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   error =
     operation::validate(reserve, "principal", capabilities, frameworkInfo);
@@ -329,24 +323,23 @@ TEST_F(ReserveOperationValidationTest, DisallowReservingToStar)
   // The role "*" matches, but is invalid since frameworks with
   // "*" role cannot reserve resources.
   Resource resource = Resources::parse("cpus", "8", "*").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  resource.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("*", "principal"));
 
   Offer::Operation::Reserve reserve;
   reserve.add_resources()->CopyFrom(resource);
 
   FrameworkInfo frameworkInfo;
   frameworkInfo.set_role("*");
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   Option<Error> error =
     operation::validate(reserve, "principal", capabilities, frameworkInfo);
 
   ASSERT_SOME(error);
-  EXPECT_TRUE(
-      strings::contains(
-          error->message,
-          "Invalid resources: Invalid resources: Resource 'cpus(*, "
-          "principal):8' is invalid: Invalid reservation: role \"*\" cannot be "
-          "dynamically reserved"));
+  EXPECT_TRUE(strings::contains(
+      error->message, "Invalid reservation: role \"*\" cannot be reserved"));
 
   // Now verify with a MULTI_ROLE framework.
   frameworkInfo.clear_role();
@@ -359,11 +352,8 @@ TEST_F(ReserveOperationValidationTest, DisallowReservingToStar)
     operation::validate(reserve, "principal", capabilities, frameworkInfo);
 
   ASSERT_SOME(error);
-  EXPECT_TRUE(
-      strings::contains(
-          error->message,
-          "Resource 'cpus(*, principal):8' is invalid: Invalid reservation: "
-          "role \"*\" cannot be dynamically reserved"));
+  EXPECT_TRUE(strings::contains(
+      error->message, "Invalid reservation: role \"*\" cannot be reserved"));
 }
 
 
@@ -373,15 +363,18 @@ TEST_F(ReserveOperationValidationTest, MatchingPrincipal)
 {
   protobuf::slave::Capabilities capabilities;
 
-  Resource resource = Resources::parse("cpus", "8", "role").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  Resource resource = Resources::parse("cpus", "8", "*").get();
+  resource.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role", "principal"));
 
   Offer::Operation::Reserve reserve;
   reserve.mutable_resources()->CopyFrom(
-      allocatedResources(resource, resource.role()));
+      allocatedResources(resource, Resources::reservationRole(resource)));
 
   FrameworkInfo frameworkInfo;
   frameworkInfo.set_role("role");
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   Option<Error> error =
     operation::validate(reserve, "principal", capabilities, frameworkInfo);
@@ -397,25 +390,27 @@ TEST_F(ReserveOperationValidationTest, NonMatchingPrincipal)
 {
   protobuf::slave::Capabilities capabilities;
 
-  Resource resource = Resources::parse("cpus", "8", "role").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo("principal2"));
+  Resource resource = Resources::parse("cpus", "8", "*").get();
+  resource.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role", "principal2"));
 
   Offer::Operation::Reserve reserve;
   reserve.add_resources()->CopyFrom(resource);
 
   FrameworkInfo frameworkInfo;
   frameworkInfo.set_role("role");
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   Option<Error> error =
     operation::validate(reserve, "principal1", capabilities, frameworkInfo);
 
   ASSERT_SOME(error);
-  EXPECT_TRUE(
-      strings::contains(
-          error->message,
-          "A reserve operation was attempted by authenticated principal "
-          "'principal1', which does not match a reserved resource in the "
-          "request with principal 'principal2'"));
+  EXPECT_TRUE(strings::contains(
+      error->message,
+      "A reserve operation was attempted by authenticated principal "
+      "'principal1', which does not match a reserved resource in the "
+      "request with principal 'principal2'"));
 }
 
 
@@ -426,25 +421,28 @@ TEST_F(ReserveOperationValidationTest, ReservationInfoMissingPrincipal)
   protobuf::slave::Capabilities capabilities;
 
   Resource::ReservationInfo reservationInfo;
+  reservationInfo.set_type(Resource::ReservationInfo::DYNAMIC);
+  reservationInfo.set_role("role");
 
-  Resource resource = Resources::parse("cpus", "8", "role").get();
-  resource.mutable_reservation()->CopyFrom(reservationInfo);
+  Resource resource = Resources::parse("cpus", "8", "*").get();
+  resource.add_reservations()->CopyFrom(reservationInfo);
 
   Offer::Operation::Reserve reserve;
   reserve.add_resources()->CopyFrom(resource);
 
   FrameworkInfo frameworkInfo;
   frameworkInfo.set_role("role");
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   Option<Error> error =
     operation::validate(reserve, "principal", capabilities, frameworkInfo);
 
   ASSERT_SOME(error);
-  EXPECT_TRUE(
-      strings::contains(
-          error->message,
-          "A reserve operation was attempted by principal 'principal', but "
-          "there is a reserved resource in the request with no principal set"));
+  EXPECT_TRUE(strings::contains(
+      error->message,
+      "A reserve operation was attempted by principal 'principal', but "
+      "there is a reserved resource in the request with no principal set"));
 }
 
 
@@ -461,6 +459,8 @@ TEST_F(ReserveOperationValidationTest, StaticReservation)
 
   FrameworkInfo frameworkInfo;
   frameworkInfo.set_role("role");
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   Option<Error> error =
     operation::validate(reserve, "principal", capabilities, frameworkInfo);
@@ -476,8 +476,9 @@ TEST_F(ReserveOperationValidationTest, NoPersistentVolumes)
 {
   protobuf::slave::Capabilities capabilities;
 
-  Resource reserved = Resources::parse("cpus", "8", "role").get();
-  reserved.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  Resource reserved = Resources::parse("cpus", "8", "*").get();
+  reserved.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role", "principal"));
 
   Resource volume = Resources::parse("disk", "128", "role").get();
   volume.mutable_disk()->CopyFrom(createDiskInfo("id1", "path1"));
@@ -485,13 +486,15 @@ TEST_F(ReserveOperationValidationTest, NoPersistentVolumes)
   Offer::Operation::Reserve reserve;
 
   reserve.mutable_resources()->CopyFrom(
-      allocatedResources(reserved, reserved.role()));
+      allocatedResources(reserved, Resources::reservationRole(reserved)));
 
   reserve.mutable_resources()->MergeFrom(
-      allocatedResources(volume, volume.role()));
+      allocatedResources(volume, Resources::reservationRole(volume)));
 
   FrameworkInfo frameworkInfo;
   frameworkInfo.set_role("role");
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   Option<Error> error =
     operation::validate(reserve, "principal", capabilities, frameworkInfo);
@@ -507,8 +510,9 @@ TEST_F(ReserveOperationValidationTest, MismatchedAllocation)
 {
   protobuf::slave::Capabilities capabilities;
 
-  Resource resource = Resources::parse("cpus", "8", "role1").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  Resource resource = Resources::parse("cpus", "8", "*").get();
+  resource.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role1", "principal"));
 
   Offer::Operation::Reserve reserve;
   reserve.mutable_resources()->CopyFrom(
@@ -519,6 +523,8 @@ TEST_F(ReserveOperationValidationTest, MismatchedAllocation)
   frameworkInfo.add_roles("role2");
   frameworkInfo.add_capabilities()->set_type(
       FrameworkInfo::Capability::MULTI_ROLE);
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   Option<Error> error =
     operation::validate(reserve, "principal", capabilities, frameworkInfo);
@@ -538,8 +544,9 @@ TEST_F(ReserveOperationValidationTest, UnexpectedAllocatedResource)
 {
   protobuf::slave::Capabilities capabilities;
 
-  Resource resource = Resources::parse("cpus", "8", "role").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  Resource resource = Resources::parse("cpus", "8", "*").get();
+  resource.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role", "principal"));
 
   Offer::Operation::Reserve reserve;
   reserve.mutable_resources()->CopyFrom(allocatedResources(resource, "role"));
@@ -562,10 +569,12 @@ TEST_F(ReserveOperationValidationTest, MixedAllocationRoles)
 {
   protobuf::slave::Capabilities capabilities;
 
-  Resource resource1 = Resources::parse("cpus", "8", "role1").get();
-  resource1.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
-  Resource resource2 = Resources::parse("mem", "8", "role2").get();
-  resource2.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  Resource resource1 = Resources::parse("cpus", "8", "*").get();
+  resource1.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role1", "principal"));
+  Resource resource2 = Resources::parse("mem", "8", "*").get();
+  resource2.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role2", "principal"));
 
   Offer::Operation::Reserve reserve;
   reserve.mutable_resources()->CopyFrom(
@@ -577,6 +586,8 @@ TEST_F(ReserveOperationValidationTest, MixedAllocationRoles)
   frameworkInfo.add_roles("role2");
   frameworkInfo.add_capabilities()->set_type(
       FrameworkInfo::Capability::MULTI_ROLE);
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   Option<Error> error =
     operation::validate(reserve, "principal", capabilities, frameworkInfo);
@@ -593,15 +604,18 @@ TEST_F(ReserveOperationValidationTest, MixedAllocationRoles)
 
 TEST_F(ReserveOperationValidationTest, AgentHierarchicalRoleCapability)
 {
-  Resource resource = Resources::parse("cpus", "8", "foo/bar").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  Resource resource = Resources::parse("cpus", "8", "*").get();
+  resource.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("foo/bar", "principal"));
 
   Offer::Operation::Reserve reserve;
   reserve.mutable_resources()->CopyFrom(
-      allocatedResources(resource, resource.role()));
+      allocatedResources(resource, Resources::reservationRole(resource)));
 
   FrameworkInfo frameworkInfo;
   frameworkInfo.set_role("foo/bar");
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   {
     protobuf::slave::Capabilities capabilities;
@@ -636,8 +650,9 @@ class UnreserveOperationValidationTest : public MesosTest {};
 // `principal`.
 TEST_F(UnreserveOperationValidationTest, WithoutACL)
 {
-  Resource resource = Resources::parse("cpus", "8", "role").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  Resource resource = Resources::parse("cpus", "8", "*").get();
+  resource.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role", "principal"));
 
   Offer::Operation::Unreserve unreserve;
   unreserve.add_resources()->CopyFrom(resource);
@@ -652,8 +667,9 @@ TEST_F(UnreserveOperationValidationTest, WithoutACL)
 // `principal` is not set.
 TEST_F(UnreserveOperationValidationTest, FrameworkMissingPrincipal)
 {
-  Resource resource = Resources::parse("cpus", "8", "role").get();
-  resource.mutable_reservation()->CopyFrom(createReservationInfo());
+  Resource resource = Resources::parse("cpus", "8", "*").get();
+  resource.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role"));
 
   Offer::Operation::Unreserve unreserve;
   unreserve.add_resources()->CopyFrom(resource);
@@ -683,8 +699,9 @@ TEST_F(UnreserveOperationValidationTest, StaticReservation)
 // volumes specified in the resources of the UNRESERVE operation.
 TEST_F(UnreserveOperationValidationTest, NoPersistentVolumes)
 {
-  Resource reserved = Resources::parse("cpus", "8", "role").get();
-  reserved.mutable_reservation()->CopyFrom(createReservationInfo("principal"));
+  Resource reserved = Resources::parse("cpus", "8", "*").get();
+  reserved.add_reservations()->CopyFrom(
+      createDynamicReservationInfo("role", "principal"));
 
   Resource volume = Resources::parse("disk", "128", "role").get();
   volume.mutable_disk()->CopyFrom(createDiskInfo("id1", "path1"));
@@ -961,6 +978,8 @@ TEST_F(CreateOperationValidationTest, MixedAllocationRole)
   frameworkInfo.add_roles("role2");
   frameworkInfo.add_capabilities()->set_type(
       FrameworkInfo::Capability::MULTI_ROLE);
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   Option<Error> error = operation::validate(
       create, Resources(), None(), capabilities, frameworkInfo);

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/persistent_volume_endpoints_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/persistent_volume_endpoints_tests.cpp b/src/tests/persistent_volume_endpoints_tests.cpp
index 0cb969c..d627569 100644
--- a/src/tests/persistent_volume_endpoints_tests.cpp
+++ b/src/tests/persistent_volume_endpoints_tests.cpp
@@ -221,9 +221,9 @@ TEST_F(PersistentVolumeEndpointsTest, DynamicReservation)
   FrameworkInfo frameworkInfo = createFrameworkInfo();
 
   Resources unreserved = Resources::parse("disk:1024").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   Future<Response> response = process::http::post(
       master.get()->pid,
@@ -254,8 +254,9 @@ TEST_F(PersistentVolumeEndpointsTest, DynamicReservation)
   ASSERT_EQ(1u, offers->size());
   Offer offer = offers.get()[0];
 
-  EXPECT_TRUE(Resources(offer.resources()).contains(
-      allocatedResources(dynamicallyReserved, frameworkInfo.role())));
+  EXPECT_TRUE(Resources(offer.resources())
+                .contains(allocatedResources(
+                    dynamicallyReserved, frameworkInfo.role())));
 
   Future<OfferID> rescindedOfferId;
 
@@ -340,9 +341,9 @@ TEST_F(PersistentVolumeEndpointsTest, DynamicReservationRoleMismatch)
   FrameworkInfo frameworkInfo = createFrameworkInfo();
 
   Resources unreserved = Resources::parse("disk:1024").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   Future<Response> response = process::http::post(
       master.get()->pid,
@@ -419,9 +420,9 @@ TEST_F(PersistentVolumeEndpointsTest, UnreserveVolumeResources)
   FrameworkInfo frameworkInfo = createFrameworkInfo();
 
   Resources unreserved = Resources::parse("disk:1024").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   Future<Response> response = process::http::post(
       master.get()->pid,
@@ -478,11 +479,12 @@ TEST_F(PersistentVolumeEndpointsTest, InvalidVolume)
   AWAIT_READY(slaveRegisteredMessage);
   const SlaveID& slaveId = slaveRegisteredMessage->slave_id();
 
-  // This volume has role "*", which is not allowed.
-  Try<Resource> disk = Resources::parse("disk", "64", "*");
-  ASSERT_SOME(disk);
+  // This volume is reserved for role "*", which is not allowed.
+  Resource disk = Resources::parse("disk", "64", "*").get();
+  disk.add_reservations()->CopyFrom(createDynamicReservationInfo("*"));
+
   Resource volume = createPersistentVolume(
-      disk.get(),
+      disk,
       "id1",
       "path1",
       DEFAULT_CREDENTIAL.principal(),
@@ -504,8 +506,9 @@ TEST_F(PersistentVolumeEndpointsTest, InvalidVolume)
         body);
 
     AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response);
-    ASSERT_EQ(response->body,
-             "Invalid reservation: role \"*\" cannot be dynamically reserved");
+    ASSERT_EQ(
+        response->body,
+        "Invalid reservation: role \"*\" cannot be reserved");
   }
 
   {
@@ -516,8 +519,9 @@ TEST_F(PersistentVolumeEndpointsTest, InvalidVolume)
         body);
 
     AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response);
-    ASSERT_EQ(response->body,
-             "Invalid reservation: role \"*\" cannot be dynamically reserved");
+    ASSERT_EQ(
+        response->body,
+        "Invalid reservation: role \"*\" cannot be reserved");
   }
 }
 
@@ -1521,9 +1525,9 @@ TEST_F(PersistentVolumeEndpointsTest, OfferCreateThenEndpointRemove)
 
   // Make a dynamic reservation for 512MB of disk.
   Resources unreserved = Resources::parse("disk:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   EXPECT_CALL(sched, registered(_, _, _));
 
@@ -1672,9 +1676,9 @@ TEST_F(PersistentVolumeEndpointsTest, EndpointCreateThenOfferRemove)
 
   // Make a dynamic reservation for 512MB of disk.
   Resources unreserved = Resources::parse("disk:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   Future<Response> response = process::http::post(
       master.get()->pid,
@@ -1743,8 +1747,11 @@ TEST_F(PersistentVolumeEndpointsTest, EndpointCreateThenOfferRemove)
   ASSERT_EQ(1u, offers->size());
   offer = offers.get()[0];
 
-  EXPECT_TRUE(Resources(offer.resources()).contains(
-      allocatedResources(dynamicallyReserved, frameworkInfo.role())));
+  EXPECT_TRUE(Resources(offer.resources())
+                .contains(allocatedResources(
+                    dynamicallyReserved, frameworkInfo.role())))
+    << Resources(offer.resources()) << " vs "
+    << allocatedResources(dynamicallyReserved, frameworkInfo.role());
 
   EXPECT_CALL(sched, resourceOffers(&driver, _))
     .WillOnce(FutureArg<1>(&offers));
@@ -1803,9 +1810,9 @@ TEST_F(PersistentVolumeEndpointsTest, ReserveAndSlaveRemoval)
 
   // Reserve all CPUs on `slave1` via HTTP endpoint.
   Resources slave1Unreserved = Resources::parse("cpus:4").get();
-  Resources slave1Reserved = slave1Unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources slave1Reserved =
+    slave1Unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   Future<Response> response = process::http::post(
       master.get()->pid,
@@ -1840,9 +1847,9 @@ TEST_F(PersistentVolumeEndpointsTest, ReserveAndSlaveRemoval)
 
   // Use the offers API to reserve all CPUs on `slave2`.
   Resources slave2Unreserved = Resources::parse("cpus:3").get();
-  Resources slave2Reserved = slave2Unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources slave2Reserved =
+    slave2Unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   for (size_t i = 0; i < offers->size(); i++) {
     const Offer& offer = offers.get()[i];
@@ -1908,9 +1915,9 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
   FrameworkInfo frameworkInfo = createFrameworkInfo();
 
   Resources unreserved = Resources::parse("cpus:1;mem:512;disk:1024").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   Future<Response> response = process::http::post(
       master.get()->pid,
@@ -1961,9 +1968,9 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
       allocatedResources(volume, frameworkInfo.role())));
 
   Resources taskUnreserved = Resources::parse("cpus:1;mem:256").get();
-  Resources taskResources = taskUnreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources taskResources =
+    taskUnreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   TaskInfo taskInfo = createTask(offer.slave_id(), taskResources, "sleep 1000");
 
@@ -2023,10 +2030,13 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             "scalar": {
               "value": 1.0
             },
-            "role": "role1",
-            "reservation": {
-              "principal": "test-principal"
-            }
+            "reservations":[
+              {
+                "principal": "test-principal",
+                "role": "role1",
+                "type": "DYNAMIC"
+              }
+            ]
           },
           {
             "name": "mem",
@@ -2034,10 +2044,13 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             "scalar": {
               "value": 512.0
             },
-            "role": "role1",
-            "reservation": {
-              "principal": "test-principal"
-            }
+            "reservations": [
+              {
+                "principal": "test-principal",
+                "role": "role1",
+                "type": "DYNAMIC"
+              }
+            ]
           },
           {
             "name": "disk",
@@ -2045,10 +2058,13 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             "scalar": {
               "value": 960.0
             },
-            "role": "role1",
-            "reservation": {
-              "principal": "test-principal"
-            }
+            "reservations": [
+              {
+                "principal": "test-principal",
+                "role": "role1",
+                "type": "DYNAMIC"
+              }
+            ]
           },
           {
             "name": "disk",
@@ -2056,10 +2072,13 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             "scalar": {
               "value": 64.0
             },
-            "role": "role1",
-            "reservation": {
-              "principal": "test-principal"
-            },
+            "reservations": [
+              {
+                "principal": "test-principal",
+                "role": "role1",
+                "type": "DYNAMIC"
+              }
+            ],
             "disk": {
               "persistence": {
                 "id": "id1",
@@ -2081,7 +2100,6 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
       [
         {
           "name": "cpus",
-          "role": "*",
           "scalar": {
             "value": 3.0
           },
@@ -2089,7 +2107,6 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
         },
         {
           "name": "mem",
-          "role": "*",
           "scalar": {
             "value": 1536.0
           },
@@ -2097,7 +2114,6 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
         },
         {
           "name": "disk",
-          "role": "*",
           "scalar": {
             "value": 3072.0
           },
@@ -2113,7 +2129,6 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
               }
             ]
           },
-          "role": "*",
           "type": "RANGES"
         }
       ])~");
@@ -2128,10 +2143,13 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             "role": "role1"
           },
           "name": "cpus",
-          "reservation": {
-            "principal": "test-principal"
-          },
-          "role": "role1",
+          "reservations": [
+            {
+              "principal": "test-principal",
+              "role": "role1",
+              "type": "DYNAMIC"
+            }
+          ],
           "scalar": {
             "value": 1.0
           },
@@ -2142,10 +2160,13 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             "role": "role1"
           },
           "name": "mem",
-          "reservation": {
-            "principal": "test-principal"
-          },
-          "role": "role1",
+          "reservations": [
+            {
+              "principal": "test-principal",
+              "role": "role1",
+              "type": "DYNAMIC"
+            }
+          ],
           "scalar": {
             "value": 256.0
           },
@@ -2163,7 +2184,6 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             "role": "role1"
           },
           "name": "cpus",
-          "role": "*",
           "scalar": {
             "value": 3.0
           },
@@ -2174,7 +2194,6 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             "role": "role1"
           },
           "name": "mem",
-          "role": "*",
           "scalar": {
             "value": 1536.0
           },
@@ -2185,7 +2204,6 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             "role": "role1"
           },
           "name": "disk",
-          "role": "*",
           "scalar": {
             "value": 3072.0
           },
@@ -2204,7 +2222,6 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
               }
             ]
           },
-          "role": "*",
           "type": "RANGES"
         },
         {
@@ -2222,10 +2239,13 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             }
           },
           "name": "disk",
-          "reservation": {
-            "principal": "test-principal"
-          },
-          "role": "role1",
+          "reservations": [
+            {
+              "principal": "test-principal",
+              "role": "role1",
+              "type": "DYNAMIC"
+            }
+          ],
           "scalar": {
             "value": 64.0
           },
@@ -2236,10 +2256,13 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             "role": "role1"
           },
           "name": "mem",
-          "reservation": {
-            "principal": "test-principal"
-          },
-          "role": "role1",
+          "reservations": [
+            {
+              "principal": "test-principal",
+              "role": "role1",
+              "type": "DYNAMIC"
+            }
+          ],
           "scalar": {
             "value": 256.0
           },
@@ -2250,10 +2273,13 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources)
             "role": "role1"
           },
           "name": "disk",
-          "reservation": {
-            "principal": "test-principal"
-          },
-          "role": "role1",
+          "reservations": [
+            {
+              "principal": "test-principal",
+              "role": "role1",
+              "type": "DYNAMIC"
+            }
+          ],
           "scalar": {
             "value": 960.0
           },

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/persistent_volume_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/persistent_volume_tests.cpp b/src/tests/persistent_volume_tests.cpp
index 787141c..7b0f436 100644
--- a/src/tests/persistent_volume_tests.cpp
+++ b/src/tests/persistent_volume_tests.cpp
@@ -478,7 +478,13 @@ TEST_P(PersistentVolumeTest, ResourcesCheckpointing)
   ASSERT_SOME(slave);
 
   AWAIT_READY(reregisterSlave);
-  EXPECT_EQ(Resources(reregisterSlave->checkpointed_resources()), volume);
+
+  google::protobuf::RepeatedPtrField<Resource> checkpointedResources =
+    reregisterSlave->checkpointed_resources();
+
+  convertResourceFormat(&checkpointedResources, POST_RESERVATION_REFINEMENT);
+
+  EXPECT_EQ(Resources(checkpointedResources), volume);
 
   driver.stop();
   driver.join();
@@ -2157,6 +2163,8 @@ TEST_P(PersistentVolumeTest, GoodACLNoPrincipal)
   frameworkInfo.set_name("no-principal");
   frameworkInfo.set_user(os::user().get());
   frameworkInfo.set_role(DEFAULT_TEST_ROLE);
+  frameworkInfo.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   // Create a master. Since the framework has no
   // principal, we don't authenticate frameworks.
@@ -2313,6 +2321,8 @@ TEST_P(PersistentVolumeTest, BadACLNoPrincipal)
   frameworkInfo1.set_name("no-principal");
   frameworkInfo1.set_user(os::user().get());
   frameworkInfo1.set_role(DEFAULT_TEST_ROLE);
+  frameworkInfo1.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   // Create a `FrameworkInfo` with a principal.
   FrameworkInfo frameworkInfo2 = DEFAULT_FRAMEWORK_INFO;
@@ -2540,6 +2550,8 @@ TEST_P(PersistentVolumeTest, BadACLDropCreateAndDestroy)
   frameworkInfo2.set_user(os::user().get());
   frameworkInfo2.set_role(DEFAULT_TEST_ROLE);
   frameworkInfo2.set_principal("creator-principal");
+  frameworkInfo2.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   // Create a master.
   master::Flags masterFlags = CreateMasterFlags();

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/reservation_endpoints_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/reservation_endpoints_tests.cpp b/src/tests/reservation_endpoints_tests.cpp
index c34f767..e2d8899 100644
--- a/src/tests/reservation_endpoints_tests.cpp
+++ b/src/tests/reservation_endpoints_tests.cpp
@@ -120,9 +120,9 @@ TEST_F(ReservationEndpointsTest, AvailableResources)
   FrameworkInfo frameworkInfo = createFrameworkInfo();
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   Future<Response> response = process::http::post(
       master.get()->pid,
@@ -204,9 +204,9 @@ TEST_F(ReservationEndpointsTest, ReserveOfferedResources)
   FrameworkInfo frameworkInfo = createFrameworkInfo();
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   MockScheduler sched;
   MesosSchedulerDriver driver(
@@ -276,9 +276,9 @@ TEST_F(ReservationEndpointsTest, UnreserveOfferedResources)
   FrameworkInfo frameworkInfo = createFrameworkInfo();
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   Future<Response> response = process::http::post(
       master.get()->pid,
@@ -363,9 +363,9 @@ TEST_F(ReservationEndpointsTest, ReserveAvailableAndOfferedResources)
   Resources offered = Resources::parse("mem:384").get();
 
   Resources total = available + offered;
-  Resources dynamicallyReserved = total.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    total.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   MockScheduler sched;
   MesosSchedulerDriver driver(
@@ -495,14 +495,12 @@ TEST_F(ReservationEndpointsTest, UnreserveAvailableAndOfferedResources)
   FrameworkInfo frameworkInfo = createFrameworkInfo();
 
   Resources available = Resources::parse("cpus:1;mem:128").get();
-  available = available.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  available = available.pushReservation(createDynamicReservationInfo(
+      frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   Resources offered = Resources::parse("mem:384").get();
-  offered = offered.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  offered = offered.pushReservation(createDynamicReservationInfo(
+      frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   Resources total = available + offered;
   Resources unreserved = total.toUnreserved();
@@ -650,12 +648,12 @@ TEST_F(ReservationEndpointsTest, LabeledResources)
   labels2.add_labels()->CopyFrom(createLabel("foo", "baz"));
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources labeledResources1 = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal(), labels1)).get();
-  Resources labeledResources2 = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal(), labels2)).get();
+  Resources labeledResources1 =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal(), labels1));
+  Resources labeledResources2 =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal(), labels2));
 
   // Make two resource reservations with different labels.
   Future<Response> response = process::http::post(
@@ -795,8 +793,8 @@ TEST_F(ReservationEndpointsTest, InvalidResource)
   // `ReservationInfo`, which is not allowed.
   Try<Resource> resource = Resources::parse("cpus", "4", "*");
   ASSERT_SOME(resource);
-  resource->mutable_reservation()->CopyFrom(
-      createReservationInfo(DEFAULT_CREDENTIAL.principal()));
+  resource->add_reservations()->CopyFrom(
+      createDynamicReservationInfo("*", DEFAULT_CREDENTIAL.principal()));
 
   process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
 
@@ -814,7 +812,7 @@ TEST_F(ReservationEndpointsTest, InvalidResource)
 
     AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response);
     ASSERT_EQ(response->body,
-             "Invalid reservation: role \"*\" cannot be dynamically reserved");
+             "Invalid reservation: role \"*\" cannot be reserved");
   }
 
   {
@@ -823,7 +821,7 @@ TEST_F(ReservationEndpointsTest, InvalidResource)
 
     AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response);
     ASSERT_EQ(response->body,
-             "Invalid reservation: role \"*\" cannot be dynamically reserved");
+             "Invalid reservation: role \"*\" cannot be reserved");
   }
 }
 
@@ -848,9 +846,9 @@ TEST_F(ReservationEndpointsTest, InsufficientResources)
   FrameworkInfo frameworkInfo = createFrameworkInfo();
 
   Resources unreserved = Resources::parse("cpus:4;mem:4096").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   string body = createRequestBody(slaveId, dynamicallyReserved);
@@ -886,9 +884,9 @@ TEST_F(ReservationEndpointsTest, NoHeader)
   FrameworkInfo frameworkInfo = createFrameworkInfo();
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   Future<Response> response = process::http::post(
       master.get()->pid,
@@ -934,8 +932,8 @@ TEST_F(ReservationEndpointsTest, BadCredentials)
   credential.set_secret("bad-secret");
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      "role", createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved = unreserved.pushReservation(
+      createDynamicReservationInfo("role", DEFAULT_CREDENTIAL.principal()));
 
   process::http::Headers headers = createBasicAuthHeaders(credential);
   string body = createRequestBody(slaveId, dynamicallyReserved);
@@ -1003,9 +1001,9 @@ TEST_F(ReservationEndpointsTest, GoodReserveAndUnreserveACL)
   process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   // Reserve the resources.
   Future<Response> response = process::http::post(
@@ -1061,12 +1059,12 @@ TEST_F(ReservationEndpointsTest, GoodReserveACLMultipleRoles)
   const SlaveID& slaveId = slaveRegisteredMessage->slave_id();
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved1 = unreserved.flatten(
-      "jedi_master",
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
-  Resources dynamicallyReserved2 = unreserved.flatten(
-      "sith_lord",
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved1 =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        "jedi_master", DEFAULT_CREDENTIAL.principal()));
+  Resources dynamicallyReserved2 =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        "sith_lord", DEFAULT_CREDENTIAL.principal()));
   Resources dynamicallyReservedMultipleRoles =
     dynamicallyReserved1 + dynamicallyReserved2;
 
@@ -1122,9 +1120,9 @@ TEST_F(ReservationEndpointsTest, BadReserveACL)
   process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   // Attempt to reserve the resources.
   Future<Response> response = process::http::post(
@@ -1179,9 +1177,9 @@ TEST_F(ReservationEndpointsTest, BadUnreserveACL)
   process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   // Reserve the resources.
   Future<Response> response = process::http::post(
@@ -1248,12 +1246,12 @@ TEST_F(ReservationEndpointsTest, BadReserveACLMultipleRoles)
   const SlaveID& slaveId = slaveRegisteredMessage->slave_id();
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved1 = unreserved.flatten(
-      AUTHORIZED_ROLE,
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
-  Resources dynamicallyReserved2 = unreserved.flatten(
-      UNAUTHORIZED_ROLE,
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved1 =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        AUTHORIZED_ROLE, DEFAULT_CREDENTIAL.principal()));
+  Resources dynamicallyReserved2 =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        UNAUTHORIZED_ROLE, DEFAULT_CREDENTIAL.principal()));
   Resources dynamicallyReservedMultipleRoles =
     dynamicallyReserved1 + dynamicallyReserved2;
 
@@ -1280,8 +1278,8 @@ TEST_F(ReservationEndpointsTest, NoSlaveId)
   ASSERT_SOME(slave);
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      "role", createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved = unreserved.pushReservation(
+      createDynamicReservationInfo("role", DEFAULT_CREDENTIAL.principal()));
 
   process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL);
   string body =
@@ -1349,8 +1347,8 @@ TEST_F(ReservationEndpointsTest, NonMatchingPrincipal)
   const SlaveID& slaveId = slaveRegisteredMessage->slave_id();
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved =
-    unreserved.flatten("role", createReservationInfo("badPrincipal")).get();
+  Resources dynamicallyReserved = unreserved.pushReservation(
+      createDynamicReservationInfo("role", "badPrincipal"));
 
   Future<Response> response = process::http::post(
       master.get()->pid,
@@ -1402,9 +1400,8 @@ TEST_F(ReservationEndpointsTest, ReserveAndUnreserveNoAuthentication)
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
 
-  Resources dynamicallyReservedWithNoPrincipal = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo()).get();
+  Resources dynamicallyReservedWithNoPrincipal = unreserved.pushReservation(
+      createDynamicReservationInfo(frameworkInfo.role()));
 
   // Try a reservation with no principal in `ReservationInfo` and no
   // authentication headers.
@@ -1426,9 +1423,9 @@ TEST_F(ReservationEndpointsTest, ReserveAndUnreserveNoAuthentication)
 
   AWAIT_EXPECT_RESPONSE_STATUS_EQ(Accepted().status, response);
 
-  Resources dynamicallyReservedWithPrincipal = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReservedWithPrincipal =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
   // Try a reservation with a principal in `ReservationInfo` and no
   // authentication headers.
@@ -1476,13 +1473,13 @@ TEST_F(ReservationEndpointsTest, DifferentPrincipalsSameRole)
   FrameworkInfo frameworkInfo = createFrameworkInfo();
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved1 = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved1 =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL.principal()));
 
-  Resources dynamicallyReserved2 = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(DEFAULT_CREDENTIAL_2.principal())).get();
+  Resources dynamicallyReserved2 =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), DEFAULT_CREDENTIAL_2.principal()));
 
   Future<Response> response = process::http::post(
       master.get()->pid,
@@ -1552,9 +1549,8 @@ TEST_F(ReservationEndpointsTest, AgentStateEndpointResources)
   const SlaveID& slaveId = slaveRegisteredMessage->slave_id();
 
   Resources unreserved = Resources::parse("cpus:1;mem:512;disk:1024").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      "role1",
-      createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
+  Resources dynamicallyReserved = unreserved.pushReservation(
+      createDynamicReservationInfo("role1", DEFAULT_CREDENTIAL.principal()));
 
   Future<CheckpointResourcesMessage> checkpointResources =
     FUTURE_PROTOBUF(CheckpointResourcesMessage(), _, _);
@@ -1634,10 +1630,13 @@ TEST_F(ReservationEndpointsTest, AgentStateEndpointResources)
               "scalar": {
                 "value": 1.0
               },
-              "role": "role1",
-              "reservation": {
-                "principal": "%s"
-              }
+              "reservations": [
+                {
+                  "principal": "%s",
+                  "role": "role1",
+                  "type": "DYNAMIC"
+                }
+              ]
             },
             {
               "name": "mem",
@@ -1645,10 +1644,13 @@ TEST_F(ReservationEndpointsTest, AgentStateEndpointResources)
               "scalar": {
                 "value": 512.0
               },
-              "role": "role1",
-              "reservation": {
-                "principal": "%s"
-              }
+              "reservations": [
+                {
+                  "principal": "%s",
+                  "role": "role1",
+                  "type": "DYNAMIC"
+                }
+              ]
             },
             {
               "name": "disk",
@@ -1656,10 +1658,13 @@ TEST_F(ReservationEndpointsTest, AgentStateEndpointResources)
               "scalar": {
                 "value": 1024.0
               },
-              "role": "role1",
-              "reservation": {
-                "principal": "%s"
-              }
+              "reservations": [
+                {
+                  "principal": "%s",
+                  "role": "role1",
+                  "type": "DYNAMIC"
+                }
+              ]
             }
           ]
         })~",
@@ -1676,7 +1681,6 @@ TEST_F(ReservationEndpointsTest, AgentStateEndpointResources)
         [
           {
             "name": "cpus",
-            "role": "*",
             "scalar": {
               "value": 3.0
             },
@@ -1684,7 +1688,6 @@ TEST_F(ReservationEndpointsTest, AgentStateEndpointResources)
           },
           {
             "name": "mem",
-            "role": "*",
             "scalar": {
               "value": 1536.0
             },
@@ -1692,7 +1695,6 @@ TEST_F(ReservationEndpointsTest, AgentStateEndpointResources)
           },
           {
             "name": "disk",
-            "role": "*",
             "scalar": {
               "value": 3072.0
             },
@@ -1708,7 +1710,6 @@ TEST_F(ReservationEndpointsTest, AgentStateEndpointResources)
                 }
               ]
             },
-            "role": "*",
             "type": "RANGES"
           }
         ])~").get();

http://git-wip-us.apache.org/repos/asf/mesos/blob/c55f44fe/src/tests/reservation_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/reservation_tests.cpp b/src/tests/reservation_tests.cpp
index daebfdf..3b4884b 100644
--- a/src/tests/reservation_tests.cpp
+++ b/src/tests/reservation_tests.cpp
@@ -115,9 +115,9 @@ TEST_F(ReservationTest, ReserveThenUnreserve)
   filters.set_refuse_seconds(0);
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -212,9 +212,8 @@ TEST_F(ReservationTest, ReserveTwiceWithDoubleValue)
 
   Resources unreserved = Resources::parse("cpus:0.1;mem:512").get();
   Resources dynamicallyReserved =
-    unreserved.flatten(
-        frameworkInfo.role(),
-        createReservationInfo(frameworkInfo.principal())).get();
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   Future<vector<Offer>> offers;
   EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -267,9 +266,8 @@ TEST_F(ReservationTest, ReserveTwiceWithDoubleValue)
 
   Resources reserved = Resources::parse("cpus:0.2;mem:512").get();
   Resources finalReservation =
-    reserved.flatten(
-        frameworkInfo.role(),
-        createReservationInfo(frameworkInfo.principal())).get();
+    reserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   EXPECT_TRUE(Resources(offer.resources()).contains(
       allocatedResources(finalReservation, frameworkInfo.role())));
@@ -316,9 +314,9 @@ TEST_F(ReservationTest, ReserveAndLaunchThenUnreserve)
       &sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL);
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -441,8 +439,8 @@ TEST_F(ReservationTest, ReserveShareWithinRole)
       &sched2, frameworkInfo2, master.get()->pid, DEFAULT_CREDENTIAL);
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      role, createReservationInfo(frameworkInfo1.principal())).get();
+  Resources dynamicallyReserved = unreserved.pushReservation(
+      createDynamicReservationInfo(role, frameworkInfo1.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -553,9 +551,9 @@ TEST_F(ReservationTest, DropReserveTooLarge)
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
   Resources unreservedTooLarge = Resources::parse("cpus:1;mem:1024").get();
-  Resources dynamicallyReservedTooLarge = unreservedTooLarge.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReservedTooLarge =
+    unreservedTooLarge.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture the offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -613,97 +611,6 @@ TEST_F(ReservationTest, DropReserveTooLarge)
 }
 
 
-// This tests that an attempt to dynamically reserve statically
-// reserved resources is dropped.
-TEST_F(ReservationTest, DropReserveStaticReservation)
-{
-  TestAllocator<> allocator;
-
-  FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
-  frameworkInfo.set_role("role");
-
-  master::Flags masterFlags = CreateMasterFlags();
-  masterFlags.allocation_interval = Milliseconds(5);
-  masterFlags.roles = frameworkInfo.role();
-
-  EXPECT_CALL(allocator, initialize(_, _, _, _, _));
-
-  Try<Owned<cluster::Master>> master = StartMaster(&allocator, masterFlags);
-  ASSERT_SOME(master);
-
-  slave::Flags slaveFlags = CreateSlaveFlags();
-  slaveFlags.resources = "cpus(role):1;mem(role):512";
-
-  EXPECT_CALL(allocator, addSlave(_, _, _, _, _, _));
-
-  Owned<MasterDetector> detector = master.get()->createDetector();
-  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), slaveFlags);
-  ASSERT_SOME(slave);
-
-  MockScheduler sched;
-  MesosSchedulerDriver driver(
-      &sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL);
-
-  Resources staticallyReserved =
-    Resources::parse("cpus(role):1;mem(role):512").get();
-  Resources dynamicallyReserved = staticallyReserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
-
-  // We use this to capture offers from 'resourceOffers'.
-  Future<vector<Offer>> offers;
-
-  EXPECT_CALL(sched, registered(&driver, _, _));
-
-  // The expectation for the first offer.
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(FutureArg<1>(&offers));
-
-  EXPECT_CALL(allocator, addFramework(_, _, _, _, _));
-
-  driver.start();
-
-  // In the first offer, expect an offer with the statically reserved
-  // resources.
-  AWAIT_READY(offers);
-
-  ASSERT_EQ(1u, offers->size());
-  Offer offer = offers.get()[0];
-
-  EXPECT_TRUE(Resources(offer.resources()).contains(
-      allocatedResources(staticallyReserved, frameworkInfo.role())));
-
-  // The expectation for the next offer.
-  EXPECT_CALL(sched, resourceOffers(&driver, _))
-    .WillOnce(FutureArg<1>(&offers));
-
-  // Expect that the reserve offer operation will be dropped.
-  EXPECT_CALL(allocator, updateAllocation(_, _, _, _))
-    .Times(0);
-
-  // We use the filter explicitly here so that the resources
-  // will not be filtered for 5 seconds (the default).
-  Filters filters;
-  filters.set_refuse_seconds(0);
-
-  // Attempt to reserve the statically reserved resources.
-  driver.acceptOffers({offer.id()}, {RESERVE(dynamicallyReserved)}, filters);
-
-  // In the next offer, still expect an offer with the statically
-  // reserved resources.
-  AWAIT_READY(offers);
-
-  ASSERT_EQ(1u, offers->size());
-  offer = offers.get()[0];
-
-  EXPECT_TRUE(Resources(offer.resources()).contains(
-      allocatedResources(staticallyReserved, frameworkInfo.role())));
-
-  driver.stop();
-  driver.join();
-}
-
-
 // This test verifies that CheckpointResourcesMessages are sent to the
 // slave when a framework reserve/unreserves resources, and the
 // resources in the messages correctly reflect the resources that need
@@ -732,14 +639,14 @@ TEST_F(ReservationTest, SendingCheckpointResourcesMessage)
       &sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL);
 
   Resources unreserved1 = Resources::parse("cpus:8").get();
-  Resources reserved1 = unreserved1.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources reserved1 =
+    unreserved1.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   Resources unreserved2 = Resources::parse("mem:2048").get();
-  Resources reserved2 = unreserved2.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources reserved2 =
+    unreserved2.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -835,9 +742,8 @@ TEST_F(ReservationTest, ResourcesCheckpointing)
       &sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL);
 
   Resources unreserved = Resources::parse("cpus:8;mem:2048").get();
-  Resources reserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources reserved = unreserved.pushReservation(createDynamicReservationInfo(
+      frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -892,7 +798,12 @@ TEST_F(ReservationTest, ResourcesCheckpointing)
   // reserved resources.
   AWAIT_READY(reregisterSlave);
 
-  EXPECT_EQ(reregisterSlave->checkpointed_resources(), reserved);
+  google::protobuf::RepeatedPtrField<Resource> checkpointedResources =
+    reregisterSlave->checkpointed_resources();
+
+  convertResourceFormat(&checkpointedResources, POST_RESERVATION_REFINEMENT);
+
+  EXPECT_EQ(checkpointedResources, reserved);
 
   driver.stop();
   driver.join();
@@ -926,9 +837,8 @@ TEST_F(ReservationTest, MasterFailover)
   TestingMesosSchedulerDriver driver(&sched, &detector, frameworkInfo);
 
   Resources unreserved = Resources::parse("cpus:8;mem:2048").get();
-  Resources reserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources reserved = unreserved.pushReservation(createDynamicReservationInfo(
+      frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -1052,9 +962,8 @@ TEST_F(ReservationTest, CompatibleCheckpointedResources)
       &sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL);
 
   Resources unreserved = Resources::parse("cpus:8;mem:2048").get();
-  Resources reserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources reserved = unreserved.pushReservation(createDynamicReservationInfo(
+      frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -1160,15 +1069,13 @@ TEST_F(ReservationTest, CompatibleCheckpointedResourcesWithPersistentVolumes)
       &sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL);
 
   Resources unreserved = Resources::parse("cpus:8;mem:2048").get();
-  Resources reserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources reserved = unreserved.pushReservation(createDynamicReservationInfo(
+      frameworkInfo.role(), frameworkInfo.principal()));
 
   Resource unreservedDisk = Resources::parse("disk", "1024", "*").get();
   Resource reservedDisk = unreservedDisk;
-  reservedDisk.set_role(frameworkInfo.role());
-  reservedDisk.mutable_reservation()->CopyFrom(
-      createReservationInfo(frameworkInfo.principal()));
+  reservedDisk.add_reservations()->CopyFrom(createDynamicReservationInfo(
+      frameworkInfo.role(), frameworkInfo.principal()));
 
   Resource volume = reservedDisk;
   volume.mutable_disk()->CopyFrom(createDiskInfo(
@@ -1311,9 +1218,8 @@ TEST_F(ReservationTest, IncompatibleCheckpointedResources)
       &sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL);
 
   Resources unreserved = Resources::parse("cpus:8;mem:2048").get();
-  Resources reserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources reserved = unreserved.pushReservation(createDynamicReservationInfo(
+      frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -1435,9 +1341,9 @@ TEST_F(ReservationTest, GoodACLReserveThenUnreserve)
   filters.set_refuse_seconds(0);
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -1538,9 +1444,9 @@ TEST_F(ReservationTest, BadACLDropReserve)
   filters.set_refuse_seconds(0);
 
   Resources unreserved = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -1632,14 +1538,14 @@ TEST_F(ReservationTest, BadACLDropUnreserve)
 
   // Define the resources to be reserved.
   Resources unreserved1 = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved1 = unreserved1.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReserved1 =
+    unreserved1.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   Resources unreserved2 = Resources::parse("cpus:0.5;mem:256").get();
-  Resources dynamicallyReserved2 = unreserved2.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReserved2 =
+    unreserved2.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -1766,14 +1672,14 @@ TEST_F(ReservationTest, ACLMultipleOperations)
 
   // Define the resources to be reserved.
   Resources unreserved1 = Resources::parse("cpus:1;mem:512").get();
-  Resources dynamicallyReserved1 = unreserved1.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReserved1 =
+    unreserved1.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   Resources unreserved2 = Resources::parse("cpus:0.5;mem:256").get();
-  Resources dynamicallyReserved2 = unreserved2.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReserved2 =
+    unreserved2.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from 'resourceOffers'.
   Future<vector<Offer>> offers;
@@ -1957,8 +1863,8 @@ TEST_F(ReservationTest, WithoutAuthenticationWithoutPrincipal)
 
   // Create dynamically reserved resources whose `ReservationInfo` does not
   // contain a principal.
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(), createReservationInfo()).get();
+  Resources dynamicallyReserved = unreserved.pushReservation(
+      createDynamicReservationInfo(frameworkInfo.role()));
 
   // We use this to capture offers from `resourceOffers`.
   Future<vector<Offer>> offers;
@@ -2064,9 +1970,9 @@ TEST_F(ReservationTest, WithoutAuthenticationWithPrincipal)
 
   // Create dynamically reserved resources whose `ReservationInfo` contains a
   // principal.
-  Resources dynamicallyReserved = unreserved.flatten(
-      frameworkInfo.role(),
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReserved =
+    unreserved.pushReservation(createDynamicReservationInfo(
+        frameworkInfo.role(), frameworkInfo.principal()));
 
   // We use this to capture offers from `resourceOffers`.
   Future<vector<Offer>> offers;
@@ -2136,10 +2042,9 @@ TEST_F(ReservationTest, WithoutAuthenticationWithPrincipal)
 
 // This tests that a framework can't reserve resources using a role different
 // from the one it registered with.
-TEST_F(ReservationTest, DropReserveWithInvalidRole)
+TEST_F(ReservationTest, DropReserveWithDifferentRole)
 {
   const string frameworkRole = "role";
-  const string invalidRole = "invalid-role";
 
   FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
   frameworkInfo.set_role(frameworkRole);
@@ -2205,13 +2110,12 @@ TEST_F(ReservationTest, DropReserveWithInvalidRole)
 
   // Attempt to reserve resources using a different role than the one the
   // framework is registered with.
-  Resources dynamicallyReservedInvalidRole = unreserved.flatten(
-      invalidRole,
-      createReservationInfo(frameworkInfo.principal())).get();
+  Resources dynamicallyReservedDifferentRole = unreserved.pushReservation(
+      createDynamicReservationInfo("foo", frameworkInfo.principal()));
 
   driver.acceptOffers(
       {offer.id()},
-      {RESERVE(dynamicallyReservedInvalidRole)},
+      {RESERVE(dynamicallyReservedDifferentRole)},
       filters);
 
   // In the next offer, still expect an offer with the unreserved resources.
@@ -2299,11 +2203,8 @@ TEST_F(ReservationTest, PreventUnreservingAlienResources)
 
   // Reserve half the memory for `frameworkRole1`.
   const Resources halfMemory = Resources::parse("mem:256").get();
-  const Resources dynamicallyReserved =
-    halfMemory
-      .flatten(
-          frameworkRole1, createReservationInfo(frameworkInfo1.principal()))
-      .get();
+  const Resources dynamicallyReserved = halfMemory.pushReservation(
+      createDynamicReservationInfo(frameworkRole1, frameworkInfo1.principal()));
 
   driver1.acceptOffers({offer.id()}, {RESERVE(dynamicallyReserved)}, filters);
 


[13/21] mesos git commit: Added the agent `RESERVATION_REFINEMENT` capability [13/20].

Posted by mp...@apache.org.
Added the agent `RESERVATION_REFINEMENT` capability [13/20].

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


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

Branch: refs/heads/master
Commit: 78ea693723cb8f12944b079d442c474ea13666db
Parents: 6be854a
Author: Michael Park <mp...@apache.org>
Authored: Mon Jun 19 13:14:18 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:35:06 2017 -0700

----------------------------------------------------------------------
 src/slave/constants.cpp    | 3 ++-
 src/tests/master_tests.cpp | 8 ++++----
 src/tests/slave_tests.cpp  | 8 ++++----
 3 files changed, 10 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/78ea6937/src/slave/constants.cpp
----------------------------------------------------------------------
diff --git a/src/slave/constants.cpp b/src/slave/constants.cpp
index d3668e4..9b60bd0 100644
--- a/src/slave/constants.cpp
+++ b/src/slave/constants.cpp
@@ -37,7 +37,8 @@ vector<SlaveInfo::Capability> AGENT_CAPABILITIES()
 {
   SlaveInfo::Capability::Type types[] = {
     SlaveInfo::Capability::MULTI_ROLE,
-    SlaveInfo::Capability::HIERARCHICAL_ROLE
+    SlaveInfo::Capability::HIERARCHICAL_ROLE,
+    SlaveInfo::Capability::RESERVATION_REFINEMENT
   };
 
   vector<SlaveInfo::Capability> result;

http://git-wip-us.apache.org/repos/asf/mesos/blob/78ea6937/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index 543c4a3..1c9b9a0 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -4284,10 +4284,10 @@ TEST_F(MasterTest, StateEndpointAgentCapabilities)
   ASSERT_EQ(1u, slaveInfo.values.count("capabilities"));
   JSON::Value slaveCapabilities = slaveInfo.values.at("capabilities");
 
-  // Agents should always have MULTI_ROLE and HIERARCHICAL_ROLE capabilities
-  // in current implementation.
-  Try<JSON::Value> expectedCapabilities =
-    JSON::parse("[\"MULTI_ROLE\",\"HIERARCHICAL_ROLE\"]");
+  // Agents should always have MULTI_ROLE, HIERARCHICAL_ROLE, and
+  // RESERVATION_REFINEMENT capabilities in current implementation.
+  Try<JSON::Value> expectedCapabilities = JSON::parse(
+      "[\"MULTI_ROLE\",\"HIERARCHICAL_ROLE\",\"RESERVATION_REFINEMENT\"]");
 
   ASSERT_SOME(expectedCapabilities);
   EXPECT_TRUE(slaveCapabilities.contains(expectedCapabilities.get()));

http://git-wip-us.apache.org/repos/asf/mesos/blob/78ea6937/src/tests/slave_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_tests.cpp b/src/tests/slave_tests.cpp
index 26901f4..b3b24b6 100644
--- a/src/tests/slave_tests.cpp
+++ b/src/tests/slave_tests.cpp
@@ -1540,10 +1540,10 @@ TEST_F(SlaveTest, StateEndpoint)
   EXPECT_FALSE(state.values["capabilities"].as<JSON::Array>().values.empty());
   JSON::Value slaveCapabilities = state.values.at("capabilities");
 
-  // Agents should always have MULTI_ROLE and HIERARCHICAL_ROLE capabilities
-  // in current implementation.
-  Try<JSON::Value> expectedCapabilities =
-    JSON::parse("[\"MULTI_ROLE\",\"HIERARCHICAL_ROLE\"]");
+  // Agents should always have MULTI_ROLE, HIERARCHICAL_ROLE, and
+  // RESERVATION_REFINEMENT capabilities in current implementation.
+  Try<JSON::Value> expectedCapabilities = JSON::parse(
+      "[\"MULTI_ROLE\",\"HIERARCHICAL_ROLE\",\"RESERVATION_REFINEMENT\"]");
 
   ASSERT_SOME(expectedCapabilities);
   EXPECT_TRUE(slaveCapabilities.contains(expectedCapabilities.get()));


[09/21] mesos git commit: Adjusted the master validation to the new resource format [9/20].

Posted by mp...@apache.org.
Adjusted the master validation to the new resource format [9/20].

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


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

Branch: refs/heads/master
Commit: 3e8311e53db9af73ee9219480b6ec9b475578048
Parents: 2398ef7
Author: Michael Park <mp...@apache.org>
Authored: Sun Jun 18 21:12:07 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:30:41 2017 -0700

----------------------------------------------------------------------
 src/master/validation.cpp | 35 +++++++++++++++++++++--------------
 1 file changed, 21 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/3e8311e5/src/master/validation.cpp
----------------------------------------------------------------------
diff --git a/src/master/validation.cpp b/src/master/validation.cpp
index bebfe53..eb1bb0b 100644
--- a/src/master/validation.cpp
+++ b/src/master/validation.cpp
@@ -720,7 +720,7 @@ Option<Error> validateUniquePersistenceID(
   Resources volumes = resources.persistentVolumes();
 
   foreach (const Resource& volume, volumes) {
-    const string& role = volume.role();
+    const string& role = Resources::reservationRole(volume);
     const string& id = volume.disk().persistence().id();
 
     if (persistenceIds.contains(role) &&
@@ -1905,10 +1905,11 @@ Option<Error> validate(
     }
 
     if (!agentCapabilities.hierarchicalRole &&
-        strings::contains(resource.role(), "/")) {
+        strings::contains(Resources::reservationRole(resource), "/")) {
       return Error(
           "Resource " + stringify(resource) +
-          " with reservation for hierarchical role '" + resource.role() + "'"
+          " with reservation for hierarchical role"
+          " '" + Resources::reservationRole(resource) + "'"
           " cannot be reserved on an agent without HIERARCHICAL_ROLE"
           " capability");
     }
@@ -1919,19 +1920,22 @@ Option<Error> validate(
       // return principals of that form.
       CHECK_SOME(principal->value);
 
-      if (!resource.reservation().has_principal()) {
+      const Resource::ReservationInfo& reservation =
+        *resource.reservations().rbegin();
+
+      if (!reservation.has_principal()) {
         return Error(
             "A reserve operation was attempted by principal '" +
             stringify(principal.get()) + "', but there is a "
             "reserved resource in the request with no principal set");
       }
 
-      if (principal != resource.reservation().principal()) {
+      if (principal != reservation.principal()) {
         return Error(
             "A reserve operation was attempted by authenticated principal '" +
             stringify(principal.get()) + "', which does not match a "
             "reserved resource in the request with principal '" +
-            resource.reservation().principal() + "'");
+            reservation.principal() + "'");
       }
     }
 
@@ -1948,11 +1952,13 @@ Option<Error> validate(
             " perform reservations on allocated resources");
       }
 
-      if (resource.allocation_info().role() != resource.role()) {
+      if (resource.allocation_info().role() !=
+          Resources::reservationRole(resource)) {
         return Error(
             "A reserve operation was attempted for a resource with role"
-            " '" + resource.role() + "', but the resource was allocated"
-            " to role '" + resource.allocation_info().role() + "'");
+            " '" + Resources::reservationRole(resource) + "', but"
+            " the resource was allocated to role"
+            " '" + resource.allocation_info().role() + "'");
       }
 
       if (!frameworkRoles->contains(resource.allocation_info().role())) {
@@ -1963,11 +1969,11 @@ Option<Error> validate(
             " '" + stringify(frameworkRoles.get()) + "'");
       }
 
-      if (!frameworkRoles->contains(resource.role())) {
+      if (!frameworkRoles->contains(Resources::reservationRole(resource))) {
         return Error(
             "A reserve operation was attempted for a resource with role"
-            " '" + resource.role() + "', but the framework can only"
-            " reserve resources with roles"
+            " '" + Resources::reservationRole(resource) + "',"
+            " but the framework can only reserve resources with roles"
             " '" + stringify(frameworkRoles.get()) + "'");
       }
     } else {
@@ -2096,10 +2102,11 @@ Option<Error> validate(
     }
 
     if (!agentCapabilities.hierarchicalRole &&
-        strings::contains(volume.role(), "/")) {
+        strings::contains(Resources::reservationRole(volume), "/")) {
       return Error(
           "Volume " + stringify(volume) +
-          " with reservation for hierarchical role '" + volume.role() + "'"
+          " with reservation for hierarchical role"
+          " '" + Resources::reservationRole(volume) + "'"
           " cannot be reserved on an agent without HIERARCHICAL_ROLE"
           " capability");
     }


[17/21] mesos git commit: Removed `modelProtobufJSON` and replaced with `JSON::Protobuf` [16/20].

Posted by mp...@apache.org.
Removed `modelProtobufJSON` and replaced with `JSON::Protobuf` [16/20].

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


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

Branch: refs/heads/master
Commit: 6749cfd58ef9d76636ebb0d5c0ad92891dd82e34
Parents: b71fe03
Author: Michael Park <mp...@apache.org>
Authored: Tue Jun 20 01:09:29 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:44:35 2017 -0700

----------------------------------------------------------------------
 src/common/http.cpp | 47 +----------------------------------------------
 src/common/http.hpp | 15 ---------------
 src/master/http.cpp | 20 ++++----------------
 src/slave/http.cpp  | 10 ++--------
 4 files changed, 7 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/6749cfd5/src/common/http.cpp
----------------------------------------------------------------------
diff --git a/src/common/http.cpp b/src/common/http.cpp
index 98899a7..2f7718c 100644
--- a/src/common/http.cpp
+++ b/src/common/http.cpp
@@ -112,7 +112,7 @@ string serialize(
       return message.SerializeAsString();
     }
     case ContentType::JSON: {
-      return stringify(modelProtobufJSON(message));
+      return stringify(JSON::protobuf(message));
     }
     case ContentType::RECORDIO: {
       LOG(FATAL) << "Serializing a RecordIO stream is not supported";
@@ -504,51 +504,6 @@ JSON::Object model(const quota::QuotaInfo& quotaInfo)
   return object;
 }
 
-
-JSON::Object modelProtobufJSON(const google::protobuf::Message& message)
-{
-  struct
-  {
-    using result_type = void;
-
-    void operator()(JSON::Boolean&) const { /* No-op. */ }
-    void operator()(JSON::Number&) const { /* No-op. */ }
-    void operator()(JSON::String&) const { /* No-op. */ }
-    void operator()(JSON::Object& object) const
-    {
-      // We assume that if an object has fields "role" and "reservations"
-      // that it is a `Resource` object. While this is clearly not robust,
-      // it's good enough for what we need.
-      auto role_iter = object.values.find("role");
-      auto reservations_iter = object.values.find("reservations");
-      if (role_iter != object.values.end() &&
-          role_iter->second.is<JSON::String>() &&
-          reservations_iter != object.values.end() &&
-          reservations_iter->second.is<JSON::Array>() &&
-          reservations_iter->second.as<JSON::Array>().values.size() > 1) {
-        CHECK_EQ(role_iter->second.as<JSON::String>().value, "*");
-        object.values.erase(role_iter);
-      }
-
-      foreachvalue (JSON::Value& value, object.values) {
-        boost::apply_visitor(*this, value);
-      }
-    }
-    void operator()(JSON::Array& array) const
-    {
-      foreach (JSON::Value& value, array.values) {
-        boost::apply_visitor(*this, value);
-      }
-    }
-    void operator()(JSON::Null&) const { /* No-op. */ }
-  } removeRoleFromResourcesWithRefinedReservations;
-
-  JSON::Object object = JSON::protobuf(message);
-  removeRoleFromResourcesWithRefinedReservations(object);
-
-  return object;
-}
-
 }  // namespace internal {
 
 void json(JSON::ObjectWriter* writer, const Attributes& attributes)

http://git-wip-us.apache.org/repos/asf/mesos/blob/6749cfd5/src/common/http.hpp
----------------------------------------------------------------------
diff --git a/src/common/http.hpp b/src/common/http.hpp
index 48f7c4a..93d6088 100644
--- a/src/common/http.hpp
+++ b/src/common/http.hpp
@@ -122,21 +122,6 @@ JSON::Object model(const Task& task);
 JSON::Object model(const FileInfo& fileInfo);
 JSON::Object model(const quota::QuotaInfo& quotaInfo);
 
-
-// With reservation refinement, we use the `Resource.reservations` field to
-// express the reservation state. Due to the fact that `Resource.role` is
-// an optional field __and__ has a default value, our generic Protobuf to JSON
-// conversion (JSON::protobuf) injects the `role` field with the default value
-// even if it's not set. Since this will likely confuse users and also result in
-// resources we consider invalid (i.e., `Resources::validate` would fail),
-// we introduce a wrapper here which manually removes the `Resource.role` field
-// if the resource has refined reservations.
-//
-// TODO(mpark): Remove this once MESOS-7674 is resolved and
-// `Resource.role` is deprecated.
-JSON::Object modelProtobufJSON(const google::protobuf::Message& message);
-
-
 void json(JSON::ObjectWriter* writer, const Task& task);
 
 } // namespace internal {

http://git-wip-us.apache.org/repos/asf/mesos/blob/6749cfd5/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index d594d67..801b809 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -2354,10 +2354,7 @@ Future<Response> Master::Http::slaves(
                              reserved) {
                   writer->field(role, [&resources](JSON::ArrayWriter* writer) {
                     foreach (const Resource& resource, resources) {
-                      // TODO(mpark): Replace the `modelProtobufJSON` back to
-                      // `JSON::Protobuf` once MESOS-7674 is resolved and
-                      // `Resource.role` is deprecated.
-                      writer->element(modelProtobufJSON(resource));
+                      writer->element(JSON::Protobuf(resource));
                     }
                   });
                 }
@@ -2370,10 +2367,7 @@ Future<Response> Master::Http::slaves(
               "unreserved_resources_full",
               [&unreservedResources](JSON::ArrayWriter* writer) {
                 foreach (const Resource& resource, unreservedResources) {
-                  // TODO(mpark): Replace the `modelProtobufJSON` back to
-                  // `JSON::Protobuf` once MESOS-7674 is resolved and
-                  // `Resource.role` is deprecated.
-                  writer->element(modelProtobufJSON(resource));
+                  writer->element(JSON::Protobuf(resource));
                 }
               });
 
@@ -2383,10 +2377,7 @@ Future<Response> Master::Http::slaves(
               "used_resources_full",
               [&usedResources](JSON::ArrayWriter* writer) {
                 foreach (const Resource& resource, usedResources) {
-                  // TODO(mpark): Replace the `modelProtobufJSON` back to
-                  // `JSON::Protobuf` once MESOS-7674 is resolved and
-                  // `Resource.role` is deprecated.
-                  writer->element(modelProtobufJSON(resource));
+                  writer->element(JSON::Protobuf(resource));
                 }
               });
 
@@ -2396,10 +2387,7 @@ Future<Response> Master::Http::slaves(
               "offered_resources_full",
               [&offeredResources](JSON::ArrayWriter* writer) {
                 foreach (const Resource& resource, offeredResources) {
-                  // TODO(mpark): Replace the `modelProtobufJSON` back to
-                  // `JSON::Protobuf` once MESOS-7674 is resolved and
-                  // `Resource.role` is deprecated.
-                  writer->element(modelProtobufJSON(resource));
+                  writer->element(JSON::Protobuf(resource));
                 }
               });
         });

http://git-wip-us.apache.org/repos/asf/mesos/blob/6749cfd5/src/slave/http.cpp
----------------------------------------------------------------------
diff --git a/src/slave/http.cpp b/src/slave/http.cpp
index e03b886..78b3586 100644
--- a/src/slave/http.cpp
+++ b/src/slave/http.cpp
@@ -1297,10 +1297,7 @@ Future<Response> Http::state(
                            totalResources.reservations()) {
                 writer->field(role, [&resources](JSON::ArrayWriter* writer) {
                   foreach (const Resource& resource, resources) {
-                    // TODO(mpark): Replace the `modelProtobufJSON` back to
-                    // `JSON::Protobuf` once MESOS-7674 is resolved and
-                    // `Resource.role` is deprecated.
-                    writer->element(modelProtobufJSON(resource));
+                    writer->element(JSON::Protobuf(resource));
                   }
                 });
               }
@@ -1310,10 +1307,7 @@ Future<Response> Http::state(
             "unreserved_resources_full",
             [&totalResources](JSON::ArrayWriter* writer) {
               foreach (const Resource& resource, totalResources.unreserved()) {
-                // TODO(mpark): Replace the `modelProtobufJSON` back to
-                // `JSON::Protobuf` once MESOS-7674 is resolved and
-                // `Resource.role` is deprecated.
-                writer->element(modelProtobufJSON(resource));
+                writer->element(JSON::Protobuf(resource));
               }
             });
 


[02/21] mesos git commit: Resources: Adjusted the predicates to the new resource format [2/20].

Posted by mp...@apache.org.
Resources: Adjusted the predicates to the new resource format [2/20].

The predicate resource functions have the same preconditions as
the `Resources`, in that they require the given `Resource` object
to be validated, and in the "post-reservation-refinement" format.
As such, the corresponding preconditions have been added as a `CHECK`,
and the functions have been updated to inspect the correct fields.

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


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

Branch: refs/heads/master
Commit: 1e220035de84245694ccf92b1fd2307aff2d3342
Parents: db2babf
Author: Michael Park <mp...@apache.org>
Authored: Sun Jun 18 22:03:25 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:29:03 2017 -0700

----------------------------------------------------------------------
 include/mesos/resources.hpp    | 13 +++++--------
 include/mesos/v1/resources.hpp | 13 +++++--------
 src/common/resources.cpp       | 32 ++++++++++++++++++++++++++++++--
 src/v1/resources.cpp           | 32 ++++++++++++++++++++++++++++++--
 4 files changed, 70 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/1e220035/include/mesos/resources.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/resources.hpp b/include/mesos/resources.hpp
index 2efe9fb..b6264e2 100644
--- a/include/mesos/resources.hpp
+++ b/include/mesos/resources.hpp
@@ -263,15 +263,12 @@ public:
   static Option<Error> validate(
       const google::protobuf::RepeatedPtrField<Resource>& resources);
 
-  // NOTE: The following predicate functions assume that the given
-  // resource is validated.
+  // NOTE: The following predicate functions assume that the given resource is
+  // validated, and is in the "post-reservation-refinement" format. That is,
+  // the reservation state is represented by `Resource.reservations` field,
+  // and `Resource.role` and `Resource.reservation` fields are not set.
   //
-  // Valid states of (role, reservation) pair in the Resource object.
-  //   Unreserved         : ("*", None)
-  //   Static reservation : (R, None)
-  //   Dynamic reservation: (R, { principal: <framework_principal> })
-  //
-  // NOTE: ("*", { principal: <framework_principal> }) is invalid.
+  // See 'Resource Format' section in `mesos.proto` for more details.
 
   // Tests if the given Resource object is empty.
   static bool isEmpty(const Resource& resource);

http://git-wip-us.apache.org/repos/asf/mesos/blob/1e220035/include/mesos/v1/resources.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/v1/resources.hpp b/include/mesos/v1/resources.hpp
index 07b9bb5..b7e390c 100644
--- a/include/mesos/v1/resources.hpp
+++ b/include/mesos/v1/resources.hpp
@@ -263,15 +263,12 @@ public:
   static Option<Error> validate(
       const google::protobuf::RepeatedPtrField<Resource>& resources);
 
-  // NOTE: The following predicate functions assume that the given
-  // resource is validated.
+  // NOTE: The following predicate functions assume that the given resource is
+  // validated, and is in the "post-reservation-refinement" format. That is,
+  // the reservation state is represented by `Resource.reservations` field,
+  // and `Resource.role` and `Resource.reservation` fields are not set.
   //
-  // Valid states of (role, reservation) pair in the Resource object.
-  //   Unreserved         : ("*", None)
-  //   Static reservation : (R, None)
-  //   Dynamic reservation: (R, { principal: <framework_principal> })
-  //
-  // NOTE: ("*", { principal: <framework_principal> }) is invalid.
+  // See 'Resource Format' section in `mesos.proto` for more details.
 
   // Tests if the given Resource object is empty.
   static bool isEmpty(const Resource& resource);

http://git-wip-us.apache.org/repos/asf/mesos/blob/1e220035/src/common/resources.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources.cpp b/src/common/resources.cpp
index ef54678..8cfe6ff 100644
--- a/src/common/resources.cpp
+++ b/src/common/resources.cpp
@@ -1026,6 +1026,9 @@ Option<Error> Resources::validate(const RepeatedPtrField<Resource>& resources)
 
 bool Resources::isEmpty(const Resource& resource)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   if (resource.type() == Value::SCALAR) {
     Value::Scalar zero;
     zero.set_value(0);
@@ -1042,6 +1045,9 @@ bool Resources::isEmpty(const Resource& resource)
 
 bool Resources::isPersistentVolume(const Resource& resource)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   return resource.has_disk() && resource.disk().has_persistence();
 }
 
@@ -1050,6 +1056,9 @@ bool Resources::isReserved(
     const Resource& resource,
     const Option<string>& role)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   if (role.isSome()) {
     return !isUnreserved(resource) && role.get() == resource.role();
   } else {
@@ -1062,6 +1071,9 @@ bool Resources::isAllocatableTo(
     const Resource& resource,
     const std::string& role)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   return isUnreserved(resource) ||
          role == resource.role() ||
          roles::isStrictSubroleOf(role, resource.role());
@@ -1070,30 +1082,46 @@ bool Resources::isAllocatableTo(
 
 bool Resources::isUnreserved(const Resource& resource)
 {
-  return resource.role() == "*" && !resource.has_reservation();
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
+  return resource.reservations_size() == 0;
 }
 
 
 bool Resources::isDynamicallyReserved(const Resource& resource)
 {
-  return resource.has_reservation();
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
+  return isReserved(resource) && (resource.reservations().rbegin()->type() ==
+                                  Resource::ReservationInfo::DYNAMIC);
 }
 
 
 bool Resources::isRevocable(const Resource& resource)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   return resource.has_revocable();
 }
 
 
 bool Resources::isShared(const Resource& resource)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   return resource.has_shared();
 }
 
 
 bool Resources::hasRefinedReservations(const Resource& resource)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   return resource.reservations_size() > 1;
 }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/1e220035/src/v1/resources.cpp
----------------------------------------------------------------------
diff --git a/src/v1/resources.cpp b/src/v1/resources.cpp
index c1b6b8a..bf054b9 100644
--- a/src/v1/resources.cpp
+++ b/src/v1/resources.cpp
@@ -1028,6 +1028,9 @@ Option<Error> Resources::validate(const RepeatedPtrField<Resource>& resources)
 
 bool Resources::isEmpty(const Resource& resource)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   if (resource.type() == Value::SCALAR) {
     Value::Scalar zero;
     zero.set_value(0);
@@ -1044,6 +1047,9 @@ bool Resources::isEmpty(const Resource& resource)
 
 bool Resources::isPersistentVolume(const Resource& resource)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   return resource.has_disk() && resource.disk().has_persistence();
 }
 
@@ -1052,6 +1058,9 @@ bool Resources::isReserved(
     const Resource& resource,
     const Option<string>& role)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   if (role.isSome()) {
     return !isUnreserved(resource) && role.get() == resource.role();
   } else {
@@ -1064,6 +1073,9 @@ bool Resources::isAllocatableTo(
     const Resource& resource,
     const std::string& role)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   return isUnreserved(resource) ||
          role == resource.role() ||
          roles::isStrictSubroleOf(role, resource.role());
@@ -1072,30 +1084,46 @@ bool Resources::isAllocatableTo(
 
 bool Resources::isUnreserved(const Resource& resource)
 {
-  return resource.role() == "*" && !resource.has_reservation();
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
+  return resource.reservations_size() == 0;
 }
 
 
 bool Resources::isDynamicallyReserved(const Resource& resource)
 {
-  return resource.has_reservation();
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
+  return isReserved(resource) && (resource.reservations().rbegin()->type() ==
+                                  Resource::ReservationInfo::DYNAMIC);
 }
 
 
 bool Resources::isRevocable(const Resource& resource)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   return resource.has_revocable();
 }
 
 
 bool Resources::isShared(const Resource& resource)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   return resource.has_shared();
 }
 
 
 bool Resources::hasRefinedReservations(const Resource& resource)
 {
+  CHECK(!resource.has_role());
+  CHECK(!resource.has_reservation());
+
   return resource.reservations_size() > 1;
 }
 


[14/21] mesos git commit: Changed the semantics of `JSON::protobuf` for deprecated fields [14/20].

Posted by mp...@apache.org.
Changed the semantics of `JSON::protobuf` for deprecated fields [14/20].

Updated `JSON::protobuf` to not emit a __deprecated__ optional field
with a default value if it's not explicitly set. The specific issue
we're solving here is that the round-trip of Protobuf to JSON and
back does not work with the current behavior. For example,
the `Resource` object in the "post-reservation-refinement" format does
not have the `Resource.role` field. During the Protobuf -> JSON
conversion, the `"role"` field is set to `"*"` since it is an optional
field with a default value. When such a JSON object is parsed back in
as a Protobuf message, the `Resource` object is in an invalid state.

In order to facilitate this at least in the short term, this patch
changes the generic Protobuf -> JSON logic to not output unset fields
if they are marked deprecated.

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


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

Branch: refs/heads/master
Commit: 9374529209fa6b7d67530b3b44ef36dc2d0fe896
Parents: 78ea693
Author: Michael Park <mp...@apache.org>
Authored: Tue Jun 20 01:06:31 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:36:40 2017 -0700

----------------------------------------------------------------------
 3rdparty/stout/include/stout/protobuf.hpp | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/93745292/3rdparty/stout/include/stout/protobuf.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/protobuf.hpp b/3rdparty/stout/include/stout/protobuf.hpp
index 2735354..15690b6 100644
--- a/3rdparty/stout/include/stout/protobuf.hpp
+++ b/3rdparty/stout/include/stout/protobuf.hpp
@@ -27,6 +27,7 @@
 #include <vector>
 
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/repeated_field.h>
 
@@ -698,8 +699,8 @@ struct Protobuf : Representation<google::protobuf::Message>
 
 
 // `json` function for protobuf messages. Refer to `jsonify.hpp` for details.
-// TODO(mpark): This currently uses the default value for optional fields with
-// a default that are not set, but we may want to revisit this decision.
+// TODO(mpark): This currently uses the default value for optional fields
+// that are not deprecated, but we may want to revisit this decision.
 inline void json(ObjectWriter* writer, const Protobuf& protobuf)
 {
   using google::protobuf::FieldDescriptor;
@@ -723,8 +724,9 @@ inline void json(ObjectWriter* writer, const Protobuf& protobuf)
         // Has repeated field with members, output as JSON.
         fields.push_back(field);
       }
-    } else if (reflection->HasField(message, field) ||
-               field->has_default_value()) {
+    } else if (
+        reflection->HasField(message, field) ||
+        (field->has_default_value() && !field->options().deprecated())) {
       // Field is set or has default, output as JSON.
       fields.push_back(field);
     }
@@ -832,8 +834,8 @@ inline void json(ObjectWriter* writer, const Protobuf& protobuf)
 }
 
 
-// TODO(bmahler): This currently uses the default value for optional
-// fields but we may want to revisit this decision.
+// TODO(bmahler): This currently uses the default value for optional fields
+// that are not deprecated, but we may want to revisit this decision.
 inline Object protobuf(const google::protobuf::Message& message)
 {
   Object object;
@@ -854,8 +856,9 @@ inline Object protobuf(const google::protobuf::Message& message)
         // Has repeated field with members, output as JSON.
         fields.push_back(field);
       }
-    } else if (reflection->HasField(message, field) ||
-               field->has_default_value()) {
+    } else if (
+        reflection->HasField(message, field) ||
+        (field->has_default_value() && !field->options().deprecated())) {
       // Field is set or has default, output as JSON.
       fields.push_back(field);
     }
@@ -978,7 +981,7 @@ inline Object protobuf(const google::protobuf::Message& message)
           break;
         case google::protobuf::FieldDescriptor::TYPE_MESSAGE:
           object.values[field->name()] =
-              protobuf(reflection->GetMessage(message, field));
+            protobuf(reflection->GetMessage(message, field));
           break;
         case google::protobuf::FieldDescriptor::TYPE_ENUM:
           object.values[field->name()] =


[16/21] mesos git commit: Adjusted test utilities to the resource format [17/20].

Posted by mp...@apache.org.
Adjusted test utilities to the resource format [17/20].

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


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

Branch: refs/heads/master
Commit: 42a1913cedd8d6174bdf60af194a5515af8c91b3
Parents: 6749cfd
Author: Michael Park <mp...@apache.org>
Authored: Tue Jun 20 01:09:47 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:44:35 2017 -0700

----------------------------------------------------------------------
 src/tests/mesos.hpp           | 95 ++++++++++++++++++++++++++++----------
 src/tests/resources_utils.cpp |  1 -
 2 files changed, 70 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/42a1913c/src/tests/mesos.hpp
----------------------------------------------------------------------
diff --git a/src/tests/mesos.hpp b/src/tests/mesos.hpp
index 3fff10f..e9e4f86 100644
--- a/src/tests/mesos.hpp
+++ b/src/tests/mesos.hpp
@@ -730,13 +730,28 @@ inline TTaskGroupInfo createTaskGroupInfo(const std::vector<TTaskInfo>& tasks)
 }
 
 
+template <typename TResource>
+inline typename TResource::ReservationInfo createStaticReservationInfo(
+    const std::string& role)
+{
+  typename TResource::ReservationInfo info;
+  info.set_type(TResource::ReservationInfo::STATIC);
+  info.set_role(role);
+  return info;
+}
+
+
 template <typename TResource, typename TLabels>
-inline typename TResource::ReservationInfo createReservationInfo(
+inline typename TResource::ReservationInfo createDynamicReservationInfo(
+    const std::string& role,
     const Option<std::string>& principal = None(),
     const Option<TLabels>& labels = None())
 {
   typename TResource::ReservationInfo info;
 
+  info.set_type(TResource::ReservationInfo::DYNAMIC);
+  info.set_role(role);
+
   if (principal.isSome()) {
     info.set_principal(principal.get());
   }
@@ -749,18 +764,23 @@ inline typename TResource::ReservationInfo createReservationInfo(
 }
 
 
-template <typename TResource, typename TResources>
+template <
+    typename TResource,
+    typename TResources,
+    typename... TReservationInfos>
 inline TResource createReservedResource(
     const std::string& name,
     const std::string& value,
-    const std::string& role,
-    const Option<typename TResource::ReservationInfo>& reservation)
+    const TReservationInfos&... reservations)
 {
-  TResource resource = TResources::parse(name, value, role).get();
+  std::initializer_list<typename TResource::ReservationInfo> reservations_ = {
+    reservations...
+  };
 
-  if (reservation.isSome()) {
-    resource.mutable_reservation()->CopyFrom(reservation.get());
-  }
+  TResource resource = TResources::parse(name, value, "*").get();
+  resource.mutable_reservations()->CopyFrom(
+      google::protobuf::RepeatedPtrField<typename TResource::ReservationInfo>{
+        reservations_.begin(), reservations_.end()});
 
   return resource;
 }
@@ -879,10 +899,8 @@ inline TResource createPersistentVolume(
     const Option<std::string>& creatorPrincipal = None(),
     bool isShared = false)
 {
-  TResource volume = TResources::parse(
-      "disk",
-      stringify(size.megabytes()),
-      role).get();
+  TResource volume =
+    TResources::parse("disk", stringify(size.megabytes()), role).get();
 
   volume.mutable_disk()->CopyFrom(
       createDiskInfo<TResource, TVolume>(
@@ -894,7 +912,11 @@ inline TResource createPersistentVolume(
           creatorPrincipal));
 
   if (reservationPrincipal.isSome()) {
-    volume.mutable_reservation()->set_principal(reservationPrincipal.get());
+    typename TResource::ReservationInfo& reservation =
+      *volume.mutable_reservations()->rbegin();
+
+    reservation.set_type(TResource::ReservationInfo::DYNAMIC);
+    reservation.set_principal(reservationPrincipal.get());
   }
 
   if (isShared) {
@@ -931,7 +953,11 @@ inline TResource createPersistentVolume(
           creatorPrincipal));
 
   if (reservationPrincipal.isSome()) {
-    volume.mutable_reservation()->set_principal(reservationPrincipal.get());
+    typename TResource::ReservationInfo& reservation =
+      *volume.mutable_reservations()->rbegin();
+
+    reservation.set_type(TResource::ReservationInfo::DYNAMIC);
+    reservation.set_principal(reservationPrincipal.get());
   }
 
   if (isShared) {
@@ -1215,11 +1241,20 @@ inline TaskGroupInfo createTaskGroupInfo(const std::vector<TaskInfo>& tasks)
 }
 
 
-template <typename... Args>
-inline Resource::ReservationInfo createReservationInfo(Args&&... args)
+inline Resource::ReservationInfo createStaticReservationInfo(
+    const std::string& role)
 {
-  return common::createReservationInfo<Resource, Labels>(
-      std::forward<Args>(args)...);
+  return common::createStaticReservationInfo<Resource>(role);
+}
+
+
+inline Resource::ReservationInfo createDynamicReservationInfo(
+    const std::string& role,
+    const Option<std::string>& principal = None(),
+    const Option<Labels>& labels = None())
+{
+  return common::createDynamicReservationInfo<Resource, Labels>(
+      role, principal, labels);
 }
 
 
@@ -1430,12 +1465,20 @@ inline mesos::v1::TaskGroupInfo createTaskGroupInfo(
 }
 
 
-template <typename... Args>
-inline mesos::v1::Resource::ReservationInfo createReservationInfo(
-    Args&&... args)
+inline mesos::v1::Resource::ReservationInfo createStaticReservationInfo(
+    const std::string& role)
 {
-  return common::createReservationInfo<mesos::v1::Resource, mesos::v1::Labels>(
-      std::forward<Args>(args)...);
+  return common::createStaticReservationInfo<mesos::v1::Resource>(role);
+}
+
+
+inline mesos::v1::Resource::ReservationInfo createDynamicReservationInfo(
+    const std::string& role,
+    const Option<std::string>& principal = None(),
+    const Option<mesos::v1::Labels>& labels = None())
+{
+  return common::createDynamicReservationInfo<
+             mesos::v1::Resource, mesos::v1::Labels>(role, principal, labels);
 }
 
 
@@ -1684,8 +1727,10 @@ ACTION_P5(LaunchTasks, executor, tasks, cpus, mem, role)
       task.mutable_slave_id()->MergeFrom(offer.slave_id());
       task.mutable_executor()->MergeFrom(executor);
 
-      Option<Resources> resources =
-        remaining.find(taskResources.flatten(role).get());
+      Option<Resources> resources = remaining.find(
+          role == std::string("*")
+            ? taskResources
+            : taskResources.pushReservation(createStaticReservationInfo(role)));
 
       CHECK_SOME(resources);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/42a1913c/src/tests/resources_utils.cpp
----------------------------------------------------------------------
diff --git a/src/tests/resources_utils.cpp b/src/tests/resources_utils.cpp
index 2cef55f..9736c2a 100644
--- a/src/tests/resources_utils.cpp
+++ b/src/tests/resources_utils.cpp
@@ -47,7 +47,6 @@ Resource createPorts(const ::mesos::Value::Ranges& ranges)
   value.mutable_ranges()->CopyFrom(ranges);
 
   Resource resource;
-  resource.set_role("*");
   resource.set_name("ports");
   resource.set_type(Value::RANGES);
   resource.mutable_ranges()->CopyFrom(value.ranges());


[08/21] mesos git commit: Adjusted (UN)RESERVE operations to handle reservation refinement [8/20].

Posted by mp...@apache.org.
Adjusted (UN)RESERVE operations to handle reservation refinement [8/20].

The logic for applying RESERVE operations now needs to ensure that the
pre-reserved resources are being refined. In other words, the RESERVE
operation should be "pushing" a single reservation to the stack. Note
that we only support "pushing" a single reservation at a time.

For UNRESERVE, the operation should "pop" the last reservation off the
stack. We only support "popping" a single reservation at a time.

This patch also replaces all of the uses of `flatten()` to
`toUnreserved()` and also removes `flatten()` entirely. We also replace
the uses of `flatten(role, reservation)` except in tests. We'll remove
this version in later patch.

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


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

Branch: refs/heads/master
Commit: 2398ef71b08ff94e3c0e93683e238fbd9ea65aed
Parents: 7877b46
Author: Michael Park <mp...@apache.org>
Authored: Wed Jun 14 23:54:38 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:30:38 2017 -0700

----------------------------------------------------------------------
 include/mesos/resources.hpp                 | 23 -------
 include/mesos/v1/resources.hpp              | 23 -------
 src/cli/execute.cpp                         | 40 +++++++----
 src/common/resources.cpp                    | 85 ++++++------------------
 src/examples/balloon_framework.cpp          |  3 +-
 src/examples/disk_full_framework.cpp        |  2 +-
 src/examples/long_lived_framework.cpp       |  6 +-
 src/examples/test_framework.cpp             |  2 +-
 src/examples/test_http_framework.cpp        |  2 +-
 src/master/allocator/mesos/hierarchical.cpp | 10 +--
 src/master/http.cpp                         | 10 +--
 src/tests/mesos.hpp                         |  2 +-
 src/tests/reservation_endpoints_tests.cpp   |  2 +-
 src/tests/resources_tests.cpp               |  6 +-
 src/v1/resources.cpp                        | 83 +++++------------------
 15 files changed, 88 insertions(+), 211 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/include/mesos/resources.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/resources.hpp b/include/mesos/resources.hpp
index 513b4c3..9f95949 100644
--- a/include/mesos/resources.hpp
+++ b/include/mesos/resources.hpp
@@ -419,29 +419,6 @@ public:
   // This must be called only when the resources are allocated!
   hashmap<std::string, Resources> allocations() const;
 
-  // Returns a Resources object with the same amount of each resource
-  // type as these Resources, but with all Resource objects marked as
-  // the specified (role, reservation) pair. This is used to cross
-  // reservation boundaries without affecting the actual resources.
-  // If the optional ReservationInfo is given, the resource's
-  // 'reservation' field is set. Otherwise, the resource's
-  // 'reservation' field is cleared.
-  // Returns an Error when the role is invalid or the reservation
-  // is set when the role is '*'.
-  //
-  // TODO(mpark): Switch over to using `(push|pop)Reservation` and remove this
-  //              once we change to the 'post-reservation-refinement' format.
-  Try<Resources> flatten(
-      const std::string& role,
-      const Option<Resource::ReservationInfo>& reservation = None()) const;
-
-  // Equivalent to `flatten("*")` except it returns a Resources directly
-  // because the result is always a valid in this case.
-  //
-  // TODO(mpark): Switch over to using `toUnreserved` and remove this once
-  //              we change to the 'post-reservation-refinement' format.
-  Resources flatten() const;
-
   // Returns a `Resources` object with the new reservation added to the back.
   // The new reservation must be a valid refinement of the current reservation.
   Resources pushReservation(const Resource::ReservationInfo& reservation) const;

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/include/mesos/v1/resources.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/v1/resources.hpp b/include/mesos/v1/resources.hpp
index eb7d70c..a621685 100644
--- a/include/mesos/v1/resources.hpp
+++ b/include/mesos/v1/resources.hpp
@@ -419,29 +419,6 @@ public:
   // This must be called only when the resources are allocated!
   hashmap<std::string, Resources> allocations() const;
 
-  // Returns a Resources object with the same amount of each resource
-  // type as these Resources, but with all Resource objects marked as
-  // the specified (role, reservation) pair. This is used to cross
-  // reservation boundaries without affecting the actual resources.
-  // If the optional ReservationInfo is given, the resource's
-  // 'reservation' field is set. Otherwise, the resource's
-  // 'reservation' field is cleared.
-  // Returns an Error when the role is invalid or the reservation
-  // is set when the role is '*'.
-  //
-  // TODO(mpark): Switch over to using `(push|pop)Reservation` and remove this
-  //              once we change to the 'post-reservation-refinement' format.
-  Try<Resources> flatten(
-      const std::string& role,
-      const Option<Resource::ReservationInfo>& reservation = None()) const;
-
-  // Equivalent to `flatten("*")` except it returns a Resources directly
-  // because the result is always a valid in this case.
-  //
-  // TODO(mpark): Switch over to using `toUnreserved` and remove this once
-  //              we change to the 'post-reservation-refinement' format.
-  Resources flatten() const;
-
   // Returns a `Resources` object with the new reservation added to the back.
   // The new reservation must be a valid refinement of the current reservation.
   Resources pushReservation(const Resource::ReservationInfo& reservation) const;

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/cli/execute.cpp
----------------------------------------------------------------------
diff --git a/src/cli/execute.cpp b/src/cli/execute.cpp
index 11a2569..6ab0cb4 100644
--- a/src/cli/execute.cpp
+++ b/src/cli/execute.cpp
@@ -74,6 +74,7 @@ using mesos::v1::Image;
 using mesos::v1::Label;
 using mesos::v1::Labels;
 using mesos::v1::Offer;
+using mesos::v1::Resource;
 using mesos::v1::Resources;
 using mesos::v1::RLimitInfo;
 using mesos::v1::TaskGroupInfo;
@@ -492,7 +493,7 @@ protected:
         }
       }
 
-      if (!launched && offered.flatten().contains(requiredResources)) {
+      if (!launched && offered.toUnreserved().contains(requiredResources)) {
         TaskInfo _task;
         TaskGroupInfo _taskGroup;
 
@@ -501,12 +502,18 @@ protected:
           _task.mutable_agent_id()->MergeFrom(offer.agent_id());
 
           // Takes resources first from the specified role, then from '*'.
-          Try<Resources> flattened =
-            Resources(_task.resources()).flatten(frameworkInfo.role());
-
-          // `frameworkInfo.role()` must be valid as it's allowed to register.
-          CHECK_SOME(flattened);
-          Option<Resources> resources = offered.find(flattened.get());
+          Option<Resources> resources = [&]() {
+            if (frameworkInfo.role() == "*") {
+              return offered.find(Resources(_task.resources()));
+            } else {
+              Resource::ReservationInfo reservation;
+              reservation.set_type(Resource::ReservationInfo::STATIC);
+              reservation.set_role(frameworkInfo.role());
+
+              return offered.find(
+                  Resources(_task.resources()).pushReservation(reservation));
+            }
+          }();
 
           CHECK_SOME(resources);
 
@@ -516,13 +523,18 @@ protected:
             _task.mutable_agent_id()->MergeFrom(offer.agent_id());
 
             // Takes resources first from the specified role, then from '*'.
-            Try<Resources> flattened =
-              Resources(_task.resources()).flatten(frameworkInfo.role());
-
-            // `frameworkInfo.role()` must be valid as it's allowed to
-            // register.
-            CHECK_SOME(flattened);
-            Option<Resources> resources = offered.find(flattened.get());
+            Option<Resources> resources = [&]() {
+              if (frameworkInfo.role() == "*") {
+                return offered.find(Resources(_task.resources()));
+              } else {
+                Resource::ReservationInfo reservation;
+                reservation.set_type(Resource::ReservationInfo::STATIC);
+                reservation.set_role(frameworkInfo.role());
+
+                return offered.find(
+                    Resources(_task.resources()).pushReservation(reservation));
+              }
+            }();
 
             CHECK_SOME(resources);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/common/resources.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources.cpp b/src/common/resources.cpp
index 1dd058f..b8c5756 100644
--- a/src/common/resources.cpp
+++ b/src/common/resources.cpp
@@ -1434,48 +1434,6 @@ hashmap<string, Resources> Resources::allocations() const
 }
 
 
-Try<Resources> Resources::flatten(
-    const string& role,
-    const Option<Resource::ReservationInfo>& reservation) const
-{
-  // Check role name.
-  Option<Error> error = roles::validate(role);
-  if (error.isSome()) {
-    return error.get();
-  }
-
-  // Checks for the invalid state of (role, reservation) pair.
-  if (role == "*" && reservation.isSome()) {
-    return Error(
-        "Invalid reservation: role \"*\" cannot be dynamically reserved");
-  }
-
-  Resources flattened;
-
-  foreach (Resource_ resource_, resources) {
-    // With the above checks, we are certain that `resource_` will
-    // remain valid after the modifications.
-    resource_.resource.set_role(role);
-    if (reservation.isNone()) {
-      resource_.resource.clear_reservation();
-    } else {
-      resource_.resource.mutable_reservation()->CopyFrom(reservation.get());
-    }
-    flattened.add(resource_);
-  }
-
-  return flattened;
-}
-
-
-Resources Resources::flatten() const
-{
-  Try<Resources> flattened = flatten("*");
-  CHECK_SOME(flattened);
-  return flattened.get();
-}
-
-
 Resources Resources::pushReservation(
     const Resource::ReservationInfo& reservation) const
 {
@@ -1596,14 +1554,15 @@ Try<Resources> Resources::apply(const Offer::Operation& operation) const
               " dynamically reserved");
         }
 
-        Resources unreserved = Resources(reserved).flatten();
+        // Note that we only allow "pushing" a single reservation at time.
+        Resources resources = Resources(reserved).popReservation();
 
-        if (!result.contains(unreserved)) {
+        if (!result.contains(resources)) {
           return Error("Invalid RESERVE Operation: " + stringify(result) +
-                       " does not contain " + stringify(unreserved));
+                       " does not contain " + stringify(resources));
         }
 
-        result -= unreserved;
+        result -= resources;
         result.add(reserved);
       }
       break;
@@ -1629,10 +1588,11 @@ Try<Resources> Resources::apply(const Offer::Operation& operation) const
                        " does not contain " + stringify(reserved));
         }
 
-        Resources unreserved = Resources(reserved).flatten();
+        // Note that we only allow "popping" a single reservation at time.
+        Resources resources = Resources(reserved).popReservation();
 
         result.subtract(reserved);
-        result += unreserved;
+        result += resources;
       }
       break;
     }
@@ -1936,7 +1896,7 @@ Option<Resources> Resources::find(const Resource& target) const
 {
   Resources found;
   Resources total = *this;
-  Resources remaining = Resources(target).flatten();
+  Resources remaining = Resources(target).toUnreserved();
 
   // First look in the target role, then unreserved, then any remaining role.
   vector<lambda::function<bool(const Resource&)>> predicates;
@@ -1951,28 +1911,23 @@ Option<Resources> Resources::find(const Resource& target) const
 
   foreach (const auto& predicate, predicates) {
     foreach (const Resource_& resource_, total.filter(predicate)) {
-      // Need to flatten to ignore the roles in contains().
-      Resources flattened = Resources(resource_.resource).flatten();
+      // Need to `toUnreserved` to ignore the roles in contains().
+      Resources unreserved = Resources(resource_.resource).toUnreserved();
 
-      if (flattened.contains(remaining)) {
+      if (unreserved.contains(remaining)) {
         // The target has been found, return the result.
-        if (!resource_.resource.has_reservation()) {
-          Try<Resources> _flattened =
-            remaining.flatten(resource_.resource.role());
+        foreach (Resource_ r, remaining) {
+          r.resource.mutable_reservations()->CopyFrom(
+              resource_.resource.reservations());
 
-          CHECK_SOME(_flattened);
-          return found + _flattened.get();
-        } else {
-          Try<Resources> _flattened = remaining.flatten(
-              resource_.resource.role(), resource_.resource.reservation());
-
-          CHECK_SOME(_flattened);
-          return found + _flattened.get();
+          found.add(r);
         }
-      } else if (remaining.contains(flattened)) {
+
+        return found;
+      } else if (remaining.contains(unreserved)) {
         found.add(resource_);
         total.subtract(resource_);
-        remaining -= flattened;
+        remaining -= unreserved;
         break;
       }
     }

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/examples/balloon_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/balloon_framework.cpp b/src/examples/balloon_framework.cpp
index bfaae37..51b01cf 100644
--- a/src/examples/balloon_framework.cpp
+++ b/src/examples/balloon_framework.cpp
@@ -178,7 +178,8 @@ public:
       // If there is an active task, or if the offer is not
       // big enough, reject the offer.
       if (taskActive ||
-          !resources.flatten().contains(taskResources + executorResources)) {
+          !resources.toUnreserved().contains(
+              taskResources + executorResources)) {
         Filters filters;
         filters.set_refuse_seconds(600);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/examples/disk_full_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/disk_full_framework.cpp b/src/examples/disk_full_framework.cpp
index a73e6cf..6c7bae6 100644
--- a/src/examples/disk_full_framework.cpp
+++ b/src/examples/disk_full_framework.cpp
@@ -153,7 +153,7 @@ public:
 
       // If we've already launched the task, or if the offer is not
       // big enough, reject the offer.
-      if (taskActive || !resources.flatten().contains(taskResources)) {
+      if (taskActive || !resources.toUnreserved().contains(taskResources)) {
         Filters filters;
         filters.set_refuse_seconds(600);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/examples/long_lived_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/long_lived_framework.cpp b/src/examples/long_lived_framework.cpp
index bbe8606..bdf20a7 100644
--- a/src/examples/long_lived_framework.cpp
+++ b/src/examples/long_lived_framework.cpp
@@ -246,7 +246,7 @@ protected:
         // No active executor running in the cluster.
         // Launch a new task with executor.
 
-        if (Resources(offer.resources()).flatten()
+        if (Resources(offer.resources()).toUnreserved()
             .contains(EXECUTOR_RESOURCES + taskResources)) {
           LOG(INFO)
             << "Starting executor and task " << tasksLaunched
@@ -262,7 +262,9 @@ protected:
         // Offer from the same agent that has an active executor.
         // Launch more tasks on that executor.
 
-        if (Resources(offer.resources()).flatten().contains(taskResources)) {
+        if (Resources(offer.resources())
+              .toUnreserved()
+              .contains(taskResources)) {
           LOG(INFO)
             << "Starting task " << tasksLaunched << " on " << offer.hostname();
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/examples/test_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/test_framework.cpp b/src/examples/test_framework.cpp
index 05ddc89..db3f5e2 100644
--- a/src/examples/test_framework.cpp
+++ b/src/examples/test_framework.cpp
@@ -95,7 +95,7 @@ public:
       // Launch tasks.
       vector<TaskInfo> tasks;
       while (tasksLaunched < totalTasks &&
-             remaining.flatten().contains(taskResources)) {
+             remaining.toUnreserved().contains(taskResources)) {
         int taskId = tasksLaunched++;
 
         cout << "Launching task " << taskId << " using offer "

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/examples/test_http_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/test_http_framework.cpp b/src/examples/test_http_framework.cpp
index 471835c..2a58b4e 100644
--- a/src/examples/test_http_framework.cpp
+++ b/src/examples/test_http_framework.cpp
@@ -232,7 +232,7 @@ private:
       // Launch tasks.
       vector<TaskInfo> tasks;
       while (tasksLaunched < totalTasks &&
-             remaining.flatten().contains(taskResources)) {
+             remaining.toUnreserved().contains(taskResources)) {
         int taskId = tasksLaunched++;
 
         cout << "Launching task " << taskId << " using offer "

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/master/allocator/mesos/hierarchical.cpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/mesos/hierarchical.cpp b/src/master/allocator/mesos/hierarchical.cpp
index 775fe41..d1fad0d 100644
--- a/src/master/allocator/mesos/hierarchical.cpp
+++ b/src/master/allocator/mesos/hierarchical.cpp
@@ -900,14 +900,14 @@ void HierarchicalAllocatorProcess::updateAllocation(
   frameworkSorter->remove(slaveId, offeredResources);
   frameworkSorter->add(slaveId, updatedOfferedResources);
 
-  // Check that the `flattened` quantities for framework allocations
+  // Check that the unreserved quantities for framework allocations
   // have not changed by the above operations.
   const Resources updatedFrameworkAllocation =
     frameworkSorter->allocation(frameworkId.value(), slaveId);
 
   CHECK_EQ(
-      frameworkAllocation.flatten().createStrippedScalarQuantity(),
-      updatedFrameworkAllocation.flatten().createStrippedScalarQuantity());
+      frameworkAllocation.toUnreserved().createStrippedScalarQuantity(),
+      updatedFrameworkAllocation.toUnreserved().createStrippedScalarQuantity());
 
   LOG(INFO) << "Updated allocation of framework " << frameworkId
             << " on agent " << slaveId
@@ -1545,8 +1545,8 @@ void HierarchicalAllocatorProcess::__allocate()
 
     // NOTE: `allocationScalarQuantities` omits dynamic reservation,
     // persistent volume info, and allocation info. We additionally
-    // strip the `Resource.role` here via `flatten()`.
-    return quotaRoleSorter->allocationScalarQuantities(role).flatten();
+    // remove the resource's `role` here via `toUnreserved()`.
+    return quotaRoleSorter->allocationScalarQuantities(role).toUnreserved();
   };
 
   // Due to the two stages in the allocation algorithm and the nature of

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index 4f83849..a9ed358 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -2271,11 +2271,11 @@ Future<Response> Master::Http::_reserve(
         return Forbidden();
       }
 
-      // NOTE: `flatten()` is important. To make a dynamic reservation,
-      // we want to ensure that the required resources are available
-      // and unreserved; `flatten()` removes the role and
-      // ReservationInfo from the resources.
-      return _operation(slaveId, resources.flatten(), operation);
+      // We only allow "pushing" a single reservation at a time, so we require
+      // the resources with one reservation "popped" to be present on the agent.
+      Resources required = resources.popReservation();
+
+      return _operation(slaveId, required, operation);
     }));
 }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/tests/mesos.hpp
----------------------------------------------------------------------
diff --git a/src/tests/mesos.hpp b/src/tests/mesos.hpp
index b938333..3fff10f 100644
--- a/src/tests/mesos.hpp
+++ b/src/tests/mesos.hpp
@@ -1676,7 +1676,7 @@ ACTION_P5(LaunchTasks, executor, tasks, cpus, mem, role)
     std::vector<TaskInfo> tasks;
     Resources remaining = offer.resources();
 
-    while (remaining.flatten().contains(taskResources) &&
+    while (remaining.toUnreserved().contains(taskResources) &&
            launched < numTasks) {
       TaskInfo task;
       task.set_name("TestTask");

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/tests/reservation_endpoints_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/reservation_endpoints_tests.cpp b/src/tests/reservation_endpoints_tests.cpp
index ba283ee..c34f767 100644
--- a/src/tests/reservation_endpoints_tests.cpp
+++ b/src/tests/reservation_endpoints_tests.cpp
@@ -505,7 +505,7 @@ TEST_F(ReservationEndpointsTest, UnreserveAvailableAndOfferedResources)
       createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
 
   Resources total = available + offered;
-  Resources unreserved = total.flatten();
+  Resources unreserved = total.toUnreserved();
 
   Future<Response> response = process::http::post(
       master.get()->pid,

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/tests/resources_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/resources_tests.cpp b/src/tests/resources_tests.cpp
index a44490a..f19f5f1 100644
--- a/src/tests/resources_tests.cpp
+++ b/src/tests/resources_tests.cpp
@@ -1715,7 +1715,7 @@ TEST(ResourceProviderIDTest, Contains) {
 }
 
 
-TEST(ResourcesTest, FlattenRoles)
+TEST(ResourcesTest, ToUnreserved)
 {
   Resource cpus1 = Resources::parse("cpus", "1", "role1").get();
   Resource cpus2 = Resources::parse("cpus", "2", "role2").get();
@@ -1726,7 +1726,7 @@ TEST(ResourcesTest, FlattenRoles)
   r += cpus2;
   r += mem1;
 
-  EXPECT_EQ(r.flatten(), Resources::parse("cpus:3;mem:5").get());
+  EXPECT_EQ(r.toUnreserved(), Resources::parse("cpus:3;mem:5").get());
 }
 
 
@@ -2422,7 +2422,7 @@ TEST(ResourcesOperationTest, UnreserveResources)
 
   Resources reserved = reservedCpus + reservedMem;
 
-  Resources unreservedCpus1 = reservedCpus.flatten();
+  Resources unreservedCpus1 = reservedCpus.toUnreserved();
 
   EXPECT_SOME_EQ(reservedMem + unreservedCpus1,
                  reserved.apply(UNRESERVE(reservedCpus)));

http://git-wip-us.apache.org/repos/asf/mesos/blob/2398ef71/src/v1/resources.cpp
----------------------------------------------------------------------
diff --git a/src/v1/resources.cpp b/src/v1/resources.cpp
index a9b0233..b002bf7 100644
--- a/src/v1/resources.cpp
+++ b/src/v1/resources.cpp
@@ -1465,48 +1465,6 @@ hashmap<string, Resources> Resources::allocations() const
 }
 
 
-Try<Resources> Resources::flatten(
-    const string& role,
-    const Option<Resource::ReservationInfo>& reservation) const
-{
-  // Check role name.
-  Option<Error> error = roles::validate(role);
-  if (error.isSome()) {
-    return error.get();
-  }
-
-  // Checks for the invalid state of (role, reservation) pair.
-  if (role == "*" && reservation.isSome()) {
-    return Error(
-        "Invalid reservation: role \"*\" cannot be dynamically reserved");
-  }
-
-  Resources flattened;
-
-  foreach (Resource_ resource_, resources) {
-    // With the above checks, we are certain that `resource_` will
-    // remain valid after the modifications.
-    resource_.resource.set_role(role);
-    if (reservation.isNone()) {
-      resource_.resource.clear_reservation();
-    } else {
-      resource_.resource.mutable_reservation()->CopyFrom(reservation.get());
-    }
-    flattened.add(resource_);
-  }
-
-  return flattened;
-}
-
-
-Resources Resources::flatten() const
-{
-  Try<Resources> flattened = flatten("*");
-  CHECK_SOME(flattened);
-  return flattened.get();
-}
-
-
 Resources Resources::pushReservation(
     const Resource::ReservationInfo& reservation) const
 {
@@ -1627,14 +1585,14 @@ Try<Resources> Resources::apply(const Offer::Operation& operation) const
               " dynamically reserved");
         }
 
-        Resources unreserved = Resources(reserved).flatten();
+        Resources resources = Resources(reserved).popReservation();
 
-        if (!result.contains(unreserved)) {
+        if (!result.contains(resources)) {
           return Error("Invalid RESERVE Operation: " + stringify(result) +
-                       " does not contain " + stringify(unreserved));
+                       " does not contain " + stringify(resources));
         }
 
-        result -= unreserved;
+        result -= resources;
         result.add(reserved);
       }
       break;
@@ -1660,10 +1618,10 @@ Try<Resources> Resources::apply(const Offer::Operation& operation) const
                        " does not contain " + stringify(reserved));
         }
 
-        Resources unreserved = Resources(reserved).flatten();
+        Resources resources = Resources(reserved).popReservation();
 
         result.subtract(reserved);
-        result += unreserved;
+        result += resources;
       }
       break;
     }
@@ -1967,7 +1925,7 @@ Option<Resources> Resources::find(const Resource& target) const
 {
   Resources found;
   Resources total = *this;
-  Resources remaining = Resources(target).flatten();
+  Resources remaining = Resources(target).toUnreserved();
 
   // First look in the target role, then unreserved, then any remaining role.
   vector<lambda::function<bool(const Resource&)>> predicates;
@@ -1982,28 +1940,23 @@ Option<Resources> Resources::find(const Resource& target) const
 
   foreach (const auto& predicate, predicates) {
     foreach (const Resource_& resource_, total.filter(predicate)) {
-      // Need to flatten to ignore the roles in contains().
-      Resources flattened = Resources(resource_.resource).flatten();
+      // Need to `toUnreserved` to ignore the roles in contains().
+      Resources unreserved = Resources(resource_.resource).toUnreserved();
 
-      if (flattened.contains(remaining)) {
+      if (unreserved.contains(remaining)) {
         // The target has been found, return the result.
-        if (!resource_.resource.has_reservation()) {
-          Try<Resources> _flattened =
-            remaining.flatten(resource_.resource.role());
+        foreach (Resource_ r, remaining) {
+          r.resource.mutable_reservations()->CopyFrom(
+              resource_.resource.reservations());
 
-          CHECK_SOME(_flattened);
-          return found + _flattened.get();
-        } else {
-          Try<Resources> _flattened = remaining.flatten(
-              resource_.resource.role(), resource_.resource.reservation());
-
-          CHECK_SOME(_flattened);
-          return found + _flattened.get();
+          found.add(r);
         }
-      } else if (remaining.contains(flattened)) {
+
+        return found;
+      } else if (remaining.contains(unreserved)) {
         found.add(resource_);
         total.subtract(resource_);
-        remaining -= flattened;
+        remaining -= unreserved;
         break;
       }
     }


[06/21] mesos git commit: Resources: Adjusted `parse` to produce new resource format [6/20].

Posted by mp...@apache.org.
Resources: Adjusted `parse` to produce new resource format [6/20].

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


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

Branch: refs/heads/master
Commit: 76b0f4ed82a51ab9eec3dc2b0d1542c8b29d1ab6
Parents: 0bae267
Author: Michael Park <mc...@gmail.com>
Authored: Tue Jun 13 01:40:21 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:30:30 2017 -0700

----------------------------------------------------------------------
 src/common/resources.cpp       | 21 +++++++++++++---
 src/common/resources_utils.cpp |  3 ++-
 src/v1/resources.cpp           | 50 ++++++++++++++++++++++++++++++++++---
 3 files changed, 65 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/76b0f4ed/src/common/resources.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources.cpp b/src/common/resources.cpp
index c088ee2..d1b9a9e 100644
--- a/src/common/resources.cpp
+++ b/src/common/resources.cpp
@@ -38,6 +38,8 @@
 #include <stout/strings.hpp>
 #include <stout/unreachable.hpp>
 
+#include "common/resources_utils.hpp"
+
 using std::map;
 using std::ostream;
 using std::set;
@@ -604,7 +606,12 @@ Try<Resource> Resources::parse(
 
   Value _value = result.get();
   resource.set_name(name);
-  resource.set_role(role);
+
+  if (role != "*") {
+    Resource::ReservationInfo* reservation = resource.add_reservations();
+    reservation->set_type(Resource::ReservationInfo::STATIC);
+    reservation->set_role(role);
+  }
 
   if (_value.type() == Value::SCALAR) {
     resource.set_type(Value::SCALAR);
@@ -640,14 +647,17 @@ Try<Resources> Resources::parse(
 
   Resources result;
 
-  // Validate individual Resource objects.
-  foreach (const Resource& resource, resources.get()) {
+  // Validate the Resource objects and convert them
+  // to the "post-reservation-refinement" format.
+  foreach (Resource resource, resources.get()) {
     // If invalid, propgate error instead of skipping the resource.
     Option<Error> error = Resources::validate(resource);
     if (error.isSome()) {
       return error.get();
     }
 
+    convertResourceFormat(&resource, POST_RESERVATION_REFINEMENT);
+
     result.add(resource);
   }
 
@@ -680,7 +690,10 @@ Try<vector<Resource>> Resources::fromJSON(
 
   foreach (Resource& resource, resourcesProtobuf.get()) {
     // Set the default role if none was specified.
-    if (!resource.has_role()) {
+    //
+    // NOTE: We rely on the fact that the result of this function is
+    // converted to the "post-reservation-refinement" format.
+    if (!resource.has_role() && resource.reservations_size() == 0) {
       resource.set_role(defaultRole);
     }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/76b0f4ed/src/common/resources_utils.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources_utils.cpp b/src/common/resources_utils.cpp
index 4671477..751194c 100644
--- a/src/common/resources_utils.cpp
+++ b/src/common/resources_utils.cpp
@@ -148,7 +148,8 @@ void convertResourceFormat(Resource* resource, ResourceFormat format)
       }
 
       // Unreserved resources.
-      if (resource->role() == "*" && !resource->has_reservation()) {
+      if (resource->role() == "*") {
+        CHECK(!resource->has_reservation());
         resource->clear_role();
         return;
       }

http://git-wip-us.apache.org/repos/asf/mesos/blob/76b0f4ed/src/v1/resources.cpp
----------------------------------------------------------------------
diff --git a/src/v1/resources.cpp b/src/v1/resources.cpp
index 0fd8eac..a853f80 100644
--- a/src/v1/resources.cpp
+++ b/src/v1/resources.cpp
@@ -606,7 +606,12 @@ Try<Resource> Resources::parse(
 
   Value _value = result.get();
   resource.set_name(name);
-  resource.set_role(role);
+
+  if (role != "*") {
+    Resource::ReservationInfo* reservation = resource.add_reservations();
+    reservation->set_type(Resource::ReservationInfo::STATIC);
+    reservation->set_role(role);
+  }
 
   if (_value.type() == Value::SCALAR) {
     resource.set_type(Value::SCALAR);
@@ -642,14 +647,48 @@ Try<Resources> Resources::parse(
 
   Resources result;
 
-  // Validate individual Resource objects.
-  foreach (const Resource& resource, resources.get()) {
+  // Validate the Resource objects and convert them
+  // to the "post-reservation-refinement" format.
+  foreach (Resource resource, resources.get()) {
     // If invalid, propgate error instead of skipping the resource.
     Option<Error> error = Resources::validate(resource);
     if (error.isSome()) {
       return error.get();
     }
 
+    // Convert the resource to the "post-reservation-refinement" format.
+    if (resource.reservations_size() > 0) {
+      // In this case, we're either already in
+      // the "post-reservation-refinement" format,
+      // or we're in the "endpoint" format.
+
+      // We clear out the "pre-reservation-refinement" fields
+      // in case the resources are in the "endpoint" format.
+      resource.clear_role();
+      resource.clear_reservation();
+    } else if (resource.role() == "*") {
+      CHECK(!resource.has_reservation());
+      // Unreserved resources.
+      resource.clear_role();
+    } else {
+      // Resource with a single reservation.
+      Resource::ReservationInfo* reservation = resource.add_reservations();
+
+      // Check the `Resource.reservation` to determine whether
+      // we have a static or dynamic reservation.
+      if (!resource.has_reservation()) {
+        reservation->set_type(Resource::ReservationInfo::STATIC);
+      } else {
+        reservation->CopyFrom(resource.reservation());
+        resource.clear_reservation();
+        reservation->set_type(Resource::ReservationInfo::DYNAMIC);
+      }
+
+      reservation->set_role(resource.role());
+      resource.clear_role();
+    }
+
+    // Add the validated and converted resource to the result.
     result.add(resource);
   }
 
@@ -682,7 +721,10 @@ Try<vector<Resource>> Resources::fromJSON(
 
   foreach (Resource& resource, resourcesProtobuf.get()) {
     // Set the default role if none was specified.
-    if (!resource.has_role()) {
+    //
+    // NOTE: We rely on the fact that the result of this function is
+    // converted to the "post-reservation-refinement" format.
+    if (!resource.has_role() && resource.reservations_size() == 0) {
       resource.set_role(defaultRole);
     }
 


[18/21] mesos git commit: Added `RESERVATION_REFINEMENT` capability to tests [18/20].

Posted by mp...@apache.org.
Added `RESERVATION_REFINEMENT` capability to tests [18/20].

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


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

Branch: refs/heads/master
Commit: ded150a97c6e80af6a7df440c313e85cf2a25fe3
Parents: 42a1913
Author: Michael Park <mp...@apache.org>
Authored: Tue Jun 20 01:10:15 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Tue Jun 20 02:44:36 2017 -0700

----------------------------------------------------------------------
 src/examples/disk_full_framework.cpp           |  2 ++
 src/examples/dynamic_reservation_framework.cpp |  2 ++
 src/examples/no_executor_framework.cpp         |  2 ++
 src/examples/persistent_volume_framework.cpp   |  2 ++
 src/examples/test_framework.cpp                |  2 ++
 src/examples/test_http_framework.cpp           |  2 ++
 src/tests/fault_tolerance_tests.cpp            | 10 ++++++++++
 src/tests/master_tests.cpp                     |  5 +++++
 src/tests/master_validation_tests.cpp          |  5 +++++
 src/tests/mesos.hpp                            |  2 ++
 10 files changed, 34 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/ded150a9/src/examples/disk_full_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/disk_full_framework.cpp b/src/examples/disk_full_framework.cpp
index 6c7bae6..9d189fa 100644
--- a/src/examples/disk_full_framework.cpp
+++ b/src/examples/disk_full_framework.cpp
@@ -436,6 +436,8 @@ int main(int argc, char** argv)
   framework.set_user(""); // Have Mesos fill the current user.
   framework.set_name("Disk Full Framework (C++)");
   framework.set_checkpoint(true);
+  framework.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   DiskFullScheduler scheduler(flags, framework);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/ded150a9/src/examples/dynamic_reservation_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/dynamic_reservation_framework.cpp b/src/examples/dynamic_reservation_framework.cpp
index 4122814..14b9c40 100644
--- a/src/examples/dynamic_reservation_framework.cpp
+++ b/src/examples/dynamic_reservation_framework.cpp
@@ -381,6 +381,8 @@ int main(int argc, char** argv)
   framework.set_name("Dynamic Reservation Framework (C++)");
   framework.set_role(flags.role.get());
   framework.set_principal(flags.principal);
+  framework.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   DynamicReservationScheduler scheduler(
       flags.command,

http://git-wip-us.apache.org/repos/asf/mesos/blob/ded150a9/src/examples/no_executor_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/no_executor_framework.cpp b/src/examples/no_executor_framework.cpp
index 77b7408..7d841c6 100644
--- a/src/examples/no_executor_framework.cpp
+++ b/src/examples/no_executor_framework.cpp
@@ -329,6 +329,8 @@ int main(int argc, char** argv)
   framework.set_user(""); // Have Mesos fill in the current user.
   framework.set_name("No Executor Framework");
   framework.set_checkpoint(flags.checkpoint);
+  framework.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   if (flags.task_revocable_resources.isSome()) {
     framework.add_capabilities()->set_type(

http://git-wip-us.apache.org/repos/asf/mesos/blob/ded150a9/src/examples/persistent_volume_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/persistent_volume_framework.cpp b/src/examples/persistent_volume_framework.cpp
index ab4597d..1714029 100644
--- a/src/examples/persistent_volume_framework.cpp
+++ b/src/examples/persistent_volume_framework.cpp
@@ -579,6 +579,8 @@ int main(int argc, char** argv)
   framework.set_principal(flags.principal);
   framework.add_capabilities()->set_type(
       FrameworkInfo::Capability::SHARED_RESOURCES);
+  framework.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   if (flags.master.get() == "local") {
     // Configure master.

http://git-wip-us.apache.org/repos/asf/mesos/blob/ded150a9/src/examples/test_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/test_framework.cpp b/src/examples/test_framework.cpp
index db3f5e2..53edc6a 100644
--- a/src/examples/test_framework.cpp
+++ b/src/examples/test_framework.cpp
@@ -250,6 +250,8 @@ int main(int argc, char** argv)
   framework.set_user(""); // Have Mesos fill in the current user.
   framework.set_name("Test Framework (C++)");
   framework.set_role(flags.role);
+  framework.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   value = os::getenv("MESOS_CHECKPOINT");
   if (value.isSome()) {

http://git-wip-us.apache.org/repos/asf/mesos/blob/ded150a9/src/examples/test_http_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/test_http_framework.cpp b/src/examples/test_http_framework.cpp
index 2a58b4e..ce1a92c 100644
--- a/src/examples/test_http_framework.cpp
+++ b/src/examples/test_http_framework.cpp
@@ -430,6 +430,8 @@ int main(int argc, char** argv)
   FrameworkInfo framework;
   framework.set_name("Event Call Scheduler using libprocess (C++)");
   framework.set_role(flags.role);
+  framework.add_capabilities()->set_type(
+      FrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
   const Result<string> user = os::user();
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/ded150a9/src/tests/fault_tolerance_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/fault_tolerance_tests.cpp b/src/tests/fault_tolerance_tests.cpp
index d48ff04..5b82135 100644
--- a/src/tests/fault_tolerance_tests.cpp
+++ b/src/tests/fault_tolerance_tests.cpp
@@ -2040,6 +2040,11 @@ TEST_F(FaultToleranceTest, UpdateFrameworkInfoOnSchedulerFailover)
   // scheduler with updated information.
 
   FrameworkInfo finfo1 = DEFAULT_FRAMEWORK_INFO;
+
+  // TODO(mpark): Remove this once `RESERVATION_REFINEMENT`
+  // is removed from `DEFAULT_FRAMEWORK_INFO`.
+  finfo1.clear_capabilities();
+
   finfo1.set_name("Framework 1");
   finfo1.set_failover_timeout(1000);
   finfo1.mutable_labels()->add_labels()->CopyFrom(createLabel("foo", "bar"));
@@ -2065,6 +2070,11 @@ TEST_F(FaultToleranceTest, UpdateFrameworkInfoOnSchedulerFailover)
   // callback.
 
   FrameworkInfo finfo2 = DEFAULT_FRAMEWORK_INFO;
+
+  // TODO(mpark): Remove this once `RESERVATION_REFINEMENT`
+  // is removed from `DEFAULT_FRAMEWORK_INFO`.
+  finfo2.clear_capabilities();
+
   finfo2.mutable_id()->MergeFrom(frameworkId.get());
   auto capabilityType = FrameworkInfo::Capability::REVOCABLE_RESOURCES;
   finfo2.add_capabilities()->set_type(capabilityType);

http://git-wip-us.apache.org/repos/asf/mesos/blob/ded150a9/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index 1c9b9a0..652f37a 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -4052,6 +4052,11 @@ TEST_F(MasterTest, StateEndpointFrameworkInfo)
   AWAIT_READY(slaveRegisteredMessage);
 
   FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
+
+  // TODO(mpark): Remove this once `RESERVATION_REFINEMENT`
+  // is removed from `DEFAULT_FRAMEWORK_INFO`.
+  frameworkInfo.clear_capabilities();
+
   frameworkInfo.set_webui_url("http://localhost:8080/");
 
   vector<FrameworkInfo::Capability::Type> capabilities = {

http://git-wip-us.apache.org/repos/asf/mesos/blob/ded150a9/src/tests/master_validation_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_validation_tests.cpp b/src/tests/master_validation_tests.cpp
index 83370fa..e392ce4 100644
--- a/src/tests/master_validation_tests.cpp
+++ b/src/tests/master_validation_tests.cpp
@@ -3601,6 +3601,11 @@ TEST_F(FrameworkInfoValidationTest, DowngradeFromMultipleRoles)
   ASSERT_SOME(master);
 
   FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO;
+
+  // TODO(mpark): Remove this once `RESERVATION_REFINEMENT`
+  // is removed from `DEFAULT_FRAMEWORK_INFO`.
+  frameworkInfo.clear_capabilities();
+
   frameworkInfo.add_roles("role1");
   frameworkInfo.add_roles("role2");
   frameworkInfo.add_capabilities()->set_type(

http://git-wip-us.apache.org/repos/asf/mesos/blob/ded150a9/src/tests/mesos.hpp
----------------------------------------------------------------------
diff --git a/src/tests/mesos.hpp b/src/tests/mesos.hpp
index e9e4f86..eac2c96 100644
--- a/src/tests/mesos.hpp
+++ b/src/tests/mesos.hpp
@@ -439,6 +439,8 @@ struct DefaultFrameworkInfo
     framework.set_user(os::user().get());
     framework.set_principal(
         DefaultCredential<TCredential>::create().principal());
+    framework.add_capabilities()->set_type(
+        TFrameworkInfo::Capability::RESERVATION_REFINEMENT);
 
     return framework;
   }