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/17 09:18:52 UTC
[1/2] mesos git commit: Resources: Updated the validation logic.
Repository: mesos
Updated Branches:
refs/heads/master dc679b2c3 -> 4f1653570
Resources: Updated the validation logic.
This patch updates `Resources::validate`, and `resource::validate`.
The `Resources::validate` function ensures that the resources are
either in the 'pre-' or 'post-' reservation-refinement formats,
but not both.
The `resource::validate` function takes an optional framework
capabilities and ensures that the resources format matches
the framework's RESERVATION_REFINEMENT capbility.
Review: https://reviews.apache.org/r/60013/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/fe6a3eb4
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/fe6a3eb4
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/fe6a3eb4
Branch: refs/heads/master
Commit: fe6a3eb48af793b5cf2e1308d9164cdec1c4875a
Parents: dc679b2
Author: Michael Park <mp...@apache.org>
Authored: Sat Jun 17 01:41:55 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Sat Jun 17 02:00:33 2017 -0700
----------------------------------------------------------------------
src/common/resources.cpp | 67 +++++++++++++++++++++++++--
src/master/validation.cpp | 103 ++++++++++++++++++++++++++++++++++-------
src/master/validation.hpp | 22 ++++++---
src/v1/resources.cpp | 67 +++++++++++++++++++++++++--
4 files changed, 227 insertions(+), 32 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/fe6a3eb4/src/common/resources.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources.cpp b/src/common/resources.cpp
index 05f20e9..7672938 100644
--- a/src/common/resources.cpp
+++ b/src/common/resources.cpp
@@ -512,8 +512,8 @@ static Option<Error> validateCommandLineResources(const Resources& resources)
" not include a 'revocable' key in the resources JSON");
} else if (Resources::isDynamicallyReserved(resource)) {
return Error(
- "Dynamic reservations cannot be specified at the command line; "
- "do not include a 'reservation' key in the resources JSON");
+ "Dynamic reservations cannot be specified at the command line; do"
+ " not include a reservation with DYNAMIC type in the resources JSON");
}
if (nameTypes.contains(resource.name()) &&
@@ -835,10 +835,10 @@ Option<Error> Resources::validate(const Resource& resource)
}
}
- // Checks for the invalid state of (role, reservation) pair.
- if (resource.role() == "*" && resource.has_reservation()) {
+ if (resource.has_reservation() && resource.reservations_size() > 0) {
return Error(
- "Invalid reservation: role \"*\" cannot be dynamically reserved");
+ "Invalid reservation: only one of 'reservation' or 'reservations'"
+ " may be present");
}
// Check role name.
@@ -847,6 +847,63 @@ Option<Error> Resources::validate(const Resource& resource)
return error;
}
+ if (resource.has_reservation()) {
+ if (resource.reservation().has_type()) {
+ return Error(
+ "'Resource.ReservationInfo.type' must not be set for the"
+ " 'Resource.reservation' field");
+ }
+
+ if (resource.reservation().has_role()) {
+ return Error(
+ "'Resource.ReservationInfo.role' must not be set for the"
+ " 'Resource.reservation' field");
+ }
+
+ // Checks for the invalid state of (role, reservation) pair.
+ if (resource.role() == "*") {
+ return Error(
+ "Invalid reservation: role \"*\" cannot be dynamically reserved");
+ }
+ }
+
+ // Validate all of the roles in `reservations`.
+ foreach (
+ const Resource::ReservationInfo& reservation, resource.reservations()) {
+ Option<Error> error = roles::validate(reservation.role());
+ if (error.isSome()) {
+ return error;
+ }
+
+ if (reservation.role() == "*") {
+ return Error("Invalid reservation: role \"*\" cannot be reserved");
+ }
+ }
+
+ if (resource.reservations_size() > 0) {
+ string ancestor = resource.reservations(0).role();
+
+ for (int i = 1; i < resource.reservations_size(); ++i) {
+ const Resource::ReservationInfo& reservation = resource.reservations(i);
+
+ if (reservation.type() == Resource::ReservationInfo::STATIC) {
+ return Error(
+ "Invalid refined reservation: A refined reservation"
+ " cannot be STATIC");
+ }
+
+ const string& descendant = reservation.role();
+
+ if (!roles::isStrictSubroleOf(descendant, ancestor)) {
+ return Error(
+ "Invalid refined reservation: role '" + descendant + "'" +
+ " is not a refinement of '" + ancestor + "'");
+ }
+
+ ancestor = descendant;
+ }
+ }
+
// Check that shareability is enabled for supported resource types.
// For now, it is for persistent volumes only.
// NOTE: We need to modify this once we extend shareability to other
http://git-wip-us.apache.org/repos/asf/mesos/blob/fe6a3eb4/src/master/validation.cpp
----------------------------------------------------------------------
diff --git a/src/master/validation.cpp b/src/master/validation.cpp
index 8bd8cd2..0164e67 100644
--- a/src/master/validation.cpp
+++ b/src/master/validation.cpp
@@ -598,6 +598,30 @@ Option<Error> validate(
namespace resource {
+Option<Error> validateFormat(
+ const RepeatedPtrField<Resource>& resources,
+ const protobuf::framework::Capabilities& capabilities)
+{
+ foreach (const Resource& resource, resources) {
+ if (capabilities.reservationRefinement) {
+ if (resource.has_role() || resource.has_reservation()) {
+ return Error(
+ "A framework with the RESERVATION_REFINEMENT capability must"
+ " not have 'Resource::role' set, nor 'Resource::reservation'");
+ }
+ } else {
+ if (resource.reservations_size() > 0) {
+ return Error(
+ "A framework without the RESERVATION_REFINEMENT capability must"
+ " not have 'Resource::reservations' set");
+ }
+ }
+ }
+
+ return None();
+}
+
+
// Validates that the `gpus` resource is not fractional.
// We rely on scalar resources only having 3 digits of precision.
Option<Error> validateGpus(const RepeatedPtrField<Resource>& resources)
@@ -772,13 +796,22 @@ Option<Error> validateAllocatedToSingleRole(const Resources& resources)
}
-Option<Error> validate(const RepeatedPtrField<Resource>& resources)
+Option<Error> validate(
+ const RepeatedPtrField<Resource>& resources,
+ const Option<protobuf::framework::Capabilities>& capabilities)
{
Option<Error> error = Resources::validate(resources);
if (error.isSome()) {
return Error("Invalid resources: " + error.get().message);
}
+ if (capabilities.isSome()) {
+ error = validateFormat(resources, capabilities.get());
+ if (error.isSome()) {
+ return Error("Invalid resource format: " + error.get().message);
+ }
+ }
+
error = validateGpus(resources);
if (error.isSome()) {
return Error("Invalid 'gpus' resource: " + error.get().message);
@@ -923,9 +956,11 @@ Option<Error> validateShutdownGracePeriod(const ExecutorInfo& executor)
}
-Option<Error> validateResources(const ExecutorInfo& executor)
+Option<Error> validateResources(
+ const ExecutorInfo& executor,
+ const Option<protobuf::framework::Capabilities>& capabilities)
{
- Option<Error> error = resource::validate(executor.resources());
+ Option<Error> error = resource::validate(executor.resources(), capabilities);
if (error.isSome()) {
return Error("Executor uses invalid resources: " + error->message);
}
@@ -983,7 +1018,8 @@ Option<Error> validate(
const vector<lambda::function<Option<Error>()>> executorValidators = {
lambda::bind(internal::validateFrameworkID, executor, framework),
- lambda::bind(internal::validateResources, executor),
+ lambda::bind(
+ internal::validateResources, executor, framework->capabilities),
lambda::bind(
internal::validateCompatibleExecutorInfo, executor, framework, slave),
};
@@ -1109,13 +1145,15 @@ Option<Error> validateHealthCheck(const TaskInfo& task)
}
-Option<Error> validateResources(const TaskInfo& task)
+Option<Error> validateResources(
+ const TaskInfo& task,
+ const Option<protobuf::framework::Capabilities>& capabilities)
{
if (task.resources().empty()) {
return Error("Task uses no resources");
}
- Option<Error> error = resource::validate(task.resources());
+ Option<Error> error = resource::validate(task.resources(), capabilities);
if (error.isSome()) {
return Error("Task uses invalid resources: " + error->message);
}
@@ -1142,14 +1180,16 @@ Option<Error> validateResources(const TaskInfo& task)
}
-Option<Error> validateTaskAndExecutorResources(const TaskInfo& task)
+Option<Error> validateTaskAndExecutorResources(
+ const TaskInfo& task,
+ const Option<protobuf::framework::Capabilities>& capabilities)
{
Resources total = task.resources();
if (task.has_executor()) {
total += task.executor().resources();
}
- Option<Error> error = resource::validate(total);
+ Option<Error> error = resource::validate(total, capabilities);
if (error.isSome()) {
return Error(
"Task and its executor use invalid resources: " + error->message);
@@ -1204,7 +1244,7 @@ Option<Error> validateTask(
lambda::bind(internal::validateKillPolicy, task),
lambda::bind(internal::validateCheck, task),
lambda::bind(internal::validateHealthCheck, task),
- lambda::bind(internal::validateResources, task),
+ lambda::bind(internal::validateResources, task, framework->capabilities),
lambda::bind(internal::validateCommandInfo, task)
};
@@ -1312,7 +1352,9 @@ Option<Error> validateExecutor(
// NOTE: This is refactored into a separate function
// so that it can be easily unit tested.
- error = task::internal::validateTaskAndExecutorResources(task);
+ error = task::internal::validateTaskAndExecutorResources(
+ task, framework->capabilities);
+
if (error.isSome()) {
return error;
}
@@ -1830,8 +1872,15 @@ Option<Error> validate(
const protobuf::slave::Capabilities& agentCapabilities,
const Option<FrameworkInfo>& frameworkInfo)
{
+ Option<protobuf::framework::Capabilities> frameworkCapabilities;
+ if (frameworkInfo.isSome()) {
+ frameworkCapabilities = frameworkInfo->capabilities();
+ }
+
// NOTE: this ensures the reservation is not being made to the "*" role.
- Option<Error> error = resource::validate(reserve.resources());
+ Option<Error> error =
+ resource::validate(reserve.resources(), frameworkCapabilities);
+
if (error.isSome()) {
return Error("Invalid resources: " + error.get().message);
}
@@ -1950,9 +1999,18 @@ Option<Error> validate(
}
-Option<Error> validate(const Offer::Operation::Unreserve& unreserve)
+Option<Error> validate(
+ const Offer::Operation::Unreserve& unreserve,
+ const Option<FrameworkInfo>& frameworkInfo)
{
- Option<Error> error = resource::validate(unreserve.resources());
+ Option<protobuf::framework::Capabilities> frameworkCapabilities;
+ if (frameworkInfo.isSome()) {
+ frameworkCapabilities = frameworkInfo->capabilities();
+ }
+
+ Option<Error> error =
+ resource::validate(unreserve.resources(), frameworkCapabilities);
+
if (error.isSome()) {
return Error("Invalid resources: " + error.get().message);
}
@@ -1989,7 +2047,14 @@ Option<Error> validate(
const protobuf::slave::Capabilities& agentCapabilities,
const Option<FrameworkInfo>& frameworkInfo)
{
- Option<Error> error = resource::validate(create.volumes());
+ Option<protobuf::framework::Capabilities> frameworkCapabilities;
+ if (frameworkInfo.isSome()) {
+ frameworkCapabilities = frameworkInfo->capabilities();
+ }
+
+ Option<Error> error =
+ resource::validate(create.volumes(), frameworkCapabilities);
+
if (error.isSome()) {
return Error("Invalid resources: " + error.get().message);
}
@@ -2074,7 +2139,8 @@ Option<Error> validate(
const Offer::Operation::Destroy& destroy,
const Resources& checkpointedResources,
const hashmap<FrameworkID, Resources>& usedResources,
- const hashmap<FrameworkID, hashmap<TaskID, TaskInfo>>& pendingTasks)
+ const hashmap<FrameworkID, hashmap<TaskID, TaskInfo>>& pendingTasks,
+ const Option<FrameworkInfo>& frameworkInfo)
{
// The operation can either contain allocated resources
// (in the case of a framework accepting offers), or
@@ -2094,7 +2160,12 @@ Option<Error> validate(
Resources volumes = unallocated(destroy.volumes());
- Option<Error> error = resource::validate(volumes);
+ Option<protobuf::framework::Capabilities> frameworkCapabilities;
+ if (frameworkInfo.isSome()) {
+ frameworkCapabilities = frameworkInfo->capabilities();
+ }
+
+ Option<Error> error = resource::validate(volumes, frameworkCapabilities);
if (error.isSome()) {
return Error("Invalid resources: " + error.get().message);
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/fe6a3eb4/src/master/validation.hpp
----------------------------------------------------------------------
diff --git a/src/master/validation.hpp b/src/master/validation.hpp
index 1be9f08..1295059 100644
--- a/src/master/validation.hpp
+++ b/src/master/validation.hpp
@@ -137,7 +137,8 @@ namespace resource {
// NOTE: We cannot take 'Resources' here because invalid resources are
// silently ignored within its constructor.
Option<Error> validate(
- const google::protobuf::RepeatedPtrField<Resource>& resources);
+ const google::protobuf::RepeatedPtrField<Resource>& resources,
+ const Option<protobuf::framework::Capabilities>& capabilities = None());
} // namespace resource {
@@ -153,7 +154,9 @@ Option<Error> validateExecutorID(const ExecutorInfo& executor);
Option<Error> validateType(const ExecutorInfo& executor);
// Validates resources of the executor.
-Option<Error> validateResources(const ExecutorInfo& executor);
+Option<Error> validateResources(
+ const ExecutorInfo& executor,
+ const Option<protobuf::framework::Capabilities>& capabilities = None());
} // namespace internal {
@@ -181,10 +184,14 @@ Option<Error> validate(
namespace internal {
// Validates resources of the task.
-Option<Error> validateResources(const TaskInfo& task);
+Option<Error> validateResources(
+ const TaskInfo& task,
+ const Option<protobuf::framework::Capabilities>& capabilities = None());
// Validates resources of the task and its executor.
-Option<Error> validateTaskAndExecutorResources(const TaskInfo& task);
+Option<Error> validateTaskAndExecutorResources(
+ const TaskInfo& task,
+ const Option<protobuf::framework::Capabilities>& capabilities = None());
// Validates the kill policy of the task.
Option<Error> validateKillPolicy(const TaskInfo& task);
@@ -268,7 +275,9 @@ Option<Error> validate(
// Validates the UNRESERVE operation.
-Option<Error> validate(const Offer::Operation::Unreserve& unreserve);
+Option<Error> validate(
+ const Offer::Operation::Unreserve& unreserve,
+ const Option<FrameworkInfo>& frameworkInfo = None());
// Validates the CREATE operation. We need slave's checkpointed resources so
@@ -293,7 +302,8 @@ Option<Error> validate(
const Offer::Operation::Destroy& destroy,
const Resources& checkpointedResources,
const hashmap<FrameworkID, Resources>& usedResources,
- const hashmap<FrameworkID, hashmap<TaskID, TaskInfo>>& pendingTasks);
+ const hashmap<FrameworkID, hashmap<TaskID, TaskInfo>>& pendingTasks,
+ const Option<FrameworkInfo>& frameworkInfo = None());
} // namespace operation {
http://git-wip-us.apache.org/repos/asf/mesos/blob/fe6a3eb4/src/v1/resources.cpp
----------------------------------------------------------------------
diff --git a/src/v1/resources.cpp b/src/v1/resources.cpp
index dfc797a..5558805 100644
--- a/src/v1/resources.cpp
+++ b/src/v1/resources.cpp
@@ -514,8 +514,8 @@ static Option<Error> validateCommandLineResources(const Resources& resources)
" not include a 'revocable' key in the resources JSON");
} else if (Resources::isDynamicallyReserved(resource)) {
return Error(
- "Dynamic reservations cannot be specified at the command line; "
- "do not include a 'reservation' key in the resources JSON");
+ "Dynamic reservations cannot be specified at the command line; do"
+ " not include a reservation with DYNAMIC type in the resources JSON");
}
if (nameTypes.contains(resource.name()) &&
@@ -837,10 +837,10 @@ Option<Error> Resources::validate(const Resource& resource)
}
}
- // Checks for the invalid state of (role, reservation) pair.
- if (resource.role() == "*" && resource.has_reservation()) {
+ if (resource.has_reservation() && resource.reservations_size() > 0) {
return Error(
- "Invalid reservation: role \"*\" cannot be dynamically reserved");
+ "Invalid reservation: only one of 'reservation' or 'reservations'"
+ " may be present");
}
// Check role name.
@@ -849,6 +849,63 @@ Option<Error> Resources::validate(const Resource& resource)
return error;
}
+ if (resource.has_reservation()) {
+ if (resource.reservation().has_type()) {
+ return Error(
+ "'Resource.ReservationInfo.type' must not be set for the"
+ " 'Resource.reservation' field");
+ }
+
+ if (resource.reservation().has_role()) {
+ return Error(
+ "'Resource.ReservationInfo.role' must not be set for the"
+ " 'Resource.reservation' field");
+ }
+
+ // Checks for the invalid state of (role, reservation) pair.
+ if (resource.role() == "*") {
+ return Error(
+ "Invalid reservation: role \"*\" cannot be dynamically reserved");
+ }
+ }
+
+ // Validate all of the roles in `reservations`.
+ foreach (
+ const Resource::ReservationInfo& reservation, resource.reservations()) {
+ Option<Error> error = roles::validate(reservation.role());
+ if (error.isSome()) {
+ return error;
+ }
+
+ if (reservation.role() == "*") {
+ return Error("Invalid reservation: role \"*\" cannot be reserved");
+ }
+ }
+
+ if (resource.reservations_size() > 0) {
+ string ancestor = resource.reservations(0).role();
+
+ for (int i = 1; i < resource.reservations_size(); ++i) {
+ const Resource::ReservationInfo& reservation = resource.reservations(i);
+
+ if (reservation.type() == Resource::ReservationInfo::STATIC) {
+ return Error(
+ "Invalid refined reservation: A refined reservation"
+ " cannot be STATIC");
+ }
+
+ const string& descendant = reservation.role();
+
+ if (!roles::isStrictSubroleOf(descendant, ancestor)) {
+ return Error(
+ "Invalid refined reservation: role '" + descendant + "'" +
+ " is not a refinement of '" + ancestor + "'");
+ }
+
+ ancestor = descendant;
+ }
+ }
+
// Check that shareability is enabled for supported resource types.
// For now, it is for persistent volumes only.
// NOTE: We need to modify this once we extend shareability to other
[2/2] mesos git commit: Resources: Added `toUnreserved()` and
`(push|pop)Reservation`.
Posted by mp...@apache.org.
Resources: Added `toUnreserved()` and `(push|pop)Reservation`.
This patches introduces utilities `toUnreserved`, `pushReservation` and
`popReservation`. They are intended to replace the current `flatten`.
We'll switch over to use them once the 'post-reservation-refinement'
format is used for `Resources`.
Review: https://reviews.apache.org/r/60020
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/4f165357
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/4f165357
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/4f165357
Branch: refs/heads/master
Commit: 4f16535704ac6f8417dfcef6c6347658114db97e
Parents: fe6a3eb
Author: Michael Park <mp...@apache.org>
Authored: Wed Jun 14 21:28:04 2017 -0700
Committer: Michael Park <mp...@apache.org>
Committed: Sat Jun 17 02:00:52 2017 -0700
----------------------------------------------------------------------
include/mesos/resources.hpp | 17 +++++++++++++++
include/mesos/v1/resources.hpp | 17 +++++++++++++++
src/common/resources.cpp | 42 +++++++++++++++++++++++++++++++++++++
src/v1/resources.cpp | 42 +++++++++++++++++++++++++++++++++++++
4 files changed, 118 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/4f165357/include/mesos/resources.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/resources.hpp b/include/mesos/resources.hpp
index 2b55847..d380a59 100644
--- a/include/mesos/resources.hpp
+++ b/include/mesos/resources.hpp
@@ -424,14 +424,31 @@ public:
// '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;
+
+ // Returns a `Resources` object with the last reservation removed.
+ // Every resource in `Resources` must have `resource.reservations_size() > 0`.
+ Resources popReservation() const;
+
+ // Returns a `Resources` object with all of the reservations removed.
+ Resources toUnreserved() const;
+
// Returns a Resources object that contains all the scalar resources
// in this object, but with their AllocationInfo, ReservationInfo,
// DiskInfo, and SharedInfo omitted. The `role` and RevocableInfo,
http://git-wip-us.apache.org/repos/asf/mesos/blob/4f165357/include/mesos/v1/resources.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/v1/resources.hpp b/include/mesos/v1/resources.hpp
index 7c6e856..66c2b21 100644
--- a/include/mesos/v1/resources.hpp
+++ b/include/mesos/v1/resources.hpp
@@ -424,14 +424,31 @@ public:
// '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;
+
+ // Returns a `Resources` object with the last reservation removed.
+ // Every resource in `Resources` must have `resource.reservations_size() > 0`.
+ Resources popReservation() const;
+
+ // Returns a `Resources` object with all of the reservations removed.
+ Resources toUnreserved() const;
+
// Returns a Resources object that contains all the scalar resources
// in this object, but with their AllocationInfo, ReservationInfo,
// DiskInfo, and SharedInfo omitted. The `role` and RevocableInfo,
http://git-wip-us.apache.org/repos/asf/mesos/blob/4f165357/src/common/resources.cpp
----------------------------------------------------------------------
diff --git a/src/common/resources.cpp b/src/common/resources.cpp
index 7672938..f12ab97 100644
--- a/src/common/resources.cpp
+++ b/src/common/resources.cpp
@@ -1330,6 +1330,48 @@ Resources Resources::flatten() const
}
+Resources Resources::pushReservation(
+ const Resource::ReservationInfo& reservation) const
+{
+ Resources result;
+
+ foreach (Resource_ resource_, *this) {
+ resource_.resource.add_reservations()->CopyFrom(reservation);
+ CHECK_NONE(Resources::validate(resource_.resource));
+ result.add(resource_);
+ }
+
+ return result;
+}
+
+
+Resources Resources::popReservation() const
+{
+ Resources result;
+
+ foreach (Resource_ resource_, resources) {
+ CHECK_GE(resource_.resource.reservations_size(), 0);
+ resource_.resource.mutable_reservations()->RemoveLast();
+ result.add(resource_);
+ }
+
+ return result;
+}
+
+
+Resources Resources::toUnreserved() const
+{
+ Resources result;
+
+ foreach (Resource_ resource_, *this) {
+ resource_.resource.clear_reservations();
+ result.add(resource_);
+ }
+
+ return result;
+}
+
+
Resources Resources::createStrippedScalarQuantity() const
{
Resources stripped;
http://git-wip-us.apache.org/repos/asf/mesos/blob/4f165357/src/v1/resources.cpp
----------------------------------------------------------------------
diff --git a/src/v1/resources.cpp b/src/v1/resources.cpp
index 5558805..30644ee 100644
--- a/src/v1/resources.cpp
+++ b/src/v1/resources.cpp
@@ -1332,6 +1332,48 @@ Resources Resources::flatten() const
}
+Resources Resources::pushReservation(
+ const Resource::ReservationInfo& reservation) const
+{
+ Resources result;
+
+ foreach (Resource_ resource_, *this) {
+ resource_.resource.add_reservations()->CopyFrom(reservation);
+ CHECK_NONE(Resources::validate(resource_.resource));
+ result.add(resource_);
+ }
+
+ return result;
+}
+
+
+Resources Resources::popReservation() const
+{
+ Resources result;
+
+ foreach (Resource_ resource_, resources) {
+ CHECK_GE(resource_.resource.reservations_size(), 0);
+ resource_.resource.mutable_reservations()->RemoveLast();
+ result.add(resource_);
+ }
+
+ return result;
+}
+
+
+Resources Resources::toUnreserved() const
+{
+ Resources result;
+
+ foreach (Resource_ resource_, *this) {
+ resource_.resource.clear_reservations();
+ result.add(resource_);
+ }
+
+ return result;
+}
+
+
Resources Resources::createStrippedScalarQuantity() const
{
Resources stripped;