You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ar...@apache.org on 2018/03/14 17:10:17 UTC
[7/8] mesos git commit: Refactored authorization logic in the agent.
Refactored authorization logic in the agent.
This patch makes uses of the new `ObjectApprovers` class which greatly
simplifies the logic for constructing and using authorization.
Review: https://reviews.apache.org/r/65313
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/83dd7f87
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/83dd7f87
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/83dd7f87
Branch: refs/heads/master
Commit: 83dd7f872499f1edc7a133f89719b210b152d54c
Parents: dc1e188
Author: Alexander Rojas <al...@gmail.com>
Authored: Wed Jan 24 18:17:20 2018 +0100
Committer: Alexander Rojas <al...@mesosphere.io>
Committed: Wed Mar 14 18:09:20 2018 +0100
----------------------------------------------------------------------
src/slave/http.cpp | 1699 ++++++++++++++++++++--------------------------
src/slave/http.hpp | 52 +-
src/slave/slave.cpp | 20 +-
3 files changed, 787 insertions(+), 984 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/83dd7f87/src/slave/http.cpp
----------------------------------------------------------------------
diff --git a/src/slave/http.cpp b/src/slave/http.cpp
index 7d7fa2b..a8ffbd1 100644
--- a/src/slave/http.cpp
+++ b/src/slave/http.cpp
@@ -80,6 +80,27 @@
using mesos::agent::ProcessIO;
using mesos::authorization::createSubject;
+using mesos::authorization::VIEW_CONTAINER;
+using mesos::authorization::VIEW_FLAGS;
+using mesos::authorization::VIEW_FRAMEWORK;
+using mesos::authorization::VIEW_TASK;
+using mesos::authorization::VIEW_EXECUTOR;
+using mesos::authorization::VIEW_ROLE;
+using mesos::authorization::SET_LOG_LEVEL;
+using mesos::authorization::ATTACH_CONTAINER_INPUT;
+using mesos::authorization::ATTACH_CONTAINER_OUTPUT;
+using mesos::authorization::LAUNCH_NESTED_CONTAINER;
+using mesos::authorization::LAUNCH_NESTED_CONTAINER_SESSION;
+using mesos::authorization::LAUNCH_STANDALONE_CONTAINER;
+using mesos::authorization::WAIT_NESTED_CONTAINER;
+using mesos::authorization::WAIT_STANDALONE_CONTAINER;
+using mesos::authorization::VIEW_STANDALONE_CONTAINER;
+using mesos::authorization::KILL_NESTED_CONTAINER;
+using mesos::authorization::KILL_STANDALONE_CONTAINER;
+using mesos::authorization::REMOVE_NESTED_CONTAINER;
+using mesos::authorization::REMOVE_STANDALONE_CONTAINER;
+using mesos::authorization::MODIFY_RESOURCE_PROVIDER_CONFIG;
+using mesos::authorization::PRUNE_IMAGES;
using mesos::internal::recordio::Reader;
@@ -175,10 +196,10 @@ using process::http::Request;
struct ExecutorWriter
{
ExecutorWriter(
- const Owned<ObjectApprover>& taskApprover,
+ const Owned<ObjectApprovers>& approvers,
const Executor* executor,
const Framework* framework)
- : taskApprover_(taskApprover),
+ : approvers_(approvers),
executor_(executor),
framework_(framework) {}
@@ -210,7 +231,7 @@ struct ExecutorWriter
writer->field("tasks", [this](JSON::ArrayWriter* writer) {
foreachvalue (Task* task, executor_->launchedTasks) {
- if (!approveViewTask(taskApprover_, *task, framework_->info)) {
+ if (!approvers_->approved<VIEW_TASK>(*task, framework_->info)) {
continue;
}
@@ -220,7 +241,7 @@ struct ExecutorWriter
writer->field("queued_tasks", [this](JSON::ArrayWriter* writer) {
foreachvalue (const TaskInfo& task, executor_->queuedTasks) {
- if (!approveViewTaskInfo(taskApprover_, task, framework_->info)) {
+ if (!approvers_->approved<VIEW_TASK>(task, framework_->info)) {
continue;
}
@@ -230,7 +251,7 @@ struct ExecutorWriter
writer->field("completed_tasks", [this](JSON::ArrayWriter* writer) {
foreach (const std::shared_ptr<Task>& task, executor_->completedTasks) {
- if (!approveViewTask(taskApprover_, *task, framework_->info)) {
+ if (!approvers_->approved<VIEW_TASK>(*task, framework_->info)) {
continue;
}
@@ -240,7 +261,7 @@ struct ExecutorWriter
// NOTE: We add 'terminatedTasks' to 'completed_tasks' for
// simplicity.
foreachvalue (Task* task, executor_->terminatedTasks) {
- if (!approveViewTask(taskApprover_, *task, framework_->info)) {
+ if (!approvers_->approved<VIEW_TASK>(*task, framework_->info)) {
continue;
}
@@ -249,7 +270,7 @@ struct ExecutorWriter
});
}
- const Owned<ObjectApprover>& taskApprover_;
+ const Owned<ObjectApprovers>& approvers_;
const Executor* executor_;
const Framework* framework_;
};
@@ -260,11 +281,9 @@ struct ExecutorWriter
struct FrameworkWriter
{
FrameworkWriter(
- const Owned<ObjectApprover>& taskApprover,
- const Owned<ObjectApprover>& executorApprover,
+ const Owned<ObjectApprovers>& approvers,
const Framework* framework)
- : taskApprover_(taskApprover),
- executorApprover_(executorApprover),
+ : approvers_(approvers),
framework_(framework) {}
void operator()(JSON::ObjectWriter* writer) const
@@ -293,13 +312,13 @@ struct FrameworkWriter
writer->field("executors", [this](JSON::ArrayWriter* writer) {
foreachvalue (Executor* executor, framework_->executors) {
- if (!approveViewExecutorInfo(
- executorApprover_, executor->info, framework_->info)) {
+ if (!approvers_->approved<VIEW_EXECUTOR>(
+ executor->info, framework_->info)) {
continue;
}
ExecutorWriter executorWriter(
- taskApprover_,
+ approvers_,
executor,
framework_);
@@ -311,13 +330,13 @@ struct FrameworkWriter
"completed_executors", [this](JSON::ArrayWriter* writer) {
foreach (
const Owned<Executor>& executor, framework_->completedExecutors) {
- if (!approveViewExecutorInfo(
- executorApprover_, executor->info, framework_->info)) {
+ if (!approvers_->approved<VIEW_EXECUTOR>(
+ executor->info, framework_->info)) {
continue;
}
ExecutorWriter executorWriter(
- taskApprover_,
+ approvers_,
executor.get(),
framework_);
@@ -326,8 +345,7 @@ struct FrameworkWriter
});
}
- const Owned<ObjectApprover>& taskApprover_;
- const Owned<ObjectApprover>& executorApprover_;
+ const Owned<ObjectApprovers>& approvers_;
const Framework* framework_;
};
@@ -936,33 +954,20 @@ Future<Response> Http::getFlags(
LOG(INFO) << "Processing GET_FLAGS call";
- Future<Owned<ObjectApprover>> approver;
-
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- approver = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_FLAGS);
- } else {
- approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
-
- return approver.then(defer(slave->self(),
- [this, acceptType](
- const Owned<ObjectApprover>& approver) -> Future<Response> {
- Try<bool> approved = approver->approved(ObjectApprover::Object());
-
- if (approved.isError()) {
- return InternalServerError(approved.error());
- } else if (!approved.get()) {
- return Forbidden();
- }
+ return ObjectApprovers::create(slave->authorizer, principal, {VIEW_FLAGS})
+ .then(defer(
+ slave->self(),
+ [this, acceptType](
+ const Owned<ObjectApprovers>& approvers) -> Response {
+ if (!approvers->approved<VIEW_FLAGS>()) {
+ return Forbidden();
+ }
- return OK(
- serialize(
- acceptType, evolve<v1::agent::Response::GET_FLAGS>(_flags())),
- stringify(acceptType));
- }));
+ return OK(
+ serialize(
+ acceptType, evolve<v1::agent::Response::GET_FLAGS>(_flags())),
+ stringify(acceptType));
+ }));
}
@@ -1083,34 +1088,18 @@ Future<Response> Http::setLoggingLevel(
LOG(INFO) << "Processing SET_LOGGING_LEVEL call for level " << level;
- Future<Owned<ObjectApprover>> approver;
-
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- approver = slave->authorizer.get()->getObjectApprover(
- subject, authorization::SET_LOG_LEVEL);
- } else {
- approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
-
- return approver.then(
- [level, duration](
- const Owned<ObjectApprover>& approver) -> Future<Response> {
- Try<bool> approved = approver->approved((ObjectApprover::Object()));
-
- if (approved.isError()) {
- return InternalServerError(approved.error());
- } else if (!approved.get()) {
- return Forbidden();
- }
+ return ObjectApprovers::create(slave->authorizer, principal, {SET_LOG_LEVEL})
+ .then([level, duration](
+ const Owned<ObjectApprovers>& approvers) -> Future<Response> {
+ if (!approvers->approved<SET_LOG_LEVEL>()) {
+ return Forbidden();
+ }
- return dispatch(
- process::logging(), &Logging::set_level, level, duration)
- .then([]() -> Response {
- return OK();
- });
- });
+ return dispatch(process::logging(), &Logging::set_level, level, duration)
+ .then([]() -> Response {
+ return OK();
+ });
+ });
}
@@ -1274,238 +1263,179 @@ Future<Response> Http::state(
return ServiceUnavailable("Agent has not finished recovery");
}
- // Retrieve `ObjectApprover`s for authorizing frameworks and tasks.
- Future<Owned<ObjectApprover>> frameworksApprover;
- Future<Owned<ObjectApprover>> tasksApprover;
- Future<Owned<ObjectApprover>> executorsApprover;
- Future<Owned<ObjectApprover>> flagsApprover;
- Future<Owned<ObjectApprover>> rolesApprover;
-
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- frameworksApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_FRAMEWORK);
-
- tasksApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_TASK);
-
- executorsApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_EXECUTOR);
-
- flagsApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_FLAGS);
-
- rolesApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_ROLE);
- } else {
- frameworksApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- tasksApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- executorsApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- flagsApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- rolesApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
-
- return collect(
- frameworksApprover,
- tasksApprover,
- executorsApprover,
- flagsApprover,
- rolesApprover)
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {VIEW_FRAMEWORK, VIEW_TASK, VIEW_EXECUTOR, VIEW_FLAGS, VIEW_ROLE})
.then(defer(
slave->self(),
- [this, request](const tuple<Owned<ObjectApprover>,
- Owned<ObjectApprover>,
- Owned<ObjectApprover>,
- Owned<ObjectApprover>,
- Owned<ObjectApprover>>& approvers)
- -> Response {
- // This lambda is consumed before the outer lambda
- // returns, hence capture by reference is fine here.
- auto state = [this, &approvers](JSON::ObjectWriter* writer) {
- // Get approver from tuple.
- Owned<ObjectApprover> frameworksApprover;
- Owned<ObjectApprover> tasksApprover;
- Owned<ObjectApprover> executorsApprover;
- Owned<ObjectApprover> flagsApprover;
- Owned<ObjectApprover> rolesApprover;
- tie(frameworksApprover,
- tasksApprover,
- executorsApprover,
- flagsApprover,
- rolesApprover) = approvers;
-
- writer->field("version", MESOS_VERSION);
-
- if (build::GIT_SHA.isSome()) {
- writer->field("git_sha", build::GIT_SHA.get());
- }
+ [this, request](const Owned<ObjectApprovers>& approvers) -> Response {
+ // This lambda is consumed before the outer lambda
+ // returns, hence capture by reference is fine here.
+ auto state = [this, &approvers](JSON::ObjectWriter* writer) {
+ writer->field("version", MESOS_VERSION);
+
+ if (build::GIT_SHA.isSome()) {
+ writer->field("git_sha", build::GIT_SHA.get());
+ }
- if (build::GIT_BRANCH.isSome()) {
- writer->field("git_branch", build::GIT_BRANCH.get());
- }
+ if (build::GIT_BRANCH.isSome()) {
+ writer->field("git_branch", build::GIT_BRANCH.get());
+ }
- if (build::GIT_TAG.isSome()) {
- writer->field("git_tag", build::GIT_TAG.get());
- }
+ if (build::GIT_TAG.isSome()) {
+ writer->field("git_tag", build::GIT_TAG.get());
+ }
- writer->field("build_date", build::DATE);
- writer->field("build_time", build::TIME);
- writer->field("build_user", build::USER);
- writer->field("start_time", slave->startTime.secs());
+ writer->field("build_date", build::DATE);
+ writer->field("build_time", build::TIME);
+ writer->field("build_user", build::USER);
+ writer->field("start_time", slave->startTime.secs());
- writer->field("id", slave->info.id().value());
- writer->field("pid", string(slave->self()));
- writer->field("hostname", slave->info.hostname());
- writer->field("capabilities", slave->capabilities.toRepeatedPtrField());
+ writer->field("id", slave->info.id().value());
+ writer->field("pid", string(slave->self()));
+ writer->field("hostname", slave->info.hostname());
+ writer->field(
+ "capabilities",
+ slave->capabilities.toRepeatedPtrField());
- if (slave->info.has_domain()) {
- writer->field("domain", slave->info.domain());
- }
+ if (slave->info.has_domain()) {
+ writer->field("domain", slave->info.domain());
+ }
- const Resources& totalResources = slave->totalResources;
-
- writer->field("resources", totalResources);
- writer->field(
- "reserved_resources",
- [&totalResources, &rolesApprover](JSON::ObjectWriter* writer) {
- foreachpair (const string& role,
- const Resources& resources,
- totalResources.reservations()) {
- if (approveViewRole(rolesApprover, role)) {
- writer->field(role, resources);
- }
- }
- });
+ const Resources& totalResources = slave->totalResources;
- writer->field("unreserved_resources", totalResources.unreserved());
-
- writer->field(
- "reserved_resources_full",
- [&totalResources, &rolesApprover](JSON::ObjectWriter* writer) {
- foreachpair (const string& role,
- const Resources& resources,
- totalResources.reservations()) {
- if (approveViewRole(rolesApprover, role)) {
- writer->field(role, [&resources](JSON::ArrayWriter* writer) {
- foreach (Resource resource, resources) {
- convertResourceFormat(&resource, ENDPOINT);
- writer->element(JSON::Protobuf(resource));
+ writer->field("resources", totalResources);
+ writer->field(
+ "reserved_resources",
+ [&totalResources, &approvers](JSON::ObjectWriter* writer) {
+ foreachpair (const string& role,
+ const Resources& resources,
+ totalResources.reservations()) {
+ if (approvers->approved<VIEW_ROLE>(role)) {
+ writer->field(role, resources);
}
- });
- }
- }
- });
-
- writer->field(
- "unreserved_resources_full",
- [&totalResources](JSON::ArrayWriter* writer) {
- foreach (Resource resource, totalResources.unreserved()) {
- convertResourceFormat(&resource, ENDPOINT);
- writer->element(JSON::Protobuf(resource));
- }
- });
+ }
+ });
- // TODO(abudnik): Consider storing the allocatedResources in the Slave
- // struct rather than computing it here each time.
- Resources allocatedResources;
+ writer->field("unreserved_resources", totalResources.unreserved());
- foreachvalue (const Framework* framework, slave->frameworks) {
- allocatedResources += framework->allocatedResources();
- }
+ writer->field(
+ "reserved_resources_full",
+ [&totalResources, &approvers](JSON::ObjectWriter* writer) {
+ foreachpair (const string& role,
+ const Resources& resources,
+ totalResources.reservations()) {
+ if (approvers->approved<VIEW_ROLE>(role)) {
+ writer->field(
+ role,
+ [&resources](JSON::ArrayWriter* writer) {
+ foreach (Resource resource, resources) {
+ convertResourceFormat(&resource, ENDPOINT);
+ writer->element(JSON::Protobuf(resource));
+ }
+ });
+ }
+ }
+ });
- writer->field(
- "reserved_resources_allocated",
- [&allocatedResources, &rolesApprover](JSON::ObjectWriter* writer) {
- foreachpair (const string& role,
- const Resources& resources,
- allocatedResources.reservations()) {
- if (approveViewRole(rolesApprover, role)) {
- writer->field(role, resources);
- }
- }
- });
+ writer->field(
+ "unreserved_resources_full",
+ [&totalResources](JSON::ArrayWriter* writer) {
+ foreach (Resource resource, totalResources.unreserved()) {
+ convertResourceFormat(&resource, ENDPOINT);
+ writer->element(JSON::Protobuf(resource));
+ }
+ });
+
+ // TODO(abudnik): Consider storing the allocatedResources in the
+ // Slave struct rather than computing it here each time.
+ Resources allocatedResources;
+
+ foreachvalue (const Framework* framework, slave->frameworks) {
+ allocatedResources += framework->allocatedResources();
+ }
- writer->field(
- "unreserved_resources_allocated", allocatedResources.unreserved());
+ writer->field(
+ "reserved_resources_allocated",
+ [&allocatedResources, &approvers](JSON::ObjectWriter* writer) {
+ foreachpair (const string& role,
+ const Resources& resources,
+ allocatedResources.reservations()) {
+ if (approvers->approved<VIEW_ROLE>(role)) {
+ writer->field(role, resources);
+ }
+ }
+ });
- writer->field("attributes", Attributes(slave->info.attributes()));
+ writer->field(
+ "unreserved_resources_allocated",
+ allocatedResources.unreserved());
- if (slave->master.isSome()) {
- Try<string> hostname =
- net::getHostname(slave->master->address.ip);
+ writer->field("attributes", Attributes(slave->info.attributes()));
- if (hostname.isSome()) {
- writer->field("master_hostname", hostname.get());
- }
- }
+ if (slave->master.isSome()) {
+ Try<string> hostname =
+ net::getHostname(slave->master->address.ip);
- if (approveViewFlags(flagsApprover)) {
- if (slave->flags.log_dir.isSome()) {
- writer->field("log_dir", slave->flags.log_dir.get());
- }
+ if (hostname.isSome()) {
+ writer->field("master_hostname", hostname.get());
+ }
+ }
- if (slave->flags.external_log_file.isSome()) {
- writer->field(
- "external_log_file", slave->flags.external_log_file.get());
- }
+ if (approvers->approved<VIEW_FLAGS>()) {
+ if (slave->flags.log_dir.isSome()) {
+ writer->field("log_dir", slave->flags.log_dir.get());
+ }
- writer->field("flags", [this](JSON::ObjectWriter* writer) {
- foreachvalue (const flags::Flag& flag, slave->flags) {
- Option<string> value = flag.stringify(slave->flags);
- if (value.isSome()) {
- writer->field(flag.effective_name().value, value.get());
+ if (slave->flags.external_log_file.isSome()) {
+ writer->field(
+ "external_log_file", slave->flags.external_log_file.get());
}
- }
- });
- }
- // Model all of the frameworks.
- writer->field(
- "frameworks",
- [this, &frameworksApprover, &executorsApprover, &tasksApprover](
- JSON::ArrayWriter* writer) {
- foreachvalue (Framework* framework, slave->frameworks) {
- // Skip unauthorized frameworks.
- if (!approveViewFrameworkInfo(
- frameworksApprover, framework->info)) {
- continue;
+ writer->field("flags", [this](JSON::ObjectWriter* writer) {
+ foreachvalue (const flags::Flag& flag, slave->flags) {
+ Option<string> value = flag.stringify(slave->flags);
+ if (value.isSome()) {
+ writer->field(flag.effective_name().value, value.get());
+ }
+ }
+ });
}
- FrameworkWriter frameworkWriter(
- tasksApprover,
- executorsApprover,
- framework);
-
- writer->element(frameworkWriter);
- }
- });
+ // Model all of the frameworks.
+ writer->field(
+ "frameworks",
+ [this, &approvers](JSON::ArrayWriter* writer) {
+ foreachvalue (Framework* framework, slave->frameworks) {
+ // Skip unauthorized frameworks.
+ if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+ continue;
+ }
- // Model all of the completed frameworks.
- writer->field(
- "completed_frameworks",
- [this, &frameworksApprover, &executorsApprover, &tasksApprover](
- JSON::ArrayWriter* writer) {
- foreachvalue (const Owned<Framework>& framework,
- slave->completedFrameworks) {
- // Skip unauthorized frameworks.
- if (!approveViewFrameworkInfo(
- frameworksApprover, framework->info)) {
- continue;
- }
+ writer->element(FrameworkWriter(approvers, framework));
+ }
+ });
- FrameworkWriter frameworkWriter(
- tasksApprover,
- executorsApprover,
- framework.get());
+ // Model all of the completed frameworks.
+ writer->field(
+ "completed_frameworks",
+ [this, &approvers](JSON::ArrayWriter* writer) {
+ foreachvalue (const Owned<Framework>& framework,
+ slave->completedFrameworks) {
+ // Skip unauthorized frameworks.
+ if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+ continue;
+ }
- writer->element(frameworkWriter);
- }
- });
- };
+ writer->element(
+ FrameworkWriter(approvers, framework.get()));
+ }
+ });
+ };
- return OK(jsonify(state), request.url.query.get("jsonp"));
- }));
+ return OK(jsonify(state), request.url.query.get("jsonp"));
+ }));
}
@@ -1518,39 +1448,28 @@ Future<Response> Http::getFrameworks(
LOG(INFO) << "Processing GET_FRAMEWORKS call";
- // Retrieve `ObjectApprover`s for authorizing frameworks.
- Future<Owned<ObjectApprover>> frameworksApprover;
-
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- frameworksApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_FRAMEWORK);
- } else {
- frameworksApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
-
- return frameworksApprover
- .then(defer(slave->self(),
- [this, acceptType](const Owned<ObjectApprover>& frameworksApprover)
- -> Future<Response> {
- mesos::agent::Response response;
- response.set_type(mesos::agent::Response::GET_FRAMEWORKS);
- *response.mutable_get_frameworks() = _getFrameworks(frameworksApprover);
+ return ObjectApprovers::create(slave->authorizer, principal, {VIEW_FRAMEWORK})
+ .then(defer(
+ slave->self(),
+ [this, acceptType](
+ const Owned<ObjectApprovers>& approvers) -> Response {
+ mesos::agent::Response response;
+ response.set_type(mesos::agent::Response::GET_FRAMEWORKS);
+ *response.mutable_get_frameworks() = _getFrameworks(approvers);
- return OK(serialize(acceptType, evolve(response)),
- stringify(acceptType));
- }));
+ return OK(serialize(acceptType, evolve(response)),
+ stringify(acceptType));
+ }));
}
mesos::agent::Response::GetFrameworks Http::_getFrameworks(
- const Owned<ObjectApprover>& frameworksApprover) const
+ const Owned<ObjectApprovers>& approvers) const
{
mesos::agent::Response::GetFrameworks getFrameworks;
foreachvalue (const Framework* framework, slave->frameworks) {
// Skip unauthorized frameworks.
- if (!approveViewFrameworkInfo(frameworksApprover, framework->info)) {
+ if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
continue;
}
@@ -1560,7 +1479,7 @@ mesos::agent::Response::GetFrameworks Http::_getFrameworks(
foreachvalue (const Owned<Framework>& framework, slave->completedFrameworks) {
// Skip unauthorized frameworks.
- if (!approveViewFrameworkInfo(frameworksApprover, framework->info)) {
+ if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
continue;
}
@@ -1581,53 +1500,33 @@ Future<Response> Http::getExecutors(
LOG(INFO) << "Processing GET_EXECUTORS call";
- // Retrieve `ObjectApprover`s for authorizing frameworks and executors.
- Future<Owned<ObjectApprover>> frameworksApprover;
- Future<Owned<ObjectApprover>> executorsApprover;
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- frameworksApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_FRAMEWORK);
-
- executorsApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_EXECUTOR);
- } else {
- frameworksApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- executorsApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
-
- return collect(frameworksApprover, executorsApprover)
- .then(defer(slave->self(),
- [this, acceptType](const tuple<Owned<ObjectApprover>,
- Owned<ObjectApprover>>& approvers)
- -> Future<Response> {
- // Get approver from tuple.
- Owned<ObjectApprover> frameworksApprover;
- Owned<ObjectApprover> executorsApprover;
- tie(frameworksApprover, executorsApprover) = approvers;
-
- mesos::agent::Response response;
- response.set_type(mesos::agent::Response::GET_EXECUTORS);
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {VIEW_FRAMEWORK, VIEW_EXECUTOR})
+ .then(defer(
+ slave->self(),
+ [this, acceptType](
+ const Owned<ObjectApprovers>& approvers) -> Response {
+ mesos::agent::Response response;
+ response.set_type(mesos::agent::Response::GET_EXECUTORS);
- *response.mutable_get_executors() =
- _getExecutors(frameworksApprover, executorsApprover);
+ *response.mutable_get_executors() = _getExecutors(approvers);
- return OK(serialize(acceptType, evolve(response)),
- stringify(acceptType));
- }));
+ return OK(serialize(acceptType, evolve(response)),
+ stringify(acceptType));
+ }));
}
mesos::agent::Response::GetExecutors Http::_getExecutors(
- const Owned<ObjectApprover>& frameworksApprover,
- const Owned<ObjectApprover>& executorsApprover) const
+ const Owned<ObjectApprovers>& approvers) const
{
// Construct framework list with both active and completed frameworks.
vector<const Framework*> frameworks;
foreachvalue (Framework* framework, slave->frameworks) {
// Skip unauthorized frameworks.
- if (!approveViewFrameworkInfo(frameworksApprover, framework->info)) {
+ if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
continue;
}
@@ -1636,7 +1535,7 @@ mesos::agent::Response::GetExecutors Http::_getExecutors(
foreachvalue (const Owned<Framework>& framework, slave->completedFrameworks) {
// Skip unauthorized frameworks.
- if (!approveViewFrameworkInfo(frameworksApprover, framework->info)) {
+ if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
continue;
}
@@ -1648,9 +1547,9 @@ mesos::agent::Response::GetExecutors Http::_getExecutors(
foreach (const Framework* framework, frameworks) {
foreachvalue (Executor* executor, framework->executors) {
// Skip unauthorized executors.
- if (!approveViewExecutorInfo(executorsApprover,
- executor->info,
- framework->info)) {
+ if (!approvers->approved<VIEW_EXECUTOR>(
+ executor->info,
+ framework->info)) {
continue;
}
@@ -1660,9 +1559,9 @@ mesos::agent::Response::GetExecutors Http::_getExecutors(
foreach (const Owned<Executor>& executor, framework->completedExecutors) {
// Skip unauthorized executors.
- if (!approveViewExecutorInfo(executorsApprover,
- executor->info,
- framework->info)) {
+ if (!approvers->approved<VIEW_EXECUTOR>(
+ executor->info,
+ framework->info)) {
continue;
}
@@ -1709,61 +1608,33 @@ Future<Response> Http::getTasks(
LOG(INFO) << "Processing GET_TASKS call";
- // Retrieve Approvers for authorizing frameworks and tasks.
- Future<Owned<ObjectApprover>> frameworksApprover;
- Future<Owned<ObjectApprover>> tasksApprover;
- Future<Owned<ObjectApprover>> executorsApprover;
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- frameworksApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_FRAMEWORK);
-
- tasksApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_TASK);
-
- executorsApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_EXECUTOR);
- } else {
- frameworksApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- tasksApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- executorsApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
-
- return collect(frameworksApprover, tasksApprover, executorsApprover)
- .then(defer(slave->self(),
- [this, acceptType](const tuple<Owned<ObjectApprover>,
- Owned<ObjectApprover>,
- Owned<ObjectApprover>>& approvers)
- -> Future<Response> {
- // Get approver from tuple.
- Owned<ObjectApprover> frameworksApprover;
- Owned<ObjectApprover> tasksApprover;
- Owned<ObjectApprover> executorsApprover;
- tie(frameworksApprover, tasksApprover, executorsApprover) = approvers;
-
- mesos::agent::Response response;
- response.set_type(mesos::agent::Response::GET_TASKS);
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {VIEW_FRAMEWORK, VIEW_TASK, VIEW_EXECUTOR})
+ .then(defer(
+ slave->self(),
+ [this, acceptType](
+ const Owned<ObjectApprovers>& approvers) -> Response {
+ mesos::agent::Response response;
+ response.set_type(mesos::agent::Response::GET_TASKS);
- *response.mutable_get_tasks() =
- _getTasks(frameworksApprover, tasksApprover, executorsApprover);
+ *response.mutable_get_tasks() = _getTasks(approvers);
- return OK(serialize(acceptType, evolve(response)),
- stringify(acceptType));
- }));
+ return OK(serialize(acceptType, evolve(response)),
+ stringify(acceptType));
+ }));
}
mesos::agent::Response::GetTasks Http::_getTasks(
- const Owned<ObjectApprover>& frameworksApprover,
- const Owned<ObjectApprover>& tasksApprover,
- const Owned<ObjectApprover>& executorsApprover) const
+ const Owned<ObjectApprovers>& approvers) const
{
// Construct framework list with both active and completed frameworks.
vector<const Framework*> frameworks;
foreachvalue (Framework* framework, slave->frameworks) {
// Skip unauthorized frameworks.
- if (!approveViewFrameworkInfo(frameworksApprover, framework->info)) {
+ if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
continue;
}
@@ -1772,7 +1643,7 @@ mesos::agent::Response::GetTasks Http::_getTasks(
foreachvalue (const Owned<Framework>& framework, slave->completedFrameworks) {
// Skip unauthorized frameworks.
- if (!approveViewFrameworkInfo(frameworksApprover, framework->info)) {
+ if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
continue;
}
@@ -1784,9 +1655,8 @@ mesos::agent::Response::GetTasks Http::_getTasks(
foreach (const Framework* framework, frameworks) {
foreachvalue (Executor* executor, framework->executors) {
// Skip unauthorized executors.
- if (!approveViewExecutorInfo(executorsApprover,
- executor->info,
- framework->info)) {
+ if (!approvers->approved<VIEW_EXECUTOR>(
+ executor->info, framework->info)) {
continue;
}
@@ -1795,9 +1665,8 @@ mesos::agent::Response::GetTasks Http::_getTasks(
foreach (const Owned<Executor>& executor, framework->completedExecutors) {
// Skip unauthorized executors.
- if (!approveViewExecutorInfo(executorsApprover,
- executor->info,
- framework->info)) {
+ if (!approvers->approved<VIEW_EXECUTOR>(
+ executor->info, framework->info)) {
continue;
}
@@ -1813,7 +1682,7 @@ mesos::agent::Response::GetTasks Http::_getTasks(
foreachvalue (const TaskMap& taskInfos, framework->pendingTasks) {
foreachvalue (const TaskInfo& taskInfo, taskInfos) {
// Skip unauthorized tasks.
- if (!approveViewTaskInfo(tasksApprover, taskInfo, framework->info)) {
+ if (!approvers->approved<VIEW_TASK>(taskInfo, framework->info)) {
continue;
}
@@ -1831,7 +1700,7 @@ mesos::agent::Response::GetTasks Http::_getTasks(
// Queued tasks.
foreachvalue (const TaskInfo& taskInfo, executor->queuedTasks) {
// Skip unauthorized tasks.
- if (!approveViewTaskInfo(tasksApprover, taskInfo, framework->info)) {
+ if (!approvers->approved<VIEW_TASK>(taskInfo, framework->info)) {
continue;
}
@@ -1845,7 +1714,7 @@ mesos::agent::Response::GetTasks Http::_getTasks(
foreachvalue (Task* task, executor->launchedTasks) {
CHECK_NOTNULL(task);
// Skip unauthorized tasks.
- if (!approveViewTask(tasksApprover, *task, framework->info)) {
+ if (!approvers->approved<VIEW_TASK>(*task, framework->info)) {
continue;
}
@@ -1856,7 +1725,7 @@ mesos::agent::Response::GetTasks Http::_getTasks(
foreachvalue (Task* task, executor->terminatedTasks) {
CHECK_NOTNULL(task);
// Skip unauthorized tasks.
- if (!approveViewTask(tasksApprover, *task, framework->info)) {
+ if (!approvers->approved<VIEW_TASK>(*task, framework->info)) {
continue;
}
@@ -1866,7 +1735,7 @@ mesos::agent::Response::GetTasks Http::_getTasks(
// Completed tasks.
foreach (const std::shared_ptr<Task>& task, executor->completedTasks) {
// Skip unauthorized tasks.
- if (!approveViewTask(tasksApprover, *task.get(), framework->info)) {
+ if (!approvers->approved<VIEW_TASK>(*task.get(), framework->info)) {
continue;
}
@@ -1936,65 +1805,31 @@ Future<Response> Http::getState(
LOG(INFO) << "Processing GET_STATE call";
- // Retrieve Approvers for authorizing frameworks and tasks.
- Future<Owned<ObjectApprover>> frameworksApprover;
- Future<Owned<ObjectApprover>> tasksApprover;
- Future<Owned<ObjectApprover>> executorsApprover;
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- frameworksApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_FRAMEWORK);
-
- tasksApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_TASK);
-
- executorsApprover = slave->authorizer.get()->getObjectApprover(
- subject, authorization::VIEW_EXECUTOR);
- } else {
- frameworksApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- tasksApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- executorsApprover = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
-
- return collect(frameworksApprover, tasksApprover, executorsApprover)
- .then(defer(slave->self(),
- [=](const tuple<Owned<ObjectApprover>,
- Owned<ObjectApprover>,
- Owned<ObjectApprover>>& approvers)
- -> Future<Response> {
- // Get approver from tuple.
- Owned<ObjectApprover> frameworksApprover;
- Owned<ObjectApprover> tasksApprover;
- Owned<ObjectApprover> executorsApprover;
- tie(frameworksApprover, tasksApprover, executorsApprover) = approvers;
-
- mesos::agent::Response response;
- response.set_type(mesos::agent::Response::GET_STATE);
- *response.mutable_get_state() =
- _getState(frameworksApprover, tasksApprover, executorsApprover);
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {VIEW_FRAMEWORK, VIEW_TASK, VIEW_EXECUTOR})
+ .then(defer(
+ slave->self(),
+ [=](const Owned<ObjectApprovers>& approvers) -> Response {
+ mesos::agent::Response response;
+ response.set_type(mesos::agent::Response::GET_STATE);
+ *response.mutable_get_state() = _getState(approvers);
- return OK(serialize(acceptType, evolve(response)),
- stringify(acceptType));
- }));
+ return OK(serialize(acceptType, evolve(response)),
+ stringify(acceptType));
+ }));
}
mesos::agent::Response::GetState Http::_getState(
- const Owned<ObjectApprover>& frameworksApprover,
- const Owned<ObjectApprover>& tasksApprover,
- const Owned<ObjectApprover>& executorsApprover) const
+ const Owned<ObjectApprovers>& approvers) const
{
mesos::agent::Response::GetState getState;
- *getState.mutable_get_tasks() =
- _getTasks(frameworksApprover, tasksApprover, executorsApprover);
-
- *getState.mutable_get_executors() =
- _getExecutors(frameworksApprover, executorsApprover);
-
- *getState.mutable_get_frameworks() =
- _getFrameworks(frameworksApprover);
+ *getState.mutable_get_tasks() = _getTasks(approvers);
+ *getState.mutable_get_executors() = _getExecutors(approvers);
+ *getState.mutable_get_frameworks() = _getFrameworks(approvers);
return getState;
}
@@ -2191,32 +2026,21 @@ Future<Response> Http::getContainers(
LOG(INFO) << "Processing GET_CONTAINERS call";
- Future<Owned<AuthorizationAcceptor>> authorizeContainer =
- AuthorizationAcceptor::create(
- principal, slave->authorizer, authorization::VIEW_CONTAINER);
-
- Future<Owned<AuthorizationAcceptor>> authorizeStandaloneContainer =
- AuthorizationAcceptor::create(
- principal, slave->authorizer, authorization::VIEW_STANDALONE_CONTAINER);
-
- return collect(authorizeContainer, authorizeStandaloneContainer)
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {VIEW_CONTAINER, VIEW_STANDALONE_CONTAINER})
.then(defer(
slave->self(),
- [this, call](const tuple<Owned<AuthorizationAcceptor>,
- Owned<AuthorizationAcceptor>>& acceptors) {
- Owned<AuthorizationAcceptor> authorizeContainer;
- Owned<AuthorizationAcceptor> authorizeStandaloneContainer;
- tie(authorizeContainer, authorizeStandaloneContainer) = acceptors;
-
+ [this, call](const Owned<ObjectApprovers>& approvers) {
// Use an empty container ID filter.
return __containers(
- authorizeContainer,
- authorizeStandaloneContainer,
+ approvers,
None(),
call.get_containers().show_nested(),
call.get_containers().show_standalone());
- })).then([acceptType](const Future<JSON::Array>& result)
- -> Future<Response> {
+ }))
+ .then([acceptType](const Future<JSON::Array>& result) -> Response {
if (!result.isReady()) {
LOG(WARNING) << "Could not collect container status and statistics: "
<< (result.isFailed()
@@ -2240,60 +2064,43 @@ Future<Response> Http::_containers(
const Request& request,
const Option<Principal>& principal) const
{
- Future<Owned<AuthorizationAcceptor>> authorizeContainer =
- AuthorizationAcceptor::create(
- principal, slave->authorizer, authorization::VIEW_CONTAINER);
+ Option<string> containerId = request.url.query.get("container_id");
- Future<Owned<AuthorizationAcceptor>> authorizeStandaloneContainer =
- AuthorizationAcceptor::create(
- principal, slave->authorizer, authorization::VIEW_STANDALONE_CONTAINER);
-
- Future<IDAcceptor<ContainerID>> selectContainerId =
- IDAcceptor<ContainerID>(request.url.query.get("container_id"));
-
- return collect(authorizeContainer,
- authorizeStandaloneContainer,
- selectContainerId)
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {VIEW_CONTAINER, VIEW_STANDALONE_CONTAINER})
.then(defer(
slave->self(),
- [this](const tuple<Owned<AuthorizationAcceptor>,
- Owned<AuthorizationAcceptor>,
- IDAcceptor<ContainerID>>& acceptors) {
- Owned<AuthorizationAcceptor> authorizeContainer;
- Owned<AuthorizationAcceptor> authorizeStandaloneContainer;
- Option<IDAcceptor<ContainerID>> selectContainerId;
-
- tie(authorizeContainer,
- authorizeStandaloneContainer,
- selectContainerId) = acceptors;
+ [this, containerId](const Owned<ObjectApprovers>& approvers) {
+ IDAcceptor<ContainerID> selectContainerId(containerId);
return __containers(
- authorizeContainer,
- authorizeStandaloneContainer,
+ approvers,
selectContainerId,
false,
false);
- })).then([request](const Future<JSON::Array>& result) -> Future<Response> {
- if (!result.isReady()) {
- LOG(WARNING) << "Could not collect container status and statistics: "
- << (result.isFailed()
- ? result.failure()
- : "Discarded");
-
- return result.isFailed()
- ? InternalServerError(result.failure())
- : InternalServerError();
- }
-
- return process::http::OK(
- result.get(), request.url.query.get("jsonp"));
+ }))
+ .then([request](const Future<JSON::Array>& result) -> Response {
+ if (!result.isReady()) {
+ LOG(WARNING) << "Could not collect container status and statistics: "
+ << (result.isFailed()
+ ? result.failure()
+ : "Discarded");
+
+ return result.isFailed()
+ ? InternalServerError(result.failure())
+ : InternalServerError();
+ }
+
+ return process::http::OK(
+ result.get(), request.url.query.get("jsonp"));
});
}
Future<JSON::Array> Http::__containers(
- Owned<AuthorizationAcceptor> authorizeContainer,
- Owned<AuthorizationAcceptor> authorizeStandaloneContainer,
+ const Owned<ObjectApprovers>& approvers,
Option<IDAcceptor<ContainerID>> selectContainerId,
bool showNestedContainers,
bool showStandaloneContainers) const
@@ -2322,7 +2129,7 @@ Future<JSON::Array> Http::__containers(
if ((selectContainerId.isSome() &&
!selectContainerId->accept(containerId)) ||
- !authorizeContainer->accept(info, framework->info)) {
+ !approvers->approved<VIEW_CONTAINER>(info, framework->info)) {
continue;
}
@@ -2381,7 +2188,7 @@ Future<JSON::Array> Http::__containers(
}
if (isRootContainerStandalone &&
- !authorizeStandaloneContainer->accept()) {
+ !approvers->approved<VIEW_STANDALONE_CONTAINER>()) {
continue;
}
@@ -2480,47 +2287,34 @@ Future<Response> Http::pruneImages(
std::back_inserter(excludedImages));
}
- Future<Owned<ObjectApprover>> approver;
-
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- approver = slave->authorizer.get()->getObjectApprover(
- subject,
- authorization::PRUNE_IMAGES);
- } else {
- approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
-
- return approver
- .then(defer(slave->self(), [this, excludedImages](
- const Owned<ObjectApprover>& approver) -> Future<Response> {
- Try<bool> approved = approver->approved(ObjectApprover::Object());
- if (approved.isError()) {
- return InternalServerError("Authorization error: " + approved.error());
- } else if (!approved.get()) {
- return Forbidden();
- }
+ return ObjectApprovers::create(slave->authorizer, principal, {PRUNE_IMAGES})
+ .then(defer(
+ slave->self(),
+ [this, excludedImages](
+ const Owned<ObjectApprovers>& approvers) -> Future<Response> {
+ if (!approvers->approved<PRUNE_IMAGES>()) {
+ return Forbidden();
+ }
- return slave->containerizer->pruneImages(excludedImages)
- .then([](const Future<Nothing>& result) -> Future<Response> {
- if (!result.isReady()) {
- // TODO(zhitao): Because `containerizer::pruneImages` returns
- // a `Nothing` now, we cannot distinguish between actual
- // failure or the case that operator should drain the agent.
- // Consider returning more information.
- LOG(WARNING)
- << "Failed to prune images: "
- << (result.isFailed() ? result.failure() : "discarded");
-
- return result.isFailed()
- ? InternalServerError(result.failure())
- : InternalServerError();
- }
+ return slave->containerizer->pruneImages(excludedImages)
+ .then([](const Future<Nothing>& result) -> Response {
+ if (!result.isReady()) {
+ // TODO(zhitao): Because `containerizer::pruneImages` returns
+ // a `Nothing` now, we cannot distinguish between actual
+ // failure or the case that operator should drain the agent.
+ // Consider returning more information.
+ LOG(WARNING)
+ << "Failed to prune images: "
+ << (result.isFailed() ? result.failure() : "discarded");
+
+ return result.isFailed()
+ ? InternalServerError(result.failure())
+ : InternalServerError();
+ }
- return OK();
- });
- }));
+ return OK();
+ });
+ }));
}
@@ -2605,15 +2399,14 @@ Future<Response> Http::launchNestedContainer(
LOG(INFO) << "Processing LAUNCH_NESTED_CONTAINER call for container '"
<< call.launch_nested_container().container_id() << "'";
- Future<Owned<AuthorizationAcceptor>> authorizer =
- AuthorizationAcceptor::create(
- principal, slave->authorizer, authorization::LAUNCH_NESTED_CONTAINER);
-
- return authorizer
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {LAUNCH_NESTED_CONTAINER})
.then(defer(
slave->self(),
- [=](const Owned<AuthorizationAcceptor>& authorizer) {
- return _launchContainer(
+ [=](const Owned<ObjectApprovers>& authorizer) {
+ return _launchContainer<LAUNCH_NESTED_CONTAINER>(
call.launch_nested_container().container_id(),
call.launch_nested_container().command(),
None(),
@@ -2638,20 +2431,34 @@ Future<Response> Http::launchContainer(
LOG(INFO) << "Processing LAUNCH_CONTAINER call for container '"
<< call.launch_container().container_id() << "'";
- Future<Owned<AuthorizationAcceptor>> authorizer =
- AuthorizationAcceptor::create(
- principal,
- slave->authorizer,
- call.launch_container().container_id().has_parent()
- ? authorization::LAUNCH_NESTED_CONTAINER
- : authorization::LAUNCH_STANDALONE_CONTAINER);
+ if (call.launch_container().container_id().has_parent()) {
+ return launchContainer<LAUNCH_NESTED_CONTAINER>(
+ call,
+ acceptType,
+ principal);
+ }
+
+ return launchContainer<LAUNCH_STANDALONE_CONTAINER>(
+ call,
+ acceptType,
+ principal);
+}
+
- return authorizer
+template <authorization::Action action>
+Future<Response> Http::launchContainer(
+ const mesos::agent::Call& call,
+ ContentType acceptType,
+ const Option<Principal>& principal) const
+{
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {action})
.then(defer(
slave->self(),
- [=](const Owned<AuthorizationAcceptor>& authorizer)
- -> Future<Response> {
- return _launchContainer(
+ [=](const Owned<ObjectApprovers>& approvers) -> Future<Response> {
+ return _launchContainer<action>(
call.launch_container().container_id(),
call.launch_container().command(),
call.launch_container().resources(),
@@ -2660,11 +2467,12 @@ Future<Response> Http::launchContainer(
: Option<ContainerInfo>::none(),
ContainerClass::DEFAULT,
acceptType,
- authorizer);
+ approvers);
}));
}
+template <authorization::Action action>
Future<Response> Http::_launchContainer(
const ContainerID& containerId,
const CommandInfo& commandInfo,
@@ -2672,7 +2480,7 @@ Future<Response> Http::_launchContainer(
const Option<ContainerInfo>& containerInfo,
const Option<ContainerClass>& containerClass,
ContentType acceptType,
- const Owned<AuthorizationAcceptor>& authorizer) const
+ const Owned<ObjectApprovers>& approvers) const
{
Option<string> user;
@@ -2682,14 +2490,14 @@ Future<Response> Http::_launchContainer(
// launching a standalone container (possibly nested).
Executor* executor = slave->getExecutor(containerId);
if (executor == nullptr) {
- if (!authorizer->accept(containerId)) {
+ if (!approvers->approved<action>(containerId)) {
return Forbidden();
}
} else {
Framework* framework = slave->getFramework(executor->frameworkId);
CHECK_NOTNULL(framework);
- if (!authorizer->accept(
+ if (!approvers->approved<action>(
executor->info, framework->info, commandInfo, containerId)) {
return Forbidden();
}
@@ -2826,18 +2634,17 @@ Future<Response> Http::waitNestedContainer(
LOG(INFO) << "Processing WAIT_NESTED_CONTAINER call for container '"
<< call.wait_nested_container().container_id() << "'";
- Future<Owned<AuthorizationAcceptor>> authorizer =
- AuthorizationAcceptor::create(
- principal, slave->authorizer, authorization::WAIT_NESTED_CONTAINER);
-
- return authorizer
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {WAIT_NESTED_CONTAINER})
.then(defer(
slave->self(),
- [=](const Owned<AuthorizationAcceptor>& authorizer) {
- return _waitContainer(
+ [=](const Owned<ObjectApprovers>& approvers) {
+ return _waitContainer<WAIT_NESTED_CONTAINER>(
call.wait_nested_container().container_id(),
acceptType,
- authorizer,
+ approvers,
true);
}));
}
@@ -2854,31 +2661,41 @@ Future<Response> Http::waitContainer(
LOG(INFO) << "Processing WAIT_CONTAINER call for container '"
<< call.wait_container().container_id() << "'";
- Future<Owned<AuthorizationAcceptor>> authorizer =
- AuthorizationAcceptor::create(
- principal,
- slave->authorizer,
- call.wait_container().container_id().has_parent()
- ? authorization::WAIT_NESTED_CONTAINER
- : authorization::WAIT_STANDALONE_CONTAINER);
+ if (call.wait_container().container_id().has_parent()) {
+ return waitContainer<WAIT_NESTED_CONTAINER>(call, acceptType, principal);
+ }
- return authorizer
+ return waitContainer<WAIT_STANDALONE_CONTAINER>(call, acceptType, principal);
+}
+
+
+template <authorization::Action action>
+Future<Response> Http::waitContainer(
+ const mesos::agent::Call& call,
+ ContentType acceptType,
+ const Option<Principal>& principal) const
+{
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {action})
.then(defer(
slave->self(),
- [=](const Owned<AuthorizationAcceptor>& authorizer) {
- return _waitContainer(
+ [=](const Owned<ObjectApprovers>& approvers) {
+ return _waitContainer<action>(
call.wait_container().container_id(),
acceptType,
- authorizer,
+ approvers,
false);
}));
}
+template <authorization::Action action>
Future<Response> Http::_waitContainer(
const ContainerID& containerId,
ContentType acceptType,
- const Owned<AuthorizationAcceptor>& authorizer,
+ const Owned<ObjectApprovers>& approvers,
const bool deprecated) const
{
// Attempt to get the executor associated with this ContainerID.
@@ -2887,17 +2704,15 @@ Future<Response> Http::_waitContainer(
// waiting on a standalone container (possibly nested).
Executor* executor = slave->getExecutor(containerId);
if (executor == nullptr) {
- if (!authorizer->accept(containerId)) {
+ if (!approvers->approved<action>(containerId)) {
return Forbidden();
}
} else {
Framework* framework = slave->getFramework(executor->frameworkId);
CHECK_NOTNULL(framework);
- if (!authorizer->accept(
- executor->info,
- framework->info,
- containerId)) {
+ if (!approvers->approved<action>(
+ executor->info, framework->info, containerId)) {
return Forbidden();
}
}
@@ -2984,25 +2799,24 @@ Future<Response> Http::killNestedContainer(
LOG(INFO) << "Processing KILL_NESTED_CONTAINER call for container '"
<< call.kill_nested_container().container_id() << "'";
- Future<Owned<AuthorizationAcceptor>> authorizer =
- AuthorizationAcceptor::create(
- principal, slave->authorizer, authorization::KILL_NESTED_CONTAINER);
-
// SIGKILL is used by default if a signal is not specified.
int signal = SIGKILL;
if (call.kill_nested_container().has_signal()) {
signal = call.kill_nested_container().signal();
}
- return authorizer
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {KILL_NESTED_CONTAINER})
.then(defer(
slave->self(),
- [=](const Owned<AuthorizationAcceptor>& authorizer) {
- return _killContainer(
+ [=](const Owned<ObjectApprovers>& approvers) {
+ return _killContainer<KILL_NESTED_CONTAINER>(
call.kill_nested_container().container_id(),
signal,
acceptType,
- authorizer);
+ approvers);
}));
}
@@ -3018,38 +2832,48 @@ Future<Response> Http::killContainer(
LOG(INFO) << "Processing KILL_CONTAINER call for container '"
<< call.kill_container().container_id() << "'";
- Future<Owned<AuthorizationAcceptor>> authorizer =
- AuthorizationAcceptor::create(
- principal,
- slave->authorizer,
- call.kill_container().container_id().has_parent()
- ? authorization::KILL_NESTED_CONTAINER
- : authorization::KILL_STANDALONE_CONTAINER);
+ if (call.kill_container().container_id().has_parent()) {
+ return killContainer<KILL_NESTED_CONTAINER>(call, acceptType, principal);
+ }
+
+ return killContainer<KILL_STANDALONE_CONTAINER>(call, acceptType, principal);
+}
+
+template <mesos::authorization::Action action>
+Future<Response> Http::killContainer(
+ const mesos::agent::Call& call,
+ ContentType acceptType,
+ const Option<Principal>& principal) const
+{
// SIGKILL is used by default if a signal is not specified.
int signal = SIGKILL;
if (call.kill_container().has_signal()) {
signal = call.kill_container().signal();
}
- return authorizer
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {action})
.then(defer(
slave->self(),
- [=](const Owned<AuthorizationAcceptor>& authorizer) {
- return _killContainer(
+ [=](const Owned<ObjectApprovers>& approvers) {
+ return _killContainer<action>(
call.kill_container().container_id(),
signal,
acceptType,
- authorizer);
+ approvers);
}));
}
+template <mesos::authorization::Action action>
Future<Response> Http::_killContainer(
const ContainerID& containerId,
const int signal,
ContentType acceptType,
- const Owned<AuthorizationAcceptor>& authorizer) const
+ const Owned<ObjectApprovers>& approvers) const
{
// Attempt to get the executor associated with this ContainerID.
// We only expect to get the executor when killing a nested container
@@ -3057,14 +2881,14 @@ Future<Response> Http::_killContainer(
// killing a standalone container (possibly nested).
Executor* executor = slave->getExecutor(containerId);
if (executor == nullptr) {
- if (!authorizer->accept(containerId)) {
+ if (!approvers->approved<action>(containerId)) {
return Forbidden();
}
} else {
Framework* framework = slave->getFramework(executor->frameworkId);
CHECK_NOTNULL(framework);
- if (!authorizer->accept(
+ if (!approvers->approved<action>(
executor->info,
framework->info,
containerId)) {
@@ -3096,19 +2920,18 @@ Future<Response> Http::removeNestedContainer(
LOG(INFO) << "Processing REMOVE_NESTED_CONTAINER call for container '"
<< call.remove_nested_container().container_id() << "'";
- Future<Owned<AuthorizationAcceptor>> authorizer =
- AuthorizationAcceptor::create(
- principal, slave->authorizer, authorization::REMOVE_NESTED_CONTAINER);
-
- return authorizer
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {REMOVE_NESTED_CONTAINER})
.then(defer(
- slave->self(),
- [=](const Owned<AuthorizationAcceptor>& authorizer) {
- return _removeContainer(
- call.remove_nested_container().container_id(),
- acceptType,
- authorizer);
- }));
+ slave->self(),
+ [=](const Owned<ObjectApprovers>& approvers) {
+ return _removeContainer<REMOVE_NESTED_CONTAINER>(
+ call.remove_nested_container().container_id(),
+ acceptType,
+ approvers);
+ }));
}
@@ -3123,30 +2946,46 @@ Future<Response> Http::removeContainer(
LOG(INFO) << "Processing REMOVE_CONTAINER call for container '"
<< call.remove_container().container_id() << "'";
- Future<Owned<AuthorizationAcceptor>> authorizer =
- AuthorizationAcceptor::create(
- principal,
- slave->authorizer,
- call.remove_container().container_id().has_parent()
- ? authorization::REMOVE_NESTED_CONTAINER
- : authorization::REMOVE_STANDALONE_CONTAINER);
+ if (call.remove_container().container_id().has_parent()) {
+ return removeContainer<REMOVE_NESTED_CONTAINER>(
+ call,
+ acceptType,
+ principal);
+ }
+
+ return removeContainer<REMOVE_STANDALONE_CONTAINER>(
+ call,
+ acceptType,
+ principal);
+}
+
- return authorizer
+template <mesos::authorization::Action action>
+Future<Response> Http::removeContainer(
+ const mesos::agent::Call& call,
+ ContentType acceptType,
+ const Option<Principal>& principal) const
+{
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {action})
.then(defer(
slave->self(),
- [=](const Owned<AuthorizationAcceptor>& authorizer) {
- return _removeContainer(
+ [=](const Owned<ObjectApprovers>& approvers) {
+ return _removeContainer<action>(
call.remove_container().container_id(),
acceptType,
- authorizer);
+ approvers);
}));
}
+template <mesos::authorization::Action action>
Future<Response> Http::_removeContainer(
const ContainerID& containerId,
ContentType acceptType,
- const Owned<AuthorizationAcceptor>& authorizer) const
+ const Owned<ObjectApprovers>& approvers) const
{
// Attempt to get the executor associated with this ContainerID.
// We only expect to get the executor when removing a nested container
@@ -3154,14 +2993,14 @@ Future<Response> Http::_removeContainer(
// removing a standalone container (possibly nested).
Executor* executor = slave->getExecutor(containerId);
if (executor == nullptr) {
- if (!authorizer->accept(containerId)) {
+ if (!approvers->approved<action>(containerId)) {
return Forbidden();
}
} else {
Framework* framework = slave->getFramework(executor->frameworkId);
CHECK_NOTNULL(framework);
- if (!authorizer->accept(
+ if (!approvers->approved<action>(
executor->info,
framework->info,
containerId)) {
@@ -3273,46 +3112,37 @@ Future<Response> Http::attachContainerInput(
LOG(INFO) << "Processing ATTACH_CONTAINER_INPUT call for container '"
<< call.attach_container_input().container_id() << "'";
- Future<Owned<ObjectApprover>> approver;
-
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- approver = slave->authorizer.get()->getObjectApprover(
- subject, authorization::ATTACH_CONTAINER_INPUT);
- } else {
- approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
-
- return approver.then(defer(slave->self(),
- [this, call, decoder, mediaTypes](
- const Owned<ObjectApprover>& attachInputApprover) -> Future<Response> {
- const ContainerID& containerId =
- call.attach_container_input().container_id();
-
- Executor* executor = slave->getExecutor(containerId);
- if (executor == nullptr) {
- return NotFound(
- "Container " + stringify(containerId) + " cannot be found");
- }
-
- Framework* framework = slave->getFramework(executor->frameworkId);
- CHECK_NOTNULL(framework);
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {ATTACH_CONTAINER_INPUT})
+ .then(defer(
+ slave->self(),
+ [this, call, decoder, mediaTypes](
+ const Owned<ObjectApprovers>& approvers) -> Future<Response> {
+ const ContainerID& containerId =
+ call.attach_container_input().container_id();
+
+ Executor* executor = slave->getExecutor(containerId);
+ if (executor == nullptr) {
+ return NotFound(
+ "Container " + stringify(containerId) + " cannot be found");
+ }
- Try<bool> approved = attachInputApprover->approved(
- ObjectApprover::Object(executor->info, framework->info));
+ Framework* framework = slave->getFramework(executor->frameworkId);
+ CHECK_NOTNULL(framework);
- if (approved.isError()) {
- return Failure(approved.error());
- } else if (!approved.get()) {
- return Forbidden();
- }
+ if (!approvers->approved<ATTACH_CONTAINER_INPUT>(
+ executor->info,
+ framework->info)) {
+ return Forbidden();
+ }
- Owned<Reader<mesos::agent::Call>> decoder_ = decoder;
+ Owned<Reader<mesos::agent::Call>> decoder_ = decoder;
- return _attachContainerInput(
- call, std::move(decoder_), mediaTypes);
- }));
+ return _attachContainerInput(
+ call, std::move(decoder_), mediaTypes);
+ }));
}
@@ -3323,52 +3153,41 @@ Future<Response> Http::addResourceProviderConfig(
CHECK_EQ(mesos::agent::Call::ADD_RESOURCE_PROVIDER_CONFIG, call.type());
CHECK(call.has_add_resource_provider_config());
- Future<Owned<ObjectApprover>> approver;
-
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- approver = slave->authorizer.get()->getObjectApprover(
- subject,
- authorization::MODIFY_RESOURCE_PROVIDER_CONFIG);
- } else {
- approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {MODIFY_RESOURCE_PROVIDER_CONFIG})
+ .then(defer(
+ slave->self(),
+ [=](const Owned<ObjectApprovers>& approvers) -> Future<Response> {
+ if (!approvers->approved<MODIFY_RESOURCE_PROVIDER_CONFIG>()) {
+ return Forbidden();
+ }
- return approver
- .then(defer(slave->self(), [=](
- const Owned<ObjectApprover>& approver) -> Future<Response> {
- Try<bool> approved = approver->approved(ObjectApprover::Object());
- if (approved.isError()) {
- return InternalServerError("Authorization error: " + approved.error());
- } else if (!approved.get()) {
- return Forbidden();
- }
+ const ResourceProviderInfo& info =
+ call.add_resource_provider_config().info();
- const ResourceProviderInfo& info =
- call.add_resource_provider_config().info();
+ LOG(INFO)
+ << "Processing ADD_RESOURCE_PROVIDER_CONFIG call with type '"
+ << info.type() << "' and name '" << info.name() << "'";
- LOG(INFO)
- << "Processing ADD_RESOURCE_PROVIDER_CONFIG call with type '"
- << info.type() << "' and name '" << info.name() << "'";
+ return slave->localResourceProviderDaemon->add(info)
+ .then([](bool added) -> Response {
+ if (!added) {
+ return Conflict();
+ }
- return slave->localResourceProviderDaemon->add(info)
- .then([](bool added) -> Response {
- if (!added) {
- return Conflict();
- }
+ return OK();
+ })
+ .repair([info](const Future<Response>& future) {
+ LOG(ERROR)
+ << "Failed to add resource provider config with type '"
+ << info.type() << "' and name '" << info.name() << "': "
+ << future.failure();
- return OK();
- })
- .repair([info](const Future<Response>& future) {
- LOG(ERROR)
- << "Failed to add resource provider config with type '"
- << info.type() << "' and name '" << info.name() << "': "
- << future.failure();
-
- return InternalServerError(future.failure());
- });
- }));
+ return InternalServerError(future.failure());
+ });
+ }));
}
@@ -3379,52 +3198,41 @@ Future<Response> Http::updateResourceProviderConfig(
CHECK_EQ(mesos::agent::Call::UPDATE_RESOURCE_PROVIDER_CONFIG, call.type());
CHECK(call.has_update_resource_provider_config());
- Future<Owned<ObjectApprover>> approver;
-
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- approver = slave->authorizer.get()->getObjectApprover(
- subject,
- authorization::MODIFY_RESOURCE_PROVIDER_CONFIG);
- } else {
- approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {MODIFY_RESOURCE_PROVIDER_CONFIG})
+ .then(defer(
+ slave->self(),
+ [=](const Owned<ObjectApprovers>& approvers) -> Future<Response> {
+ if (!approvers->approved<MODIFY_RESOURCE_PROVIDER_CONFIG>()) {
+ return Forbidden();
+ }
- return approver
- .then(defer(slave->self(), [=](
- const Owned<ObjectApprover>& approver) -> Future<Response> {
- Try<bool> approved = approver->approved(ObjectApprover::Object());
- if (approved.isError()) {
- return InternalServerError("Authorization error: " + approved.error());
- } else if (!approved.get()) {
- return Forbidden();
- }
+ const ResourceProviderInfo& info =
+ call.update_resource_provider_config().info();
- const ResourceProviderInfo& info =
- call.update_resource_provider_config().info();
+ LOG(INFO)
+ << "Processing UPDATE_RESOURCE_PROVIDER_CONFIG call with type '"
+ << info.type() << "' and name '" << info.name() << "'";
- LOG(INFO)
- << "Processing UPDATE_RESOURCE_PROVIDER_CONFIG call with type '"
- << info.type() << "' and name '" << info.name() << "'";
+ return slave->localResourceProviderDaemon->update(info)
+ .then([](bool updated) -> Response {
+ if (!updated) {
+ return NotFound();
+ }
- return slave->localResourceProviderDaemon->update(info)
- .then([](bool updated) -> Response {
- if (!updated) {
- return NotFound();
- }
+ return OK();
+ })
+ .repair([info](const Future<Response>& future) {
+ LOG(ERROR)
+ << "Failed to update resource provider config with type '"
+ << info.type() << "' and name '" << info.name() << "': "
+ << future.failure();
- return OK();
- })
- .repair([info](const Future<Response>& future) {
- LOG(ERROR)
- << "Failed to update resource provider config with type '"
- << info.type() << "' and name '" << info.name() << "': "
- << future.failure();
-
- return InternalServerError(future.failure());
- });
- }));
+ return InternalServerError(future.failure());
+ });
+ }));
}
@@ -3435,51 +3243,41 @@ Future<Response> Http::removeResourceProviderConfig(
CHECK_EQ(mesos::agent::Call::REMOVE_RESOURCE_PROVIDER_CONFIG, call.type());
CHECK(call.has_remove_resource_provider_config());
- Future<Owned<ObjectApprover>> approver;
-
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- approver = slave->authorizer.get()->getObjectApprover(
- subject,
- authorization::MODIFY_RESOURCE_PROVIDER_CONFIG);
- } else {
- approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
-
- return approver
- .then(defer(slave->self(), [=](
- const Owned<ObjectApprover>& approver) -> Future<Response> {
- Try<bool> approved = approver->approved(ObjectApprover::Object());
- if (approved.isError()) {
- return InternalServerError("Authorization error: " + approved.error());
- } else if (!approved.get()) {
- return Forbidden();
- }
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {MODIFY_RESOURCE_PROVIDER_CONFIG})
+ .then(defer(
+ slave->self(),
+ [=](const Owned<ObjectApprovers>& approvers) -> Future<Response> {
+ if (!approvers->approved<MODIFY_RESOURCE_PROVIDER_CONFIG>()) {
+ return Forbidden();
+ }
- const string& type = call.remove_resource_provider_config().type();
- const string& name = call.remove_resource_provider_config().name();
+ const string& type = call.remove_resource_provider_config().type();
+ const string& name = call.remove_resource_provider_config().name();
- LOG(INFO)
- << "Processing REMOVE_RESOURCE_PROVIDER_CONFIG call with type '" << type
- << "' and name '" << name << "'";
+ LOG(INFO)
+ << "Processing REMOVE_RESOURCE_PROVIDER_CONFIG call with type '"
+ << type << "' and name '" << name << "'";
- return slave->localResourceProviderDaemon->remove(type, name)
- .then([](bool removed) -> Response {
- if (!removed) {
- return NotFound();
- }
+ return slave->localResourceProviderDaemon->remove(type, name)
+ .then([](bool removed) -> Response {
+ if (!removed) {
+ return NotFound();
+ }
- return OK();
- })
- .repair([type, name](const Future<Response>& future) {
- LOG(ERROR)
- << "Failed to remove resource provider config with type '" << type
- << "' and name '" << name << "': " << future.failure();
+ return OK();
+ })
+ .repair([type, name](const Future<Response>& future) {
+ LOG(ERROR)
+ << "Failed to remove resource provider config with type '"
+ << type << "' and name '" << name << "': "
+ << future.failure();
- return InternalServerError(future.failure());
- });
- }));
+ return InternalServerError(future.failure());
+ });
+ }));
}
@@ -3520,28 +3318,6 @@ Future<Response> Http::launchNestedContainerSession(
LOG(INFO) << "Processing LAUNCH_NESTED_CONTAINER_SESSION call for container '"
<< call.launch_nested_container_session().container_id() << "'";
- Future<Owned<AuthorizationAcceptor>> authorizer =
- AuthorizationAcceptor::create(
- principal,
- slave->authorizer,
- authorization::LAUNCH_NESTED_CONTAINER_SESSION);
-
- Future<Response> response = authorizer
- .then(defer(
- slave->self(),
- [=](const Owned<AuthorizationAcceptor>& authorizer) {
- return _launchContainer(
- call.launch_nested_container_session().container_id(),
- call.launch_nested_container_session().command(),
- None(),
- call.launch_nested_container_session().has_container()
- ? call.launch_nested_container_session().container()
- : Option<ContainerInfo>::none(),
- ContainerClass::DEBUG,
- mediaTypes.accept,
- authorizer);
- }));
-
// Helper to destroy the container.
auto destroy = [this](const ContainerID& containerId) {
slave->containerizer->destroy(containerId)
@@ -3551,99 +3327,125 @@ Future<Response> Http::launchNestedContainerSession(
});
};
- // If `response` has failed or is not `OK`, the container will be
- // destroyed by `_launchContainer`.
- return response
- .then(defer(slave->self(),
- [=](const Response& response) -> Future<Response> {
- const ContainerID& containerId =
- call.launch_nested_container_session().container_id();
-
- if (response.status != OK().status) {
- return response;
- }
-
- // If launch is successful, attach to the container output.
- mesos::agent::Call call;
- call.set_type(mesos::agent::Call::ATTACH_CONTAINER_OUTPUT);
- call.mutable_attach_container_output()->mutable_container_id()
- ->CopyFrom(containerId);
-
- // Instead of directly returning the response of `attachContainerOutput`
- // to the client, we use a level of indirection to make sure the container
- // is destroyed when the client connection breaks.
- return attachContainerOutput(call, mediaTypes, principal)
- .then(defer(slave->self(),
- [=](const Response& response) -> Future<Response> {
- if (response.status != OK().status) {
- LOG(WARNING) << "Failed to attach to nested container "
- << containerId << ": '" << response.status << "' ("
- << response.body << ")";
-
- destroy(containerId);
- return response;
- }
-
- Pipe pipe;
- Pipe::Writer writer = pipe.writer();
-
- OK ok;
- ok.headers = response.headers; // Reuse the headers from the response.
- ok.type = Response::PIPE;
- ok.reader = pipe.reader();
-
- CHECK_EQ(Response::PIPE, response.type);
- CHECK_SOME(response.reader);
- Pipe::Reader reader = response.reader.get();
-
- // Read from the `response` pipe and write to
- // the client's response pipe.
- // NOTE: Need to cast the lambda to std::function here because of a
- // limitation of `defer`; `defer` does not work with `mutable` lambda.
- std::function<void (const Future<Nothing>&)> _connect =
- [=](const Future<Nothing>& future) mutable {
- CHECK(!future.isDiscarded());
-
- if (future.isFailed()) {
- LOG(WARNING) << "Failed to send attach response for "
- << containerId << ": " << future.failure();
-
- writer.fail(future.failure());
- reader.close();
- } else {
- // EOF case.
- LOG(INFO) << "Received EOF attach response for " << containerId;
-
- writer.close();
- reader.close();
- }
-
- destroy(containerId);
- };
-
- connect(reader, writer)
- .onAny(defer(slave->self(), _connect));
-
- // Destroy the container if the connection to client is closed.
- writer.readerClosed()
- .onAny(defer(slave->self(), [=](const Future<Nothing>& future) {
- LOG(WARNING)
- << "Launch nested container session connection"
- << " for container " << containerId << " closed"
- << (future.isFailed() ? ": " + future.failure() : "");
-
- destroy(containerId);
- }));
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {LAUNCH_NESTED_CONTAINER_SESSION})
+ .then(defer(
+ slave->self(),
+ [=](const Owned<ObjectApprovers>& approvers) {
+ return _launchContainer<LAUNCH_NESTED_CONTAINER_SESSION>(
+ call.launch_nested_container_session().container_id(),
+ call.launch_nested_container_session().command(),
+ None(),
+ call.launch_nested_container_session().has_container()
+ ? call.launch_nested_container_session().container()
+ : Option<ContainerInfo>::none(),
+ ContainerClass::DEBUG,
+ mediaTypes.accept,
+ approvers);
+ }))
+ .then(defer(
+ slave->self(),
+ [=](const Response& response) -> Future<Response> {
+ // If `response` has failed or is not `OK`, the container will be
+ // destroyed by `_launchContainer`.
+ const ContainerID& containerId =
+ call.launch_nested_container_session().container_id();
+
+ if (response.status != OK().status) {
+ return response;
+ }
- return ok;
- }))
- .onFailed(defer(slave->self(), [=](const string& failure) {
- LOG(WARNING) << "Failed to attach to nested container "
- << containerId << ": " << failure;
+ // If launch is successful, attach to the container output.
+ mesos::agent::Call call;
+ call.set_type(mesos::agent::Call::ATTACH_CONTAINER_OUTPUT);
+ call.mutable_attach_container_output()->mutable_container_id()
+ ->CopyFrom(containerId);
+
+ // Instead of directly returning the response of `attachContainerOutput`
+ // to the client, we use a level of indirection to make sure the
+ // container is destroyed when the client connection breaks.
+ return attachContainerOutput(call, mediaTypes, principal)
+ .then(defer(
+ slave->self(),
+ [=](const Response& response) -> Future<Response> {
+ if (response.status != OK().status) {
+ LOG(WARNING) << "Failed to attach to nested container "
+ << containerId << ": '" << response.status
+ << "' (" << response.body << ")";
+
+ destroy(containerId);
+ return response;
+ }
- destroy(containerId);
- }));
- }));
+ Pipe pipe;
+ Pipe::Writer writer = pipe.writer();
+
+ OK ok;
+ ok.headers = response.headers; // Reuse headers from response.
+ ok.type = Response::PIPE;
+ ok.reader = pipe.reader();
+
+ CHECK_EQ(Response::PIPE, response.type);
+ CHECK_SOME(response.reader);
+ Pipe::Reader reader = response.reader.get();
+
+ // Read from the `response` pipe and write to
+ // the client's response pipe.
+ // NOTE: Need to cast the lambda to std::function here because
+ // of a limitation of `defer`; `defer` does not work with
+ // `mutable` lambda.
+ std::function<void (const Future<Nothing>&)> _connect =
+ [=](const Future<Nothing>& future) mutable {
+ CHECK(!future.isDiscarded());
+
+ if (future.isFailed()) {
+ LOG(WARNING) << "Failed to send attach response for "
+ << containerId << ": " << future.failure();
+
+ writer.fail(future.failure());
+ reader.close();
+ } else {
+ // EOF case.
+ LOG(INFO) << "Received EOF attach response for "
+ << containerId;
+
+ writer.close();
+ reader.close();
+ }
+
+ destroy(containerId);
+ };
+
+ connect(reader, writer).onAny(defer(slave->self(), _connect));
+
+ // Destroy the container if the connection to client is closed.
+ writer.readerClosed()
+ .onAny(defer(
+ slave->self(),
+ [=](const Future<Nothing>& future) {
+ LOG(WARNING)
+ << "Launch nested container session connection"
+ << " for container " << containerId << " closed"
+ << (future.isFailed()
+ ? ": " + future.failure()
+ : "");
+
+ destroy(containerId);
+ }));
+
+ return ok;
+ }))
+ .onFailed(defer(
+ slave->self(),
+ [=](const string& failure) {
+ LOG(WARNING) << "Failed to attach to nested container "
+ << containerId << ": " << failure;
+
+ destroy(containerId);
+ }));
+ }));
}
@@ -3760,47 +3562,32 @@ Future<Response> Http::attachContainerOutput(
LOG(INFO) << "Processing ATTACH_CONTAINER_OUTPUT call for container '"
<< call.attach_container_output().container_id() << "'";
+ return ObjectApprovers::create(
+ slave->authorizer,
+ principal,
+ {ATTACH_CONTAINER_OUTPUT})
+ .then(defer(
+ slave->self(),
+ [=](const Owned<ObjectApprovers>& approvers) -> Future<Response> {
+ const ContainerID& containerId =
+ call.attach_container_output().container_id();
+
+ Executor* executor = slave->getExecutor(containerId);
+ if (executor == nullptr) {
+ return NotFound(
+ "Container " + stringify(containerId) + " cannot be found");
+ }
- Future<Owned<ObjectApprover>> approver;
-
- if (slave->authorizer.isSome()) {
- Option<authorization::Subject> subject = createSubject(principal);
-
- approver = slave->authorizer.get()->getObjectApprover(
- subject, authorization::ATTACH_CONTAINER_OUTPUT);
- } else {
- approver = Owned<ObjectApprover>(new AcceptingObjectApprover());
- }
-
- return approver.then(defer(slave->self(),
- [this, call, mediaTypes](
- const Owned<ObjectApprover>& attachOutputApprover) -> Future<Response> {
- const ContainerID& containerId =
- call.attach_container_output().container_id();
-
- Executor* executor = slave->getExecutor(containerId);
- if (executor == nullptr) {
- return NotFound(
- "Container " + stringify(containerId) + " cannot be found");
- }
-
- Framework* framework = slave->getFramework(executor->frameworkId);
- CHECK_NOTNULL(framework);
-
- Try<bool> approved = attachOutputApprover->approved(
- ObjectApprover::Object(
- executor->info,
- framework->info,
- containerId));
+ Framework* framework = slave->getFramework(executor->frameworkId);
+ CHECK_NOTNULL(framework);
- if (approved.isError()) {
- return Failure(approved.error());
- } else if (!approved.get()) {
- return Forbidden();
- }
+ if (!approvers->approved<ATTACH_CONTAINER_OUTPUT>(
+ executor->info, framework->info, containerId)) {
+ return Forbidden();
+ }
- return _attachContainerOutput(call, mediaTypes);
- }));
+ return _attachContainerOutput(call, mediaTypes);
+ }));
}
} // namespace slave {