Repository: mesos Updated Branches: refs/heads/master f9cb6f496 -> 491371c77
Avoided resource validation when flattening resources. Instead of validating each resource, in flatten(...) we validate the arguments just once. We can then use validation-free `add()` instead of `+=`. 1) Previously if role or reservation info are invalid, the result is an empty Resources object, now it returns an error. 2) Added a new flatten() method to flatten resources with star role and empty reservation. Review: https://reviews.apache.org/r/51683/ Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/491371c7 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/491371c7 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/491371c7 Branch: refs/heads/master Commit: 491371c773cec8b565fe643f33682ee5cce267c7 Parents: f9cb6f4 Author: Guangya Liu <gyliu...@gmail.com> Authored: Fri Sep 16 15:50:09 2016 -0700 Committer: Jiang Yan Xu <xuj...@apple.com> Committed: Fri Sep 16 16:06:44 2016 -0700 ---------------------------------------------------------------------- include/mesos/resources.hpp | 10 ++- include/mesos/v1/resources.hpp | 10 ++- src/cli/execute.cpp | 8 ++- src/common/resources.cpp | 37 +++++++++-- src/examples/dynamic_reservation_framework.cpp | 5 +- src/examples/test_framework.cpp | 5 +- src/examples/test_http_framework.cpp | 5 +- src/tests/api_tests.cpp | 4 +- src/tests/hierarchical_allocator_tests.cpp | 6 +- src/tests/mesos.hpp | 2 +- src/tests/persistent_volume_endpoints_tests.cpp | 18 +++--- src/tests/reservation_endpoints_tests.cpp | 48 +++++++-------- src/tests/reservation_tests.cpp | 64 +++++++++++++------- src/tests/resources_tests.cpp | 24 +++++++- src/tests/role_tests.cpp | 3 +- src/v1/resources.cpp | 35 +++++++++-- 16 files changed, 200 insertions(+), 84 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/include/mesos/resources.hpp ---------------------------------------------------------------------- diff --git a/include/mesos/resources.hpp b/include/mesos/resources.hpp index 7ba422d..3ef8cac 100644 --- a/include/mesos/resources.hpp +++ b/include/mesos/resources.hpp @@ -348,10 +348,16 @@ public: // If the optional ReservationInfo is given, the resource's // 'reservation' field is set. Otherwise, the resource's // 'reservation' field is cleared. - Resources flatten( - const std::string& role = "*", + // Returns an Error when the role is invalid or the reservation + // is set when the role is '*'. + 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. + Resources flatten() const; + // Returns a Resources object that contains all the scalar resources // in this object, but with their ReservationInfo and DiskInfo // omitted. Note that the `role` and RevocableInfo, if any, are http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/include/mesos/v1/resources.hpp ---------------------------------------------------------------------- diff --git a/include/mesos/v1/resources.hpp b/include/mesos/v1/resources.hpp index add48c7..ef56b49 100644 --- a/include/mesos/v1/resources.hpp +++ b/include/mesos/v1/resources.hpp @@ -348,10 +348,16 @@ public: // If the optional ReservationInfo is given, the resource's // 'reservation' field is set. Otherwise, the resource's // 'reservation' field is cleared. - Resources flatten( - const std::string& role = "*", + // Returns an Error when the role is invalid or the reservation + // is set when the role is '*'. + 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. + Resources flatten() const; + // Returns a Resources object that contains all the scalar resources // in this object, but with their ReservationInfo and DiskInfo // omitted. Note that the `role` and RevocableInfo, if any, are http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/cli/execute.cpp ---------------------------------------------------------------------- diff --git a/src/cli/execute.cpp b/src/cli/execute.cpp index c9f56af..525c898 100644 --- a/src/cli/execute.cpp +++ b/src/cli/execute.cpp @@ -373,8 +373,12 @@ protected: task.mutable_agent_id()->MergeFrom(offer.agent_id()); // Takes resources first from the specified role, then from '*'. - Option<Resources> resources = - offered.find(TASK_RESOURCES.get().flatten(frameworkInfo.role())); + Try<Resources> flattened = + TASK_RESOURCES.get().flatten(frameworkInfo.role()); + + // `frameworkInfo.role()` must be valid as it's allowed to register. + CHECK_SOME(flattened); + Option<Resources> resources = offered.find(flattened.get()); CHECK_SOME(resources); http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/common/resources.cpp ---------------------------------------------------------------------- diff --git a/src/common/resources.cpp b/src/common/resources.cpp index aa4d6b5..4602bff 100644 --- a/src/common/resources.cpp +++ b/src/common/resources.cpp @@ -1077,26 +1077,48 @@ Resources Resources::nonShared() const } -Resources Resources::flatten( +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 += resource_; + flattened.add(resource_); } return flattened; } +Resources Resources::flatten() const +{ + Try<Resources> flattened = flatten("*"); + CHECK_SOME(flattened); + return flattened.get(); +} + + Resources Resources::createStrippedScalarQuantity() const { Resources stripped; @@ -1507,10 +1529,17 @@ Option<Resources> Resources::find(const Resource& target) const if (flattened.contains(remaining)) { // The target has been found, return the result. if (!resource_.resource.has_reservation()) { - return found + remaining.flatten(resource_.resource.role()); + Try<Resources> _flattened = + remaining.flatten(resource_.resource.role()); + + CHECK_SOME(_flattened); + return found + _flattened.get(); } else { - return found + remaining.flatten( + Try<Resources> _flattened = remaining.flatten( resource_.resource.role(), resource_.resource.reservation()); + + CHECK_SOME(_flattened); + return found + _flattened.get(); } } else if (remaining.contains(flattened)) { found.add(resource_); http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/examples/dynamic_reservation_framework.cpp ---------------------------------------------------------------------- diff --git a/src/examples/dynamic_reservation_framework.cpp b/src/examples/dynamic_reservation_framework.cpp index 850bb2a..c9a6863 100644 --- a/src/examples/dynamic_reservation_framework.cpp +++ b/src/examples/dynamic_reservation_framework.cpp @@ -61,7 +61,10 @@ public: principal(_principal) { reservationInfo.set_principal(principal); - taskResources = TASK_RESOURCES.flatten(role, reservationInfo); + + Try<Resources> flattened = TASK_RESOURCES.flatten(role, reservationInfo); + CHECK_SOME(flattened); + taskResources = flattened.get(); } virtual ~DynamicReservationScheduler() {} http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/examples/test_framework.cpp ---------------------------------------------------------------------- diff --git a/src/examples/test_framework.cpp b/src/examples/test_framework.cpp index a83766a..a910640 100644 --- a/src/examples/test_framework.cpp +++ b/src/examples/test_framework.cpp @@ -106,8 +106,9 @@ public: task.mutable_slave_id()->MergeFrom(offer.slave_id()); task.mutable_executor()->MergeFrom(executor); - Option<Resources> resources = - remaining.find(TASK_RESOURCES.flatten(role)); + Try<Resources> flattened = TASK_RESOURCES.flatten(role); + CHECK_SOME(flattened); + Option<Resources> resources = remaining.find(flattened.get()); CHECK_SOME(resources); task.mutable_resources()->MergeFrom(resources.get()); http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/examples/test_http_framework.cpp ---------------------------------------------------------------------- diff --git a/src/examples/test_http_framework.cpp b/src/examples/test_http_framework.cpp index 441e86c..d6e248c 100644 --- a/src/examples/test_http_framework.cpp +++ b/src/examples/test_http_framework.cpp @@ -244,8 +244,9 @@ private: task.mutable_agent_id()->MergeFrom(offer.agent_id()); task.mutable_executor()->MergeFrom(executor); - Option<Resources> resources = - remaining.find(TASK_RESOURCES.flatten(framework.role())); + Try<Resources> flattened = TASK_RESOURCES.flatten(framework.role()); + CHECK_SOME(flattened); + Option<Resources> resources = remaining.find(flattened.get()); CHECK_SOME(resources); http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/tests/api_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/api_tests.cpp b/src/tests/api_tests.cpp index e440d1b..26f99f7 100644 --- a/src/tests/api_tests.cpp +++ b/src/tests/api_tests.cpp @@ -966,7 +966,7 @@ TEST_P(MasterAPITest, ReserveResources) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); MockScheduler sched; MesosSchedulerDriver driver( @@ -1060,7 +1060,7 @@ TEST_P(MasterAPITest, UnreserveResources) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); v1::master::Call v1Call; v1Call.set_type(v1::master::Call::RESERVE_RESOURCES); http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/tests/hierarchical_allocator_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/hierarchical_allocator_tests.cpp b/src/tests/hierarchical_allocator_tests.cpp index 621f1f4..46553f6 100644 --- a/src/tests/hierarchical_allocator_tests.cpp +++ b/src/tests/hierarchical_allocator_tests.cpp @@ -1479,7 +1479,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")); + unreserved.flatten("role1", createReservationInfo("ops")).get(); Offer::Operation reserve = RESERVE(dynamicallyReserved); @@ -1532,7 +1532,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")); + unreserved.flatten("role1", createReservationInfo("ops")).get(); Offer::Operation reserve = RESERVE(dynamicallyReserved); @@ -2633,7 +2633,7 @@ 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")); + unreserved.flatten(NO_QUOTA_ROLE, createReservationInfo("ops")).get(); Offer::Operation reserve = RESERVE(dynamicallyReserved); http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/tests/mesos.hpp ---------------------------------------------------------------------- diff --git a/src/tests/mesos.hpp b/src/tests/mesos.hpp index fa6789b..7095101 100644 --- a/src/tests/mesos.hpp +++ b/src/tests/mesos.hpp @@ -844,7 +844,7 @@ ACTION_P5(LaunchTasks, executor, tasks, cpus, mem, role) task.mutable_executor()->MergeFrom(executor); Option<Resources> resources = - remaining.find(TASK_RESOURCES.flatten(role)); + remaining.find(TASK_RESOURCES.flatten(role).get()); CHECK_SOME(resources); http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/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 266c2a0..f35592a 100644 --- a/src/tests/persistent_volume_endpoints_tests.cpp +++ b/src/tests/persistent_volume_endpoints_tests.cpp @@ -231,7 +231,7 @@ TEST_F(PersistentVolumeEndpointsTest, DynamicReservation) Resources unreserved = Resources::parse("disk:1024").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Future<Response> response = process::http::post( master.get()->pid, @@ -351,7 +351,7 @@ TEST_F(PersistentVolumeEndpointsTest, DynamicReservationRoleMismatch) Resources unreserved = Resources::parse("disk:1024").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Future<Response> response = process::http::post( master.get()->pid, @@ -432,7 +432,7 @@ TEST_F(PersistentVolumeEndpointsTest, UnreserveVolumeResources) Resources unreserved = Resources::parse("disk:1024").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Future<Response> response = process::http::post( master.get()->pid, @@ -1557,7 +1557,7 @@ TEST_F(PersistentVolumeEndpointsTest, OfferCreateThenEndpointRemove) Resources unreserved = Resources::parse("disk:512").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); EXPECT_CALL(allocator, addFramework(_, _, _)); @@ -1709,7 +1709,7 @@ TEST_F(PersistentVolumeEndpointsTest, EndpointCreateThenOfferRemove) Resources unreserved = Resources::parse("disk:512").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Future<Response> response = process::http::post( master.get()->pid, @@ -1843,7 +1843,7 @@ TEST_F(PersistentVolumeEndpointsTest, ReserveAndSlaveRemoval) Resources slave1Unreserved = Resources::parse("cpus:4").get(); Resources slave1Reserved = slave1Unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Future<Response> response = process::http::post( master.get()->pid, @@ -1882,7 +1882,7 @@ TEST_F(PersistentVolumeEndpointsTest, ReserveAndSlaveRemoval) Resources slave2Unreserved = Resources::parse("cpus:3").get(); Resources slave2Reserved = slave2Unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); for (size_t i = 0; i < offers.get().size(); i++) { Offer offer = offers.get()[i]; @@ -1962,7 +1962,7 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources) Resources unreserved = Resources::parse("cpus:1;mem:512;disk:1024").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Future<Response> response = process::http::post( master.get()->pid, @@ -2014,7 +2014,7 @@ TEST_F(PersistentVolumeEndpointsTest, SlavesEndpointFullResources) Resources taskUnreserved = Resources::parse("cpus:1;mem:256").get(); Resources taskResources = taskUnreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); TaskInfo taskInfo = createTask(offer.slave_id(), taskResources, "sleep 1000"); http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/tests/reservation_endpoints_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/reservation_endpoints_tests.cpp b/src/tests/reservation_endpoints_tests.cpp index bee5ea6..28b497e 100644 --- a/src/tests/reservation_endpoints_tests.cpp +++ b/src/tests/reservation_endpoints_tests.cpp @@ -125,7 +125,7 @@ TEST_F(ReservationEndpointsTest, AvailableResources) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Future<Response> response = process::http::post( master.get()->pid, @@ -222,7 +222,7 @@ TEST_F(ReservationEndpointsTest, ReserveOfferedResources) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); MockScheduler sched; MesosSchedulerDriver driver( @@ -295,7 +295,7 @@ TEST_F(ReservationEndpointsTest, UnreserveOfferedResources) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Future<Response> response = process::http::post( master.get()->pid, @@ -383,7 +383,7 @@ TEST_F(ReservationEndpointsTest, ReserveAvailableAndOfferedResources) Resources total = available + offered; Resources dynamicallyReserved = total.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); MockScheduler sched; MesosSchedulerDriver driver( @@ -530,12 +530,12 @@ TEST_F(ReservationEndpointsTest, UnreserveAvailableAndOfferedResources) Resources available = Resources::parse("cpus:1;mem:128").get(); available = available.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Resources offered = Resources::parse("mem:384").get(); offered = offered.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Resources total = available + offered; Resources unreserved = total.flatten(); @@ -700,10 +700,10 @@ TEST_F(ReservationEndpointsTest, LabeledResources) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources labeledResources1 = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal(), labels1)); + createReservationInfo(DEFAULT_CREDENTIAL.principal(), labels1)).get(); Resources labeledResources2 = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal(), labels2)); + createReservationInfo(DEFAULT_CREDENTIAL.principal(), labels2)).get(); // Make two resource reservations with different labels. Future<Response> response = process::http::post( @@ -900,7 +900,7 @@ TEST_F(ReservationEndpointsTest, InsufficientResources) Resources unreserved = Resources::parse("cpus:4;mem:4096").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); string body = createRequestBody(slaveId.get(), dynamicallyReserved); @@ -941,7 +941,7 @@ TEST_F(ReservationEndpointsTest, NoHeader) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Future<Response> response = process::http::post( master.get()->pid, @@ -991,7 +991,7 @@ TEST_F(ReservationEndpointsTest, BadCredentials) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( - "role", createReservationInfo(DEFAULT_CREDENTIAL.principal())); + "role", createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); process::http::Headers headers = createBasicAuthHeaders(credential); string body = createRequestBody(slaveId.get(), dynamicallyReserved); @@ -1063,7 +1063,7 @@ TEST_F(ReservationEndpointsTest, GoodReserveAndUnreserveACL) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); // Reserve the resources. Future<Response> response = process::http::post( @@ -1123,10 +1123,10 @@ TEST_F(ReservationEndpointsTest, GoodReserveACLMultipleRoles) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved1 = unreserved.flatten( "jedi_master", - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Resources dynamicallyReserved2 = unreserved.flatten( "sith_lord", - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Resources dynamicallyReservedMultipleRoles = dynamicallyReserved1 + dynamicallyReserved2; @@ -1186,7 +1186,7 @@ TEST_F(ReservationEndpointsTest, BadReserveACL) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); // Attempt to reserve the resources. Future<Response> response = process::http::post( @@ -1245,7 +1245,7 @@ TEST_F(ReservationEndpointsTest, BadUnreserveACL) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); // Reserve the resources. Future<Response> response = process::http::post( @@ -1316,10 +1316,10 @@ TEST_F(ReservationEndpointsTest, BadReserveACLMultipleRoles) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved1 = unreserved.flatten( AUTHORIZED_ROLE, - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Resources dynamicallyReserved2 = unreserved.flatten( UNAUTHORIZED_ROLE, - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Resources dynamicallyReservedMultipleRoles = dynamicallyReserved1 + dynamicallyReserved2; @@ -1347,7 +1347,7 @@ TEST_F(ReservationEndpointsTest, NoSlaveId) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( - "role", createReservationInfo(DEFAULT_CREDENTIAL.principal())); + "role", createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); string body = @@ -1422,7 +1422,7 @@ TEST_F(ReservationEndpointsTest, NonMatchingPrincipal) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = - unreserved.flatten("role", createReservationInfo("badPrincipal")); + unreserved.flatten("role", createReservationInfo("badPrincipal")).get(); Future<Response> response = process::http::post( master.get()->pid, @@ -1474,7 +1474,7 @@ TEST_F(ReservationEndpointsTest, ReserveAndUnreserveNoAuthentication) Resources dynamicallyReservedWithNoPrincipal = unreserved.flatten( frameworkInfo.role(), - createReservationInfo()); + createReservationInfo()).get(); // Try a reservation with no principal in `ReservationInfo` and no // authentication headers. @@ -1498,7 +1498,7 @@ TEST_F(ReservationEndpointsTest, ReserveAndUnreserveNoAuthentication) Resources dynamicallyReservedWithPrincipal = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); // Try a reservation with a principal in `ReservationInfo` and no // authentication headers. @@ -1551,11 +1551,11 @@ TEST_F(ReservationEndpointsTest, DifferentPrincipalsSameRole) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved1 = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL.principal())); + createReservationInfo(DEFAULT_CREDENTIAL.principal())).get(); Resources dynamicallyReserved2 = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(DEFAULT_CREDENTIAL_2.principal())); + createReservationInfo(DEFAULT_CREDENTIAL_2.principal())).get(); Future<Response> response = process::http::post( master.get()->pid, http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/tests/reservation_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/reservation_tests.cpp b/src/tests/reservation_tests.cpp index 93e95a9..6c28ab4 100644 --- a/src/tests/reservation_tests.cpp +++ b/src/tests/reservation_tests.cpp @@ -115,7 +115,8 @@ TEST_F(ReservationTest, ReserveThenUnreserve) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -209,7 +210,7 @@ TEST_F(ReservationTest, ReserveTwiceWithDoubleValue) Resources dynamicallyReserved = unreserved.flatten( frameworkInfo.role(), - createReservationInfo(frameworkInfo.principal())); + createReservationInfo(frameworkInfo.principal())).get(); Future<vector<Offer>> offers; EXPECT_CALL(sched, resourceOffers(&driver, _)) @@ -262,7 +263,7 @@ TEST_F(ReservationTest, ReserveTwiceWithDoubleValue) Resources finalReservation = reserved.flatten( frameworkInfo.role(), - createReservationInfo(frameworkInfo.principal())); + createReservationInfo(frameworkInfo.principal())).get(); EXPECT_TRUE(Resources(offer.resources()).contains(finalReservation)); @@ -309,7 +310,8 @@ TEST_F(ReservationTest, ReserveAndLaunchThenUnreserve) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -430,7 +432,7 @@ TEST_F(ReservationTest, ReserveShareWithinRole) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( - role, createReservationInfo(frameworkInfo1.principal())); + role, createReservationInfo(frameworkInfo1.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -539,7 +541,8 @@ 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())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture the offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -629,7 +632,8 @@ TEST_F(ReservationTest, DropReserveStaticReservation) Resources staticallyReserved = Resources::parse("cpus(role):1;mem(role):512").get(); Resources dynamicallyReserved = staticallyReserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -712,11 +716,13 @@ TEST_F(ReservationTest, SendingCheckpointResourcesMessage) Resources unreserved1 = Resources::parse("cpus:8").get(); Resources reserved1 = unreserved1.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); Resources unreserved2 = Resources::parse("mem:2048").get(); Resources reserved2 = unreserved2.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -812,7 +818,8 @@ TEST_F(ReservationTest, ResourcesCheckpointing) Resources unreserved = Resources::parse("cpus:8;mem:2048").get(); Resources reserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -901,7 +908,8 @@ TEST_F(ReservationTest, MasterFailover) Resources unreserved = Resources::parse("cpus:8;mem:2048").get(); Resources reserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -1018,7 +1026,8 @@ TEST_F(ReservationTest, CompatibleCheckpointedResources) Resources unreserved = Resources::parse("cpus:8;mem:2048").get(); Resources reserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -1124,7 +1133,8 @@ TEST_F(ReservationTest, CompatibleCheckpointedResourcesWithPersistentVolumes) Resources unreserved = Resources::parse("cpus:8;mem:2048").get(); Resources reserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); Resource unreservedDisk = Resources::parse("disk", "1024", "*").get(); Resource reservedDisk = unreservedDisk; @@ -1273,7 +1283,8 @@ TEST_F(ReservationTest, IncompatibleCheckpointedResources) Resources unreserved = Resources::parse("cpus:8;mem:2048").get(); Resources reserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -1395,7 +1406,8 @@ TEST_F(ReservationTest, GoodACLReserveThenUnreserve) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -1494,7 +1506,8 @@ TEST_F(ReservationTest, BadACLDropReserve) Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -1585,10 +1598,13 @@ 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())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); + Resources unreserved2 = Resources::parse("cpus:0.5;mem:256").get(); Resources dynamicallyReserved2 = unreserved2.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -1716,10 +1732,13 @@ 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())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); + Resources unreserved2 = Resources::parse("cpus:0.5;mem:256").get(); Resources dynamicallyReserved2 = unreserved2.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from 'resourceOffers'. Future<vector<Offer>> offers; @@ -1903,7 +1922,7 @@ TEST_F(ReservationTest, WithoutAuthenticationWithoutPrincipal) // Create dynamically reserved resources whose `ReservationInfo` does not // contain a principal. Resources dynamicallyReserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo()); + frameworkInfo.role(), createReservationInfo()).get(); // We use this to capture offers from `resourceOffers`. Future<vector<Offer>> offers; @@ -2005,7 +2024,8 @@ TEST_F(ReservationTest, WithoutAuthenticationWithPrincipal) // Create dynamically reserved resources whose `ReservationInfo` contains a // principal. Resources dynamicallyReserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from `resourceOffers`. Future<vector<Offer>> offers; http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/tests/resources_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/resources_tests.cpp b/src/tests/resources_tests.cpp index 157b9f6..3e49300 100644 --- a/src/tests/resources_tests.cpp +++ b/src/tests/resources_tests.cpp @@ -2184,7 +2184,7 @@ TEST(ResourcesOperationTest, ReserveResources) Resources unreserved = unreservedCpus + unreservedMem; Resources reservedCpus1 = - unreservedCpus.flatten("role", createReservationInfo("principal")); + unreservedCpus.flatten("role", createReservationInfo("principal")).get(); EXPECT_SOME_EQ(unreservedMem + reservedCpus1, unreserved.apply(RESERVE(reservedCpus1))); @@ -2272,7 +2272,7 @@ TEST(ResourcesOperationTest, StrippedResourcesReserved) { Resources unreserved = Resources::parse("cpus:1;mem:512").get(); Resources dynamicallyReserved = unreserved.flatten( - "role", createReservationInfo("principal")); + "role", createReservationInfo("principal")).get(); Resources stripped = dynamicallyReserved.createStrippedScalarQuantity(); @@ -2361,6 +2361,24 @@ TEST(ResourcesOperationTest, CreateSharedPersistentVolume) } +TEST(ResourcesOperationTest, FlattenResources) +{ + Resources unreservedCpus = Resources::parse("cpus:1").get(); + Resources unreservedMem = Resources::parse("mem:512").get(); + + Resources unreserved = unreservedCpus + unreservedMem; + + EXPECT_ERROR(unreserved.flatten("*", createReservationInfo("principal"))); + EXPECT_ERROR(unreserved.flatten("-role")); + + Resources reservedCpus = + unreservedCpus.flatten("role", createReservationInfo("principal")).get(); + + EXPECT_SOME_EQ(unreservedMem + reservedCpus, + unreserved.apply(RESERVE(reservedCpus))); +} + + // Helper for creating a revocable resource. static Resource createRevocableResource( const string& name, @@ -2762,7 +2780,7 @@ public: reservation.mutable_labels()->add_labels()->CopyFrom(label); reservations.resources += - scalars.resources.flatten(stringify(i), reservation); + scalars.resources.flatten(stringify(i), reservation).get(); } reservations.totalOperations = 10; http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/tests/role_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/role_tests.cpp b/src/tests/role_tests.cpp index 162c941..47fe0f0 100644 --- a/src/tests/role_tests.cpp +++ b/src/tests/role_tests.cpp @@ -116,7 +116,8 @@ TEST_F(RoleTest, ImplicitRoleRegister) Resources unreserved = Resources::parse("disk:1024").get(); Resources dynamicallyReserved = unreserved.flatten( - frameworkInfo.role(), createReservationInfo(frameworkInfo.principal())); + frameworkInfo.role(), + createReservationInfo(frameworkInfo.principal())).get(); // We use this to capture offers from `resourceOffers`. Future<vector<Offer>> offers; http://git-wip-us.apache.org/repos/asf/mesos/blob/491371c7/src/v1/resources.cpp ---------------------------------------------------------------------- diff --git a/src/v1/resources.cpp b/src/v1/resources.cpp index 4b66acb..aefba49 100644 --- a/src/v1/resources.cpp +++ b/src/v1/resources.cpp @@ -1080,10 +1080,22 @@ Resources Resources::nonShared() const } -Resources Resources::flatten( +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) { @@ -1093,13 +1105,21 @@ Resources Resources::flatten( } else { resource_.resource.mutable_reservation()->CopyFrom(reservation.get()); } - flattened += resource_; + flattened.add(resource_); } return flattened; } +Resources Resources::flatten() const +{ + Try<Resources> flattened = flatten("*"); + CHECK_SOME(flattened); + return flattened.get(); +} + + Resources Resources::createStrippedScalarQuantity() const { Resources stripped; @@ -1510,10 +1530,17 @@ Option<Resources> Resources::find(const Resource& target) const if (flattened.contains(remaining)) { // The target has been found, return the result. if (!resource_.resource.has_reservation()) { - return found + remaining.flatten(resource_.resource.role()); + Try<Resources> _flattened = + remaining.flatten(resource_.resource.role()); + + CHECK_SOME(_flattened); + return found + _flattened.get(); } else { - return found + remaining.flatten( + Try<Resources> _flattened = remaining.flatten( resource_.resource.role(), resource_.resource.reservation()); + + CHECK_SOME(_flattened); + return found + _flattened.get(); } } else if (remaining.contains(flattened)) { found.add(resource_);