You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by me...@apache.org on 2016/03/14 10:36:04 UTC

[1/4] mesos git commit: Added tests for http endpoints with bad authentication.

Repository: mesos
Updated Branches:
  refs/heads/master 33f6e3e85 -> 79e28b614


Added tests for http endpoints with bad authentication.

With enabling http authentication for http endpoints we should also
add tests to check that http request to those endpoints return
"401 Unauthorized" if queried without or with bad credentials.

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


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

Branch: refs/heads/master
Commit: abd911ccfcb09a6755e91b02a38977d898a31b0d
Parents: 33f6e3e
Author: Joerg Schad <jo...@mesosphere.io>
Authored: Mon Mar 14 01:12:20 2016 -0700
Committer: Adam B <ad...@mesosphere.io>
Committed: Mon Mar 14 01:12:20 2016 -0700

----------------------------------------------------------------------
 src/tests/master_maintenance_tests.cpp | 127 ++++++++++++++++++++++++++++
 src/tests/master_tests.cpp             | 126 +++++++++++++++++++++++++++
 src/tests/repair_tests.cpp             |  59 +++++++++++++
 src/tests/role_tests.cpp               |  34 ++++++++
 4 files changed, 346 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/abd911cc/src/tests/master_maintenance_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_maintenance_tests.cpp b/src/tests/master_maintenance_tests.cpp
index 5a421d4..1dce98b 100644
--- a/src/tests/master_maintenance_tests.cpp
+++ b/src/tests/master_maintenance_tests.cpp
@@ -77,6 +77,7 @@ using process::Time;
 using process::http::BadRequest;
 using process::http::OK;
 using process::http::Response;
+using process::http::Unauthorized;
 
 using mesos::internal::protobuf::maintenance::createSchedule;
 using mesos::internal::protobuf::maintenance::createUnavailability;
@@ -1736,6 +1737,132 @@ TEST_F(MasterMaintenanceTest, InverseOffersFilters)
   Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
 }
 
+
+// Testing post and get without authentication and with bad credentials.
+TEST_F(MasterMaintenanceTest, EndpointsBadAuthentication)
+{
+  // Set up a master with authentication required.
+  // Note that the default master test flags enable HTTP authentication.
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  // Headers for POSTs to maintenance endpoints without authentication.
+  process::http::Headers unauthenticatedHeaders;
+  unauthenticatedHeaders["Content-Type"] = "application/json";
+
+  // A valid schedule with one machine.
+  maintenance::Schedule schedule = createSchedule(
+      {createWindow({machine1}, unavailability)});
+
+  // Bad credentials which should fail authentication.
+  Credential badCredential;
+  badCredential.set_principal("badPrincipal");
+  badCredential.set_secret("badSecret");
+
+  // Headers for POSTs to maintenance endpoints with bad authentication.
+  process::http::Headers badAuthenticationHeaders;
+  badAuthenticationHeaders = createBasicAuthHeaders(badCredential);
+  badAuthenticationHeaders["Content-Type"] = "application/json";
+
+  // maintenance/schedule endpoint.
+  {
+    // Post the maintenance schedule without authentication.
+    Future<Response> response = process::http::post(
+        master.get(),
+        "maintenance/schedule",
+        unauthenticatedHeaders,
+        stringify(JSON::protobuf(schedule)));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Get the maintenance schedule without authentication.
+    response = process::http::get(master.get(), "maintenance/schedule");
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Post the maintenance schedule with bad authentication.
+    response = process::http::post(
+        master.get(),
+        "maintenance/schedule",
+        badAuthenticationHeaders,
+        stringify(JSON::protobuf(schedule)));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Get the maintenance schedule with bad authentication.
+    response = process::http::get(
+        master.get(),
+        "maintenance/schedule",
+        None(),
+        createBasicAuthHeaders(badCredential));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+  }
+
+  // machine/up endpoint.
+  {
+    // Post to machine/up without authentication.
+    Future<Response> response = process::http::post(
+        master.get(),
+        "machine/up",
+        unauthenticatedHeaders,
+        stringify(JSON::protobuf(schedule)));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Post to machine/up with bad authentication.
+    response = process::http::post(
+        master.get(),
+        "machine/up",
+        badAuthenticationHeaders,
+        stringify(JSON::protobuf(schedule)));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+  }
+
+  // machine/down endpoint.
+  {
+    // Post to machine/down without authentication.
+    Future<Response> response = process::http::post(
+        master.get(),
+        "machine/down",
+        unauthenticatedHeaders,
+        stringify(JSON::protobuf(schedule)));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Post to machine/down with bad authentication.
+    response = process::http::post(
+        master.get(),
+        "machine/down",
+        badAuthenticationHeaders,
+        stringify(JSON::protobuf(schedule)));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+  }
+
+  // maintenance/status endpoint.
+  {
+    // Get the maintenance status without authentication.
+    Future<Response> response = process::http::get(
+        master.get(),
+        "maintenance/status");
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Get the maintenance status with bad authentication.
+    response = process::http::get(
+        master.get(),
+        "maintenance/status",
+        None(),
+        createBasicAuthHeaders(badCredential));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+  }
+
+  Shutdown();
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/abd911cc/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index e9ddd36..e8c39e7 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -83,6 +83,7 @@ using process::Promise;
 
 using process::http::OK;
 using process::http::Response;
+using process::http::Unauthorized;
 
 using std::shared_ptr;
 using std::string;
@@ -4190,6 +4191,131 @@ TEST_F(MasterTest, MaxCompletedTasksPerFrameworkFlag)
   }
 }
 
+
+// Test get requests on various endpoints without authentication and
+// with bad credentials.
+// Note that we have similar checks for the maintenance, roles, quota, teardown,
+// reserve, unreserve, create-volumes, destroy-volumes, observe endpoints in the
+// respective test files.
+TEST_F(MasterTest, EndpointsBadAuthentication)
+{
+  // Set up a master with authentication required.
+  // Note that the default master test flags enable HTTP authentication.
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  // Bad credentials which should fail authentication.
+  Credential badCredential;
+  badCredential.set_principal("badPrincipal");
+  badCredential.set_secret("badSecret");
+
+  // frameworks endpoint.
+  {
+    // Get request without authentication.
+    Future<Response> response = process::http::get(master.get(), "frameworks");
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Get request with bad authentication.
+    response = process::http::get(
+      master.get(),
+      "frameworks",
+      None(),
+      createBasicAuthHeaders(badCredential));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+  }
+
+  // flags endpoint.
+  {
+    // Get request without authentication.
+    Future<Response> response = process::http::get(master.get(), "flags");
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Get request with bad authentication.
+    response = process::http::get(
+      master.get(),
+      "flags",
+      None(),
+      createBasicAuthHeaders(badCredential));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+  }
+
+  // slaves endpoint.
+  {
+    // Get request without authentication.
+    Future<Response> response = process::http::get(master.get(), "slaves");
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Get request with bad authentication.
+    response = process::http::get(
+      master.get(),
+      "slaves",
+      None(),
+      createBasicAuthHeaders(badCredential));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+  }
+
+  // state endpoint.
+  {
+    // Get request without authentication.
+    Future<Response> response = process::http::get(master.get(), "state");
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Get request with bad authentication.
+    response = process::http::get(
+      master.get(),
+      "state",
+      None(),
+      createBasicAuthHeaders(badCredential));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+  }
+
+  // stateSummary endpoint.
+  {
+    // Get request without authentication.
+    Future<Response> response = process::http::get(
+        master.get(),
+        "state-summary");
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Get request with bad authentication.
+    response = process::http::get(
+      master.get(),
+      "state-summary",
+      None(),
+      createBasicAuthHeaders(badCredential));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+  }
+
+  // tasks endpoint.
+  {
+    // Get request without authentication.
+    Future<Response> response = process::http::get(master.get(), "tasks");
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+    // Get request with bad authentication.
+    response = process::http::get(
+      master.get(),
+      "tasks",
+      None(),
+      createBasicAuthHeaders(badCredential));
+
+    AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+  }
+
+  Shutdown();
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/abd911cc/src/tests/repair_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/repair_tests.cpp b/src/tests/repair_tests.cpp
index cb38bb1..0dfb557 100644
--- a/src/tests/repair_tests.cpp
+++ b/src/tests/repair_tests.cpp
@@ -35,6 +35,7 @@ using process::PID;
 using process::http::BadRequest;
 using process::http::OK;
 using process::http::Response;
+using process::http::Unauthorized;
 
 using std::string;
 using std::vector;
@@ -220,6 +221,64 @@ TEST_F(HealthTest, ObserveEndpoint)
   Shutdown();
 }
 
+
+// Testing get without authentication and with bad credentials.
+TEST_F(HealthTest, ObserveEndpointBadAuthentication)
+{
+  // Set up a master with authentication required.
+  // Note that the default master test flags enable HTTP authentication.
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  // Headers for POSTs to maintenance endpoints without authentication.
+  process::http::Headers unauthenticatedHeaders;
+  unauthenticatedHeaders["Content-Type"] = "application/json";
+
+  // Bad credentials which should fail authentication.
+  Credential badCredential;
+  badCredential.set_principal("badPrincipal");
+  badCredential.set_secret("badSecret");
+
+  // Headers for POSTs to maintenance endpoints with bad authentication.
+  process::http::Headers badAuthenticationHeaders;
+  badAuthenticationHeaders = createBasicAuthHeaders(badCredential);
+  badAuthenticationHeaders["Content-Type"] = "application/json";
+
+  // Post to observe without authentication.
+  Future<Response> response = process::http::post(
+      master.get(),
+      "observe",
+      unauthenticatedHeaders,
+      "monitor=a&hosts=b&level=Ok");
+
+  AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+  // Get request without authentication.
+  response = process::http::get(master.get(), "observe");
+
+  AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+  // Post to observe with bad authentication.
+  response = process::http::post(
+      master.get(),
+      "observe",
+      badAuthenticationHeaders,
+      "monitor=a&hosts=b&level=Ok");
+
+  AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+  // Get request with bad authentication.
+  response = process::http::get(
+    master.get(),
+    "observe",
+    None(),
+    createBasicAuthHeaders(badCredential));
+
+  AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+  Shutdown();
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/abd911cc/src/tests/role_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/role_tests.cpp b/src/tests/role_tests.cpp
index 2e23926..f45ee81 100644
--- a/src/tests/role_tests.cpp
+++ b/src/tests/role_tests.cpp
@@ -37,6 +37,7 @@ using process::PID;
 
 using process::http::OK;
 using process::http::Response;
+using process::http::Unauthorized;
 
 using testing::AtMost;
 
@@ -651,6 +652,39 @@ TEST(RolesTest, Validate)
   EXPECT_SOME(roles::validate({"foo", ".", "*"}));
 }
 
+
+// Testing get without authentication and with bad credentials.
+TEST_F(RoleTest, EndpointBadAuthentication)
+{
+  // Set up a master with authentication required.
+  // Note that the default master test flags enable HTTP authentication.
+  Try<PID<Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  // Get request without authentication.
+  Future<Response> response = process::http::get(
+      master.get(),
+      "roles");
+
+  AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+  // Bad credentials which should fail authentication.
+  Credential badCredential;
+  badCredential.set_principal("badPrincipal");
+  badCredential.set_secret("badSecret");
+
+  // Get request with bad authentication.
+  response = process::http::get(
+    master.get(),
+    "roles",
+    None(),
+    createBasicAuthHeaders(badCredential));
+
+  AWAIT_EXPECT_RESPONSE_STATUS_EQ(Unauthorized({}).status, response);
+
+  Shutdown();
+}
+
 }  // namespace tests {
 }  // namespace internal {
 }  // namespace mesos {


[3/4] mesos git commit: Made 'framework' endpoint help string consistent.

Posted by me...@apache.org.
Made 'framework' endpoint help string consistent.

All other endpoint HELP functions are already named 'endpoint'_HELP().

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


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

Branch: refs/heads/master
Commit: 662f7b5f9ddd0fadb304698b5c4d739c6f2aa140
Parents: e78be41
Author: Joerg Schad <jo...@mesosphere.io>
Authored: Mon Mar 14 01:19:40 2016 -0700
Committer: Adam B <ad...@mesosphere.io>
Committed: Mon Mar 14 01:19:40 2016 -0700

----------------------------------------------------------------------
 src/master/http.cpp   | 2 +-
 src/master/master.cpp | 2 +-
 src/master/master.hpp | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/662f7b5f/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index 6dec322..bda03da 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -728,7 +728,7 @@ Future<Response> Master::Http::destroyVolumes(
 }
 
 
-string Master::Http::FRAMEWORKS()
+string Master::Http::FRAMEWORKS_HELP()
 {
   return HELP(TLDR("Exposes the frameworks info."));
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/662f7b5f/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 255b4d1..d0380db 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -846,7 +846,7 @@ void Master::initialize()
         });
   route("/frameworks",
         DEFAULT_HTTP_AUTHENTICATION_REALM,
-        Http::FRAMEWORKS(),
+        Http::FRAMEWORKS_HELP(),
         [this](const process::http::Request& request,
                const Option<string>& principal) {
           Http::log(request);

http://git-wip-us.apache.org/repos/asf/mesos/blob/662f7b5f/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 7b51391..124d439 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1169,7 +1169,7 @@ private:
 
     static std::string SCHEDULER_HELP();
     static std::string FLAGS_HELP();
-    static std::string FRAMEWORKS();
+    static std::string FRAMEWORKS_HELP();
     static std::string HEALTH_HELP();
     static std::string OBSERVE_HELP();
     static std::string REDIRECT_HELP();


[2/4] mesos git commit: Updated authentication.md after many endpoints enable authentication.

Posted by me...@apache.org.
Updated authentication.md after many endpoints enable authentication.

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


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

Branch: refs/heads/master
Commit: e78be41521a45c5d58efbdf3e00e2194056a7570
Parents: abd911c
Author: Joerg Schad <jo...@mesosphere.io>
Authored: Mon Mar 14 01:14:43 2016 -0700
Committer: Adam B <ad...@mesosphere.io>
Committed: Mon Mar 14 01:16:43 2016 -0700

----------------------------------------------------------------------
 docs/authentication.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/e78be415/docs/authentication.md
----------------------------------------------------------------------
diff --git a/docs/authentication.md b/docs/authentication.md
index dd538b5..e7c0bf3 100644
--- a/docs/authentication.md
+++ b/docs/authentication.md
@@ -5,11 +5,11 @@ layout: documentation
 
 # Authentication
 
-Authentication permits only trusted entities to interact with a Mesos cluster. Authentication is used by Mesos in three ways:
+Authentication permits only trusted entities to interact with a Mesos cluster. Authentication can be used by Mesos in three ways:
 
 1. To require that frameworks be authenticated in order to register with the master.
 2. To require that slaves be authenticated in order to register with the master.
-3. To require that operators be authenticated to use certain [HTTP endpoints](endpoints/index.md), such as `/teardown`.
+3. To require that operators be authenticated to use many [HTTP endpoints](endpoints/index.md).
 
 Authentication is disabled by default. When authentication is enabled, operators
 can configure Mesos to either use the default authentication module or to use a


[4/4] mesos git commit: Added Scheduler-Driver API to app-framework-development-guide.md.

Posted by me...@apache.org.
Added Scheduler-Driver API to app-framework-development-guide.md.

Previously the app-framework-development-guide only explained the
scheduler callback interface. Equally important when developing
frameworks is the knowledge if potential actions a scheduler can
trigger via the SchedulerDriver.

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


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

Branch: refs/heads/master
Commit: 79e28b61447a96aa30289a109283b490f312b66b
Parents: 662f7b5
Author: Joerg Schad <jo...@mesosphere.io>
Authored: Mon Mar 14 01:38:21 2016 -0700
Committer: Adam B <ad...@mesosphere.io>
Committed: Mon Mar 14 01:38:21 2016 -0700

----------------------------------------------------------------------
 docs/app-framework-development-guide.md | 180 ++++++++++++++++++++++-----
 1 file changed, 150 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/79e28b61/docs/app-framework-development-guide.md
----------------------------------------------------------------------
diff --git a/docs/app-framework-development-guide.md b/docs/app-framework-development-guide.md
index 55f09c7..1d8bebd 100644
--- a/docs/app-framework-development-guide.md
+++ b/docs/app-framework-development-guide.md
@@ -15,15 +15,12 @@ You can write a framework scheduler in C, C++, Java/Scala, or Python. Your frame
 
 ### Scheduler API
 
+Callback interface to be implemented by framework schedulers.
+
 Declared in `MESOS_HOME/include/mesos/scheduler.hpp`
 
 ~~~{.cpp}
 /*
- * Empty virtual destructor (necessary to instantiate subclasses).
- */
-virtual ~Scheduler() {}
-
-/*
  * Invoked when the scheduler successfully registers with a Mesos
  * master. A unique ID (generated by the master) used for
  * distinguishing this framework from others and MasterInfo
@@ -31,7 +28,7 @@ virtual ~Scheduler() {}
  */
 virtual void registered(SchedulerDriver* driver,
                         const FrameworkID& frameworkId,
-                        const MasterInfo& masterInfo) = 0;
+                        const MasterInfo& masterInfo);
 
 /*
  * Invoked when the scheduler re-registers with a newly elected Mesos master.
@@ -40,13 +37,13 @@ virtual void registered(SchedulerDriver* driver,
  * is provided as an argument.
  */
 virtual void reregistered(SchedulerDriver* driver,
-                          const MasterInfo& masterInfo) = 0;
+                          const MasterInfo& masterInfo);
 
 /*
  * Invoked when the scheduler becomes "disconnected" from the master
  * (e.g., the master fails and another is taking over).
  */
-virtual void disconnected(SchedulerDriver* driver) = 0;
+virtual void disconnected(SchedulerDriver* driver);
 
 /*
  * Invoked when resources have been offered to this framework. A
@@ -64,7 +61,7 @@ virtual void disconnected(SchedulerDriver* driver) = 0;
  * fail with a TASK_LOST status and a message saying as much).
  */
 virtual void resourceOffers(SchedulerDriver* driver,
-                            const std::vector<Offer>& offers) = 0;
+                            const std::vector<Offer>& offers);
 
 /*
  * Invoked when an offer is no longer valid (e.g., the slave was
@@ -74,8 +71,7 @@ virtual void resourceOffers(SchedulerDriver* driver,
  * to launch tasks using an invalid offer will receive TASK_LOST
  * status updates for those tasks (see Scheduler::resourceOffers).
  */
-virtual void offerRescinded(SchedulerDriver* driver,
-                            const OfferID& offerId) = 0;
+virtual void offerRescinded(SchedulerDriver* driver, const OfferID& offerId);
 
 /*
  * Invoked when the status of a task has changed (e.g., a slave is
@@ -90,8 +86,7 @@ virtual void offerRescinded(SchedulerDriver* driver,
  * acknowledgements are in use, the scheduler must acknowledge this
  * status on the driver.
  */
-virtual void statusUpdate(SchedulerDriver* driver,
-                          const TaskStatus& status) = 0;
+virtual void statusUpdate(SchedulerDriver* driver, const TaskStatus& status);
 
 /*
  * Invoked when an executor sends a message. These messages are best
@@ -101,34 +96,162 @@ virtual void statusUpdate(SchedulerDriver* driver,
 virtual void frameworkMessage(SchedulerDriver* driver,
                               const ExecutorID& executorId,
                               const SlaveID& slaveId,
-                              const std::string& data) = 0;
+                              const std::string& data);
 
 /*
  * Invoked when a slave has been determined unreachable (e.g.,
  * machine failure, network partition). Most frameworks will need to
  * reschedule any tasks launched on this slave on a new slave.
  */
-virtual void slaveLost(SchedulerDriver* driver,
-                       const SlaveID& slaveId) = 0;
+virtual void slaveLost(SchedulerDriver* driver, const SlaveID& slaveId);
 
 /*
  * Invoked when an executor has exited/terminated. Note that any
  * tasks running will have TASK_LOST status updates automagically
  * generated.
- *
  * NOTE: This callback is not reliably delivered.
  */
 virtual void executorLost(SchedulerDriver* driver,
                           const ExecutorID& executorId,
                           const SlaveID& slaveId,
-                          int status) = 0;
+                          int status);
 
 /*
  * Invoked when there is an unrecoverable error in the scheduler or
  * scheduler driver. The driver will be aborted BEFORE invoking this
  * callback.
  */
-virtual void error(SchedulerDriver* driver, const std::string& message) = 0;
+virtual void error(SchedulerDriver* driver, const std::string& message);
+~~~
+
+### Scheduler Driver API
+
+The Scheduler Driver is responsible for managing the scheduler's lifecycle
+(e.g., start, stop, or wait to finish) and interacting with Mesos Master
+(e.g., launch tasks, kill tasks, etc.).
+
+Note that this interface is usually not implemented by a framework itself,
+but it describes the possible calls a framework scheduler can make to
+interact with the Mesos Master.
+
+Please note that usage of this interface requires an instantiated
+MesosSchedulerDiver.
+See `src/examples/test_framework.cpp` for an example of using the
+MesosSchedulerDriver.
+
+Declared in `MESOS_HOME/include/mesos/scheduler.hpp`
+
+~~~{.cpp}
+// Starts the scheduler driver. This needs to be called before any
+// other driver calls are made.
+virtual Status start();
+
+// Stops the scheduler driver. If the 'failover' flag is set to
+// false then it is expected that this framework will never
+// reconnect to Mesos. So Mesos will unregister the framework and
+// shutdown all its tasks and executors. If 'failover' is true, all
+// executors and tasks will remain running (for some framework
+// specific failover timeout) allowing the scheduler to reconnect
+// (possibly in the same process, or from a different process, for
+// example, on a different machine).
+virtual Status stop(bool failover = false);
+
+// Aborts the driver so that no more callbacks can be made to the
+// scheduler. The semantics of abort and stop have deliberately been
+// separated so that code can detect an aborted driver (i.e., via
+// the return status of SchedulerDriver::join, see below), and
+// instantiate and start another driver if desired (from within the
+// same process). Note that 'stop()' is not automatically called
+// inside 'abort()'.
+virtual Status abort();
+
+// Waits for the driver to be stopped or aborted, possibly
+// _blocking_ the current thread indefinitely. The return status of
+// this function can be used to determine if the driver was aborted
+// (see mesos.proto for a description of Status).
+virtual Status join();
+
+// Starts and immediately joins (i.e., blocks on) the driver.
+virtual Status run();
+
+// Requests resources from Mesos (see mesos.proto for a description
+// of Request and how, for example, to request resources from
+// specific slaves). Any resources available are offered to the
+// framework via Scheduler::resourceOffers callback, asynchronously.
+virtual Status requestResources(const std::vector<Request>& requests);
+
+// Launches the given set of tasks. Any resources remaining (i.e.,
+// not used by the tasks or their executors) will be considered
+// declined. The specified filters are applied on all unused
+// resources (see mesos.proto for a description of Filters).
+// Available resources are aggregated when multiple offers are
+// provided. Note that all offers must belong to the same slave.
+// Invoking this function with an empty collection of tasks declines
+// offers in their entirety (see Scheduler::declineOffer).
+virtual Status launchTasks(
+    const std::vector<OfferID>& offerIds,
+    const std::vector<TaskInfo>& tasks,
+    const Filters& filters = Filters());
+
+// Kills the specified task. Note that attempting to kill a task is
+// currently not reliable. If, for example, a scheduler fails over
+// while it was attempting to kill a task it will need to retry in
+// the future. Likewise, if unregistered / disconnected, the request
+// will be dropped (these semantics may be changed in the future).
+virtual Status killTask(const TaskID& taskId);
+
+// Accepts the given offers and performs a sequence of operations on
+// those accepted offers. See Offer.Operation in mesos.proto for the
+// set of available operations. Available resources are aggregated
+// when multiple offers are provided. Note that all offers must
+// belong to the same slave. Any unused resources will be considered
+// declined. The specified filters are applied on all unused
+// resources (see mesos.proto for a description of Filters).
+virtual Status acceptOffers(
+    const std::vector<OfferID>& offerIds,
+    const std::vector<Offer::Operation>& operations,
+    const Filters& filters = Filters());
+
+// Declines an offer in its entirety and applies the specified
+// filters on the resources (see mesos.proto for a description of
+// Filters). Note that this can be done at any time, it is not
+// necessary to do this within the Scheduler::resourceOffers
+// callback.
+virtual Status declineOffer(
+    const OfferID& offerId,
+    const Filters& filters = Filters());
+
+// Removes all filters previously set by the framework (via
+// launchTasks()). This enables the framework to receive offers from
+// those filtered slaves.
+virtual Status reviveOffers();
+
+// Inform Mesos master to stop sending offers to the framework. The
+// scheduler should call reviveOffers() to resume getting offers.
+virtual Status suppressOffers();
+
+// Acknowledges the status update. This should only be called
+// once the status update is processed durably by the scheduler.
+// Not that explicit acknowledgements must be requested via the
+// constructor argument, otherwise a call to this method will
+// cause the driver to crash.
+virtual Status acknowledgeStatusUpdate(const TaskStatus& status);
+
+// Sends a message from the framework to one of its executors. These
+// messages are best effort; do not expect a framework message to be
+// retransmitted in any reliable fashion.
+virtual Status sendFrameworkMessage(
+    const ExecutorID& executorId,
+    const SlaveID& slaveId,
+    const std::string& data);
+
+// Allows the framework to query the status for non-terminal tasks.
+// This causes the master to send back the latest task status for
+// each task in 'statuses', if possible. Tasks that are no longer
+// known will result in a TASK_LOST update. If statuses is empty,
+// then the master will send the latest status for each task
+// currently known.
+virtual Status reconcileTasks(const std::vector<TaskStatus>& statuses);
 ~~~
 
 ### Handling Failures
@@ -172,19 +295,18 @@ Declared in `MESOS_HOME/include/mesos/executor.hpp`
 virtual void registered(ExecutorDriver* driver,
                         const ExecutorInfo& executorInfo,
                         const FrameworkInfo& frameworkInfo,
-                        const SlaveInfo& slaveInfo) = 0;
+                        const SlaveInfo& slaveInfo);
 
 /*
  * Invoked when the executor re-registers with a restarted slave.
  */
-virtual void reregistered(ExecutorDriver* driver,
-                          const SlaveInfo& slaveInfo) = 0;
+virtual void reregistered(ExecutorDriver* driver, const SlaveInfo& slaveInfo);
 
 /*
  * Invoked when the executor becomes "disconnected" from the slave
  * (e.g., the slave is being restarted due to an upgrade).
  */
-virtual void disconnected(ExecutorDriver* driver) = 0;
+virtual void disconnected(ExecutorDriver* driver);
 
 /*
  * Invoked when a task has been launched on this executor (initiated
@@ -193,8 +315,7 @@ virtual void disconnected(ExecutorDriver* driver) = 0;
  * other callbacks will be invoked on this executor until this
  * callback has returned.
  */
-virtual void launchTask(ExecutorDriver* driver,
-                        const TaskInfo& task) = 0;
+virtual void launchTask(ExecutorDriver* driver, const TaskInfo& task);
 
 /*
  * Invoked when a task running within this executor has been killed
@@ -203,15 +324,14 @@ virtual void launchTask(ExecutorDriver* driver,
  * for creating a new TaskStatus (i.e., with TASK_KILLED) and
  * invoking ExecutorDriver::sendStatusUpdate.
  */
-virtual void killTask(ExecutorDriver* driver, const TaskID& taskId) = 0;
+virtual void killTask(ExecutorDriver* driver, const TaskID& taskId);
 
 /*
  * Invoked when a framework message has arrived for this
  * executor. These messages are best effort; do not expect a
  * framework message to be retransmitted in any reliable fashion.
  */
-virtual void frameworkMessage(ExecutorDriver* driver,
-                              const std::string& data) = 0;
+virtual void frameworkMessage(ExecutorDriver* driver, const std::string& data);
 
 /*
  * Invoked when the executor should terminate all of it's currently
@@ -220,14 +340,14 @@ virtual void frameworkMessage(ExecutorDriver* driver,
  * terminal status updates for (e.g., TASK_KILLED, TASK_FINISHED,
  * TASK_FAILED, etc) a TASK_LOST status update will be created.
  */
-virtual void shutdown(ExecutorDriver* driver) = 0;
+virtual void shutdown(ExecutorDriver* driver);
 
 /*
  * Invoked when a fatal error has occurred with the executor and/or
  * executor driver. The driver will be aborted BEFORE invoking this
  * callback.
  */
-virtual void error(ExecutorDriver* driver, const std::string& message) = 0;
+virtual void error(ExecutorDriver* driver, const std::string& message);
 ~~~
 
 #### Install your custom Framework Executor