You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by vi...@apache.org on 2014/08/09 02:37:07 UTC
[1/2] git commit: Added authorization support for "/shutdown"
endpoint and updated ACLs format.
Repository: mesos
Updated Branches:
refs/heads/master 52cf9b3ff -> a5cc9b435
Added authorization support for "/shutdown" endpoint and updated
ACLs format.
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/a5cc9b43
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/a5cc9b43
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/a5cc9b43
Branch: refs/heads/master
Commit: a5cc9b435aad080a79230f0366a6ce77116c95a4
Parents: 94b9439
Author: Benjamin Hindman <be...@gmail.com>
Authored: Fri Aug 8 16:53:12 2014 -0700
Committer: Vinod Kone <vi...@gmail.com>
Committed: Fri Aug 8 17:03:17 2014 -0700
----------------------------------------------------------------------
docs/authorization.md | 129 +++++++------
include/mesos/mesos.proto | 62 +++---
src/authorizer/authorizer.cpp | 93 +++------
src/authorizer/authorizer.hpp | 18 +-
src/credentials/credentials.hpp | 6 +-
src/master/flags.hpp | 41 ++--
src/master/http.cpp | 124 +++++++++---
src/master/master.cpp | 4 +-
src/master/master.hpp | 10 +
src/sasl/authenticator.hpp | 6 +-
src/tests/authorization_tests.cpp | 260 ++++----------------------
src/tests/master_authorization_tests.cpp | 30 +--
src/tests/mesos.cpp | 5 +-
src/tests/mesos.hpp | 17 +-
src/tests/reconciliation_tests.cpp | 2 +-
src/tests/script.cpp | 8 +-
src/tests/shutdown_tests.cpp | 109 ++++++++++-
17 files changed, 425 insertions(+), 499 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/docs/authorization.md
----------------------------------------------------------------------
diff --git a/docs/authorization.md b/docs/authorization.md
index fea743a..6697944 100644
--- a/docs/authorization.md
+++ b/docs/authorization.md
@@ -6,11 +6,10 @@ layout: documentation
Mesos 0.20.0 adds support for framework authorization. Authorization allows
- 1. Frameworks to only launch tasks/executors as authorized `users`.
- 2. Frameworks to be able to receive offers for authorized `roles`.
- 3. HTTP endpoints exposed by Mesos to be accessible to authorized `clients`.
+ 1. Frameworks to (re-)register with authorized `roles`.
+ 2. Frameworks to launch tasks/executors as authorized `users`.
+ 3. Authorized `principals` to shutdown framework(s) through "/shutdown" HTTP endpoint.
-> NOTE: While ACLs support for HTTP is present, currently access to the HTTP endpoints are not authorized.
## ACLs
@@ -20,40 +19,41 @@ Each ACL specifies a set of `Subjects` that can perform an `Action` on a set of
The currently supported `Actions` are :
-1. "run_tasks" : Run tasks/executors
-2. "receive_offers" : Receive offers
-3. "http_get" : HTTP GET access
-4. "http_put" : HTTP_PUT access
+1. "register_frameworks" : Register Frameworks
+2. "run_tasks" : Run tasks/executors
+3. "shutdown_frameworks" : Shutdown frameworks
The currently supported `Subjects` are :
-1. "principals" : Framework principals (used by "run_tasks" and "receive_offers" actions)
-2. "usernames" : Username used in HTTP Basic/Digest authentication. (used by "http_get" and "http_put" actions)
-3. "ips" : IP Addresses of the clients (used by "http_get" and "http_put" actions)
-4. "hostnames" : Hostnames of the clients (used by "http_get" and "http_put" actions)
+1. "principals"
+ - Framework principals (used by "register_frameworks" and "run_tasks" actions)
+ - Usernames (used by "shutdown_frameworks" action)
The currently supported `Objects` are :
-1. "users" : Unix user to launch the task/executor as (used by "run_tasks" action)
-2. "roles" : Resource roles to receive offers from (used by "receive_offers" action)
-3. "urls" : HTTP URL endpoint exposed by the master (used by "http_get" and "http_put" actions)
+1. "roles" : Resource roles that framework can register with (used by "register_frameworks" action)
+2. "users" : Unix user to launch the task/executor as (used by "run_tasks" action)
+3. "framework_principals" : Framework principals that can be shutdown by HTTP POST (used by "shutdown_frameworks" action).
-> NOTE: Both `Subjects` and `Objects` can take a list of strings or special values (`ANY` and `NONE`).
+> NOTE: Both `Subjects` and `Objects` can take a list of strings or special values (`ANY` or `NONE`).
## How does it work?
-The Mesos master checks the ACLs to verify whether a request is authorized or not. For example, when a framework launches a task, "run_tasks" ACLs are checked to see if the framework (`FrameworkInfo.principal`) is authorized to run the task/executor as the given user. If not authorized, the launch is rejected and the framework gets a TASK_LOST.
+The Mesos master checks the ACLs to verify whether a request is authorized or not.
-Similarly, when a framework (re-)registers the Mesos master checks whether it is authorized to receive offers for given resource role (`FrameworkInfo.role`). If not authorized, the framework is not allowed to (re-)register and gets an Error message back.
+For example, when a framework (re-)registers with the master, the "register_frameworks" ACLs are checked to see if the framework (`FrameworkInfo.principal`) is authorized to receive offers for the given resource role (`FrameworkInfo.role`). If not authorized, the framework is not allowed to (re-)register and gets an `Error` message back (which aborts the scheduler driver).
+
+Similarly, when a framework launches a task(s), "run_tasks" ACLs are checked to see if the framework (`FrameworkInfo.principal`) is authorized to run the task/executor as the given `user`. If not authorized, the launch is rejected and the framework gets a TASK_LOST.
+
+In the same vein, when a user/principal attempts to shutdown a framework through the "/shutdown" HTTP endpoint on the master, "shutdown_frameworks" ACLs are checked to see if the `principal` is authorized to shutdown the given framework. If not authorized, the shutdown is rejected and the user receives an `Unauthorized` HTTP response.
-While not yet implemented, GET/PUT access to HTTP endpoints exposed by the Mesos master will be authorized in a similar way.
There are couple of important things to note:
1. ACLs are matched in the order that they are setup. In other words, the first matching ACL determines whether a request is authorized or not.
-2. If none of the specified ACLs match the given request, whether the request is authorized or not is defined by `ACLs.permissive` field. By default this "true" i.e., a non-matching request is authorized.
+2. If none of the specified ACLs match the given request, whether the request is authorized or not is defined by `ACLs.permissive` field. By default this is "true" i.e., a non-matching request is authorized.
## Examples
@@ -66,7 +66,7 @@ There are couple of important things to note:
"principals": { "values": ["foo", "bar"] },
"users": { "values": ["alice"] }
}
- ],
+ ]
}
2. Any framework can run tasks as user `guest`.
@@ -77,7 +77,7 @@ There are couple of important things to note:
"principals": { "type": "ANY" },
"users": { "values": ["guest"] }
}
- ],
+ ]
}
3. No framework can run tasks as `root`.
@@ -88,7 +88,7 @@ There are couple of important things to note:
"principals": { "type": "NONE" },
"users": { "values": ["root"] }
}
- ],
+ ]
}
@@ -102,52 +102,66 @@ There are couple of important things to note:
},
{
"principals": { "values": [ "foo" ] },
- "users": { "type": ["NONE"] }
+ "users": { "type": "NONE" }
}
- ],
+ ]
}
-5. Framework `foo` can be offered resources for `analytics` and `ads` roles.
+5. Framework `foo` can register with `analytics` and `ads` roles.
{
- "receive_offers": [
- {
- "principals": { "values": ["foo"] },
- "roles": { "values": ["analytics", "ads"] }
- }
- ],
+ "register_frameworks": [
+ {
+ "principals": { "values": ["foo"] },
+ "roles": { "values": ["analytics", "ads"] }
+ }
+ ]
}
-6. Only framework `foo` and no one else can be offered resources for `analytics` role.
+6. Only framework `foo` and no one else can register with `analytics` role.
{
- "receive_offers": [
- {
- "principals": { "values": ["foo"] },
- "roles": { "values": ["analytics"] }
- },
- {
- "principals": { "type": "NONE" },
- "roles": { "values": ["analytics"] }
- }
- ],
+ "register_frameworks": [
+ {
+ "principals": { "values": ["foo"] },
+ "roles": { "values": ["analytics"] }
+ },
+ {
+ "principals": { "type": "NONE" },
+ "roles": { "values": ["analytics"] }
+ }
+ ]
}
-7. Framework `foo` can only receive offers for `analytics` role but no other roles. Also, no other framework can receive offers for any role.
+7. Framework `foo` can only register with `analytics` role but no other roles. Also, no other framework can register with any roles.
{
"permissive" : "false",
- "receive_offers": [
- {
- "principals": { "values": ["foo"] },
- "roles": { "values": ["analytics"] }
- }
- ],
+ "register_frameworks": [
+ {
+ "principals": { "values": ["foo"] },
+ "roles": { "values": ["analytics"] }
+ }
+ ]
+ }
+
+
+8. Only `ops` principal can shutdown any frameworks through "/shutdown" HTTP endpoint.
+
+ {
+ "permissive" : "false",
+
+ "shutdown_frameworks": [
+ {
+ "principals": { "values": ["ops"] },
+ "framework_principals": { "type": "ANY" }
+ }
+ ]
}
@@ -161,20 +175,5 @@ As part of this feature, a new flag was added to the master.
or '/path/to/file'.
See the ACLs protobuf in mesos.proto for the expected format.
- Example:
- {
- "run_tasks": [
- {
- "principals": { "values": ["a", "b"] },
- "users": { "values": ["root"] }
- }
- ],
- "receive_offers": [
- {
- "principals": { "type": "ANY" },
- "roles": { "values": ["foo"] }
- }
- ]
- }
**For the complete list of master options: ./mesos-master.sh --help**
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/include/mesos/mesos.proto
----------------------------------------------------------------------
diff --git a/include/mesos/mesos.proto b/include/mesos/mesos.proto
index efb4239..cc9f20e 100644
--- a/include/mesos/mesos.proto
+++ b/include/mesos/mesos.proto
@@ -658,12 +658,13 @@ message Parameters {
/**
- * Credential used for authentication.
+ * Credential used in various places for authentication and
+ * authorization.
*
- * NOTE: The 'principal' is used for authenticating the framework or slave
- * with the master. This is different from 'FrameworkInfo.user'
- * which is used to determine the user under which the framework's
- * executors/tasks are run.
+ * NOTE: A 'principal' is different from 'FrameworkInfo.user'. The
+ * former is used for authentication and authorization while the
+ * latter is used to determine the default user under which the
+ * framework's executors/tasks are run.
*/
message Credential {
required string principal = 1;
@@ -672,18 +673,12 @@ message Credential {
/**
- * Credentials used for authentication.
- *
+ * Credentials used for framework authentication, HTTP authentication
+ * (where the common 'username' and 'password' are captured as
+ * 'principal' and 'secret' respectively), etc.
*/
message Credentials {
- // Collection of credentials used to authenticate "registration" of
- // either frameworks or slaves.
- repeated Credential registration = 1;
-
- // Collection of credentails used to authenticate HTTP endpoints
- // (where the common "username" and "password" are captured as
- // 'principal' and 'secret' respectively).
- repeated Credential http = 2;
+ repeated Credential credentials = 1;
}
@@ -707,40 +702,30 @@ message ACL {
}
// ACLs.
- message RunTasks {
+ message RegisterFramework {
// Subjects.
required Entity principals = 1; // Framework principals.
// Objects.
- required Entity users = 2; // Users to run the tasks/executors as.
+ required Entity roles = 2; // Roles for resource offers.
}
- message ReceiveOffers {
+ message RunTask {
// Subjects.
required Entity principals = 1; // Framework principals.
// Objects.
- required Entity roles = 2; // Resource roles that can be offered.
- }
-
- message HTTPGet {
- // Subjects (At least one of these should be set).
- optional Entity usernames = 1; // HTTP authentication based usernames.
- optional Entity ips = 2;
- optional Entity hostnames = 3;
-
- // Objects.
- required Entity urls = 4;
+ required Entity users = 2; // Users to run the tasks/executors as.
}
- message HTTPPut {
- // Subjects (At least one of these should be set).
- optional Entity usernames = 1; // HTTP authentication based usernames.
- optional Entity ips = 2;
- optional Entity hostnames = 3;
+ // Which principals are authorized to shutdown frameworks of other
+ // principals.
+ message ShutdownFramework {
+ // Subjects.
+ required Entity principals = 1;
// Objects.
- required Entity urls = 4;
+ required Entity framework_principals = 2;
}
}
@@ -766,10 +751,9 @@ message ACL {
*/
message ACLs {
optional bool permissive = 1 [default = true];
- repeated ACL.RunTasks run_tasks = 2;
- repeated ACL.ReceiveOffers receive_offers = 3;
- repeated ACL.HTTPGet http_get = 4;
- repeated ACL.HTTPPut http_put = 5;
+ repeated ACL.RegisterFramework register_frameworks = 2;
+ repeated ACL.RunTask run_tasks = 3;
+ repeated ACL.ShutdownFramework shutdown_frameworks = 4;
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/authorizer/authorizer.cpp
----------------------------------------------------------------------
diff --git a/src/authorizer/authorizer.cpp b/src/authorizer/authorizer.cpp
index 40a14be..21e97e3 100644
--- a/src/authorizer/authorizer.cpp
+++ b/src/authorizer/authorizer.cpp
@@ -54,73 +54,53 @@ public:
LocalAuthorizerProcess(const ACLs& _acls)
: ProcessBase(process::ID::generate("authorizer")), acls(_acls) {}
- Future<bool> authorize(const ACL::RunTasks& request)
+ Future<bool> authorize(const ACL::RegisterFramework& request)
{
- foreach (const ACL::RunTasks& acl, acls.run_tasks()) {
+ foreach (const ACL::RegisterFramework& acl, acls.register_frameworks()) {
// ACL matches if both subjects and objects match.
if (matches(request.principals(), acl.principals()) &&
- matches(request.users(), acl.users())) {
+ matches(request.roles(), acl.roles())) {
// ACL is allowed if both subjects and objects are allowed.
return allows(request.principals(), acl.principals()) &&
- allows(request.users(), acl.users());
+ allows(request.roles(), acl.roles());
}
}
return acls.permissive(); // None of the ACLs match.
}
- Future<bool> authorize(const ACL::ReceiveOffers& request)
+ Future<bool> authorize(const ACL::RunTask& request)
{
- foreach (const ACL::ReceiveOffers& acl, acls.receive_offers()) {
+ foreach (const ACL::RunTask& acl, acls.run_tasks()) {
// ACL matches if both subjects and objects match.
if (matches(request.principals(), acl.principals()) &&
- matches(request.roles(), acl.roles())) {
+ matches(request.users(), acl.users())) {
// ACL is allowed if both subjects and objects are allowed.
return allows(request.principals(), acl.principals()) &&
- allows(request.roles(), acl.roles());
+ allows(request.users(), acl.users());
}
}
return acls.permissive(); // None of the ACLs match.
}
- Future<bool> authorize(const ACL::HTTPGet& request)
+ Future<bool> authorize(const ACL::ShutdownFramework& request)
{
- foreach (const ACL::HTTPGet& acl, acls.http_get()) {
+ foreach (const ACL::ShutdownFramework& acl, acls.shutdown_frameworks()) {
// ACL matches if both subjects and objects match.
- if (matches(request.usernames(), acl.usernames()) &&
- matches(request.ips(), acl.ips()) &&
- matches(request.hostnames(), acl.hostnames()) &&
- matches(request.urls(), acl.urls())) {
+ if (matches(request.principals(), acl.principals()) &&
+ matches(request.framework_principals(),
+ acl.framework_principals())) {
// ACL is allowed if both subjects and objects are allowed.
- return allows(request.usernames(), acl.usernames()) &&
- allows(request.ips(), acl.ips()) &&
- allows(request.hostnames(), acl.hostnames()) &&
- allows(request.urls(), acl.urls());
+ return allows(request.principals(), acl.principals()) &&
+ allows(request.framework_principals(),
+ acl.framework_principals());
}
}
return acls.permissive(); // None of the ACLs match.
}
- Future<bool> authorize(const ACL::HTTPPut& request)
- {
- foreach (const ACL::HTTPPut& acl, acls.http_put()) {
- // ACL matches if both subjects and objects match.
- if (matches(request.usernames(), acl.usernames()) &&
- matches(request.ips(), acl.ips()) &&
- matches(request.hostnames(), acl.hostnames()) &&
- matches(request.urls(), acl.urls())) {
- // ACL is allowed if both subjects and objects are allowed.
- return allows(request.usernames(), acl.usernames()) &&
- allows(request.ips(), acl.ips()) &&
- allows(request.hostnames(), acl.hostnames()) &&
- allows(request.urls(), acl.urls());
- }
- }
-
- return acls.permissive(); // None of the ACLs match.
- }
private:
// Match matrix:
//
@@ -263,61 +243,36 @@ LocalAuthorizer::~LocalAuthorizer()
Try<Owned<LocalAuthorizer> > LocalAuthorizer::create(const ACLs& acls)
{
- // Validate ACLs.
- foreach (const ACL::HTTPGet& acl, acls.http_get()) {
- // At least one of the subjects should be set.
- if (acl.has_usernames() + acl.has_ips() + acl.has_hostnames() < 1) {
- return Error("At least one of the subjects should be set for ACL: " +
- acl.DebugString());
- }
- }
-
- foreach (const ACL::HTTPPut& acl, acls.http_put()) {
- // At least one of the subjects should be set.
- if (acl.has_usernames() + acl.has_ips() + acl.has_hostnames() < 1) {
- return Error("At least one of the subjects should be set for ACL: " +
- acl.DebugString());
- }
- }
-
return new LocalAuthorizer(acls);
}
-Future<bool> LocalAuthorizer::authorize(const ACL::RunTasks& request)
-{
- // Necessary to disambiguate.
- typedef Future<bool>(LocalAuthorizerProcess::*F)(const ACL::RunTasks&);
-
- return dispatch(
- process, static_cast<F>(&LocalAuthorizerProcess::authorize), request);
-}
-
-
-Future<bool> LocalAuthorizer::authorize(const ACL::ReceiveOffers& request)
+Future<bool> LocalAuthorizer::authorize(const ACL::RegisterFramework& request)
{
// Necessary to disambiguate.
- typedef Future<bool>(LocalAuthorizerProcess::*F)(const ACL::ReceiveOffers&);
+ typedef Future<bool>(LocalAuthorizerProcess::*F)(
+ const ACL::RegisterFramework&);
return dispatch(
process, static_cast<F>(&LocalAuthorizerProcess::authorize), request);
}
-Future<bool> LocalAuthorizer::authorize(const ACL::HTTPGet& request)
+Future<bool> LocalAuthorizer::authorize(const ACL::RunTask& request)
{
// Necessary to disambiguate.
- typedef Future<bool>(LocalAuthorizerProcess::*F)(const ACL::HTTPGet&);
+ typedef Future<bool>(LocalAuthorizerProcess::*F)(const ACL::RunTask&);
return dispatch(
process, static_cast<F>(&LocalAuthorizerProcess::authorize), request);
}
-Future<bool> LocalAuthorizer::authorize(const ACL::HTTPPut& request)
+Future<bool> LocalAuthorizer::authorize(const ACL::ShutdownFramework& request)
{
// Necessary to disambiguate.
- typedef Future<bool>(LocalAuthorizerProcess::*F)(const ACL::HTTPPut&);
+ typedef Future<bool>(LocalAuthorizerProcess::*F)(
+ const ACL::ShutdownFramework&);
return dispatch(
process, static_cast<F>(&LocalAuthorizerProcess::authorize), request);
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/authorizer/authorizer.hpp
----------------------------------------------------------------------
diff --git a/src/authorizer/authorizer.hpp b/src/authorizer/authorizer.hpp
index b7f1119..c039d94 100644
--- a/src/authorizer/authorizer.hpp
+++ b/src/authorizer/authorizer.hpp
@@ -49,13 +49,11 @@ public:
// A failed future indicates a transient failure and the user
// can (should) retry.
virtual process::Future<bool> authorize(
- const ACL::RunTasks& request) = 0;
+ const ACL::RegisterFramework& request) = 0;
virtual process::Future<bool> authorize(
- const ACL::ReceiveOffers& request) = 0;
+ const ACL::RunTask& request) = 0;
virtual process::Future<bool> authorize(
- const ACL::HTTPGet& request) = 0;
- virtual process::Future<bool> authorize(
- const ACL::HTTPPut& request) = 0;
+ const ACL::ShutdownFramework& request) = 0;
protected:
Authorizer() {}
@@ -71,10 +69,12 @@ public:
virtual ~LocalAuthorizer();
// Implementation of Authorizer interface.
- virtual process::Future<bool> authorize(const ACL::RunTasks& request);
- virtual process::Future<bool> authorize(const ACL::ReceiveOffers& request);
- virtual process::Future<bool> authorize(const ACL::HTTPGet& request);
- virtual process::Future<bool> authorize(const ACL::HTTPPut& request);
+ virtual process::Future<bool> authorize(
+ const ACL::RegisterFramework& request);
+ virtual process::Future<bool> authorize(
+ const ACL::RunTask& request);
+ virtual process::Future<bool> authorize(
+ const ACL::ShutdownFramework& request);
private:
LocalAuthorizer(const ACLs& acls);
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/credentials/credentials.hpp
----------------------------------------------------------------------
diff --git a/src/credentials/credentials.hpp b/src/credentials/credentials.hpp
index 1790793..4cdadb1 100644
--- a/src/credentials/credentials.hpp
+++ b/src/credentials/credentials.hpp
@@ -53,7 +53,7 @@ inline Result<Credentials> read(const std::string& path)
<< "credentials file is NOT accessible by others.";
}
- // TODO(ijimenez) deprecate text support only JSON like acls
+ // TODO(ijimenez): Deprecate text and support only JSON like ACLs.
Try<JSON::Object> json = JSON::parse<JSON::Object>(read.get());
if (!json.isError()) {
Try<Credentials> credentials = ::protobuf::parse<Credentials>(json.get());
@@ -67,11 +67,11 @@ inline Result<Credentials> read(const std::string& path)
const std::vector<std::string>& pairs = strings::tokenize(line, " ");
if (pairs.size() != 2) {
return Error("Invalid credential format at line " +
- stringify(credentials.registration().size() + 1));
+ stringify(credentials.credentials().size() + 1));
}
// Add the credential.
- Credential* credential = credentials.add_registration();
+ Credential* credential = credentials.add_credentials();
credential->set_principal(pairs[0]);
credential->set_secret(pairs[1]);
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/master/flags.hpp
----------------------------------------------------------------------
diff --git a/src/master/flags.hpp b/src/master/flags.hpp
index 0db4c95..5e9ecb5 100644
--- a/src/master/flags.hpp
+++ b/src/master/flags.hpp
@@ -213,24 +213,17 @@ public:
"Either a path to a text file with a list of credentials,\n"
"each line containing 'principal' and 'secret' separated by "
"whitespace,\n"
- "or, a path to a JSON-formatted file containing credentials\n"
- "for identification/registration and http authentication."
+ "or, a path to a JSON-formatted file containing credentials.\n"
"Path could be of the form 'file:///path/to/file' or '/path/to/file'."
"\n"
"JSON file Example:\n"
"{\n"
- " \"http\": [\n"
- " {\n"
- " \"principal\": \"username\",\n"
- " \"secret\": \"secret\",\n"
- " }\n"
- " ],\n"
- " \"identification\": [\n"
- " {\n"
- " \"principal\": \"username\",\n"
- " \"secret\": \"secret\",\n"
- " }\n"
- " ]\n"
+ " \"credentials\": [\n"
+ " {\n"
+ " \"principal\": \"sherman\",\n"
+ " \"secret\": \"kitesurf\",\n"
+ " }\n"
+ " ]\n"
"}\n"
"Text file Example:\n"
"username secret\n"
@@ -247,18 +240,24 @@ public:
"\n"
"Example:\n"
"{\n"
+ " \"register_frameworks\": [\n"
+ " {\n"
+ " \"principals\": { \"type\": \"ANY\" },\n"
+ " \"roles\": { \"values\": [\"a\"] }\n"
+ " }\n"
+ " ],\n"
" \"run_tasks\": [\n"
" {\n"
" \"principals\": { \"values\": [\"a\", \"b\"] },\n"
- " \"users\": { \"values\": [\"root\"] }\n"
+ " \"users\": { \"values\": [\"c\"] }\n"
" }\n"
" ],\n"
- " \"receive_offers\": [\n"
- " {\n"
- " \"principals\": { \"type\": \"ANY\" },\n"
- " \"roles\": { \"values\": [\"foo\"] }\n"
- " }\n"
- " ]\n"
+ " \"shutdown_frameworks\": [\n"
+ " {\n"
+ " \"principals\": { \"values\": [\"a\", \"b\"] },\n"
+ " \"framework_principals\": { \"values\": [\"c\"] }\n"
+ " }\n"
+ " ]\n"
"}");
add(&Flags::rate_limits,
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index f2ca659..9317a95 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -39,6 +39,8 @@
#include <stout/result.hpp>
#include <stout/strings.hpp>
+#include "authorizer/authorizer.hpp"
+
#include "common/attributes.hpp"
#include "common/build.hpp"
#include "common/http.hpp"
@@ -620,42 +622,80 @@ const string Master::Http::SHUTDOWN_HELP = HELP(
Future<Response> Master::Http::shutdown(const Request& request)
{
- if (master->credentials.isNone()) {
- return Unauthorized("Mesos master");
+ if (request.method != "POST") {
+ return BadRequest("Expecting POST");
}
+
+ // Parse the query string in the request body (since this is a POST)
+ // in order to determine the framework ID to shutdown.
hashmap<string, string> values =
process::http::query::parse(request.body);
- Option<string> frameworkId = values.get("frameworkId");
- if (frameworkId.isNone()) {
- return BadRequest();
+
+ if (values.get("frameworkId").isNone()) {
+ return BadRequest("Missing 'frameworkId' query parameter");
}
+
FrameworkID id;
- id.set_value(frameworkId.get());
+ id.set_value(values.get("frameworkId").get());
+
Framework* framework = master->getFramework(id);
- Option<string> authHeader = request.headers.get("Authorization");
- if (authHeader.isNone()) {
- return Unauthorized("Mesos master");
+ if (framework == NULL) {
+ return BadRequest("No framework found with specified ID");
}
- const string& decodedAuth =
- base64::decode(strings::split(authHeader.get(), " ", 2)[1]);
- const std::vector<string>& pairs = strings::split(decodedAuth, ":", 2);
- if (pairs.size() != 2) {
+
+ Result<Credential> credential = authenticate(request);
+
+ if (credential.isError()) {
+ return Unauthorized("Mesos master", credential.error());
+ }
+
+ // Skip authorization if no ACLs were provided to the master.
+ if (master->authorizer.isNone()) {
+ return _shutdown(id);
+ }
+
+ mesos::ACL::ShutdownFramework shutdown;
+
+ if (credential.isSome()) {
+ shutdown.mutable_principals()->add_values(credential.get().principal());
+ } else {
+ shutdown.mutable_principals()->set_type(ACL::Entity::ANY);
+ }
+
+ if (framework->info.has_principal()) {
+ shutdown.mutable_framework_principals()->add_values(
+ framework->info.principal());
+ } else {
+ shutdown.mutable_framework_principals()->set_type(ACL::Entity::ANY);
+ }
+
+ lambda::function<Future<Response>(bool)> _shutdown =
+ lambda::bind(&Master::Http::_shutdown, this, id, lambda::_1);
+
+ return master->authorizer.get()->authorize(shutdown)
+ .then(defer(master->self(), _shutdown));
+}
+
+
+Future<Response> Master::Http::_shutdown(
+ const FrameworkID& id,
+ bool authorized)
+{
+ if (!authorized) {
return Unauthorized("Mesos master");
}
- const string& username = pairs[0];
- const string& password = pairs[1];
+ Framework* framework = master->getFramework(id);
- foreach (const Credential& credential, master->credentials.get().http()) {
- if (credential.principal() == username &&
- (!credential.has_secret() || credential.secret() == password)) {
- // TODO(ijimenez) make removeFramework asynchronously
- master->removeFramework(framework);
- return OK();
- }
+ if (framework == NULL) {
+ return BadRequest("No framework found with ID " + stringify(id));
}
- return Unauthorized("Mesos master");
+
+ // TODO(ijimenez): Do 'removeFramework' asynchronously.
+ master->removeFramework(framework);
+
+ return OK();
}
@@ -780,6 +820,44 @@ Future<Response> Master::Http::tasks(const Request& request)
}
+Result<Credential> Master::Http::authenticate(const Request& request)
+{
+ // By default, assume everyone is authenticated if no credentials
+ // were provided.
+ if (master->credentials.isNone()) {
+ return None();
+ }
+
+ Option<string> authorization = request.headers.get("Authorization");
+
+ if (authorization.isNone()) {
+ return Error("Missing 'Authorization' request header");
+ }
+
+ const string& decoded =
+ base64::decode(strings::split(authorization.get(), " ", 2)[1]);
+
+ const vector<string>& pairs = strings::split(decoded, ":", 2);
+
+ if (pairs.size() != 2) {
+ return Error("Malformed 'Authorization' request header");
+ }
+
+ const string& username = pairs[0];
+ const string& password = pairs[1];
+
+ foreach (const Credential& credential,
+ master->credentials.get().credentials()) {
+ if (credential.principal() == username &&
+ credential.secret() == password) {
+ return credential;
+ }
+ }
+
+ return Error("Could not authenticate '" + username + "'");
+}
+
+
} // namespace master {
} // namespace internal {
} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index e688b41..d53d6c2 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -1276,7 +1276,7 @@ Future<Option<Error> > Master::validate(
<< "Authorizing framework principal '" << frameworkInfo.principal()
<< "' to receive offers for role '" << frameworkInfo.role() << "'";
- mesos::ACL::ReceiveOffers request;
+ mesos::ACL::RegisterFramework request;
if (frameworkInfo.has_principal()) {
request.mutable_principals()->add_values(frameworkInfo.principal());
} else {
@@ -2286,7 +2286,7 @@ Future<Option<Error> > Master::validateTask(
<< "Authorizing framework principal '" << framework->info.principal()
<< "' to launch task " << task.task_id() << " as user '" << user << "'";
- mesos::ACL::RunTasks request;
+ mesos::ACL::RunTask request;
if (framework->info.has_principal()) {
request.mutable_principals()->add_values(framework->info.principal());
} else {
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 29e8f49..c9f989a 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -437,6 +437,16 @@ private:
const static std::string TASKS_HELP;
private:
+ // Helper for doing authentication, returns the credential used if
+ // the authentication was successful (or none if no credentials
+ // have been given to the master), otherwise an Error.
+ Result<Credential> authenticate(const process::http::Request& request);
+
+ // Continuations.
+ process::Future<process::http::Response> _shutdown(
+ const FrameworkID& id,
+ bool authorized = true);
+
Master* master;
} http;
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/sasl/authenticator.hpp
----------------------------------------------------------------------
diff --git a/src/sasl/authenticator.hpp b/src/sasl/authenticator.hpp
index aa222d3..35ab794 100644
--- a/src/sasl/authenticator.hpp
+++ b/src/sasl/authenticator.hpp
@@ -466,11 +466,11 @@ void load(const std::map<std::string, std::string>& secrets)
InMemoryAuxiliaryPropertyPlugin::load(properties);
}
-void load(const Credentials& c)
+void load(const Credentials& credentials)
{
std::map<std::string, std::string> secrets;
- foreach(const Credential& registration, c.registration()) {
- secrets[registration.principal()] = registration.secret();
+ foreach(const Credential& credential, credentials.credentials()) {
+ secrets[credential.principal()] = credential.secret();
}
load(secrets);
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/tests/authorization_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/authorization_tests.cpp b/src/tests/authorization_tests.cpp
index 611f371..a8fa4cc 100644
--- a/src/tests/authorization_tests.cpp
+++ b/src/tests/authorization_tests.cpp
@@ -37,7 +37,7 @@ TEST_F(AuthorizationTest, AnyPrincipalRunAsUser)
{
// Any principal can run as "guest" user.
ACLs acls;
- mesos::ACL::RunTasks* acl = acls.add_run_tasks();
+ mesos::ACL::RunTask* acl = acls.add_run_tasks();
acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY);
acl->mutable_users()->add_values("guest");
@@ -46,14 +46,14 @@ TEST_F(AuthorizationTest, AnyPrincipalRunAsUser)
ASSERT_SOME(authorizer);
// Principals "foo" and "bar" can run as "guest".
- mesos::ACL::RunTasks request;
+ mesos::ACL::RunTask request;
request.mutable_principals()->add_values("foo");
request.mutable_principals()->add_values("bar");
request.mutable_users()->add_values("guest");
AWAIT_EXPECT_EQ(true, authorizer.get()->authorize(request));
// Principal "foo" can run as "root" since the ACLs are permissive.
- mesos::ACL::RunTasks request2;
+ mesos::ACL::RunTask request2;
request2.mutable_principals()->add_values("foo");
request2.mutable_users()->add_values("root");
AWAIT_EXPECT_EQ(true, authorizer.get()->authorize(request2));
@@ -64,7 +64,7 @@ TEST_F(AuthorizationTest, NoPrincipalRunAsUser)
{
// No principal can run as "root" user.
ACLs acls;
- mesos::ACL::RunTasks* acl = acls.add_run_tasks();
+ mesos::ACL::RunTask* acl = acls.add_run_tasks();
acl->mutable_principals()->set_type(mesos::ACL::Entity::NONE);
acl->mutable_users()->add_values("root");
@@ -73,7 +73,7 @@ TEST_F(AuthorizationTest, NoPrincipalRunAsUser)
ASSERT_SOME(authorizer);
// Principal "foo" cannot run as "root".
- mesos::ACL::RunTasks request;
+ mesos::ACL::RunTask request;
request.mutable_principals()->add_values("foo");
request.mutable_users()->add_values("root");
AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request));
@@ -84,7 +84,7 @@ TEST_F(AuthorizationTest, PrincipalRunAsAnyUser)
{
// A principal "foo" can run as any user.
ACLs acls;
- mesos::ACL::RunTasks* acl = acls.add_run_tasks();
+ mesos::ACL::RunTask* acl = acls.add_run_tasks();
acl->mutable_principals()->add_values("foo");
acl->mutable_users()->set_type(mesos::ACL::Entity::ANY);
@@ -93,7 +93,7 @@ TEST_F(AuthorizationTest, PrincipalRunAsAnyUser)
ASSERT_SOME(authorizer);
// Principal "foo" can run as "user1" and "user2".
- mesos::ACL::RunTasks request;
+ mesos::ACL::RunTask request;
request.mutable_principals()->add_values("foo");
request.mutable_users()->add_values("user1");
request.mutable_users()->add_values("user2");
@@ -105,7 +105,7 @@ TEST_F(AuthorizationTest, AnyPrincipalRunAsAnyUser)
{
// Any principal can run as any user.
ACLs acls;
- mesos::ACL::RunTasks* acl = acls.add_run_tasks();
+ mesos::ACL::RunTask* acl = acls.add_run_tasks();
acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY);
acl->mutable_users()->set_type(mesos::ACL::Entity::ANY);
@@ -114,7 +114,7 @@ TEST_F(AuthorizationTest, AnyPrincipalRunAsAnyUser)
ASSERT_SOME(authorizer);
// Principals "foo" and "bar" can run as "user1" and "user2".
- mesos::ACL::RunTasks request;
+ mesos::ACL::RunTask request;
request.mutable_principals()->add_values("foo");
request.mutable_principals()->add_values("bar");
request.mutable_users()->add_values("user1");
@@ -129,14 +129,14 @@ TEST_F(AuthorizationTest, OnlySomePrincipalsRunAsSomeUsers)
ACLs acls;
// ACL for some principals to run as some users.
- mesos::ACL::RunTasks* acl = acls.add_run_tasks();
+ mesos::ACL::RunTask* acl = acls.add_run_tasks();
acl->mutable_principals()->add_values("foo");
acl->mutable_principals()->add_values("bar");
acl->mutable_users()->add_values("user1");
acl->mutable_users()->add_values("user2");
// ACL for no one else to run as some users.
- mesos::ACL::RunTasks* acl2 = acls.add_run_tasks();
+ mesos::ACL::RunTask* acl2 = acls.add_run_tasks();
acl2->mutable_principals()->set_type(mesos::ACL::Entity::NONE);
acl2->mutable_users()->add_values("user1");
acl2->mutable_users()->add_values("user2");
@@ -146,7 +146,7 @@ TEST_F(AuthorizationTest, OnlySomePrincipalsRunAsSomeUsers)
ASSERT_SOME(authorizer);
// Principals "foo" and "bar" can run as "user1" and "user2".
- mesos::ACL::RunTasks request;
+ mesos::ACL::RunTask request;
request.mutable_principals()->add_values("foo");
request.mutable_principals()->add_values("bar");
request.mutable_users()->add_values("user1");
@@ -154,13 +154,13 @@ TEST_F(AuthorizationTest, OnlySomePrincipalsRunAsSomeUsers)
AWAIT_EXPECT_EQ(true, authorizer.get()->authorize(request));
// Principal "baz" cannot run as "user1".
- mesos::ACL::RunTasks request2;
+ mesos::ACL::RunTask request2;
request2.mutable_principals()->add_values("baz");
request2.mutable_users()->add_values("user1");
AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request2));
// Principal "baz" cannot run as "user2".
- mesos::ACL::RunTasks request3;
+ mesos::ACL::RunTask request3;
request3.mutable_principals()->add_values("baz");
request3.mutable_users()->add_values("user1");
AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request3));
@@ -173,12 +173,12 @@ TEST_F(AuthorizationTest, SomePrincipalOnlySomeUser)
ACLs acls;
// ACL for some principal to run as some user.
- mesos::ACL::RunTasks* acl = acls.add_run_tasks();
+ mesos::ACL::RunTask* acl = acls.add_run_tasks();
acl->mutable_principals()->add_values("foo");
acl->mutable_users()->add_values("user1");
// ACL for some principal to not run as any other user.
- mesos::ACL::RunTasks* acl2 = acls.add_run_tasks();
+ mesos::ACL::RunTask* acl2 = acls.add_run_tasks();
acl2->mutable_principals()->add_values("foo");
acl2->mutable_users()->set_type(mesos::ACL::Entity::NONE);
@@ -187,19 +187,19 @@ TEST_F(AuthorizationTest, SomePrincipalOnlySomeUser)
ASSERT_SOME(authorizer);
// Principal "foo" can run as "user1".
- mesos::ACL::RunTasks request;
+ mesos::ACL::RunTask request;
request.mutable_principals()->add_values("foo");
request.mutable_users()->add_values("user1");
AWAIT_EXPECT_EQ(true, authorizer.get()->authorize(request));
// Principal "foo" cannot run as "user2".
- mesos::ACL::RunTasks request2;
+ mesos::ACL::RunTask request2;
request2.mutable_principals()->add_values("foo");
request2.mutable_users()->add_values("user2");
AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request2));
// Principal "bar" can run as "user1" and "user2".
- mesos::ACL::RunTasks request3;
+ mesos::ACL::RunTask request3;
request3.mutable_principals()->add_values("bar");
request3.mutable_users()->add_values("user1");
request3.mutable_users()->add_values("user2");
@@ -212,7 +212,7 @@ TEST_F(AuthorizationTest, PrincipalRunAsSomeUserRestrictive)
// A principal can run as "user1";
ACLs acls;
acls.set_permissive(false); // Restrictive.
- mesos::ACL::RunTasks* acl = acls.add_run_tasks();
+ mesos::ACL::RunTask* acl = acls.add_run_tasks();
acl->mutable_principals()->add_values("foo");
acl->mutable_users()->add_values("user1");
@@ -221,19 +221,19 @@ TEST_F(AuthorizationTest, PrincipalRunAsSomeUserRestrictive)
ASSERT_SOME(authorizer);
// Principal "foo" can run as "user1".
- mesos::ACL::RunTasks request;
+ mesos::ACL::RunTask request;
request.mutable_principals()->add_values("foo");
request.mutable_users()->add_values("user1");
AWAIT_EXPECT_EQ(true, authorizer.get()->authorize(request));
// Principal "foo" cannot run as "user2".
- mesos::ACL::RunTasks request2;
+ mesos::ACL::RunTask request2;
request2.mutable_principals()->add_values("foo");
request2.mutable_users()->add_values("user2");
AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request2));
// Principal "bar" cannot run as "user2" since no ACL is set.
- mesos::ACL::RunTasks request3;
+ mesos::ACL::RunTask request3;
request3.mutable_principals()->add_values("bar");
request3.mutable_users()->add_values("user2");
AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request3));
@@ -244,7 +244,7 @@ TEST_F(AuthorizationTest, AnyPrincipalOfferedRole)
{
// Any principal can be offered "*" role's resources.
ACLs acls;
- mesos::ACL::ReceiveOffers* acl = acls.add_receive_offers();
+ mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
acl->mutable_principals()->set_type(mesos::ACL::Entity::ANY);
acl->mutable_roles()->add_values("*");
@@ -253,7 +253,7 @@ TEST_F(AuthorizationTest, AnyPrincipalOfferedRole)
ASSERT_SOME(authorizer);
// Principals "foo" and "bar" can be offered "*" role's resources.
- mesos::ACL::ReceiveOffers request;
+ mesos::ACL::RegisterFramework request;
request.mutable_principals()->add_values("foo");
request.mutable_principals()->add_values("bar");
request.mutable_roles()->add_values("*");
@@ -265,7 +265,7 @@ TEST_F(AuthorizationTest, SomePrincipalsOfferedRole)
{
// Some principals can be offered "ads" role's resources.
ACLs acls;
- mesos::ACL::ReceiveOffers* acl = acls.add_receive_offers();
+ mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
acl->mutable_principals()->add_values("foo");
acl->mutable_principals()->add_values("bar");
acl->mutable_roles()->add_values("ads");
@@ -276,7 +276,7 @@ TEST_F(AuthorizationTest, SomePrincipalsOfferedRole)
// Principals "foo", "bar" and "baz" (no ACL) can be offered "ads"
// role's resources.
- mesos::ACL::ReceiveOffers request;
+ mesos::ACL::RegisterFramework request;
request.mutable_principals()->add_values("foo");
request.mutable_principals()->add_values("bar");
request.mutable_principals()->add_values("baz");
@@ -291,12 +291,12 @@ TEST_F(AuthorizationTest, PrincipalOfferedRole)
ACLs acls;
// ACL for a principal to be offered "analytics" role's resources.
- mesos::ACL::ReceiveOffers* acl = acls.add_receive_offers();
+ mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
acl->mutable_principals()->add_values("foo");
acl->mutable_roles()->add_values("analytics");
// ACL for no one else to be offered "analytics" role's resources.
- mesos::ACL::ReceiveOffers* acl2 = acls.add_receive_offers();
+ mesos::ACL::RegisterFramework* acl2 = acls.add_register_frameworks();
acl2->mutable_principals()->set_type(mesos::ACL::Entity::NONE);
acl2->mutable_roles()->add_values("analytics");
@@ -305,13 +305,13 @@ TEST_F(AuthorizationTest, PrincipalOfferedRole)
ASSERT_SOME(authorizer);
// Principal "foo" can be offered "analytics" role's resources.
- mesos::ACL::ReceiveOffers request;
+ mesos::ACL::RegisterFramework request;
request.mutable_principals()->add_values("foo");
request.mutable_roles()->add_values("analytics");
AWAIT_EXPECT_EQ(true, authorizer.get()->authorize(request));
// Principal "bar" cannot be offered "analytics" role's resources.
- mesos::ACL::ReceiveOffers request2;
+ mesos::ACL::RegisterFramework request2;
request2.mutable_principals()->add_values("bar");
request2.mutable_roles()->add_values("analytics");
AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request2));
@@ -323,7 +323,7 @@ TEST_F(AuthorizationTest, PrincipalNotOfferedAnyRoleRestrictive)
// A principal "foo" can be offered "analytics" role's resources.
ACLs acls;
acls.set_permissive(false);
- mesos::ACL::ReceiveOffers* acl = acls.add_receive_offers();
+ mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
acl->mutable_principals()->add_values("foo");
acl->mutable_roles()->add_values("analytics");
@@ -332,210 +332,20 @@ TEST_F(AuthorizationTest, PrincipalNotOfferedAnyRoleRestrictive)
ASSERT_SOME(authorizer);
// Principal "foo" can be offered "analytics" role's resources.
- mesos::ACL::ReceiveOffers request;
+ mesos::ACL::RegisterFramework request;
request.mutable_principals()->add_values("foo");
request.mutable_roles()->add_values("analytics");
AWAIT_EXPECT_EQ(true, authorizer.get()->authorize(request));
// Principal "bar" cannot be offered "analytics" role's resources.
- mesos::ACL::ReceiveOffers request2;
+ mesos::ACL::RegisterFramework request2;
request2.mutable_principals()->add_values("bar");
request2.mutable_roles()->add_values("analytics");
AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request2));
// Principal "bar" cannot be offered "ads" role's resources because no ACL.
- mesos::ACL::ReceiveOffers request3;
+ mesos::ACL::RegisterFramework request3;
request3.mutable_principals()->add_values("bar");
request3.mutable_roles()->add_values("ads");
AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request3));
}
-
-
-TEST_F(AuthorizationTest, AnyClientGETSomeURL)
-{
- // Any client can GET access "/help".
- ACLs acls;
- mesos::ACL::HTTPGet* acl = acls.add_http_get();
- acl->mutable_usernames()->set_type(mesos::ACL::Entity::ANY);
- acl->mutable_ips()->set_type(mesos::ACL::Entity::ANY);
- acl->mutable_hostnames()->set_type(mesos::ACL::Entity::ANY);
- acl->mutable_urls()->add_values("/help");
-
- // Create an Authorizer with the ACLs.
- Try<Owned<LocalAuthorizer> > authorizer = LocalAuthorizer::create(acls);
- ASSERT_SOME(authorizer);
-
- // Clients "foo", "127.0.0.1", "localhost" can GET access "/help".
- mesos::ACL::HTTPGet request;
- request.mutable_usernames()->add_values("foo");
- request.mutable_ips()->add_values("127.0.0.1");
- request.mutable_hostnames()->add_values("localhost");
- request.mutable_urls()->add_values("/help");
- AWAIT_EXPECT_EQ(true, authorizer.get()->authorize(request));
-}
-
-
-TEST_F(AuthorizationTest, SomeClientsPUTSomeURL)
-{
- // Only some clients can PUT access "/admin".
- ACLs acls;
-
- // Some clients can PUT access "/admin".
- mesos::ACL::HTTPPut* acl = acls.add_http_put();
- acl->mutable_ips()->add_values("127.0.0.1");
- acl->mutable_hostnames()->add_values("localhost");
- acl->mutable_urls()->add_values("/admin");
-
- // No one else can PUT access "/admin".
- mesos::ACL::HTTPPut* acl2 = acls.add_http_put();
- acl2->mutable_usernames()->set_type(mesos::ACL::Entity::NONE);
- acl2->mutable_ips()->set_type(mesos::ACL::Entity::NONE);
- acl2->mutable_hostnames()->set_type(mesos::ACL::Entity::NONE);
- acl2->mutable_urls()->add_values("/admin");
-
- // Create an Authorizer with the ACLs.
- Try<Owned<LocalAuthorizer> > authorizer = LocalAuthorizer::create(acls);
- ASSERT_SOME(authorizer);
-
- // Clients "127.0.0.1" and "localhost" can PUT access "/admin".
- mesos::ACL::HTTPPut request;
- request.mutable_ips()->add_values("127.0.0.1");
- request.mutable_hostnames()->add_values("localhost");
- request.mutable_urls()->add_values("/admin");
- AWAIT_EXPECT_EQ(true, authorizer.get()->authorize(request));
-
- // Client "10.0.0.0" cannot PUT access "/admin".
- mesos::ACL::HTTPPut request2;
- request2.mutable_ips()->add_values("10.0.0.0");
- request2.mutable_urls()->add_values("/admin");
- AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request2));
-}
-
-
-TEST_F(AuthorizationTest, NoClientGETPUTSomeURL)
-{
- // No client can GET access "/secret".
- ACLs acls;
- mesos::ACL::HTTPGet* acl = acls.add_http_get();
- acl->mutable_usernames()->set_type(mesos::ACL::Entity::NONE);
- acl->mutable_ips()->set_type(mesos::ACL::Entity::NONE);
- acl->mutable_hostnames()->set_type(mesos::ACL::Entity::NONE);
- acl->mutable_urls()->add_values("/secret");
-
- // No client can PUT access "/secret".
- mesos::ACL::HTTPPut* acl2 = acls.add_http_put();
- acl2->mutable_usernames()->set_type(mesos::ACL::Entity::NONE);
- acl2->mutable_ips()->set_type(mesos::ACL::Entity::NONE);
- acl2->mutable_hostnames()->set_type(mesos::ACL::Entity::NONE);
- acl2->mutable_urls()->add_values("/secret");
-
- // Create an Authorizer with the ACLs.
- Try<Owned<LocalAuthorizer> > authorizer = LocalAuthorizer::create(acls);
- ASSERT_SOME(authorizer);
-
- // Clients "127.0.0.1" and "localhost" cannot GET access "/secret".
- mesos::ACL::HTTPGet request;
- request.mutable_ips()->add_values("127.0.0.1");
- request.mutable_hostnames()->add_values("localhost");
- request.mutable_urls()->add_values("/secret");
- AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request));
-
- // Clients "127.0.0.1" and "localhost" cannot PUT access "/secret".
- mesos::ACL::HTTPPut request2;
- request2.mutable_ips()->add_values("127.0.0.1");
- request2.mutable_hostnames()->add_values("localhost");
- request2.mutable_urls()->add_values("/secret");
- AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request2));
-}
-
-
-TEST_F(AuthorizationTest, SomeClientsCannotGETAnyURL)
-{
- // Some clients cannot GET access any URL.
- ACLs acls;
- mesos::ACL::HTTPGet* acl = acls.add_http_get();
- acl->mutable_ips()->add_values("127.0.0.1");
- acl->mutable_hostnames()->add_values("localhost");
- acl->mutable_urls()->set_type(mesos::ACL::Entity::NONE);
-
- // Create an Authorizer with the ACLs.
- Try<Owned<LocalAuthorizer> > authorizer = LocalAuthorizer::create(acls);
- ASSERT_SOME(authorizer);
-
- // Clients "127.0.0.1" and "localhost" cannot GET access "/help".
- mesos::ACL::HTTPGet request;
- request.mutable_ips()->add_values("127.0.0.1");
- request.mutable_hostnames()->add_values("localhost");
- request.mutable_urls()->add_values("/help");
- AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request));
-}
-
-
-TEST_F(AuthorizationTest, NoClientsCanGETPUTAnyURLRestrictive)
-{
- // No clients can GET/PUT access any URL.
- ACLs acls;
- acls.set_permissive(false);
-
- // Create an Authorizer with the ACLs.
- Try<Owned<LocalAuthorizer> > authorizer = LocalAuthorizer::create(acls);
- ASSERT_SOME(authorizer);
-
- // Clients "foo", "127.0.0.1" cannot GET access "/help".
- mesos::ACL::HTTPGet request;
- request.mutable_usernames()->add_values("foo");
- request.mutable_ips()->add_values("127.0.0.1");
- request.mutable_urls()->add_values("/help");
- AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request));
-
- // Clients "127.0.0.1", "localhost" cannot PUT access "/help".
- mesos::ACL::HTTPPut request2;
- request2.mutable_ips()->add_values("127.0.0.1");
- request2.mutable_hostnames()->add_values("localhost");
- request2.mutable_urls()->add_values("/help");
- AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request2));
-}
-
-
-TEST_F(AuthorizationTest, SomeClientsAggregatePUTRequestRestrictive)
-{
- // Some clients can PUT access "/admin" but ACLs are setup
- // separately.
- ACLs acls;
- acls.set_permissive(false);
-
- // "foo" can PUT access "/admin".
- mesos::ACL::HTTPPut* acl = acls.add_http_put();
- acl->mutable_usernames()->add_values("foo");
- acl->mutable_urls()->add_values("/admin");
-
- // "bar" can PUT access "/admin".
- mesos::ACL::HTTPPut* acl2 = acls.add_http_put();
- acl2->mutable_usernames()->add_values("bar");
- acl2->mutable_urls()->add_values("/admin");
-
- // Create an Authorizer with the ACLs.
- Try<Owned<LocalAuthorizer> > authorizer = LocalAuthorizer::create(acls);
- ASSERT_SOME(authorizer);
-
- // "foo" can PUT access "/admin".
- mesos::ACL::HTTPPut request;
- request.mutable_usernames()->add_values("foo");
- request.mutable_urls()->add_values("/admin");
- AWAIT_EXPECT_EQ(true, authorizer.get()->authorize(request));
-
- // "bar" can PUT access "/admin".
- mesos::ACL::HTTPPut request2;
- request2.mutable_usernames()->add_values("bar");
- request2.mutable_urls()->add_values("/admin");
- AWAIT_EXPECT_EQ(true, authorizer.get()->authorize(request2));
-
- // Aggregate request for clients "foo" and "bar" for PUT access to
- // "/admin" is not allowed because ACLs are not aggregated.
- mesos::ACL::HTTPPut request3;
- request3.mutable_usernames()->add_values("foo");
- request3.mutable_usernames()->add_values("bar");
- request3.mutable_urls()->add_values("/admin");
- AWAIT_EXPECT_EQ(false, authorizer.get()->authorize(request3));
-}
-
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/tests/master_authorization_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_authorization_tests.cpp b/src/tests/master_authorization_tests.cpp
index 5c35577..f0f0648 100644
--- a/src/tests/master_authorization_tests.cpp
+++ b/src/tests/master_authorization_tests.cpp
@@ -72,7 +72,7 @@ TEST_F(MasterAuthorizationTest, AuthorizedTask)
{
// Setup ACLs so that the framework can launch tasks as "foo".
ACLs acls;
- mesos::ACL::RunTasks* acl = acls.add_run_tasks();
+ mesos::ACL::RunTask* acl = acls.add_run_tasks();
acl->mutable_principals()->add_values(DEFAULT_FRAMEWORK_INFO.principal());
acl->mutable_users()->add_values("foo");
@@ -150,7 +150,7 @@ TEST_F(MasterAuthorizationTest, UnauthorizedTask)
{
// Setup ACLs so that no framework can launch as "foo".
ACLs acls;
- mesos::ACL::RunTasks* acl = acls.add_run_tasks();
+ mesos::ACL::RunTask* acl = acls.add_run_tasks();
acl->mutable_principals()->set_type(mesos::ACL::Entity::NONE);
acl->mutable_users()->add_values("foo");
@@ -251,7 +251,7 @@ TEST_F(MasterAuthorizationTest, KillTask)
// Return a pending future from authorizer.
Future<Nothing> future;
Promise<bool> promise;
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTasks&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTask&>()))
.WillOnce(DoAll(FutureSatisfy(&future),
Return(promise.future())));
@@ -325,7 +325,7 @@ TEST_F(MasterAuthorizationTest, SlaveRemoved)
// Return a pending future from authorizer.
Future<Nothing> future;
Promise<bool> promise;
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTasks&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTask&>()))
.WillOnce(DoAll(FutureSatisfy(&future),
Return(promise.future())));
@@ -409,7 +409,7 @@ TEST_F(MasterAuthorizationTest, SlaveDisconnected)
// Return a pending future from authorizer.
Future<Nothing> future;
Promise<bool> promise;
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTasks&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTask&>()))
.WillOnce(DoAll(FutureSatisfy(&future),
Return(promise.future())));
@@ -491,7 +491,7 @@ TEST_F(MasterAuthorizationTest, FrameworkRemoved)
// Return a pending future from authorizer.
Future<Nothing> future;
Promise<bool> promise;
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTasks&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTask&>()))
.WillOnce(DoAll(FutureSatisfy(&future),
Return(promise.future())));
@@ -560,7 +560,7 @@ TEST_F(MasterAuthorizationTest, ReconcileTask)
// Return a pending future from authorizer.
Future<Nothing> future;
Promise<bool> promise;
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTasks&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTask&>()))
.WillOnce(DoAll(FutureSatisfy(&future),
Return(promise.future())));
@@ -649,7 +649,7 @@ TEST_F(MasterAuthorizationTest, PendingExecutorInfoDiffersOnDifferentSlaves)
// Return a pending future from authorizer.
Future<Nothing> future;
Promise<bool> promise;
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTasks&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTask&>()))
.WillOnce(DoAll(FutureSatisfy(&future),
Return(promise.future())));
@@ -694,7 +694,7 @@ TEST_F(MasterAuthorizationTest, PendingExecutorInfoDiffersOnDifferentSlaves)
EXPECT_CALL(sched, statusUpdate(&driver, _))
.WillOnce(FutureArg<1>(&status2));
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTasks&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTask&>()))
.WillOnce(Return(true));
driver.launchTasks(offers2.get()[0].id(), tasks2);
@@ -738,7 +738,7 @@ TEST_F(MasterAuthorizationTest, AuthorizedRole)
// Setup ACLs so that the framework can receive offers for role
// "foo".
ACLs acls;
- mesos::ACL::ReceiveOffers* acl = acls.add_receive_offers();
+ mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
acl->mutable_principals()->add_values(DEFAULT_FRAMEWORK_INFO.principal());
acl->mutable_roles()->add_values("foo");
@@ -779,7 +779,7 @@ TEST_F(MasterAuthorizationTest, UnauthorizedRole)
// Setup ACLs so that no framework can receive offers for role
// "foo".
ACLs acls;
- mesos::ACL::ReceiveOffers* acl = acls.add_receive_offers();
+ mesos::ACL::RegisterFramework* acl = acls.add_register_frameworks();
acl->mutable_principals()->set_type(mesos::ACL::Entity::NONE);
acl->mutable_roles()->add_values("foo");
@@ -840,7 +840,7 @@ TEST_F(MasterAuthorizationTest, DuplicateRegistration)
Promise<bool> promise1;
Future<Nothing> future2;
Promise<bool> promise2;
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::ReceiveOffers&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RegisterFramework&>()))
.WillOnce(DoAll(FutureSatisfy(&future1),
Return(promise1.future())))
.WillOnce(DoAll(FutureSatisfy(&future2),
@@ -906,7 +906,7 @@ TEST_F(MasterAuthorizationTest, DuplicateReregistration)
Promise<bool> promise2;
Future<Nothing> future3;
Promise<bool> promise3;
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::ReceiveOffers&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RegisterFramework&>()))
.WillOnce(Return(true))
.WillOnce(DoAll(FutureSatisfy(&future2),
Return(promise2.future())))
@@ -974,7 +974,7 @@ TEST_F(MasterAuthorizationTest, FrameworkRemovedBeforeRegistration)
// Return a pending future from authorizer.
Future<Nothing> future;
Promise<bool> promise;
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::ReceiveOffers&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RegisterFramework&>()))
.WillOnce(DoAll(FutureSatisfy(&future),
Return(promise.future())));
@@ -1032,7 +1032,7 @@ TEST_F(MasterAuthorizationTest, FrameworkRemovedBeforeReregistration)
// Return a pending future from authorizer after first attempt.
Future<Nothing> future2;
Promise<bool> promise2;
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::ReceiveOffers&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RegisterFramework&>()))
.WillOnce(Return(true))
.WillOnce(DoAll(FutureSatisfy(&future2),
Return(promise2.future())));
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/tests/mesos.cpp
----------------------------------------------------------------------
diff --git a/src/tests/mesos.cpp b/src/tests/mesos.cpp
index 6b5c43f..5bd8ba0 100644
--- a/src/tests/mesos.cpp
+++ b/src/tests/mesos.cpp
@@ -101,10 +101,7 @@ master::Flags MesosTest::CreateMasterFlags()
// JSON default format for credentials
Credentials credentials;
- Credential* credential = credentials.add_registration();
- credential->set_principal(DEFAULT_CREDENTIAL.principal());
- credential->set_secret(DEFAULT_CREDENTIAL.secret());
- credential = credentials.add_http();
+ Credential* credential = credentials.add_credentials();
credential->set_principal(DEFAULT_CREDENTIAL.principal());
credential->set_secret(DEFAULT_CREDENTIAL.secret());
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/tests/mesos.hpp
----------------------------------------------------------------------
diff --git a/src/tests/mesos.hpp b/src/tests/mesos.hpp
index 8cf71d1..b31c347 100644
--- a/src/tests/mesos.hpp
+++ b/src/tests/mesos.hpp
@@ -492,27 +492,22 @@ public:
// NOTE: We use 'EXPECT_CALL' and 'WillRepeatedly' here instead of
// 'ON_CALL' and 'WillByDefault'. See 'TestContainerizer::SetUp()'
// for more details.
- EXPECT_CALL(*this, authorize(An<const mesos::ACL::RunTasks&>()))
+ EXPECT_CALL(*this, authorize(An<const mesos::ACL::RegisterFramework&>()))
.WillRepeatedly(Return(true));
- EXPECT_CALL(*this, authorize(An<const mesos::ACL::ReceiveOffers&>()))
+ EXPECT_CALL(*this, authorize(An<const mesos::ACL::RunTask&>()))
.WillRepeatedly(Return(true));
- EXPECT_CALL(*this, authorize(An<const mesos::ACL::HTTPGet&>()))
- .WillRepeatedly(Return(true));
-
- EXPECT_CALL(*this, authorize(An<const mesos::ACL::HTTPPut&>()))
+ EXPECT_CALL(*this, authorize(An<const mesos::ACL::ShutdownFramework&>()))
.WillRepeatedly(Return(true));
}
MOCK_METHOD1(
- authorize, process::Future<bool>(const ACL::RunTasks& request));
- MOCK_METHOD1(
- authorize, process::Future<bool>(const ACL::ReceiveOffers& request));
+ authorize, process::Future<bool>(const ACL::RegisterFramework& request));
MOCK_METHOD1(
- authorize, process::Future<bool>(const ACL::HTTPGet& request));
+ authorize, process::Future<bool>(const ACL::RunTask& request));
MOCK_METHOD1(
- authorize, process::Future<bool>(const ACL::HTTPPut& request));
+ authorize, process::Future<bool>(const ACL::ShutdownFramework& request));
};
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/tests/reconciliation_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/reconciliation_tests.cpp b/src/tests/reconciliation_tests.cpp
index 952f29b..3c4d7ed 100644
--- a/src/tests/reconciliation_tests.cpp
+++ b/src/tests/reconciliation_tests.cpp
@@ -622,7 +622,7 @@ TEST_F(ReconciliationTest, PendingTask)
// Return a pending future from authorizer.
Future<Nothing> future;
Promise<bool> promise;
- EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTasks&>()))
+ EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTask&>()))
.WillOnce(DoAll(FutureSatisfy(&future),
Return(promise.future())));
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/tests/script.cpp
----------------------------------------------------------------------
diff --git a/src/tests/script.cpp b/src/tests/script.cpp
index 3129479..515e314 100644
--- a/src/tests/script.cpp
+++ b/src/tests/script.cpp
@@ -135,16 +135,16 @@ void execute(const string& script)
ACLs acls;
acls.set_permissive(false);
- mesos::ACL::RunTasks* run = acls.add_run_tasks();
+ mesos::ACL::RunTask* run = acls.add_run_tasks();
run->mutable_principals()->add_values(DEFAULT_CREDENTIAL.principal());
Result<string> user = os::user();
CHECK_SOME(user) << "Failed to get current user name";
run->mutable_users()->add_values(user.get());
- mesos::ACL::ReceiveOffers* offer = acls.add_receive_offers();
- offer->mutable_principals()->add_values(DEFAULT_CREDENTIAL.principal());
- offer->mutable_roles()->add_values("*");
+ mesos::ACL::RegisterFramework* register_ = acls.add_register_frameworks();
+ register_->mutable_principals()->add_values(DEFAULT_CREDENTIAL.principal());
+ register_->mutable_roles()->add_values("*");
const string& aclsPath = path::join(directory.get(), "acls");
http://git-wip-us.apache.org/repos/asf/mesos/blob/a5cc9b43/src/tests/shutdown_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/shutdown_tests.cpp b/src/tests/shutdown_tests.cpp
index ad13aa1..12ebef4 100644
--- a/src/tests/shutdown_tests.cpp
+++ b/src/tests/shutdown_tests.cpp
@@ -64,9 +64,9 @@ using testing::Return;
class ShutdownTest : public MesosTest {};
// Testing /master/shutdown so this endopoint shuts down
-// designated framework or return adequate error
+// designated framework or return adequate error.
-// Testing route with authorization header and good credentials
+// Testing route with authorization header and good credentials.
TEST_F(ShutdownTest, ShutdownEndpoint)
{
Try<PID<Master> > master = StartMaster();
@@ -105,7 +105,7 @@ TEST_F(ShutdownTest, ShutdownEndpoint)
}
-// Testing route with bad credentials
+// Testing route with bad credentials.
TEST_F(ShutdownTest, ShutdownEndpointBadCredentials)
{
Try<PID<Master> > master = StartMaster();
@@ -145,7 +145,106 @@ TEST_F(ShutdownTest, ShutdownEndpointBadCredentials)
}
-// Testing route without frameworkId value
+// Testing route with good ACLs.
+TEST_F(ShutdownTest, ShutdownEndpointGoodACLs)
+{
+ // Setup ACLs so that the default principal can shutdown the
+ // framework.
+ ACLs acls;
+ mesos::ACL::ShutdownFramework* acl = acls.add_shutdown_frameworks();
+ acl->mutable_principals()->add_values(DEFAULT_CREDENTIAL.principal());
+ acl->mutable_framework_principals()->add_values(
+ DEFAULT_CREDENTIAL.principal());
+
+ master::Flags flags = CreateMasterFlags();
+ flags.acls = acls;
+ Try<PID<Master> > master = StartMaster(flags);
+ ASSERT_SOME(master);
+
+ MockScheduler sched;
+ MesosSchedulerDriver driver(
+ &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+ Future<FrameworkID> frameworkId;
+ EXPECT_CALL(sched, registered(&driver, _, _))
+ .WillOnce(FutureArg<1>(&frameworkId));
+
+ ASSERT_EQ(DRIVER_RUNNING, driver.start());
+
+ AWAIT_READY(frameworkId);
+
+ hashmap<string, string> headers;
+ headers["Authorization"] = "Basic " +
+ base64::encode(DEFAULT_CREDENTIAL.principal() +
+ ":" + DEFAULT_CREDENTIAL.secret());
+
+ Future<Response> response = process::http::post(
+ master.get(),
+ "shutdown",
+ headers,
+ "frameworkId=" + frameworkId.get().value());
+
+ AWAIT_READY(response);
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
+
+ driver.stop();
+ driver.join();
+
+ Shutdown();
+}
+
+
+// Testing route with bad ACLs.
+TEST_F(ShutdownTest, ShutdownEndpointBadACLs)
+{
+ // Setup ACLs so that no principal can do shutdown the framework.
+ ACLs acls;
+ mesos::ACL::ShutdownFramework* acl = acls.add_shutdown_frameworks();
+ acl->mutable_principals()->set_type(mesos::ACL::Entity::NONE);
+ acl->mutable_framework_principals()->add_values(
+ DEFAULT_CREDENTIAL.principal());
+
+ master::Flags flags = CreateMasterFlags();
+ flags.acls = acls;
+ Try<PID<Master> > master = StartMaster(flags);
+ ASSERT_SOME(master);
+
+ MockScheduler sched;
+ MesosSchedulerDriver driver(
+ &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+ Future<FrameworkID> frameworkId;
+ EXPECT_CALL(sched, registered(&driver, _, _))
+ .WillOnce(FutureArg<1>(&frameworkId));
+
+ ASSERT_EQ(DRIVER_RUNNING, driver.start());
+
+ AWAIT_READY(frameworkId);
+
+ hashmap<string, string> headers;
+ headers["Authorization"] = "Basic " +
+ base64::encode(DEFAULT_CREDENTIAL.principal() +
+ ":" + DEFAULT_CREDENTIAL.secret());
+
+ Future<Response> response = process::http::post(
+ master.get(),
+ "shutdown",
+ headers,
+ "frameworkId=" + frameworkId.get().value());
+
+ AWAIT_READY(response);
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(
+ Unauthorized("Mesos master").status,
+ response);
+
+ driver.stop();
+ driver.join();
+
+ Shutdown();
+}
+
+
+// Testing route without frameworkId value.
TEST_F(ShutdownTest, ShutdownEndpointNoFrameworkId)
{
Try<PID<Master> > master = StartMaster();
@@ -177,7 +276,7 @@ TEST_F(ShutdownTest, ShutdownEndpointNoFrameworkId)
}
-// Testing route without authorization header
+// Testing route without authorization header.
TEST_F(ShutdownTest, ShutdownEndpointNoHeader)
{
Try<PID<Master> > master = StartMaster();
[2/2] git commit: Added overloads to 'process::defer()' to dispatch
lambda function to a specific pid.
Posted by vi...@apache.org.
Added overloads to 'process::defer()' to dispatch lambda function
to a specific pid.
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/94b94393
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/94b94393
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/94b94393
Branch: refs/heads/master
Commit: 94b9439371db9e8e7e3a102fdbe73b80a1da6a8b
Parents: 52cf9b3
Author: Benjamin Hindman <be...@gmail.com>
Authored: Fri Aug 8 16:51:23 2014 -0700
Committer: Vinod Kone <vi...@gmail.com>
Committed: Fri Aug 8 17:03:17 2014 -0700
----------------------------------------------------------------------
3rdparty/libprocess/include/process/defer.hpp | 36 ++++++++++++++++++++
.../libprocess/include/process/deferred.hpp | 17 ++++++++-
2 files changed, 52 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/94b94393/3rdparty/libprocess/include/process/defer.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/defer.hpp b/3rdparty/libprocess/include/process/defer.hpp
index dc2ec3b..dce7f3b 100644
--- a/3rdparty/libprocess/include/process/defer.hpp
+++ b/3rdparty/libprocess/include/process/defer.hpp
@@ -384,6 +384,18 @@ inline void dispatcher(
// Now we define defer calls for functions and bind statements.
+inline Deferred<void(void)> defer(
+ const UPID& pid,
+ const std::tr1::function<void(void)>& f)
+{
+ return std::tr1::function<void(void)>(
+ std::tr1::bind(&internal::dispatcher,
+ pid,
+ f));
+}
+
+
+// Now we define defer calls for functions and bind statements.
inline Deferred<void(void)> defer(const std::tr1::function<void(void)>& f)
{
if (__process__ != NULL) {
@@ -405,6 +417,18 @@ inline Deferred<void(void)> defer(const std::tr1::function<void(void)>& f)
#define TEMPLATE(Z, N, DATA) \
template <ENUM_PARAMS(N, typename A)> \
Deferred<void(ENUM_PARAMS(N, A))> defer( \
+ const UPID& pid, \
+ const std::tr1::function<void(ENUM_PARAMS(N, A))>& f) \
+ { \
+ return std::tr1::function<void(ENUM_PARAMS(N, A))>( \
+ std::tr1::bind(&internal::CAT(dispatcher, N)<ENUM_PARAMS(N, A)>, \
+ pid, \
+ f, \
+ ENUM_BINARY_PARAMS(N, internal::_, () INTERCEPT))); \
+ } \
+ \
+ template <ENUM_PARAMS(N, typename A)> \
+ Deferred<void(ENUM_PARAMS(N, A))> defer( \
const std::tr1::function<void(ENUM_PARAMS(N, A))>& f) \
{ \
if (__process__ != NULL) { \
@@ -420,6 +444,18 @@ inline Deferred<void(void)> defer(const std::tr1::function<void(void)>& f)
\
template <typename R, ENUM_PARAMS(N, typename A)> \
Deferred<Future<R>(ENUM_PARAMS(N, A))> defer( \
+ const UPID& pid, \
+ const std::tr1::function<Future<R>(ENUM_PARAMS(N, A))>& f) \
+ { \
+ return std::tr1::function<Future<R>(ENUM_PARAMS(N, A))>( \
+ std::tr1::bind(&internal::CAT(dispatcher, N)<ENUM_PARAMS(N, A)>, \
+ pid, \
+ f, \
+ ENUM_BINARY_PARAMS(N, internal::_, () INTERCEPT))); \
+ } \
+ \
+ template <typename R, ENUM_PARAMS(N, typename A)> \
+ Deferred<Future<R>(ENUM_PARAMS(N, A))> defer( \
const std::tr1::function<Future<R>(ENUM_PARAMS(N, A))>& f) \
{ \
if (__process__ != NULL) { \
http://git-wip-us.apache.org/repos/asf/mesos/blob/94b94393/3rdparty/libprocess/include/process/deferred.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/deferred.hpp b/3rdparty/libprocess/include/process/deferred.hpp
index 0552fb5..8bdc692 100644
--- a/3rdparty/libprocess/include/process/deferred.hpp
+++ b/3rdparty/libprocess/include/process/deferred.hpp
@@ -31,15 +31,30 @@ private:
template <typename _F> friend struct _Defer;
- friend Deferred<void(void)> defer(const std::tr1::function<void(void)>& f);
+ friend Deferred<void(void)> defer(
+ const UPID& pid,
+ const std::tr1::function<void(void)>& f);
+
+ friend Deferred<void(void)> defer(
+ const std::tr1::function<void(void)>& f);
#define TEMPLATE(Z, N, DATA) \
template <ENUM_PARAMS(N, typename A)> \
friend Deferred<void(ENUM_PARAMS(N, A))> defer( \
+ const UPID& pid, \
+ const std::tr1::function<void(ENUM_PARAMS(N, A))>& f); \
+ \
+ template <ENUM_PARAMS(N, typename A)> \
+ friend Deferred<void(ENUM_PARAMS(N, A))> defer( \
const std::tr1::function<void(ENUM_PARAMS(N, A))>& f); \
\
template <typename R, ENUM_PARAMS(N, typename A)> \
friend Deferred<Future<R>(ENUM_PARAMS(N, A))> defer( \
+ const UPID& pid, \
+ const std::tr1::function<Future<R>(ENUM_PARAMS(N, A))>& f); \
+ \
+ template <typename R, ENUM_PARAMS(N, typename A)> \
+ friend Deferred<Future<R>(ENUM_PARAMS(N, A))> defer( \
const std::tr1::function<Future<R>(ENUM_PARAMS(N, A))>& f);
REPEAT_FROM_TO(1, 11, TEMPLATE, _) // Args A0 -> A9.