You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by al...@apache.org on 2018/08/28 19:50:10 UTC

[mesos] branch master updated (c4ec354 -> 4930ec2)

This is an automated email from the ASF dual-hosted git repository.

alexr pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git.


    from c4ec354  Fixed misplaced table element in the agent docs.
     new 4118a48  Added '/state-summary' to the set of batched master endpoints.
     new 63e9096  Added '/tasks' to the set of batched master endpoints.
     new 33c38c9  Added '/slaves' to the set of batched master endpoints.
     new 102dcca  Added '/frameworks' to the set of batched master endpoints.
     new 44e5234  Moved members of `ReadOnlyHandler` into separate file.
     new 4930ec2  Cleaned up some style issues in `ReadOnlyHandler`.

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/CMakeLists.txt              |    1 +
 src/Makefile.am                 |    1 +
 src/common/http.cpp             |  126 +++--
 src/common/http.hpp             |   11 +-
 src/master/http.cpp             | 1112 +------------------------------------
 src/master/master.hpp           |   28 +
 src/master/readonly_handler.cpp | 1146 +++++++++++++++++++++++++++++++++++++++
 src/slave/http.cpp              |    7 -
 8 files changed, 1292 insertions(+), 1140 deletions(-)
 create mode 100644 src/master/readonly_handler.cpp


[mesos] 06/06: Cleaned up some style issues in `ReadOnlyHandler`.

Posted by al...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

alexr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit 4930ec2e141920411fb9050500f385f5ef6a78a2
Author: Benno Evers <be...@mesosphere.com>
AuthorDate: Tue Aug 28 21:26:36 2018 +0200

    Cleaned up some style issues in `ReadOnlyHandler`.
    
    This commit fixes several minor style issues:
     - Sorted member function declarations of `ReadOnlyHandler`
       alphabetically.
     - Added notes to remind readers of the fact that requests
       to certain endpoints are batched.
     - Changed captured variable in `/frameworks` endpoint handler.
    
    Review: https://reviews.apache.org/r/68537/
---
 src/common/http.hpp             |  2 +-
 src/master/master.hpp           | 26 ++++++++++++++++----------
 src/master/readonly_handler.cpp | 19 +++++++++----------
 3 files changed, 26 insertions(+), 21 deletions(-)

diff --git a/src/common/http.hpp b/src/common/http.hpp
index 76abafa..4f994a0 100644
--- a/src/common/http.hpp
+++ b/src/common/http.hpp
@@ -162,6 +162,7 @@ void json(JSON::ArrayWriter* writer, const Labels& labels);
 void json(JSON::ObjectWriter* writer, const MasterInfo& info);
 void json(
     JSON::StringWriter* writer, const MasterInfo::Capability& capability);
+void json(JSON::ObjectWriter* writer, const Offer& offer);
 void json(JSON::ObjectWriter* writer, const Resources& resources);
 void json(
     JSON::ObjectWriter* writer,
@@ -171,7 +172,6 @@ void json(
     JSON::StringWriter* writer, const SlaveInfo::Capability& capability);
 void json(JSON::ObjectWriter* writer, const Task& task);
 void json(JSON::ObjectWriter* writer, const TaskStatus& status);
-void json(JSON::ObjectWriter* writer, const Offer& offer);
 
 namespace authorization {
 
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 9b98771..eecb66c 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1396,28 +1396,28 @@ private:
   public:
     explicit ReadOnlyHandler(const Master* _master) : master(_master) {}
 
-    // /state
-    process::http::Response state(
+    // /frameworks
+    process::http::Response frameworks(
         const process::http::Request& request,
         const process::Owned<ObjectApprovers>& approvers) const;
 
-    // /state-summary
-    process::http::Response stateSummary(
+    // /slaves
+    process::http::Response slaves(
         const process::http::Request& request,
         const process::Owned<ObjectApprovers>& approvers) const;
 
-    // /tasks
-    process::http::Response tasks(
+    // /state
+    process::http::Response state(
         const process::http::Request& request,
         const process::Owned<ObjectApprovers>& approvers) const;
 
-    // /slaves
-    process::http::Response slaves(
+    // /state-summary
+    process::http::Response stateSummary(
         const process::http::Request& request,
         const process::Owned<ObjectApprovers>& approvers) const;
 
-    // /frameworks
-    process::http::Response frameworks(
+    // /tasks
+    process::http::Response tasks(
         const process::http::Request& request,
         const process::Owned<ObjectApprovers>& approvers) const;
 
@@ -1466,6 +1466,8 @@ private:
             principal) const;
 
     // /master/frameworks
+    //
+    // NOTE: Requests to this endpoint are batched.
     process::Future<process::http::Response> frameworks(
         const process::http::Request& request,
         const Option<process::http::authentication::Principal>&
@@ -1498,6 +1500,8 @@ private:
             principal) const;
 
     // /master/slaves
+    //
+    // NOTE: Requests to this endpoint are batched.
     process::Future<process::http::Response> slaves(
         const process::http::Request& request,
         const Option<process::http::authentication::Principal>&
@@ -1520,6 +1524,8 @@ private:
             principal) const;
 
     // /master/tasks
+    //
+    // NOTE: Requests to this endpoint are batched.
     process::Future<process::http::Response> tasks(
         const process::http::Request& request,
         const Option<process::http::authentication::Principal>&
diff --git a/src/master/readonly_handler.cpp b/src/master/readonly_handler.cpp
index 8026c6d..47d7de5 100644
--- a/src/master/readonly_handler.cpp
+++ b/src/master/readonly_handler.cpp
@@ -16,15 +16,15 @@
 
 #include "master/master.hpp"
 
-#include <vector>
 #include <string>
+#include <vector>
 
 #include <mesos/mesos.hpp>
 
 #include <mesos/authorizer/authorizer.hpp>
 
-#include <process/owned.hpp>
 #include <process/http.hpp>
+#include <process/owned.hpp>
 
 #include <stout/foreach.hpp>
 #include <stout/hashmap.hpp>
@@ -36,7 +36,6 @@
 #include "common/build.hpp"
 #include "common/http.hpp"
 
-
 using process::Owned;
 
 using process::http::OK;
@@ -637,14 +636,16 @@ process::http::Response Master::ReadOnlyHandler::frameworks(
 {
   IDAcceptor<FrameworkID> selectFrameworkId(
       request.url.query.get("framework_id"));
+
   // This lambda is consumed before the outer lambda
   // returns, hence capture by reference is fine here.
-  auto frameworks = [this, &approvers, &selectFrameworkId](
+  const Master* master = this->master;
+  auto frameworks = [master, &approvers, &selectFrameworkId](
       JSON::ObjectWriter* writer) {
     // Model all of the frameworks.
     writer->field(
         "frameworks",
-        [this, &approvers, &selectFrameworkId](
+        [master, &approvers, &selectFrameworkId](
             JSON::ArrayWriter* writer) {
           foreachvalue (
               Framework* framework, master->frameworks.registered) {
@@ -662,7 +663,7 @@ process::http::Response Master::ReadOnlyHandler::frameworks(
     // Model all of the completed frameworks.
     writer->field(
         "completed_frameworks",
-        [this, &approvers, &selectFrameworkId](
+        [master, &approvers, &selectFrameworkId](
             JSON::ArrayWriter* writer) {
           foreachvalue (const Owned<Framework>& framework,
                         master->frameworks.completed) {
@@ -691,13 +692,11 @@ process::http::Response Master::ReadOnlyHandler::slaves(
     const process::http::Request& request,
     const process::Owned<ObjectApprovers>& approvers) const
 {
-  Option<string> slaveId = request.url.query.get("slave_id");
-  Option<string> jsonp = request.url.query.get("jsonp");
-  IDAcceptor<SlaveID> selectSlaveId(slaveId);
+  IDAcceptor<SlaveID> selectSlaveId(request.url.query.get("slave_id"));
 
   return process::http::OK(
       jsonify(SlavesWriter(master->slaves, approvers, selectSlaveId)),
-      jsonp);
+      request.url.query.get("jsonp"));
 }
 
 


[mesos] 02/06: Added '/tasks' to the set of batched master endpoints.

Posted by al...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

alexr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit 63e9096b0cd883d9edc8907a577bcba0b150b541
Author: Benno Evers <be...@mesosphere.com>
AuthorDate: Tue Aug 28 21:26:03 2018 +0200

    Added '/tasks' to the set of batched master endpoints.
    
    Review: https://reviews.apache.org/r/68440/
---
 src/master/http.cpp   | 212 ++++++++++++++++++++++++++------------------------
 src/master/master.hpp |   5 ++
 2 files changed, 115 insertions(+), 102 deletions(-)

diff --git a/src/master/http.cpp b/src/master/http.cpp
index 5cd177e..897c80d 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -4041,25 +4041,10 @@ string Master::Http::TASKS_HELP()
         "See the authorization documentation for details."));
 }
 
-
-Future<Response> Master::Http::tasks(
-    const Request& request,
-    const Option<Principal>& principal) const
+process::http::Response Master::ReadOnlyHandler::tasks(
+  const process::http::Request& request,
+  const process::Owned<ObjectApprovers>& approvers) const
 {
-  // TODO(greggomann): Remove this check once the `Principal` type is used in
-  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
-  // See MESOS-7202.
-  if (principal.isSome() && principal->value.isNone()) {
-    return Forbidden(
-        "The request's authenticated principal contains claims, but no value "
-        "string. The master currently requires that principals have a value");
-  }
-
-  // When current master is not the leader, redirect to the leading master.
-  if (!master->elected()) {
-    return redirect(request);
-  }
-
   // Get list options (limit and offset).
   Result<int> result = numify<int>(request.url.query.get("limit"));
   size_t limit = result.isSome() ? result.get() : TASK_LIMIT;
@@ -4073,103 +4058,126 @@ Future<Response> Master::Http::tasks(
   Option<string> frameworkId = request.url.query.get("framework_id");
   Option<string> taskId = request.url.query.get("task_id");
 
-  return ObjectApprovers::create(
-      master->authorizer,
-      principal,
-      {VIEW_FRAMEWORK, VIEW_TASK})
-    .then(defer(
-        master->self(),
-        [=](const Owned<ObjectApprovers>& approvers) -> Response {
-          IDAcceptor<FrameworkID> selectFrameworkId(frameworkId);
-          IDAcceptor<TaskID> selectTaskId(taskId);
-
-          // Construct framework list with both active and completed frameworks.
-          vector<const Framework*> frameworks;
-          foreachvalue (Framework* framework, master->frameworks.registered) {
-            // Skip unauthorized frameworks or frameworks without matching
-            // framework ID.
-            if (!selectFrameworkId.accept(framework->id()) ||
-                !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-              continue;
-            }
+  IDAcceptor<FrameworkID> selectFrameworkId(frameworkId);
+  IDAcceptor<TaskID> selectTaskId(taskId);
 
-            frameworks.push_back(framework);
-          }
+  // Construct framework list with both active and completed frameworks.
+  vector<const Framework*> frameworks;
+  foreachvalue (Framework* framework, master->frameworks.registered) {
+    // Skip unauthorized frameworks or frameworks without matching
+    // framework ID.
+    if (!selectFrameworkId.accept(framework->id()) ||
+        !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+      continue;
+    }
 
-          foreachvalue (const Owned<Framework>& framework,
-                        master->frameworks.completed) {
-            // Skip unauthorized frameworks or frameworks without matching
-            // framework ID.
-            if (!selectFrameworkId.accept(framework->id()) ||
-                !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-             continue;
-            }
+    frameworks.push_back(framework);
+  }
 
-            frameworks.push_back(framework.get());
-          }
+  foreachvalue (const Owned<Framework>& framework,
+                master->frameworks.completed) {
+    // Skip unauthorized frameworks or frameworks without matching
+    // framework ID.
+    if (!selectFrameworkId.accept(framework->id()) ||
+        !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+     continue;
+    }
 
-          // Construct task list with both running,
-          // completed and unreachable tasks.
-          vector<const Task*> tasks;
-          foreach (const Framework* framework, frameworks) {
-            foreachvalue (Task* task, framework->tasks) {
-              CHECK_NOTNULL(task);
-              // Skip unauthorized tasks or tasks without matching task ID.
-              if (!selectTaskId.accept(task->task_id()) ||
-                  !approvers->approved<VIEW_TASK>(*task, framework->info)) {
-                continue;
-              }
+    frameworks.push_back(framework.get());
+  }
 
-              tasks.push_back(task);
-            }
+  // Construct task list with both running,
+  // completed and unreachable tasks.
+  vector<const Task*> tasks;
+  foreach (const Framework* framework, frameworks) {
+    foreachvalue (Task* task, framework->tasks) {
+      CHECK_NOTNULL(task);
+      // Skip unauthorized tasks or tasks without matching task ID.
+      if (!selectTaskId.accept(task->task_id()) ||
+          !approvers->approved<VIEW_TASK>(*task, framework->info)) {
+        continue;
+      }
 
-            foreachvalue (
-                const Owned<Task>& task,
-                framework->unreachableTasks) {
-              // Skip unauthorized tasks or tasks without matching task ID.
-              if (!selectTaskId.accept(task->task_id()) ||
-                  !approvers->approved<VIEW_TASK>(*task, framework->info)) {
-                continue;
-              }
+      tasks.push_back(task);
+    }
 
-              tasks.push_back(task.get());
-            }
+    foreachvalue (
+        const Owned<Task>& task,
+        framework->unreachableTasks) {
+      // Skip unauthorized tasks or tasks without matching task ID.
+      if (!selectTaskId.accept(task->task_id()) ||
+          !approvers->approved<VIEW_TASK>(*task, framework->info)) {
+        continue;
+      }
 
-            foreach (const Owned<Task>& task, framework->completedTasks) {
-              // Skip unauthorized tasks or tasks without matching task ID.
-              if (!selectTaskId.accept(task->task_id()) ||
-                  !approvers->approved<VIEW_TASK>(*task, framework->info)) {
-                continue;
-              }
+      tasks.push_back(task.get());
+    }
 
-              tasks.push_back(task.get());
+    foreach (const Owned<Task>& task, framework->completedTasks) {
+      // Skip unauthorized tasks or tasks without matching task ID.
+      if (!selectTaskId.accept(task->task_id()) ||
+          !approvers->approved<VIEW_TASK>(*task, framework->info)) {
+        continue;
+      }
+
+      tasks.push_back(task.get());
+    }
+  }
+
+  // Sort tasks by task status timestamp. Default order is descending.
+  // The earliest timestamp is chosen for comparison when
+  // multiple are present.
+  if (_order == "asc") {
+    sort(tasks.begin(), tasks.end(), TaskComparator::ascending);
+  } else {
+    sort(tasks.begin(), tasks.end(), TaskComparator::descending);
+  }
+
+  auto tasksWriter =
+    [&tasks, limit, offset](JSON::ObjectWriter* writer) {
+      writer->field(
+          "tasks",
+          [&tasks, limit, offset](JSON::ArrayWriter* writer) {
+            // Collect 'limit' number of tasks starting from 'offset'.
+            size_t end = std::min(offset + limit, tasks.size());
+            for (size_t i = offset; i < end; i++) {
+              writer->element(*tasks[i]);
             }
-          }
+          });
+  };
 
-          // Sort tasks by task status timestamp. Default order is descending.
-          // The earliest timestamp is chosen for comparison when
-          // multiple are present.
-          if (_order == "asc") {
-            sort(tasks.begin(), tasks.end(), TaskComparator::ascending);
-          } else {
-            sort(tasks.begin(), tasks.end(), TaskComparator::descending);
-          }
+  return OK(jsonify(tasksWriter), request.url.query.get("jsonp"));
+}
 
-          auto tasksWriter =
-            [&tasks, limit, offset](JSON::ObjectWriter* writer) {
-              writer->field(
-                  "tasks",
-                  [&tasks, limit, offset](JSON::ArrayWriter* writer) {
-                    // Collect 'limit' number of tasks starting from 'offset'.
-                    size_t end = std::min(offset + limit, tasks.size());
-                    for (size_t i = offset; i < end; i++) {
-                      writer->element(*tasks[i]);
-                    }
-                  });
-          };
 
-          return OK(jsonify(tasksWriter), request.url.query.get("jsonp"));
-  }));
+Future<Response> Master::Http::tasks(
+    const Request& request,
+    const Option<Principal>& principal) const
+{
+  // TODO(greggomann): Remove this check once the `Principal` type is used in
+  // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map.
+  // See MESOS-7202.
+  if (principal.isSome() && principal->value.isNone()) {
+    return Forbidden(
+        "The request's authenticated principal contains claims, but no value "
+        "string. The master currently requires that principals have a value");
+  }
+
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
+  return ObjectApprovers::create(
+      master->authorizer,
+      principal,
+      {VIEW_FRAMEWORK, VIEW_TASK})
+    .then(defer(
+        master->self(),
+        [this, request](const Owned<ObjectApprovers>& approvers) {
+          return deferBatchedRequest(
+              &Master::ReadOnlyHandler::tasks, request, approvers);
+        }));
 }
 
 
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 9db5aae..381db90 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1406,6 +1406,11 @@ private:
         const process::http::Request& request,
         const process::Owned<ObjectApprovers>& approvers) const;
 
+    // /tasks
+    process::http::Response tasks(
+        const process::http::Request& request,
+        const process::Owned<ObjectApprovers>& approvers) const;
+
   private:
     const Master* master;
   };


[mesos] 01/06: Added '/state-summary' to the set of batched master endpoints.

Posted by al...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

alexr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit 4118a482a95793252f4713c5e20ef2c70f2ab07b
Author: Benno Evers <be...@mesosphere.com>
AuthorDate: Tue Aug 28 21:25:52 2018 +0200

    Added '/state-summary' to the set of batched master endpoints.
    
    Review: https://reviews.apache.org/r/68321/
---
 src/master/http.cpp   | 268 ++++++++++++++++++++++++++------------------------
 src/master/master.hpp |   7 ++
 2 files changed, 146 insertions(+), 129 deletions(-)

diff --git a/src/master/http.cpp b/src/master/http.cpp
index ae28d52..5cd177e 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -3334,147 +3334,157 @@ Future<Response> Master::Http::stateSummary(
       {VIEW_ROLE, VIEW_FRAMEWORK})
     .then(defer(
         master->self(),
-        [this, request](const Owned<ObjectApprovers>& approvers) -> Response {
-          auto stateSummary = [this, &approvers](JSON::ObjectWriter* writer) {
-            writer->field("hostname", master->info().hostname());
+        [this, request](const Owned<ObjectApprovers>& approvers) {
+          return deferBatchedRequest(
+              &Master::ReadOnlyHandler::stateSummary, request, approvers);
+        }));
+}
 
-            if (master->flags.cluster.isSome()) {
-              writer->field("cluster", master->flags.cluster.get());
-            }
 
-            // We use the tasks in the 'Frameworks' struct to compute summaries
-            // for this endpoint. This is done 1) for consistency between the
-            // 'slaves' and 'frameworks' subsections below 2) because we want to
-            // provide summary information for frameworks that are currently
-            // registered 3) the frameworks keep a circular buffer of completed
-            // tasks that we can use to keep a limited view on the history of
-            // recent completed / failed tasks.
+process::http::Response Master::ReadOnlyHandler::stateSummary(
+    const process::http::Request& request,
+    const process::Owned<ObjectApprovers>& approvers) const
+{
+  const Master* master = this->master;
+  auto stateSummary = [master, &approvers](JSON::ObjectWriter* writer) {
+    writer->field("hostname", master->info().hostname());
 
-            // Generate mappings from 'slave' to 'framework' and reverse.
-            SlaveFrameworkMapping slaveFrameworkMapping(
-                master->frameworks.registered);
+    if (master->flags.cluster.isSome()) {
+      writer->field("cluster", master->flags.cluster.get());
+    }
 
-            // Generate 'TaskState' summaries for all framework and slave ids.
-            TaskStateSummaries taskStateSummaries(
-                master->frameworks.registered);
+    // We use the tasks in the 'Frameworks' struct to compute summaries
+    // for this endpoint. This is done 1) for consistency between the
+    // 'slaves' and 'frameworks' subsections below 2) because we want to
+    // provide summary information for frameworks that are currently
+    // registered 3) the frameworks keep a circular buffer of completed
+    // tasks that we can use to keep a limited view on the history of
+    // recent completed / failed tasks.
 
-            // Model all of the slaves.
-            writer->field(
-                "slaves",
-                [this,
+    // Generate mappings from 'slave' to 'framework' and reverse.
+    SlaveFrameworkMapping slaveFrameworkMapping(
+        master->frameworks.registered);
+
+    // Generate 'TaskState' summaries for all framework and slave ids.
+    TaskStateSummaries taskStateSummaries(
+        master->frameworks.registered);
+
+    // Model all of the slaves.
+    writer->field(
+        "slaves",
+        [master,
+         &slaveFrameworkMapping,
+         &taskStateSummaries,
+         &approvers](JSON::ArrayWriter* writer) {
+          foreachvalue (Slave* slave, master->slaves.registered) {
+            writer->element(
+                [&slave,
                  &slaveFrameworkMapping,
                  &taskStateSummaries,
-                 &approvers](JSON::ArrayWriter* writer) {
-                  foreachvalue (Slave* slave, master->slaves.registered) {
-                    writer->element(
-                        [&slave,
-                         &slaveFrameworkMapping,
-                         &taskStateSummaries,
-                         &approvers](JSON::ObjectWriter* writer) {
-                          SlaveWriter slaveWriter(*slave, approvers);
-                          slaveWriter(writer);
-
-                          // Add the 'TaskState' summary for this slave.
-                          const TaskStateSummary& summary =
-                              taskStateSummaries.slave(slave->id);
-
-                          // Certain per-agent status totals will always be zero
-                          // (e.g., TASK_ERROR, TASK_UNREACHABLE). We report
-                          // them here anyway, for completeness.
-                          //
-                          // TODO(neilc): Update for TASK_GONE and
-                          // TASK_GONE_BY_OPERATOR.
-                          writer->field("TASK_STAGING", summary.staging);
-                          writer->field("TASK_STARTING", summary.starting);
-                          writer->field("TASK_RUNNING", summary.running);
-                          writer->field("TASK_KILLING", summary.killing);
-                          writer->field("TASK_FINISHED", summary.finished);
-                          writer->field("TASK_KILLED", summary.killed);
-                          writer->field("TASK_FAILED", summary.failed);
-                          writer->field("TASK_LOST", summary.lost);
-                          writer->field("TASK_ERROR", summary.error);
-                          writer->field(
-                              "TASK_UNREACHABLE",
-                              summary.unreachable);
-
-                          // Add the ids of all the frameworks running on this
-                          // slave.
-                          const hashset<FrameworkID>& frameworks =
-                              slaveFrameworkMapping.frameworks(slave->id);
-
-                          writer->field(
-                              "framework_ids",
-                              [&frameworks](JSON::ArrayWriter* writer) {
-                                foreach (
-                                    const FrameworkID& frameworkId,
-                                    frameworks) {
-                                  writer->element(frameworkId.value());
-                                }
-                              });
-                        });
-                  }
+                 &approvers](JSON::ObjectWriter* writer) {
+                  SlaveWriter slaveWriter(*slave, approvers);
+                  slaveWriter(writer);
+
+                  // Add the 'TaskState' summary for this slave.
+                  const TaskStateSummary& summary =
+                      taskStateSummaries.slave(slave->id);
+
+                  // Certain per-agent status totals will always be zero
+                  // (e.g., TASK_ERROR, TASK_UNREACHABLE). We report
+                  // them here anyway, for completeness.
+                  //
+                  // TODO(neilc): Update for TASK_GONE and
+                  // TASK_GONE_BY_OPERATOR.
+                  writer->field("TASK_STAGING", summary.staging);
+                  writer->field("TASK_STARTING", summary.starting);
+                  writer->field("TASK_RUNNING", summary.running);
+                  writer->field("TASK_KILLING", summary.killing);
+                  writer->field("TASK_FINISHED", summary.finished);
+                  writer->field("TASK_KILLED", summary.killed);
+                  writer->field("TASK_FAILED", summary.failed);
+                  writer->field("TASK_LOST", summary.lost);
+                  writer->field("TASK_ERROR", summary.error);
+                  writer->field(
+                      "TASK_UNREACHABLE",
+                      summary.unreachable);
+
+                  // Add the ids of all the frameworks running on this
+                  // slave.
+                  const hashset<FrameworkID>& frameworks =
+                      slaveFrameworkMapping.frameworks(slave->id);
+
+                  writer->field(
+                      "framework_ids",
+                      [&frameworks](JSON::ArrayWriter* writer) {
+                        foreach (
+                            const FrameworkID& frameworkId,
+                            frameworks) {
+                          writer->element(frameworkId.value());
+                        }
+                      });
                 });
+          }
+        });
 
-            // Model all of the frameworks.
-            writer->field(
-                "frameworks",
-                [this,
-                 &slaveFrameworkMapping,
-                 &taskStateSummaries,
-                 &approvers](JSON::ArrayWriter* writer) {
-                  foreachpair (const FrameworkID& frameworkId,
-                               Framework* framework,
-                               master->frameworks.registered) {
-                    // Skip unauthorized frameworks.
-                    if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-                      continue;
-                    }
+    // Model all of the frameworks.
+    writer->field(
+        "frameworks",
+        [master,
+         &slaveFrameworkMapping,
+         &taskStateSummaries,
+         &approvers](JSON::ArrayWriter* writer) {
+          foreachpair (const FrameworkID& frameworkId,
+                       Framework* framework,
+                       master->frameworks.registered) {
+            // Skip unauthorized frameworks.
+            if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+              continue;
+            }
 
-                    writer->element(
-                        [&frameworkId,
-                         &framework,
-                         &slaveFrameworkMapping,
-                         &taskStateSummaries](JSON::ObjectWriter* writer) {
-                          json(writer, Summary<Framework>(*framework));
-
-                          // Add the 'TaskState' summary for this framework.
-                          const TaskStateSummary& summary =
-                              taskStateSummaries.framework(frameworkId);
-
-                          // TODO(neilc): Update for TASK_GONE and
-                          // TASK_GONE_BY_OPERATOR.
-                          writer->field("TASK_STAGING", summary.staging);
-                          writer->field("TASK_STARTING", summary.starting);
-                          writer->field("TASK_RUNNING", summary.running);
-                          writer->field("TASK_KILLING", summary.killing);
-                          writer->field("TASK_FINISHED", summary.finished);
-                          writer->field("TASK_KILLED", summary.killed);
-                          writer->field("TASK_FAILED", summary.failed);
-                          writer->field("TASK_LOST", summary.lost);
-                          writer->field("TASK_ERROR", summary.error);
-                          writer->field(
-                              "TASK_UNREACHABLE",
-                              summary.unreachable);
-
-                          // Add the ids of all the slaves running
-                          // this framework.
-                          const hashset<SlaveID>& slaves =
-                              slaveFrameworkMapping.slaves(frameworkId);
-
-                          writer->field(
-                              "slave_ids",
-                              [&slaves](JSON::ArrayWriter* writer) {
-                                foreach (const SlaveID& slaveId, slaves) {
-                                  writer->element(slaveId.value());
-                                }
-                              });
-                        });
-                  }
+            writer->element(
+                [&frameworkId,
+                 &framework,
+                 &slaveFrameworkMapping,
+                 &taskStateSummaries](JSON::ObjectWriter* writer) {
+                  json(writer, Summary<Framework>(*framework));
+
+                  // Add the 'TaskState' summary for this framework.
+                  const TaskStateSummary& summary =
+                      taskStateSummaries.framework(frameworkId);
+
+                  // TODO(neilc): Update for TASK_GONE and
+                  // TASK_GONE_BY_OPERATOR.
+                  writer->field("TASK_STAGING", summary.staging);
+                  writer->field("TASK_STARTING", summary.starting);
+                  writer->field("TASK_RUNNING", summary.running);
+                  writer->field("TASK_KILLING", summary.killing);
+                  writer->field("TASK_FINISHED", summary.finished);
+                  writer->field("TASK_KILLED", summary.killed);
+                  writer->field("TASK_FAILED", summary.failed);
+                  writer->field("TASK_LOST", summary.lost);
+                  writer->field("TASK_ERROR", summary.error);
+                  writer->field(
+                      "TASK_UNREACHABLE",
+                      summary.unreachable);
+
+                  // Add the ids of all the slaves running
+                  // this framework.
+                  const hashset<SlaveID>& slaves =
+                      slaveFrameworkMapping.slaves(frameworkId);
+
+                  writer->field(
+                      "slave_ids",
+                      [&slaves](JSON::ArrayWriter* writer) {
+                        foreach (const SlaveID& slaveId, slaves) {
+                          writer->element(slaveId.value());
+                        }
+                      });
                 });
-          };
+          }
+        });
+    };
 
-          return OK(jsonify(stateSummary), request.url.query.get("jsonp"));
-        }));
+  return OK(jsonify(stateSummary), request.url.query.get("jsonp"));
 }
 
 
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 1e01dab..9db5aae 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1401,6 +1401,11 @@ private:
         const process::http::Request& request,
         const process::Owned<ObjectApprovers>& approvers) const;
 
+    // /state-summary
+    process::http::Response stateSummary(
+        const process::http::Request& request,
+        const process::Owned<ObjectApprovers>& approvers) const;
+
   private:
     const Master* master;
   };
@@ -1492,6 +1497,8 @@ private:
             principal) const;
 
     // /master/state-summary
+    //
+    // NOTE: Requests to this endpoint are batched.
     process::Future<process::http::Response> stateSummary(
         const process::http::Request& request,
         const Option<process::http::authentication::Principal>&


[mesos] 05/06: Moved members of `ReadOnlyHandler` into separate file.

Posted by al...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

alexr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit 44e523490b394e6c43bce8b5304996137d176f96
Author: Benno Evers <be...@mesosphere.com>
AuthorDate: Tue Aug 28 21:26:25 2018 +0200

    Moved members of `ReadOnlyHandler` into separate file.
    
    Moved the member functions of class `ReadOnlyHandler` into
    the new file `readonly_handler.cpp`. This follows the pattern
    established by `weights_handler.cpp` and `quota_handler.cpp`.
    
    As part of this move, it was also necessary to move some JSON
    serialization that are used from both `master.cpp` and
    `readonly_handler.cpp` to a new pair of files `json.{cpp,hpp}`
    that can be used from both places.
    
    Review: https://reviews.apache.org/r/68473/
---
 src/CMakeLists.txt              |    1 +
 src/Makefile.am                 |    1 +
 src/common/http.cpp             |  126 +++--
 src/common/http.hpp             |   11 +-
 src/master/http.cpp             | 1120 --------------------------------------
 src/master/readonly_handler.cpp | 1147 +++++++++++++++++++++++++++++++++++++++
 src/slave/http.cpp              |    7 -
 7 files changed, 1252 insertions(+), 1161 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a80b011..7b4a421 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -374,6 +374,7 @@ set(MASTER_SRC
   master/metrics.cpp
   master/quota.cpp
   master/quota_handler.cpp
+  master/readonly_handler.cpp
   master/registrar.cpp
   master/registry_operations.cpp
   master/weights.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
index cf0cf22..db661c3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1019,6 +1019,7 @@ libmesos_no_3rdparty_la_SOURCES +=					\
   master/metrics.cpp							\
   master/quota.cpp							\
   master/quota_handler.cpp						\
+  master/readonly_handler.cpp						\
   master/registrar.cpp							\
   master/registry_operations.cpp					\
   master/validation.cpp							\
diff --git a/src/common/http.cpp b/src/common/http.cpp
index 932111d..9070071 100644
--- a/src/common/http.cpp
+++ b/src/common/http.cpp
@@ -583,6 +583,39 @@ static void json(JSON::ObjectWriter* writer, const ContainerStatus& status)
 }
 
 
+static void json(
+    JSON::ObjectWriter* writer,
+    const DomainInfo::FaultDomain::RegionInfo& regionInfo)
+{
+  writer->field("name", regionInfo.name());
+}
+
+
+static void json(
+    JSON::ObjectWriter* writer,
+    const DomainInfo::FaultDomain::ZoneInfo& zoneInfo)
+{
+  writer->field("name", zoneInfo.name());
+}
+
+
+static void json(
+    JSON::ObjectWriter* writer,
+    const DomainInfo::FaultDomain& faultDomain)
+{
+    writer->field("region", faultDomain.region());
+    writer->field("zone", faultDomain.zone());
+}
+
+
+void json(JSON::ObjectWriter* writer, const DomainInfo& domainInfo)
+{
+  if (domainInfo.has_fault_domain()) {
+    writer->field("fault_domain", domainInfo.fault_domain());
+  }
+}
+
+
 void json(JSON::ObjectWriter* writer, const ExecutorInfo& executorInfo)
 {
   writer->field("executor_id", executorInfo.executor_id().value());
@@ -610,6 +643,14 @@ void json(JSON::ObjectWriter* writer, const ExecutorInfo& executorInfo)
 }
 
 
+void json(
+    JSON::StringWriter* writer,
+    const FrameworkInfo::Capability& capability)
+{
+  writer->set(FrameworkInfo::Capability::Type_Name(capability.type()));
+}
+
+
 void json(JSON::ArrayWriter* writer, const Labels& labels)
 {
   foreach (const Label& label, labels.labels()) {
@@ -618,6 +659,27 @@ void json(JSON::ArrayWriter* writer, const Labels& labels)
 }
 
 
+void json(JSON::ObjectWriter* writer, const MasterInfo& info)
+{
+  writer->field("id", info.id());
+  writer->field("pid", info.pid());
+  writer->field("port", info.port());
+  writer->field("hostname", info.hostname());
+
+  if (info.has_domain()) {
+    writer->field("domain", info.domain());
+  }
+}
+
+
+void json(
+    JSON::StringWriter* writer,
+    const MasterInfo::Capability& capability)
+{
+  writer->set(MasterInfo::Capability::Type_Name(capability.type()));
+}
+
+
 static void json(JSON::ObjectWriter* writer, const NetworkInfo& info)
 {
   if (info.groups().size() > 0) {
@@ -651,6 +713,16 @@ static void json(JSON::ObjectWriter* writer, const NetworkInfo& info)
 }
 
 
+void json(JSON::ObjectWriter* writer, const Offer& offer)
+{
+  writer->field("id", offer.id().value());
+  writer->field("framework_id", offer.framework_id().value());
+  writer->field("allocation_info", JSON::Protobuf(offer.allocation_info()));
+  writer->field("slave_id", offer.slave_id().value());
+  writer->field("resources", offer.resources());
+}
+
+
 template <typename ResourceIterable>
 void json(
     JSON::ObjectWriter* writer,
@@ -702,6 +774,27 @@ void json(
 }
 
 
+void json(JSON::ObjectWriter* writer, const SlaveInfo& slaveInfo)
+{
+  writer->field("id", slaveInfo.id().value());
+  writer->field("hostname", slaveInfo.hostname());
+  writer->field("port", slaveInfo.port());
+  writer->field("attributes", Attributes(slaveInfo.attributes()));
+
+  if (slaveInfo.has_domain()) {
+    writer->field("domain", slaveInfo.domain());
+  }
+}
+
+
+void json(
+    JSON::StringWriter* writer,
+    const SlaveInfo::Capability& capability)
+{
+  writer->set(SlaveInfo::Capability::Type_Name(capability.type()));
+}
+
+
 void json(JSON::ObjectWriter* writer, const Task& task)
 {
   writer->field("id", task.task_id().value());
@@ -755,39 +848,6 @@ void json(JSON::ObjectWriter* writer, const TaskStatus& status)
 }
 
 
-static void json(
-    JSON::ObjectWriter* writer,
-    const DomainInfo::FaultDomain::RegionInfo& regionInfo)
-{
-  writer->field("name", regionInfo.name());
-}
-
-
-static void json(
-    JSON::ObjectWriter* writer,
-    const DomainInfo::FaultDomain::ZoneInfo& zoneInfo)
-{
-  writer->field("name", zoneInfo.name());
-}
-
-
-static void json(
-    JSON::ObjectWriter* writer,
-    const DomainInfo::FaultDomain& faultDomain)
-{
-    writer->field("region", faultDomain.region());
-    writer->field("zone", faultDomain.zone());
-}
-
-
-void json(JSON::ObjectWriter* writer, const DomainInfo& domainInfo)
-{
-  if (domainInfo.has_fault_domain()) {
-    writer->field("fault_domain", domainInfo.fault_domain());
-  }
-}
-
-
 static void json(JSON::NumberWriter* writer, const Value::Scalar& scalar)
 {
   writer->set(scalar.value());
diff --git a/src/common/http.hpp b/src/common/http.hpp
index 19f0da2..76abafa 100644
--- a/src/common/http.hpp
+++ b/src/common/http.hpp
@@ -154,15 +154,24 @@ void json(JSON::ObjectWriter* writer, const Task& task);
 
 void json(JSON::ObjectWriter* writer, const Attributes& attributes);
 void json(JSON::ObjectWriter* writer, const CommandInfo& command);
+void json(JSON::ObjectWriter* writer, const DomainInfo& domainInfo);
 void json(JSON::ObjectWriter* writer, const ExecutorInfo& executorInfo);
+void json(
+    JSON::StringWriter* writer, const FrameworkInfo::Capability& capability);
 void json(JSON::ArrayWriter* writer, const Labels& labels);
+void json(JSON::ObjectWriter* writer, const MasterInfo& info);
+void json(
+    JSON::StringWriter* writer, const MasterInfo::Capability& capability);
 void json(JSON::ObjectWriter* writer, const Resources& resources);
 void json(
     JSON::ObjectWriter* writer,
     const google::protobuf::RepeatedPtrField<Resource>& resources);
+void json(JSON::ObjectWriter* writer, const SlaveInfo& slaveInfo);
+void json(
+    JSON::StringWriter* writer, const SlaveInfo::Capability& capability);
 void json(JSON::ObjectWriter* writer, const Task& task);
 void json(JSON::ObjectWriter* writer, const TaskStatus& status);
-void json(JSON::ObjectWriter* writer, const DomainInfo& domainInfo);
+void json(JSON::ObjectWriter* writer, const Offer& offer);
 
 namespace authorization {
 
diff --git a/src/master/http.cpp b/src/master/http.cpp
index 9f8539e..85413cb 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -68,7 +68,6 @@
 #include <stout/utils.hpp>
 #include <stout/uuid.hpp>
 
-#include "common/build.hpp"
 #include "common/http.hpp"
 #include "common/protobuf_utils.hpp"
 #include "common/resources_utils.hpp"
@@ -143,66 +142,6 @@ using mesos::authorization::VIEW_ROLE;
 using mesos::authorization::VIEW_TASK;
 
 namespace mesos {
-
-static void json(
-    JSON::StringWriter* writer,
-    const FrameworkInfo::Capability& capability)
-{
-  writer->set(FrameworkInfo::Capability::Type_Name(capability.type()));
-}
-
-
-static void json(
-    JSON::StringWriter* writer,
-    const SlaveInfo::Capability& capability)
-{
-  writer->set(SlaveInfo::Capability::Type_Name(capability.type()));
-}
-
-
-static void json(
-    JSON::StringWriter* writer,
-    const MasterInfo::Capability& capability)
-{
-  writer->set(MasterInfo::Capability::Type_Name(capability.type()));
-}
-
-
-static void json(JSON::ObjectWriter* writer, const Offer& offer)
-{
-  writer->field("id", offer.id().value());
-  writer->field("framework_id", offer.framework_id().value());
-  writer->field("allocation_info", JSON::Protobuf(offer.allocation_info()));
-  writer->field("slave_id", offer.slave_id().value());
-  writer->field("resources", offer.resources());
-}
-
-
-static void json(JSON::ObjectWriter* writer, const MasterInfo& info)
-{
-  writer->field("id", info.id());
-  writer->field("pid", info.pid());
-  writer->field("port", info.port());
-  writer->field("hostname", info.hostname());
-
-  if (info.has_domain()) {
-    writer->field("domain", info.domain());
-  }
-}
-
-
-static void json(JSON::ObjectWriter* writer, const SlaveInfo& slaveInfo)
-{
-  writer->field("id", slaveInfo.id().value());
-  writer->field("hostname", slaveInfo.hostname());
-  writer->field("port", slaveInfo.port());
-  writer->field("attributes", Attributes(slaveInfo.attributes()));
-
-  if (slaveInfo.has_domain()) {
-    writer->field("domain", slaveInfo.domain());
-  }
-}
-
 namespace internal {
 namespace master {
 
@@ -215,379 +154,6 @@ using process::http::Request;
 using process::Owned;
 
 
-// The summary representation of `T` to support the `/state-summary` endpoint.
-// e.g., `Summary<Slave>`.
-template <typename T>
-struct Summary : Representation<T>
-{
-  using Representation<T>::Representation;
-};
-
-
-// The full representation of `T` to support the `/state` endpoint.
-// e.g., `Full<Slave>`.
-template <typename T>
-struct Full : Representation<T>
-{
-  using Representation<T>::Representation;
-};
-
-
-// Forward declaration for `FullFrameworkWriter`.
-static void json(JSON::ObjectWriter* writer, const Summary<Framework>& summary);
-
-
-// Filtered representation of Full<Framework>.
-// Executors and Tasks are filtered based on whether the
-// user is authorized to view them.
-struct FullFrameworkWriter {
-  FullFrameworkWriter(
-      const Owned<ObjectApprovers>& approvers,
-      const Framework* framework)
-    : approvers_(approvers),
-      framework_(framework) {}
-
-  void operator()(JSON::ObjectWriter* writer) const
-  {
-    json(writer, Summary<Framework>(*framework_));
-
-    // Add additional fields to those generated by the
-    // `Summary<Framework>` overload.
-    writer->field("user", framework_->info.user());
-    writer->field("failover_timeout", framework_->info.failover_timeout());
-    writer->field("checkpoint", framework_->info.checkpoint());
-    writer->field("registered_time", framework_->registeredTime.secs());
-    writer->field("unregistered_time", framework_->unregisteredTime.secs());
-
-    if (framework_->info.has_principal()) {
-      writer->field("principal", framework_->info.principal());
-    }
-
-    // TODO(bmahler): Consider deprecating this in favor of the split
-    // used and offered resources added in `Summary<Framework>`.
-    writer->field(
-        "resources",
-        framework_->totalUsedResources + framework_->totalOfferedResources);
-
-    // TODO(benh): Consider making reregisteredTime an Option.
-    if (framework_->registeredTime != framework_->reregisteredTime) {
-      writer->field("reregistered_time", framework_->reregisteredTime.secs());
-    }
-
-    // For multi-role frameworks the `role` field will be unset.
-    // Note that we could set `roles` here for both cases, which
-    // would make tooling simpler (only need to look for `roles`).
-    // However, we opted to just mirror the protobuf akin to how
-    // generic protobuf -> JSON translation works.
-    if (framework_->capabilities.multiRole) {
-      writer->field("roles", framework_->info.roles());
-    } else {
-      writer->field("role", framework_->info.role());
-    }
-
-    // Model all of the tasks associated with a framework.
-    writer->field("tasks", [this](JSON::ArrayWriter* writer) {
-      foreachvalue (const TaskInfo& taskInfo, framework_->pendingTasks) {
-        // Skip unauthorized tasks.
-        if (!approvers_->approved<VIEW_TASK>(taskInfo, framework_->info)) {
-          continue;
-        }
-
-        writer->element([this, &taskInfo](JSON::ObjectWriter* writer) {
-          writer->field("id", taskInfo.task_id().value());
-          writer->field("name", taskInfo.name());
-          writer->field("framework_id", framework_->id().value());
-
-          writer->field(
-              "executor_id",
-              taskInfo.executor().executor_id().value());
-
-          writer->field("slave_id", taskInfo.slave_id().value());
-          writer->field("state", TaskState_Name(TASK_STAGING));
-          writer->field("resources", taskInfo.resources());
-
-          // Tasks are not allowed to mix resources allocated to
-          // different roles, see MESOS-6636.
-          writer->field(
-              "role",
-              taskInfo.resources().begin()->allocation_info().role());
-
-          writer->field("statuses", std::initializer_list<TaskStatus>{});
-
-          if (taskInfo.has_labels()) {
-            writer->field("labels", taskInfo.labels());
-          }
-
-          if (taskInfo.has_discovery()) {
-            writer->field("discovery", JSON::Protobuf(taskInfo.discovery()));
-          }
-
-          if (taskInfo.has_container()) {
-            writer->field("container", JSON::Protobuf(taskInfo.container()));
-          }
-        });
-      }
-
-      foreachvalue (Task* task, framework_->tasks) {
-        // Skip unauthorized tasks.
-        if (!approvers_->approved<VIEW_TASK>(*task, framework_->info)) {
-          continue;
-        }
-
-        writer->element(*task);
-      }
-    });
-
-    writer->field("unreachable_tasks", [this](JSON::ArrayWriter* writer) {
-      foreachvalue (const Owned<Task>& task, framework_->unreachableTasks) {
-        // Skip unauthorized tasks.
-        if (!approvers_->approved<VIEW_TASK>(*task, framework_->info)) {
-          continue;
-        }
-
-        writer->element(*task);
-      }
-    });
-
-    writer->field("completed_tasks", [this](JSON::ArrayWriter* writer) {
-      foreach (const Owned<Task>& task, framework_->completedTasks) {
-        // Skip unauthorized tasks.
-        if (!approvers_->approved<VIEW_TASK>(*task, framework_->info)) {
-          continue;
-        }
-
-        writer->element(*task);
-      }
-    });
-
-    // Model all of the offers associated with a framework.
-    writer->field("offers", [this](JSON::ArrayWriter* writer) {
-      foreach (Offer* offer, framework_->offers) {
-        writer->element(*offer);
-      }
-    });
-
-    // Model all of the executors of a framework.
-    writer->field("executors", [this](JSON::ArrayWriter* writer) {
-      foreachpair (
-          const SlaveID& slaveId,
-          const auto& executorsMap,
-          framework_->executors) {
-        foreachvalue (const ExecutorInfo& executor, executorsMap) {
-          writer->element([this,
-                           &executor,
-                           &slaveId](JSON::ObjectWriter* writer) {
-            // Skip unauthorized executors.
-            if (!approvers_->approved<VIEW_EXECUTOR>(
-                    executor, framework_->info)) {
-              return;
-            }
-
-            json(writer, executor);
-            writer->field("slave_id", slaveId.value());
-          });
-        }
-      }
-    });
-
-    // Model all of the labels associated with a framework.
-    if (framework_->info.has_labels()) {
-      writer->field("labels", framework_->info.labels());
-    }
-  }
-
-  const Owned<ObjectApprovers>& approvers_;
-  const Framework* framework_;
-};
-
-
-struct SlaveWriter
-{
-  SlaveWriter(
-      const Slave& slave,
-      const Owned<ObjectApprovers>& approvers)
-    : slave_(slave), approvers_(approvers) {}
-
-  void operator()(JSON::ObjectWriter* writer) const
-  {
-    json(writer, slave_.info);
-
-    writer->field("pid", string(slave_.pid));
-    writer->field("registered_time", slave_.registeredTime.secs());
-
-    if (slave_.reregisteredTime.isSome()) {
-      writer->field("reregistered_time", slave_.reregisteredTime->secs());
-    }
-
-    const Resources& totalResources = slave_.totalResources;
-    writer->field("resources", totalResources);
-    writer->field("used_resources", Resources::sum(slave_.usedResources));
-    writer->field("offered_resources", slave_.offeredResources);
-    writer->field(
-        "reserved_resources",
-        [&totalResources, this](JSON::ObjectWriter* writer) {
-          foreachpair (const string& role, const Resources& reservation,
-                       totalResources.reservations()) {
-            // TODO(arojas): Consider showing unapproved resources in an
-            // aggregated special field, so that all resource values add up
-            // MESOS-7779.
-            if (approvers_->approved<VIEW_ROLE>(role)) {
-              writer->field(role, reservation);
-            }
-          }
-        });
-    writer->field("unreserved_resources", totalResources.unreserved());
-
-    writer->field("active", slave_.active);
-    writer->field("version", slave_.version);
-    writer->field("capabilities", slave_.capabilities.toRepeatedPtrField());
-  }
-
-  const Slave& slave_;
-  const Owned<ObjectApprovers>& approvers_;
-};
-
-
-struct SlavesWriter
-{
-  SlavesWriter(
-      const Master::Slaves& slaves,
-      const Owned<ObjectApprovers>& approvers,
-      const IDAcceptor<SlaveID>& selectSlaveId)
-    : slaves_(slaves),
-      approvers_(approvers),
-      selectSlaveId_(selectSlaveId) {}
-
-  void operator()(JSON::ObjectWriter* writer) const
-  {
-    writer->field("slaves", [this](JSON::ArrayWriter* writer) {
-      foreachvalue (const Slave* slave, slaves_.registered) {
-        if (!selectSlaveId_.accept(slave->id)) {
-          continue;
-        }
-
-        writer->element([this, &slave](JSON::ObjectWriter* writer) {
-          writeSlave(slave, writer);
-        });
-      }
-    });
-
-    writer->field("recovered_slaves", [this](JSON::ArrayWriter* writer) {
-      foreachvalue (const SlaveInfo& slaveInfo, slaves_.recovered) {
-        if (!selectSlaveId_.accept(slaveInfo.id())) {
-          continue;
-        }
-
-        writer->element([&slaveInfo](JSON::ObjectWriter* writer) {
-          json(writer, slaveInfo);
-        });
-      }
-    });
-  }
-
-  void writeSlave(const Slave* slave, JSON::ObjectWriter* writer) const
-  {
-    SlaveWriter(*slave, approvers_)(writer);
-
-    // Add the complete protobuf->JSON for all used, reserved,
-    // and offered resources. The other endpoints summarize
-    // resource information, which omits the details of
-    // reservations and persistent volumes. Full resource
-    // information is necessary so that operators can use the
-    // `/unreserve` and `/destroy-volumes` endpoints.
-
-    hashmap<string, Resources> reserved = slave->totalResources.reservations();
-
-    writer->field(
-        "reserved_resources_full",
-        [&reserved, this](JSON::ObjectWriter* writer) {
-          foreachpair (const string& role,
-                       const Resources& resources,
-                       reserved) {
-            if (approvers_->approved<VIEW_ROLE>(role)) {
-              writer->field(role, [&resources, this](
-                  JSON::ArrayWriter* writer) {
-                foreach (Resource resource, resources) {
-                  if (approvers_->approved<VIEW_ROLE>(resource)) {
-                    convertResourceFormat(&resource, ENDPOINT);
-                    writer->element(JSON::Protobuf(resource));
-                  }
-                }
-              });
-            }
-          }
-        });
-
-    Resources unreservedResources = slave->totalResources.unreserved();
-
-    writer->field(
-        "unreserved_resources_full",
-        [&unreservedResources, this](JSON::ArrayWriter* writer) {
-          foreach (Resource resource, unreservedResources) {
-            if (approvers_->approved<VIEW_ROLE>(resource)) {
-              convertResourceFormat(&resource, ENDPOINT);
-              writer->element(JSON::Protobuf(resource));
-            }
-          }
-        });
-
-    Resources usedResources = Resources::sum(slave->usedResources);
-
-    writer->field(
-        "used_resources_full",
-        [&usedResources, this](JSON::ArrayWriter* writer) {
-          foreach (Resource resource, usedResources) {
-            if (approvers_->approved<VIEW_ROLE>(resource)) {
-              convertResourceFormat(&resource, ENDPOINT);
-              writer->element(JSON::Protobuf(resource));
-            }
-          }
-        });
-
-    const Resources& offeredResources = slave->offeredResources;
-
-    writer->field(
-        "offered_resources_full",
-        [&offeredResources, this](JSON::ArrayWriter* writer) {
-          foreach (Resource resource, offeredResources) {
-            if (approvers_->approved<VIEW_ROLE>(resource)) {
-              convertResourceFormat(&resource, ENDPOINT);
-              writer->element(JSON::Protobuf(resource));
-            }
-          }
-        });
-  }
-
-  const Master::Slaves& slaves_;
-  const Owned<ObjectApprovers>& approvers_;
-  const IDAcceptor<SlaveID>& selectSlaveId_;
-};
-
-
-static void json(JSON::ObjectWriter* writer, const Summary<Framework>& summary)
-{
-  const Framework& framework = summary;
-
-  writer->field("id", framework.id().value());
-  writer->field("name", framework.info.name());
-
-  // Omit pid for http frameworks.
-  if (framework.pid.isSome()) {
-    writer->field("pid", string(framework.pid.get()));
-  }
-
-  // TODO(bmahler): Use these in the webui.
-  writer->field("used_resources", framework.totalUsedResources);
-  writer->field("offered_resources", framework.totalOfferedResources);
-  writer->field("capabilities", framework.info.capabilities());
-  writer->field("hostname", framework.info.hostname());
-  writer->field("webui_url", framework.info.webui_url());
-  writer->field("active", framework.active());
-  writer->field("connected", framework.connected());
-  writer->field("recovered", framework.recovered());
-}
-
-
 string Master::Http::API_HELP()
 {
   return HELP(
@@ -1689,62 +1255,6 @@ Future<Response> Master::Http::frameworks(
 }
 
 
-process::http::Response Master::ReadOnlyHandler::frameworks(
-    const process::http::Request& request,
-    const process::Owned<ObjectApprovers>& approvers) const
-{
-  IDAcceptor<FrameworkID> selectFrameworkId(
-      request.url.query.get("framework_id"));
-  // This lambda is consumed before the outer lambda
-  // returns, hence capture by reference is fine here.
-  auto frameworks = [this, &approvers, &selectFrameworkId](
-      JSON::ObjectWriter* writer) {
-    // Model all of the frameworks.
-    writer->field(
-        "frameworks",
-        [this, &approvers, &selectFrameworkId](
-            JSON::ArrayWriter* writer) {
-          foreachvalue (
-              Framework* framework, master->frameworks.registered) {
-            // Skip unauthorized frameworks or frameworks
-            // without a matching ID.
-            if (!selectFrameworkId.accept(framework->id()) ||
-                !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-              continue;
-            }
-
-            writer->element(FullFrameworkWriter(approvers, framework));
-          }
-        });
-
-    // Model all of the completed frameworks.
-    writer->field(
-        "completed_frameworks",
-        [this, &approvers, &selectFrameworkId](
-            JSON::ArrayWriter* writer) {
-          foreachvalue (const Owned<Framework>& framework,
-                        master->frameworks.completed) {
-            // Skip unauthorized frameworks or frameworks
-            // without a matching ID.
-            if (!selectFrameworkId.accept(framework->id()) ||
-                !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-              continue;
-            }
-
-            writer->element(
-                FullFrameworkWriter(approvers, framework.get()));
-          }
-        });
-
-    // Unregistered frameworks are no longer possible. We emit an
-    // empty array for the sake of backward compatibility.
-    writer->field("unregistered_frameworks", [](JSON::ArrayWriter*) {});
-  };
-
-  return OK(jsonify(frameworks), request.url.query.get("jsonp"));
-}
-
-
 mesos::master::Response::GetFrameworks::Framework model(
     const Framework& framework)
 {
@@ -2526,20 +2036,6 @@ string Master::Http::SLAVES_HELP()
 }
 
 
-process::http::Response Master::ReadOnlyHandler::slaves(
-    const process::http::Request& request,
-    const process::Owned<ObjectApprovers>& approvers) const
-{
-  Option<string> slaveId = request.url.query.get("slave_id");
-  Option<string> jsonp = request.url.query.get("jsonp");
-  IDAcceptor<SlaveID> selectSlaveId(slaveId);
-
-  return process::http::OK(
-      jsonify(SlavesWriter(master->slaves, approvers, selectSlaveId)),
-      jsonp);
-}
-
-
 Future<Response> Master::Http::slaves(
     const Request& request,
     const Option<Principal>& principal) const
@@ -2891,148 +2387,6 @@ Future<Response> Master::Http::deferBatchedRequest(
 }
 
 
-process::http::Response Master::ReadOnlyHandler::state(
-    const process::http::Request& request,
-    const process::Owned<ObjectApprovers>& approvers) const
-{
-  const Master* master = this->master;
-  auto calculateState = [master, &approvers](JSON::ObjectWriter* writer) {
-    writer->field("version", MESOS_VERSION);
-
-    if (build::GIT_SHA.isSome()) {
-      writer->field("git_sha", build::GIT_SHA.get());
-    }
-
-    if (build::GIT_BRANCH.isSome()) {
-      writer->field("git_branch", build::GIT_BRANCH.get());
-    }
-
-    if (build::GIT_TAG.isSome()) {
-      writer->field("git_tag", build::GIT_TAG.get());
-    }
-
-    writer->field("build_date", build::DATE);
-    writer->field("build_time", build::TIME);
-    writer->field("build_user", build::USER);
-    writer->field("start_time", master->startTime.secs());
-
-    if (master->electedTime.isSome()) {
-      writer->field("elected_time", master->electedTime->secs());
-    }
-
-    writer->field("id", master->info().id());
-    writer->field("pid", string(master->self()));
-    writer->field("hostname", master->info().hostname());
-    writer->field("capabilities", master->info().capabilities());
-    writer->field("activated_slaves", master->_const_slaves_active());
-    writer->field("deactivated_slaves", master->_const_slaves_inactive());
-    writer->field("unreachable_slaves", master->_const_slaves_unreachable());
-
-    if (master->info().has_domain()) {
-      writer->field("domain", master->info().domain());
-    }
-
-    // TODO(haosdent): Deprecated this in favor of `leader_info` below.
-    if (master->leader.isSome()) {
-      writer->field("leader", master->leader->pid());
-    }
-
-    if (master->leader.isSome()) {
-      writer->field("leader_info", [master](JSON::ObjectWriter* writer) {
-        json(writer, master->leader.get());
-      });
-    }
-
-    if (approvers->approved<VIEW_FLAGS>()) {
-      if (master->flags.cluster.isSome()) {
-        writer->field("cluster", master->flags.cluster.get());
-      }
-
-      if (master->flags.log_dir.isSome()) {
-        writer->field("log_dir", master->flags.log_dir.get());
-      }
-
-      if (master->flags.external_log_file.isSome()) {
-        writer->field("external_log_file",
-                      master->flags.external_log_file.get());
-      }
-
-      writer->field("flags", [master](JSON::ObjectWriter* writer) {
-          foreachvalue (const flags::Flag& flag, master->flags) {
-            Option<string> value = flag.stringify(master->flags);
-            if (value.isSome()) {
-              writer->field(flag.effective_name().value, value.get());
-            }
-          }
-        });
-    }
-
-    // Model all of the registered slaves.
-    writer->field(
-        "slaves",
-        [master, &approvers](JSON::ArrayWriter* writer) {
-          foreachvalue (Slave* slave, master->slaves.registered) {
-            writer->element(SlaveWriter(*slave, approvers));
-          }
-        });
-
-    // Model all of the recovered slaves.
-    writer->field(
-        "recovered_slaves",
-        [master](JSON::ArrayWriter* writer) {
-          foreachvalue (
-              const SlaveInfo& slaveInfo, master->slaves.recovered) {
-            writer->element([&slaveInfo](JSON::ObjectWriter* writer) {
-              json(writer, slaveInfo);
-            });
-          }
-        });
-
-    // Model all of the frameworks.
-    writer->field(
-        "frameworks",
-        [master, &approvers](JSON::ArrayWriter* writer) {
-          foreachvalue (
-              Framework* framework, master->frameworks.registered) {
-            // Skip unauthorized frameworks.
-            if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-              continue;
-            }
-
-            writer->element(FullFrameworkWriter(approvers, framework));
-          }
-        });
-
-    // Model all of the completed frameworks.
-    writer->field(
-        "completed_frameworks",
-        [master, &approvers](JSON::ArrayWriter* writer) {
-          foreachvalue (
-              const Owned<Framework>& framework,
-              master->frameworks.completed) {
-            // Skip unauthorized frameworks.
-            if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-              continue;
-            }
-
-            writer->element(
-                FullFrameworkWriter(approvers, framework.get()));
-          }
-        });
-
-    // Orphan tasks are no longer possible. We emit an empty array
-    // for the sake of backward compatibility.
-    writer->field("orphan_tasks", [](JSON::ArrayWriter*) {});
-
-    // Unregistered frameworks are no longer possible. We emit an
-    // empty array for the sake of backward compatibility.
-    writer->field("unregistered_frameworks", [](JSON::ArrayWriter*) {});
-  };
-
-  return OK(jsonify(calculateState), request.url.query.get("jsonp"));
-}
-
-
 void Master::Http::processRequestsBatch() const
 {
   CHECK(!batchedRequests.empty())
@@ -3123,181 +2477,6 @@ Future<Response> Master::Http::readFile(
 }
 
 
-// This abstraction has no side-effects. It factors out computing the
-// mapping from 'slaves' to 'frameworks' to answer the questions 'what
-// frameworks are running on a given slave?' and 'what slaves are
-// running the given framework?'.
-class SlaveFrameworkMapping
-{
-public:
-  SlaveFrameworkMapping(const hashmap<FrameworkID, Framework*>& frameworks)
-  {
-    foreachpair (const FrameworkID& frameworkId,
-                 const Framework* framework,
-                 frameworks) {
-      foreachvalue (const TaskInfo& taskInfo, framework->pendingTasks) {
-        frameworksToSlaves[frameworkId].insert(taskInfo.slave_id());
-        slavesToFrameworks[taskInfo.slave_id()].insert(frameworkId);
-      }
-
-      foreachvalue (const Task* task, framework->tasks) {
-        frameworksToSlaves[frameworkId].insert(task->slave_id());
-        slavesToFrameworks[task->slave_id()].insert(frameworkId);
-      }
-
-      foreachvalue (const Owned<Task>& task, framework->unreachableTasks) {
-        frameworksToSlaves[frameworkId].insert(task->slave_id());
-        slavesToFrameworks[task->slave_id()].insert(frameworkId);
-      }
-
-      foreach (const Owned<Task>& task, framework->completedTasks) {
-        frameworksToSlaves[frameworkId].insert(task->slave_id());
-        slavesToFrameworks[task->slave_id()].insert(frameworkId);
-      }
-    }
-  }
-
-  const hashset<FrameworkID>& frameworks(const SlaveID& slaveId) const
-  {
-    const auto iterator = slavesToFrameworks.find(slaveId);
-    return iterator != slavesToFrameworks.end() ?
-      iterator->second : hashset<FrameworkID>::EMPTY;
-  }
-
-  const hashset<SlaveID>& slaves(const FrameworkID& frameworkId) const
-  {
-    const auto iterator = frameworksToSlaves.find(frameworkId);
-    return iterator != frameworksToSlaves.end() ?
-      iterator->second : hashset<SlaveID>::EMPTY;
-  }
-
-private:
-  hashmap<SlaveID, hashset<FrameworkID>> slavesToFrameworks;
-  hashmap<FrameworkID, hashset<SlaveID>> frameworksToSlaves;
-};
-
-
-// This abstraction has no side-effects. It factors out the accounting
-// for a 'TaskState' summary. We use this to summarize 'TaskState's
-// for both frameworks as well as slaves.
-struct TaskStateSummary
-{
-  // TODO(jmlvanre): Possibly clean this up as per MESOS-2694.
-  const static TaskStateSummary EMPTY;
-
-  TaskStateSummary()
-    : staging(0),
-      starting(0),
-      running(0),
-      killing(0),
-      finished(0),
-      killed(0),
-      failed(0),
-      lost(0),
-      error(0),
-      dropped(0),
-      unreachable(0),
-      gone(0),
-      gone_by_operator(0),
-      unknown(0) {}
-
-  // Account for the state of the given task.
-  void count(const Task& task)
-  {
-    switch (task.state()) {
-      case TASK_STAGING: { ++staging; break; }
-      case TASK_STARTING: { ++starting; break; }
-      case TASK_RUNNING: { ++running; break; }
-      case TASK_KILLING: { ++killing; break; }
-      case TASK_FINISHED: { ++finished; break; }
-      case TASK_KILLED: { ++killed; break; }
-      case TASK_FAILED: { ++failed; break; }
-      case TASK_LOST: { ++lost; break; }
-      case TASK_ERROR: { ++error; break; }
-      case TASK_DROPPED: { ++dropped; break; }
-      case TASK_UNREACHABLE: { ++unreachable; break; }
-      case TASK_GONE: { ++gone; break; }
-      case TASK_GONE_BY_OPERATOR: { ++gone_by_operator; break; }
-      case TASK_UNKNOWN: { ++unknown; break; }
-      // No default case allows for a helpful compiler error if we
-      // introduce a new state.
-    }
-  }
-
-  size_t staging;
-  size_t starting;
-  size_t running;
-  size_t killing;
-  size_t finished;
-  size_t killed;
-  size_t failed;
-  size_t lost;
-  size_t error;
-  size_t dropped;
-  size_t unreachable;
-  size_t gone;
-  size_t gone_by_operator;
-  size_t unknown;
-};
-
-
-const TaskStateSummary TaskStateSummary::EMPTY;
-
-
-// This abstraction has no side-effects. It factors out computing the
-// 'TaskState' summaries for frameworks and slaves. This answers the
-// questions 'How many tasks are in each state for a given framework?'
-// and 'How many tasks are in each state for a given slave?'.
-class TaskStateSummaries
-{
-public:
-  TaskStateSummaries(const hashmap<FrameworkID, Framework*>& frameworks)
-  {
-    foreachpair (const FrameworkID& frameworkId,
-                 const Framework* framework,
-                 frameworks) {
-      foreachvalue (const TaskInfo& taskInfo, framework->pendingTasks) {
-        frameworkTaskSummaries[frameworkId].staging++;
-        slaveTaskSummaries[taskInfo.slave_id()].staging++;
-      }
-
-      foreachvalue (const Task* task, framework->tasks) {
-        frameworkTaskSummaries[frameworkId].count(*task);
-        slaveTaskSummaries[task->slave_id()].count(*task);
-      }
-
-      foreachvalue (const Owned<Task>& task, framework->unreachableTasks) {
-        frameworkTaskSummaries[frameworkId].count(*task);
-        slaveTaskSummaries[task->slave_id()].count(*task);
-      }
-
-      foreach (const Owned<Task>& task, framework->completedTasks) {
-        frameworkTaskSummaries[frameworkId].count(*task);
-        slaveTaskSummaries[task->slave_id()].count(*task);
-      }
-    }
-  }
-
-  const TaskStateSummary& framework(const FrameworkID& frameworkId) const
-  {
-    const auto iterator = frameworkTaskSummaries.find(frameworkId);
-    return iterator != frameworkTaskSummaries.end() ?
-      iterator->second : TaskStateSummary::EMPTY;
-  }
-
-  const TaskStateSummary& slave(const SlaveID& slaveId) const
-  {
-    const auto iterator = slaveTaskSummaries.find(slaveId);
-    return iterator != slaveTaskSummaries.end() ?
-      iterator->second : TaskStateSummary::EMPTY;
-  }
-
-private:
-  hashmap<FrameworkID, TaskStateSummary> frameworkTaskSummaries;
-  hashmap<SlaveID, TaskStateSummary> slaveTaskSummaries;
-};
-
-
 string Master::Http::STATESUMMARY_HELP()
 {
   return HELP(
@@ -3357,153 +2536,6 @@ Future<Response> Master::Http::stateSummary(
 }
 
 
-process::http::Response Master::ReadOnlyHandler::stateSummary(
-    const process::http::Request& request,
-    const process::Owned<ObjectApprovers>& approvers) const
-{
-  const Master* master = this->master;
-  auto stateSummary = [master, &approvers](JSON::ObjectWriter* writer) {
-    writer->field("hostname", master->info().hostname());
-
-    if (master->flags.cluster.isSome()) {
-      writer->field("cluster", master->flags.cluster.get());
-    }
-
-    // We use the tasks in the 'Frameworks' struct to compute summaries
-    // for this endpoint. This is done 1) for consistency between the
-    // 'slaves' and 'frameworks' subsections below 2) because we want to
-    // provide summary information for frameworks that are currently
-    // registered 3) the frameworks keep a circular buffer of completed
-    // tasks that we can use to keep a limited view on the history of
-    // recent completed / failed tasks.
-
-    // Generate mappings from 'slave' to 'framework' and reverse.
-    SlaveFrameworkMapping slaveFrameworkMapping(
-        master->frameworks.registered);
-
-    // Generate 'TaskState' summaries for all framework and slave ids.
-    TaskStateSummaries taskStateSummaries(
-        master->frameworks.registered);
-
-    // Model all of the slaves.
-    writer->field(
-        "slaves",
-        [master,
-         &slaveFrameworkMapping,
-         &taskStateSummaries,
-         &approvers](JSON::ArrayWriter* writer) {
-          foreachvalue (Slave* slave, master->slaves.registered) {
-            writer->element(
-                [&slave,
-                 &slaveFrameworkMapping,
-                 &taskStateSummaries,
-                 &approvers](JSON::ObjectWriter* writer) {
-                  SlaveWriter slaveWriter(*slave, approvers);
-                  slaveWriter(writer);
-
-                  // Add the 'TaskState' summary for this slave.
-                  const TaskStateSummary& summary =
-                      taskStateSummaries.slave(slave->id);
-
-                  // Certain per-agent status totals will always be zero
-                  // (e.g., TASK_ERROR, TASK_UNREACHABLE). We report
-                  // them here anyway, for completeness.
-                  //
-                  // TODO(neilc): Update for TASK_GONE and
-                  // TASK_GONE_BY_OPERATOR.
-                  writer->field("TASK_STAGING", summary.staging);
-                  writer->field("TASK_STARTING", summary.starting);
-                  writer->field("TASK_RUNNING", summary.running);
-                  writer->field("TASK_KILLING", summary.killing);
-                  writer->field("TASK_FINISHED", summary.finished);
-                  writer->field("TASK_KILLED", summary.killed);
-                  writer->field("TASK_FAILED", summary.failed);
-                  writer->field("TASK_LOST", summary.lost);
-                  writer->field("TASK_ERROR", summary.error);
-                  writer->field(
-                      "TASK_UNREACHABLE",
-                      summary.unreachable);
-
-                  // Add the ids of all the frameworks running on this
-                  // slave.
-                  const hashset<FrameworkID>& frameworks =
-                      slaveFrameworkMapping.frameworks(slave->id);
-
-                  writer->field(
-                      "framework_ids",
-                      [&frameworks](JSON::ArrayWriter* writer) {
-                        foreach (
-                            const FrameworkID& frameworkId,
-                            frameworks) {
-                          writer->element(frameworkId.value());
-                        }
-                      });
-                });
-          }
-        });
-
-    // Model all of the frameworks.
-    writer->field(
-        "frameworks",
-        [master,
-         &slaveFrameworkMapping,
-         &taskStateSummaries,
-         &approvers](JSON::ArrayWriter* writer) {
-          foreachpair (const FrameworkID& frameworkId,
-                       Framework* framework,
-                       master->frameworks.registered) {
-            // Skip unauthorized frameworks.
-            if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-              continue;
-            }
-
-            writer->element(
-                [&frameworkId,
-                 &framework,
-                 &slaveFrameworkMapping,
-                 &taskStateSummaries](JSON::ObjectWriter* writer) {
-                  json(writer, Summary<Framework>(*framework));
-
-                  // Add the 'TaskState' summary for this framework.
-                  const TaskStateSummary& summary =
-                      taskStateSummaries.framework(frameworkId);
-
-                  // TODO(neilc): Update for TASK_GONE and
-                  // TASK_GONE_BY_OPERATOR.
-                  writer->field("TASK_STAGING", summary.staging);
-                  writer->field("TASK_STARTING", summary.starting);
-                  writer->field("TASK_RUNNING", summary.running);
-                  writer->field("TASK_KILLING", summary.killing);
-                  writer->field("TASK_FINISHED", summary.finished);
-                  writer->field("TASK_KILLED", summary.killed);
-                  writer->field("TASK_FAILED", summary.failed);
-                  writer->field("TASK_LOST", summary.lost);
-                  writer->field("TASK_ERROR", summary.error);
-                  writer->field(
-                      "TASK_UNREACHABLE",
-                      summary.unreachable);
-
-                  // Add the ids of all the slaves running
-                  // this framework.
-                  const hashset<SlaveID>& slaves =
-                      slaveFrameworkMapping.slaves(frameworkId);
-
-                  writer->field(
-                      "slave_ids",
-                      [&slaves](JSON::ArrayWriter* writer) {
-                        foreach (const SlaveID& slaveId, slaves) {
-                          writer->element(slaveId.value());
-                        }
-                      });
-                });
-          }
-        });
-    };
-
-  return OK(jsonify(stateSummary), request.url.query.get("jsonp"));
-}
-
-
 // Returns a JSON object modeled after a role.
 JSON::Object model(
     const string& name,
@@ -3975,50 +3007,6 @@ Future<Response> Master::Http::getOperations(
 }
 
 
-struct TaskComparator
-{
-  static bool ascending(const Task* lhs, const Task* rhs)
-  {
-    size_t lhsSize = lhs->statuses().size();
-    size_t rhsSize = rhs->statuses().size();
-
-    if ((lhsSize == 0) && (rhsSize == 0)) {
-      return false;
-    }
-
-    if (lhsSize == 0) {
-      return true;
-    }
-
-    if (rhsSize == 0) {
-      return false;
-    }
-
-    return (lhs->statuses(0).timestamp() < rhs->statuses(0).timestamp());
-  }
-
-  static bool descending(const Task* lhs, const Task* rhs)
-  {
-    size_t lhsSize = lhs->statuses().size();
-    size_t rhsSize = rhs->statuses().size();
-
-    if ((lhsSize == 0) && (rhsSize == 0)) {
-      return false;
-    }
-
-    if (rhsSize == 0) {
-      return true;
-    }
-
-    if (lhsSize == 0) {
-      return false;
-    }
-
-    return (lhs->statuses(0).timestamp() > rhs->statuses(0).timestamp());
-  }
-};
-
-
 string Master::Http::TASKS_HELP()
 {
   return HELP(
@@ -4057,114 +3045,6 @@ string Master::Http::TASKS_HELP()
         "See the authorization documentation for details."));
 }
 
-process::http::Response Master::ReadOnlyHandler::tasks(
-  const process::http::Request& request,
-  const process::Owned<ObjectApprovers>& approvers) const
-{
-  // Get list options (limit and offset).
-  Result<int> result = numify<int>(request.url.query.get("limit"));
-  size_t limit = result.isSome() ? result.get() : TASK_LIMIT;
-
-  result = numify<int>(request.url.query.get("offset"));
-  size_t offset = result.isSome() ? result.get() : 0;
-
-  Option<string> order = request.url.query.get("order");
-  string _order = order.isSome() && (order.get() == "asc") ? "asc" : "des";
-
-  Option<string> frameworkId = request.url.query.get("framework_id");
-  Option<string> taskId = request.url.query.get("task_id");
-
-  IDAcceptor<FrameworkID> selectFrameworkId(frameworkId);
-  IDAcceptor<TaskID> selectTaskId(taskId);
-
-  // Construct framework list with both active and completed frameworks.
-  vector<const Framework*> frameworks;
-  foreachvalue (Framework* framework, master->frameworks.registered) {
-    // Skip unauthorized frameworks or frameworks without matching
-    // framework ID.
-    if (!selectFrameworkId.accept(framework->id()) ||
-        !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-      continue;
-    }
-
-    frameworks.push_back(framework);
-  }
-
-  foreachvalue (const Owned<Framework>& framework,
-                master->frameworks.completed) {
-    // Skip unauthorized frameworks or frameworks without matching
-    // framework ID.
-    if (!selectFrameworkId.accept(framework->id()) ||
-        !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-     continue;
-    }
-
-    frameworks.push_back(framework.get());
-  }
-
-  // Construct task list with both running,
-  // completed and unreachable tasks.
-  vector<const Task*> tasks;
-  foreach (const Framework* framework, frameworks) {
-    foreachvalue (Task* task, framework->tasks) {
-      CHECK_NOTNULL(task);
-      // Skip unauthorized tasks or tasks without matching task ID.
-      if (!selectTaskId.accept(task->task_id()) ||
-          !approvers->approved<VIEW_TASK>(*task, framework->info)) {
-        continue;
-      }
-
-      tasks.push_back(task);
-    }
-
-    foreachvalue (
-        const Owned<Task>& task,
-        framework->unreachableTasks) {
-      // Skip unauthorized tasks or tasks without matching task ID.
-      if (!selectTaskId.accept(task->task_id()) ||
-          !approvers->approved<VIEW_TASK>(*task, framework->info)) {
-        continue;
-      }
-
-      tasks.push_back(task.get());
-    }
-
-    foreach (const Owned<Task>& task, framework->completedTasks) {
-      // Skip unauthorized tasks or tasks without matching task ID.
-      if (!selectTaskId.accept(task->task_id()) ||
-          !approvers->approved<VIEW_TASK>(*task, framework->info)) {
-        continue;
-      }
-
-      tasks.push_back(task.get());
-    }
-  }
-
-  // Sort tasks by task status timestamp. Default order is descending.
-  // The earliest timestamp is chosen for comparison when
-  // multiple are present.
-  if (_order == "asc") {
-    sort(tasks.begin(), tasks.end(), TaskComparator::ascending);
-  } else {
-    sort(tasks.begin(), tasks.end(), TaskComparator::descending);
-  }
-
-  auto tasksWriter =
-    [&tasks, limit, offset](JSON::ObjectWriter* writer) {
-      writer->field(
-          "tasks",
-          [&tasks, limit, offset](JSON::ArrayWriter* writer) {
-            // Collect 'limit' number of tasks starting from 'offset'.
-            size_t end = std::min(offset + limit, tasks.size());
-            for (size_t i = offset; i < end; i++) {
-              writer->element(*tasks[i]);
-            }
-          });
-  };
-
-  return OK(jsonify(tasksWriter), request.url.query.get("jsonp"));
-}
-
 
 Future<Response> Master::Http::tasks(
     const Request& request,
diff --git a/src/master/readonly_handler.cpp b/src/master/readonly_handler.cpp
new file mode 100644
index 0000000..8026c6d
--- /dev/null
+++ b/src/master/readonly_handler.cpp
@@ -0,0 +1,1147 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License
+
+#include "master/master.hpp"
+
+#include <vector>
+#include <string>
+
+#include <mesos/mesos.hpp>
+
+#include <mesos/authorizer/authorizer.hpp>
+
+#include <process/owned.hpp>
+#include <process/http.hpp>
+
+#include <stout/foreach.hpp>
+#include <stout/hashmap.hpp>
+#include <stout/hashset.hpp>
+#include <stout/jsonify.hpp>
+#include <stout/option.hpp>
+#include <stout/representation.hpp>
+
+#include "common/build.hpp"
+#include "common/http.hpp"
+
+
+using process::Owned;
+
+using process::http::OK;
+
+using mesos::authorization::VIEW_EXECUTOR;
+using mesos::authorization::VIEW_FLAGS;
+using mesos::authorization::VIEW_FRAMEWORK;
+using mesos::authorization::VIEW_ROLE;
+using mesos::authorization::VIEW_TASK;
+
+using std::vector;
+using std::string;
+
+namespace mesos {
+namespace internal {
+namespace master {
+
+// The summary representation of `T` to support the `/state-summary` endpoint.
+// e.g., `Summary<Slave>`.
+template <typename T>
+struct Summary : Representation<T>
+{
+  using Representation<T>::Representation;
+};
+
+
+// The full representation of `T` to support the `/state` endpoint.
+// e.g., `Full<Slave>`.
+template <typename T>
+struct Full : Representation<T>
+{
+  using Representation<T>::Representation;
+};
+
+
+// Filtered representation of Full<Framework>.
+// Executors and Tasks are filtered based on whether the
+// user is authorized to view them.
+struct FullFrameworkWriter {
+  FullFrameworkWriter(
+      const process::Owned<ObjectApprovers>& approvers,
+      const Framework* framework);
+
+  void operator()(JSON::ObjectWriter* writer) const;
+
+  const process::Owned<ObjectApprovers>& approvers_;
+  const Framework* framework_;
+};
+
+
+struct SlaveWriter
+{
+  SlaveWriter(
+      const Slave& slave,
+      const process::Owned<ObjectApprovers>& approvers);
+
+  void operator()(JSON::ObjectWriter* writer) const;
+
+  const Slave& slave_;
+  const process::Owned<ObjectApprovers>& approvers_;
+};
+
+
+struct SlavesWriter
+{
+  SlavesWriter(
+      const Master::Slaves& slaves,
+      const process::Owned<ObjectApprovers>& approvers,
+      const IDAcceptor<SlaveID>& selectSlaveId);
+
+  void operator()(JSON::ObjectWriter* writer) const;
+
+  void writeSlave(const Slave* slave, JSON::ObjectWriter* writer) const;
+
+  const Master::Slaves& slaves_;
+  const process::Owned<ObjectApprovers>& approvers_;
+  const IDAcceptor<SlaveID>& selectSlaveId_;
+};
+
+
+void json(JSON::ObjectWriter* writer, const Summary<Framework>& summary);
+
+
+FullFrameworkWriter::FullFrameworkWriter(
+    const Owned<ObjectApprovers>& approvers,
+    const Framework* framework)
+  : approvers_(approvers),
+    framework_(framework)
+{}
+
+
+void FullFrameworkWriter::operator()(JSON::ObjectWriter* writer) const
+{
+  json(writer, Summary<Framework>(*framework_));
+
+  // Add additional fields to those generated by the
+  // `Summary<Framework>` overload.
+  writer->field("user", framework_->info.user());
+  writer->field("failover_timeout", framework_->info.failover_timeout());
+  writer->field("checkpoint", framework_->info.checkpoint());
+  writer->field("registered_time", framework_->registeredTime.secs());
+  writer->field("unregistered_time", framework_->unregisteredTime.secs());
+
+  if (framework_->info.has_principal()) {
+    writer->field("principal", framework_->info.principal());
+  }
+
+  // TODO(bmahler): Consider deprecating this in favor of the split
+  // used and offered resources added in `Summary<Framework>`.
+  writer->field(
+      "resources",
+      framework_->totalUsedResources + framework_->totalOfferedResources);
+
+  // TODO(benh): Consider making reregisteredTime an Option.
+  if (framework_->registeredTime != framework_->reregisteredTime) {
+    writer->field("reregistered_time", framework_->reregisteredTime.secs());
+  }
+
+  // For multi-role frameworks the `role` field will be unset.
+  // Note that we could set `roles` here for both cases, which
+  // would make tooling simpler (only need to look for `roles`).
+  // However, we opted to just mirror the protobuf akin to how
+  // generic protobuf -> JSON translation works.
+  if (framework_->capabilities.multiRole) {
+    writer->field("roles", framework_->info.roles());
+  } else {
+    writer->field("role", framework_->info.role());
+  }
+
+  // Model all of the tasks associated with a framework.
+  writer->field("tasks", [this](JSON::ArrayWriter* writer) {
+    foreachvalue (const TaskInfo& taskInfo, framework_->pendingTasks) {
+      // Skip unauthorized tasks.
+      if (!approvers_->approved<VIEW_TASK>(taskInfo, framework_->info)) {
+        continue;
+      }
+
+      writer->element([this, &taskInfo](JSON::ObjectWriter* writer) {
+        writer->field("id", taskInfo.task_id().value());
+        writer->field("name", taskInfo.name());
+        writer->field("framework_id", framework_->id().value());
+
+        writer->field(
+            "executor_id",
+            taskInfo.executor().executor_id().value());
+
+        writer->field("slave_id", taskInfo.slave_id().value());
+        writer->field("state", TaskState_Name(TASK_STAGING));
+        writer->field("resources", taskInfo.resources());
+
+        // Tasks are not allowed to mix resources allocated to
+        // different roles, see MESOS-6636.
+        writer->field(
+            "role",
+            taskInfo.resources().begin()->allocation_info().role());
+
+        writer->field("statuses", std::initializer_list<TaskStatus>{});
+
+        if (taskInfo.has_labels()) {
+          writer->field("labels", taskInfo.labels());
+        }
+
+        if (taskInfo.has_discovery()) {
+          writer->field("discovery", JSON::Protobuf(taskInfo.discovery()));
+        }
+
+        if (taskInfo.has_container()) {
+          writer->field("container", JSON::Protobuf(taskInfo.container()));
+        }
+      });
+    }
+
+    foreachvalue (Task* task, framework_->tasks) {
+      // Skip unauthorized tasks.
+      if (!approvers_->approved<VIEW_TASK>(*task, framework_->info)) {
+        continue;
+      }
+
+      writer->element(*task);
+    }
+  });
+
+  writer->field("unreachable_tasks", [this](JSON::ArrayWriter* writer) {
+    foreachvalue (const Owned<Task>& task, framework_->unreachableTasks) {
+      // Skip unauthorized tasks.
+      if (!approvers_->approved<VIEW_TASK>(*task, framework_->info)) {
+        continue;
+      }
+
+      writer->element(*task);
+    }
+  });
+
+  writer->field("completed_tasks", [this](JSON::ArrayWriter* writer) {
+    foreach (const Owned<Task>& task, framework_->completedTasks) {
+      // Skip unauthorized tasks.
+      if (!approvers_->approved<VIEW_TASK>(*task, framework_->info)) {
+        continue;
+      }
+
+      writer->element(*task);
+    }
+  });
+
+  // Model all of the offers associated with a framework.
+  writer->field("offers", [this](JSON::ArrayWriter* writer) {
+    foreach (Offer* offer, framework_->offers) {
+      writer->element(*offer);
+    }
+  });
+
+  // Model all of the executors of a framework.
+  writer->field("executors", [this](JSON::ArrayWriter* writer) {
+    foreachpair (
+        const SlaveID& slaveId,
+        const auto& executorsMap,
+        framework_->executors) {
+      foreachvalue (const ExecutorInfo& executor, executorsMap) {
+        writer->element([this,
+                         &executor,
+                         &slaveId](JSON::ObjectWriter* writer) {
+          // Skip unauthorized executors.
+          if (!approvers_->approved<VIEW_EXECUTOR>(
+                  executor, framework_->info)) {
+            return;
+          }
+
+          json(writer, executor);
+          writer->field("slave_id", slaveId.value());
+        });
+      }
+    }
+  });
+
+  // Model all of the labels associated with a framework.
+  if (framework_->info.has_labels()) {
+    writer->field("labels", framework_->info.labels());
+  }
+}
+
+
+SlaveWriter::SlaveWriter(
+    const Slave& slave,
+    const Owned<ObjectApprovers>& approvers)
+  : slave_(slave), approvers_(approvers)
+{}
+
+
+void SlaveWriter::operator()(JSON::ObjectWriter* writer) const
+{
+  json(writer, slave_.info);
+
+  writer->field("pid", string(slave_.pid));
+  writer->field("registered_time", slave_.registeredTime.secs());
+
+  if (slave_.reregisteredTime.isSome()) {
+    writer->field("reregistered_time", slave_.reregisteredTime->secs());
+  }
+
+  const Resources& totalResources = slave_.totalResources;
+  writer->field("resources", totalResources);
+  writer->field("used_resources", Resources::sum(slave_.usedResources));
+  writer->field("offered_resources", slave_.offeredResources);
+  writer->field(
+      "reserved_resources",
+      [&totalResources, this](JSON::ObjectWriter* writer) {
+        foreachpair (const string& role, const Resources& reservation,
+                     totalResources.reservations()) {
+          // TODO(arojas): Consider showing unapproved resources in an
+          // aggregated special field, so that all resource values add up
+          // MESOS-7779.
+          if (approvers_->approved<VIEW_ROLE>(role)) {
+            writer->field(role, reservation);
+          }
+        }
+      });
+  writer->field("unreserved_resources", totalResources.unreserved());
+
+  writer->field("active", slave_.active);
+  writer->field("version", slave_.version);
+  writer->field("capabilities", slave_.capabilities.toRepeatedPtrField());
+}
+
+
+SlavesWriter::SlavesWriter(
+    const Master::Slaves& slaves,
+    const Owned<ObjectApprovers>& approvers,
+    const IDAcceptor<SlaveID>& selectSlaveId)
+  : slaves_(slaves), approvers_(approvers), selectSlaveId_(selectSlaveId)
+{}
+
+
+void SlavesWriter::operator()(JSON::ObjectWriter* writer) const
+{
+  writer->field("slaves", [this](JSON::ArrayWriter* writer) {
+    foreachvalue (const Slave* slave, slaves_.registered) {
+      if (!selectSlaveId_.accept(slave->id)) {
+        continue;
+      }
+
+      writer->element([this, &slave](JSON::ObjectWriter* writer) {
+        writeSlave(slave, writer);
+      });
+    }
+  });
+
+  writer->field("recovered_slaves", [this](JSON::ArrayWriter* writer) {
+    foreachvalue (const SlaveInfo& slaveInfo, slaves_.recovered) {
+      if (!selectSlaveId_.accept(slaveInfo.id())) {
+        continue;
+      }
+
+      writer->element([&slaveInfo](JSON::ObjectWriter* writer) {
+        json(writer, slaveInfo);
+      });
+    }
+  });
+}
+
+
+void SlavesWriter::writeSlave(
+  const Slave* slave, JSON::ObjectWriter* writer) const
+{
+  SlaveWriter(*slave, approvers_)(writer);
+
+  // Add the complete protobuf->JSON for all used, reserved,
+  // and offered resources. The other endpoints summarize
+  // resource information, which omits the details of
+  // reservations and persistent volumes. Full resource
+  // information is necessary so that operators can use the
+  // `/unreserve` and `/destroy-volumes` endpoints.
+
+  hashmap<string, Resources> reserved = slave->totalResources.reservations();
+
+  writer->field(
+      "reserved_resources_full",
+      [&reserved, this](JSON::ObjectWriter* writer) {
+        foreachpair (const string& role,
+                     const Resources& resources,
+                     reserved) {
+          if (approvers_->approved<VIEW_ROLE>(role)) {
+            writer->field(role, [&resources, this](
+                JSON::ArrayWriter* writer) {
+              foreach (Resource resource, resources) {
+                if (approvers_->approved<VIEW_ROLE>(resource)) {
+                  convertResourceFormat(&resource, ENDPOINT);
+                  writer->element(JSON::Protobuf(resource));
+                }
+              }
+            });
+          }
+        }
+      });
+
+  Resources unreservedResources = slave->totalResources.unreserved();
+
+  writer->field(
+      "unreserved_resources_full",
+      [&unreservedResources, this](JSON::ArrayWriter* writer) {
+        foreach (Resource resource, unreservedResources) {
+          if (approvers_->approved<VIEW_ROLE>(resource)) {
+            convertResourceFormat(&resource, ENDPOINT);
+            writer->element(JSON::Protobuf(resource));
+          }
+        }
+      });
+
+  Resources usedResources = Resources::sum(slave->usedResources);
+
+  writer->field(
+      "used_resources_full",
+      [&usedResources, this](JSON::ArrayWriter* writer) {
+        foreach (Resource resource, usedResources) {
+          if (approvers_->approved<VIEW_ROLE>(resource)) {
+            convertResourceFormat(&resource, ENDPOINT);
+            writer->element(JSON::Protobuf(resource));
+          }
+        }
+      });
+
+  const Resources& offeredResources = slave->offeredResources;
+
+  writer->field(
+      "offered_resources_full",
+      [&offeredResources, this](JSON::ArrayWriter* writer) {
+        foreach (Resource resource, offeredResources) {
+          if (approvers_->approved<VIEW_ROLE>(resource)) {
+            convertResourceFormat(&resource, ENDPOINT);
+            writer->element(JSON::Protobuf(resource));
+          }
+        }
+      });
+}
+
+
+void json(JSON::ObjectWriter* writer, const Summary<Framework>& summary)
+{
+  const Framework& framework = summary;
+
+  writer->field("id", framework.id().value());
+  writer->field("name", framework.info.name());
+
+  // Omit pid for http frameworks.
+  if (framework.pid.isSome()) {
+    writer->field("pid", string(framework.pid.get()));
+  }
+
+  // TODO(bmahler): Use these in the webui.
+  writer->field("used_resources", framework.totalUsedResources);
+  writer->field("offered_resources", framework.totalOfferedResources);
+  writer->field("capabilities", framework.info.capabilities());
+  writer->field("hostname", framework.info.hostname());
+  writer->field("webui_url", framework.info.webui_url());
+  writer->field("active", framework.active());
+  writer->field("connected", framework.connected());
+  writer->field("recovered", framework.recovered());
+}
+
+
+// This abstraction has no side-effects. It factors out computing the
+// mapping from 'slaves' to 'frameworks' to answer the questions 'what
+// frameworks are running on a given slave?' and 'what slaves are
+// running the given framework?'.
+class SlaveFrameworkMapping
+{
+public:
+  SlaveFrameworkMapping(const hashmap<FrameworkID, Framework*>& frameworks)
+  {
+    foreachpair (const FrameworkID& frameworkId,
+                 const Framework* framework,
+                 frameworks) {
+      foreachvalue (const TaskInfo& taskInfo, framework->pendingTasks) {
+        frameworksToSlaves[frameworkId].insert(taskInfo.slave_id());
+        slavesToFrameworks[taskInfo.slave_id()].insert(frameworkId);
+      }
+
+      foreachvalue (const Task* task, framework->tasks) {
+        frameworksToSlaves[frameworkId].insert(task->slave_id());
+        slavesToFrameworks[task->slave_id()].insert(frameworkId);
+      }
+
+      foreachvalue (const Owned<Task>& task, framework->unreachableTasks) {
+        frameworksToSlaves[frameworkId].insert(task->slave_id());
+        slavesToFrameworks[task->slave_id()].insert(frameworkId);
+      }
+
+      foreach (const Owned<Task>& task, framework->completedTasks) {
+        frameworksToSlaves[frameworkId].insert(task->slave_id());
+        slavesToFrameworks[task->slave_id()].insert(frameworkId);
+      }
+    }
+  }
+
+  const hashset<FrameworkID>& frameworks(const SlaveID& slaveId) const
+  {
+    const auto iterator = slavesToFrameworks.find(slaveId);
+    return iterator != slavesToFrameworks.end() ?
+      iterator->second : hashset<FrameworkID>::EMPTY;
+  }
+
+  const hashset<SlaveID>& slaves(const FrameworkID& frameworkId) const
+  {
+    const auto iterator = frameworksToSlaves.find(frameworkId);
+    return iterator != frameworksToSlaves.end() ?
+      iterator->second : hashset<SlaveID>::EMPTY;
+  }
+
+private:
+  hashmap<SlaveID, hashset<FrameworkID>> slavesToFrameworks;
+  hashmap<FrameworkID, hashset<SlaveID>> frameworksToSlaves;
+};
+
+
+// This abstraction has no side-effects. It factors out the accounting
+// for a 'TaskState' summary. We use this to summarize 'TaskState's
+// for both frameworks as well as slaves.
+struct TaskStateSummary
+{
+  // TODO(jmlvanre): Possibly clean this up as per MESOS-2694.
+  const static TaskStateSummary EMPTY;
+
+  TaskStateSummary()
+    : staging(0),
+      starting(0),
+      running(0),
+      killing(0),
+      finished(0),
+      killed(0),
+      failed(0),
+      lost(0),
+      error(0),
+      dropped(0),
+      unreachable(0),
+      gone(0),
+      gone_by_operator(0),
+      unknown(0) {}
+
+  // Account for the state of the given task.
+  void count(const Task& task)
+  {
+    switch (task.state()) {
+      case TASK_STAGING: { ++staging; break; }
+      case TASK_STARTING: { ++starting; break; }
+      case TASK_RUNNING: { ++running; break; }
+      case TASK_KILLING: { ++killing; break; }
+      case TASK_FINISHED: { ++finished; break; }
+      case TASK_KILLED: { ++killed; break; }
+      case TASK_FAILED: { ++failed; break; }
+      case TASK_LOST: { ++lost; break; }
+      case TASK_ERROR: { ++error; break; }
+      case TASK_DROPPED: { ++dropped; break; }
+      case TASK_UNREACHABLE: { ++unreachable; break; }
+      case TASK_GONE: { ++gone; break; }
+      case TASK_GONE_BY_OPERATOR: { ++gone_by_operator; break; }
+      case TASK_UNKNOWN: { ++unknown; break; }
+      // No default case allows for a helpful compiler error if we
+      // introduce a new state.
+    }
+  }
+
+  size_t staging;
+  size_t starting;
+  size_t running;
+  size_t killing;
+  size_t finished;
+  size_t killed;
+  size_t failed;
+  size_t lost;
+  size_t error;
+  size_t dropped;
+  size_t unreachable;
+  size_t gone;
+  size_t gone_by_operator;
+  size_t unknown;
+};
+
+
+const TaskStateSummary TaskStateSummary::EMPTY;
+
+
+// This abstraction has no side-effects. It factors out computing the
+// 'TaskState' summaries for frameworks and slaves. This answers the
+// questions 'How many tasks are in each state for a given framework?'
+// and 'How many tasks are in each state for a given slave?'.
+class TaskStateSummaries
+{
+public:
+  TaskStateSummaries(const hashmap<FrameworkID, Framework*>& frameworks)
+  {
+    foreachpair (const FrameworkID& frameworkId,
+                 const Framework* framework,
+                 frameworks) {
+      foreachvalue (const TaskInfo& taskInfo, framework->pendingTasks) {
+        frameworkTaskSummaries[frameworkId].staging++;
+        slaveTaskSummaries[taskInfo.slave_id()].staging++;
+      }
+
+      foreachvalue (const Task* task, framework->tasks) {
+        frameworkTaskSummaries[frameworkId].count(*task);
+        slaveTaskSummaries[task->slave_id()].count(*task);
+      }
+
+      foreachvalue (const Owned<Task>& task, framework->unreachableTasks) {
+        frameworkTaskSummaries[frameworkId].count(*task);
+        slaveTaskSummaries[task->slave_id()].count(*task);
+      }
+
+      foreach (const Owned<Task>& task, framework->completedTasks) {
+        frameworkTaskSummaries[frameworkId].count(*task);
+        slaveTaskSummaries[task->slave_id()].count(*task);
+      }
+    }
+  }
+
+  const TaskStateSummary& framework(const FrameworkID& frameworkId) const
+  {
+    const auto iterator = frameworkTaskSummaries.find(frameworkId);
+    return iterator != frameworkTaskSummaries.end() ?
+      iterator->second : TaskStateSummary::EMPTY;
+  }
+
+  const TaskStateSummary& slave(const SlaveID& slaveId) const
+  {
+    const auto iterator = slaveTaskSummaries.find(slaveId);
+    return iterator != slaveTaskSummaries.end() ?
+      iterator->second : TaskStateSummary::EMPTY;
+  }
+
+private:
+  hashmap<FrameworkID, TaskStateSummary> frameworkTaskSummaries;
+  hashmap<SlaveID, TaskStateSummary> slaveTaskSummaries;
+};
+
+
+process::http::Response Master::ReadOnlyHandler::frameworks(
+    const process::http::Request& request,
+    const process::Owned<ObjectApprovers>& approvers) const
+{
+  IDAcceptor<FrameworkID> selectFrameworkId(
+      request.url.query.get("framework_id"));
+  // This lambda is consumed before the outer lambda
+  // returns, hence capture by reference is fine here.
+  auto frameworks = [this, &approvers, &selectFrameworkId](
+      JSON::ObjectWriter* writer) {
+    // Model all of the frameworks.
+    writer->field(
+        "frameworks",
+        [this, &approvers, &selectFrameworkId](
+            JSON::ArrayWriter* writer) {
+          foreachvalue (
+              Framework* framework, master->frameworks.registered) {
+            // Skip unauthorized frameworks or frameworks
+            // without a matching ID.
+            if (!selectFrameworkId.accept(framework->id()) ||
+                !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+              continue;
+            }
+
+            writer->element(FullFrameworkWriter(approvers, framework));
+          }
+        });
+
+    // Model all of the completed frameworks.
+    writer->field(
+        "completed_frameworks",
+        [this, &approvers, &selectFrameworkId](
+            JSON::ArrayWriter* writer) {
+          foreachvalue (const Owned<Framework>& framework,
+                        master->frameworks.completed) {
+            // Skip unauthorized frameworks or frameworks
+            // without a matching ID.
+            if (!selectFrameworkId.accept(framework->id()) ||
+                !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+              continue;
+            }
+
+            writer->element(
+                FullFrameworkWriter(approvers, framework.get()));
+          }
+        });
+
+    // Unregistered frameworks are no longer possible. We emit an
+    // empty array for the sake of backward compatibility.
+    writer->field("unregistered_frameworks", [](JSON::ArrayWriter*) {});
+  };
+
+  return OK(jsonify(frameworks), request.url.query.get("jsonp"));
+}
+
+
+process::http::Response Master::ReadOnlyHandler::slaves(
+    const process::http::Request& request,
+    const process::Owned<ObjectApprovers>& approvers) const
+{
+  Option<string> slaveId = request.url.query.get("slave_id");
+  Option<string> jsonp = request.url.query.get("jsonp");
+  IDAcceptor<SlaveID> selectSlaveId(slaveId);
+
+  return process::http::OK(
+      jsonify(SlavesWriter(master->slaves, approvers, selectSlaveId)),
+      jsonp);
+}
+
+
+process::http::Response Master::ReadOnlyHandler::state(
+    const process::http::Request& request,
+    const process::Owned<ObjectApprovers>& approvers) const
+{
+  const Master* master = this->master;
+  auto calculateState = [master, &approvers](JSON::ObjectWriter* writer) {
+    writer->field("version", MESOS_VERSION);
+
+    if (build::GIT_SHA.isSome()) {
+      writer->field("git_sha", build::GIT_SHA.get());
+    }
+
+    if (build::GIT_BRANCH.isSome()) {
+      writer->field("git_branch", build::GIT_BRANCH.get());
+    }
+
+    if (build::GIT_TAG.isSome()) {
+      writer->field("git_tag", build::GIT_TAG.get());
+    }
+
+    writer->field("build_date", build::DATE);
+    writer->field("build_time", build::TIME);
+    writer->field("build_user", build::USER);
+    writer->field("start_time", master->startTime.secs());
+
+    if (master->electedTime.isSome()) {
+      writer->field("elected_time", master->electedTime->secs());
+    }
+
+    writer->field("id", master->info().id());
+    writer->field("pid", string(master->self()));
+    writer->field("hostname", master->info().hostname());
+    writer->field("capabilities", master->info().capabilities());
+    writer->field("activated_slaves", master->_const_slaves_active());
+    writer->field("deactivated_slaves", master->_const_slaves_inactive());
+    writer->field("unreachable_slaves", master->_const_slaves_unreachable());
+
+    if (master->info().has_domain()) {
+      writer->field("domain", master->info().domain());
+    }
+
+    // TODO(haosdent): Deprecated this in favor of `leader_info` below.
+    if (master->leader.isSome()) {
+      writer->field("leader", master->leader->pid());
+    }
+
+    if (master->leader.isSome()) {
+      writer->field("leader_info", [master](JSON::ObjectWriter* writer) {
+        json(writer, master->leader.get());
+      });
+    }
+
+    if (approvers->approved<VIEW_FLAGS>()) {
+      if (master->flags.cluster.isSome()) {
+        writer->field("cluster", master->flags.cluster.get());
+      }
+
+      if (master->flags.log_dir.isSome()) {
+        writer->field("log_dir", master->flags.log_dir.get());
+      }
+
+      if (master->flags.external_log_file.isSome()) {
+        writer->field("external_log_file",
+                      master->flags.external_log_file.get());
+      }
+
+      writer->field("flags", [master](JSON::ObjectWriter* writer) {
+          foreachvalue (const flags::Flag& flag, master->flags) {
+            Option<string> value = flag.stringify(master->flags);
+            if (value.isSome()) {
+              writer->field(flag.effective_name().value, value.get());
+            }
+          }
+        });
+    }
+
+    // Model all of the registered slaves.
+    writer->field(
+        "slaves",
+        [master, &approvers](JSON::ArrayWriter* writer) {
+          foreachvalue (Slave* slave, master->slaves.registered) {
+            writer->element(SlaveWriter(*slave, approvers));
+          }
+        });
+
+    // Model all of the recovered slaves.
+    writer->field(
+        "recovered_slaves",
+        [master](JSON::ArrayWriter* writer) {
+          foreachvalue (
+              const SlaveInfo& slaveInfo, master->slaves.recovered) {
+            writer->element([&slaveInfo](JSON::ObjectWriter* writer) {
+              json(writer, slaveInfo);
+            });
+          }
+        });
+
+    // Model all of the frameworks.
+    writer->field(
+        "frameworks",
+        [master, &approvers](JSON::ArrayWriter* writer) {
+          foreachvalue (
+              Framework* framework, master->frameworks.registered) {
+            // Skip unauthorized frameworks.
+            if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+              continue;
+            }
+
+            writer->element(FullFrameworkWriter(approvers, framework));
+          }
+        });
+
+    // Model all of the completed frameworks.
+    writer->field(
+        "completed_frameworks",
+        [master, &approvers](JSON::ArrayWriter* writer) {
+          foreachvalue (
+              const Owned<Framework>& framework,
+              master->frameworks.completed) {
+            // Skip unauthorized frameworks.
+            if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+              continue;
+            }
+
+            writer->element(
+                FullFrameworkWriter(approvers, framework.get()));
+          }
+        });
+
+    // Orphan tasks are no longer possible. We emit an empty array
+    // for the sake of backward compatibility.
+    writer->field("orphan_tasks", [](JSON::ArrayWriter*) {});
+
+    // Unregistered frameworks are no longer possible. We emit an
+    // empty array for the sake of backward compatibility.
+    writer->field("unregistered_frameworks", [](JSON::ArrayWriter*) {});
+  };
+
+  return OK(jsonify(calculateState), request.url.query.get("jsonp"));
+}
+
+
+process::http::Response Master::ReadOnlyHandler::stateSummary(
+    const process::http::Request& request,
+    const process::Owned<ObjectApprovers>& approvers) const
+{
+  const Master* master = this->master;
+  auto stateSummary = [master, &approvers](JSON::ObjectWriter* writer) {
+    writer->field("hostname", master->info().hostname());
+
+    if (master->flags.cluster.isSome()) {
+      writer->field("cluster", master->flags.cluster.get());
+    }
+
+    // We use the tasks in the 'Frameworks' struct to compute summaries
+    // for this endpoint. This is done 1) for consistency between the
+    // 'slaves' and 'frameworks' subsections below 2) because we want to
+    // provide summary information for frameworks that are currently
+    // registered 3) the frameworks keep a circular buffer of completed
+    // tasks that we can use to keep a limited view on the history of
+    // recent completed / failed tasks.
+
+    // Generate mappings from 'slave' to 'framework' and reverse.
+    SlaveFrameworkMapping slaveFrameworkMapping(
+        master->frameworks.registered);
+
+    // Generate 'TaskState' summaries for all framework and slave ids.
+    TaskStateSummaries taskStateSummaries(
+        master->frameworks.registered);
+
+    // Model all of the slaves.
+    writer->field(
+        "slaves",
+        [master,
+         &slaveFrameworkMapping,
+         &taskStateSummaries,
+         &approvers](JSON::ArrayWriter* writer) {
+          foreachvalue (Slave* slave, master->slaves.registered) {
+            writer->element(
+                [&slave,
+                 &slaveFrameworkMapping,
+                 &taskStateSummaries,
+                 &approvers](JSON::ObjectWriter* writer) {
+                  SlaveWriter slaveWriter(*slave, approvers);
+                  slaveWriter(writer);
+
+                  // Add the 'TaskState' summary for this slave.
+                  const TaskStateSummary& summary =
+                      taskStateSummaries.slave(slave->id);
+
+                  // Certain per-agent status totals will always be zero
+                  // (e.g., TASK_ERROR, TASK_UNREACHABLE). We report
+                  // them here anyway, for completeness.
+                  //
+                  // TODO(neilc): Update for TASK_GONE and
+                  // TASK_GONE_BY_OPERATOR.
+                  writer->field("TASK_STAGING", summary.staging);
+                  writer->field("TASK_STARTING", summary.starting);
+                  writer->field("TASK_RUNNING", summary.running);
+                  writer->field("TASK_KILLING", summary.killing);
+                  writer->field("TASK_FINISHED", summary.finished);
+                  writer->field("TASK_KILLED", summary.killed);
+                  writer->field("TASK_FAILED", summary.failed);
+                  writer->field("TASK_LOST", summary.lost);
+                  writer->field("TASK_ERROR", summary.error);
+                  writer->field(
+                      "TASK_UNREACHABLE",
+                      summary.unreachable);
+
+                  // Add the ids of all the frameworks running on this
+                  // slave.
+                  const hashset<FrameworkID>& frameworks =
+                      slaveFrameworkMapping.frameworks(slave->id);
+
+                  writer->field(
+                      "framework_ids",
+                      [&frameworks](JSON::ArrayWriter* writer) {
+                        foreach (
+                            const FrameworkID& frameworkId,
+                            frameworks) {
+                          writer->element(frameworkId.value());
+                        }
+                      });
+                });
+          }
+        });
+
+    // Model all of the frameworks.
+    writer->field(
+        "frameworks",
+        [master,
+         &slaveFrameworkMapping,
+         &taskStateSummaries,
+         &approvers](JSON::ArrayWriter* writer) {
+          foreachpair (const FrameworkID& frameworkId,
+                       Framework* framework,
+                       master->frameworks.registered) {
+            // Skip unauthorized frameworks.
+            if (!approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+              continue;
+            }
+
+            writer->element(
+                [&frameworkId,
+                 &framework,
+                 &slaveFrameworkMapping,
+                 &taskStateSummaries](JSON::ObjectWriter* writer) {
+                  json(writer, Summary<Framework>(*framework));
+
+                  // Add the 'TaskState' summary for this framework.
+                  const TaskStateSummary& summary =
+                      taskStateSummaries.framework(frameworkId);
+
+                  // TODO(neilc): Update for TASK_GONE and
+                  // TASK_GONE_BY_OPERATOR.
+                  writer->field("TASK_STAGING", summary.staging);
+                  writer->field("TASK_STARTING", summary.starting);
+                  writer->field("TASK_RUNNING", summary.running);
+                  writer->field("TASK_KILLING", summary.killing);
+                  writer->field("TASK_FINISHED", summary.finished);
+                  writer->field("TASK_KILLED", summary.killed);
+                  writer->field("TASK_FAILED", summary.failed);
+                  writer->field("TASK_LOST", summary.lost);
+                  writer->field("TASK_ERROR", summary.error);
+                  writer->field(
+                      "TASK_UNREACHABLE",
+                      summary.unreachable);
+
+                  // Add the ids of all the slaves running
+                  // this framework.
+                  const hashset<SlaveID>& slaves =
+                      slaveFrameworkMapping.slaves(frameworkId);
+
+                  writer->field(
+                      "slave_ids",
+                      [&slaves](JSON::ArrayWriter* writer) {
+                        foreach (const SlaveID& slaveId, slaves) {
+                          writer->element(slaveId.value());
+                        }
+                      });
+                });
+          }
+        });
+    };
+
+  return OK(jsonify(stateSummary), request.url.query.get("jsonp"));
+}
+
+
+struct TaskComparator
+{
+  static bool ascending(const Task* lhs, const Task* rhs)
+  {
+    size_t lhsSize = lhs->statuses().size();
+    size_t rhsSize = rhs->statuses().size();
+
+    if ((lhsSize == 0) && (rhsSize == 0)) {
+      return false;
+    }
+
+    if (lhsSize == 0) {
+      return true;
+    }
+
+    if (rhsSize == 0) {
+      return false;
+    }
+
+    return (lhs->statuses(0).timestamp() < rhs->statuses(0).timestamp());
+  }
+
+  static bool descending(const Task* lhs, const Task* rhs)
+  {
+    size_t lhsSize = lhs->statuses().size();
+    size_t rhsSize = rhs->statuses().size();
+
+    if ((lhsSize == 0) && (rhsSize == 0)) {
+      return false;
+    }
+
+    if (rhsSize == 0) {
+      return true;
+    }
+
+    if (lhsSize == 0) {
+      return false;
+    }
+
+    return (lhs->statuses(0).timestamp() > rhs->statuses(0).timestamp());
+  }
+};
+
+
+process::http::Response Master::ReadOnlyHandler::tasks(
+  const process::http::Request& request,
+  const process::Owned<ObjectApprovers>& approvers) const
+{
+  // Get list options (limit and offset).
+  Result<int> result = numify<int>(request.url.query.get("limit"));
+  size_t limit = result.isSome() ? result.get() : TASK_LIMIT;
+
+  result = numify<int>(request.url.query.get("offset"));
+  size_t offset = result.isSome() ? result.get() : 0;
+
+  Option<string> order = request.url.query.get("order");
+  string _order = order.isSome() && (order.get() == "asc") ? "asc" : "des";
+
+  Option<string> frameworkId = request.url.query.get("framework_id");
+  Option<string> taskId = request.url.query.get("task_id");
+
+  IDAcceptor<FrameworkID> selectFrameworkId(frameworkId);
+  IDAcceptor<TaskID> selectTaskId(taskId);
+
+  // Construct framework list with both active and completed frameworks.
+  vector<const Framework*> frameworks;
+  foreachvalue (Framework* framework, master->frameworks.registered) {
+    // Skip unauthorized frameworks or frameworks without matching
+    // framework ID.
+    if (!selectFrameworkId.accept(framework->id()) ||
+        !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+      continue;
+    }
+
+    frameworks.push_back(framework);
+  }
+
+  foreachvalue (const Owned<Framework>& framework,
+                master->frameworks.completed) {
+    // Skip unauthorized frameworks or frameworks without matching
+    // framework ID.
+    if (!selectFrameworkId.accept(framework->id()) ||
+        !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+     continue;
+    }
+
+    frameworks.push_back(framework.get());
+  }
+
+  // Construct task list with both running,
+  // completed and unreachable tasks.
+  vector<const Task*> tasks;
+  foreach (const Framework* framework, frameworks) {
+    foreachvalue (Task* task, framework->tasks) {
+      CHECK_NOTNULL(task);
+      // Skip unauthorized tasks or tasks without matching task ID.
+      if (!selectTaskId.accept(task->task_id()) ||
+          !approvers->approved<VIEW_TASK>(*task, framework->info)) {
+        continue;
+      }
+
+      tasks.push_back(task);
+    }
+
+    foreachvalue (
+        const Owned<Task>& task,
+        framework->unreachableTasks) {
+      // Skip unauthorized tasks or tasks without matching task ID.
+      if (!selectTaskId.accept(task->task_id()) ||
+          !approvers->approved<VIEW_TASK>(*task, framework->info)) {
+        continue;
+      }
+
+      tasks.push_back(task.get());
+    }
+
+    foreach (const Owned<Task>& task, framework->completedTasks) {
+      // Skip unauthorized tasks or tasks without matching task ID.
+      if (!selectTaskId.accept(task->task_id()) ||
+          !approvers->approved<VIEW_TASK>(*task, framework->info)) {
+        continue;
+      }
+
+      tasks.push_back(task.get());
+    }
+  }
+
+  // Sort tasks by task status timestamp. Default order is descending.
+  // The earliest timestamp is chosen for comparison when
+  // multiple are present.
+  if (_order == "asc") {
+    sort(tasks.begin(), tasks.end(), TaskComparator::ascending);
+  } else {
+    sort(tasks.begin(), tasks.end(), TaskComparator::descending);
+  }
+
+  auto tasksWriter =
+    [&tasks, limit, offset](JSON::ObjectWriter* writer) {
+      writer->field(
+          "tasks",
+          [&tasks, limit, offset](JSON::ArrayWriter* writer) {
+            // Collect 'limit' number of tasks starting from 'offset'.
+            size_t end = std::min(offset + limit, tasks.size());
+            for (size_t i = offset; i < end; i++) {
+              writer->element(*tasks[i]);
+            }
+          });
+  };
+
+  return OK(jsonify(tasksWriter), request.url.query.get("jsonp"));
+}
+
+} // namespace master {
+} // namespace internal {
+} // namespace mesos {
diff --git a/src/slave/http.cpp b/src/slave/http.cpp
index 1b6d266..d0f6e1c 100644
--- a/src/slave/http.cpp
+++ b/src/slave/http.cpp
@@ -177,13 +177,6 @@ static void json(JSON::ObjectWriter* writer, const TaskInfo& task)
   }
 }
 
-static void json(
-    JSON::StringWriter* writer,
-    const SlaveInfo::Capability& capability)
-{
-  writer->set(SlaveInfo::Capability::Type_Name(capability.type()));
-}
-
 namespace internal {
 namespace slave {
 


[mesos] 03/06: Added '/slaves' to the set of batched master endpoints.

Posted by al...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

alexr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit 33c38c9baa20b42562b519971df508283d988abc
Author: Benno Evers <be...@mesosphere.com>
AuthorDate: Tue Aug 28 21:26:11 2018 +0200

    Added '/slaves' to the set of batched master endpoints.
    
    Review: https://reviews.apache.org/r/68441/
---
 src/master/http.cpp   | 27 +++++++++++++++++----------
 src/master/master.hpp |  5 +++++
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/src/master/http.cpp b/src/master/http.cpp
index 897c80d..42d4dad 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -2517,6 +2517,20 @@ string Master::Http::SLAVES_HELP()
 }
 
 
+process::http::Response Master::ReadOnlyHandler::slaves(
+    const process::http::Request& request,
+    const process::Owned<ObjectApprovers>& approvers) const
+{
+  Option<string> slaveId = request.url.query.get("slave_id");
+  Option<string> jsonp = request.url.query.get("jsonp");
+  IDAcceptor<SlaveID> selectSlaveId(slaveId);
+
+  return process::http::OK(
+      jsonify(SlavesWriter(master->slaves, approvers, selectSlaveId)),
+      jsonp);
+}
+
+
 Future<Response> Master::Http::slaves(
     const Request& request,
     const Option<Principal>& principal) const
@@ -2526,19 +2540,12 @@ Future<Response> Master::Http::slaves(
     return redirect(request);
   }
 
-  Option<string> slaveId = request.url.query.get("slave_id");
-  Option<string> jsonp = request.url.query.get("jsonp");
-
   return ObjectApprovers::create(master->authorizer, principal, {VIEW_ROLE})
     .then(defer(
         master->self(),
-        [this, slaveId, jsonp](const Owned<ObjectApprovers>& approvers)
-            -> Response {
-          IDAcceptor<SlaveID> selectSlaveId(slaveId);
-
-          return OK(
-              jsonify(SlavesWriter(master->slaves, approvers, selectSlaveId)),
-              jsonp);
+        [this, request](const Owned<ObjectApprovers>& approvers) {
+          return deferBatchedRequest(
+              &Master::ReadOnlyHandler::slaves, request, approvers);
         }));
 }
 
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 381db90..ac6e6d3 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1411,6 +1411,11 @@ private:
         const process::http::Request& request,
         const process::Owned<ObjectApprovers>& approvers) const;
 
+    // /slaves
+    process::http::Response slaves(
+        const process::http::Request& request,
+        const process::Owned<ObjectApprovers>& approvers) const;
+
   private:
     const Master* master;
   };


[mesos] 04/06: Added '/frameworks' to the set of batched master endpoints.

Posted by al...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

alexr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit 102dcca4e0116d2ffbdcd78d998e032841ffbabe
Author: Benno Evers <be...@mesosphere.com>
AuthorDate: Tue Aug 28 21:26:18 2018 +0200

    Added '/frameworks' to the set of batched master endpoints.
    
    Review: https://reviews.apache.org/r/68442/
---
 src/master/http.cpp   | 105 +++++++++++++++++++++++++++-----------------------
 src/master/master.hpp |   5 +++
 2 files changed, 62 insertions(+), 48 deletions(-)

diff --git a/src/master/http.cpp b/src/master/http.cpp
index 42d4dad..9f8539e 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -1682,57 +1682,66 @@ Future<Response> Master::Http::frameworks(
       {VIEW_FRAMEWORK, VIEW_TASK, VIEW_EXECUTOR})
     .then(defer(
         master->self(),
-        [this, request](const Owned<ObjectApprovers>& approvers) -> Response {
-          IDAcceptor<FrameworkID> selectFrameworkId(
-              request.url.query.get("framework_id"));
-          // This lambda is consumed before the outer lambda
-          // returns, hence capture by reference is fine here.
-          auto frameworks = [this, &approvers, &selectFrameworkId](
-              JSON::ObjectWriter* writer) {
-            // Model all of the frameworks.
-            writer->field(
-                "frameworks",
-                [this, &approvers, &selectFrameworkId](
-                    JSON::ArrayWriter* writer) {
-                  foreachvalue (
-                      Framework* framework, master->frameworks.registered) {
-                    // Skip unauthorized frameworks or frameworks
-                    // without a matching ID.
-                    if (!selectFrameworkId.accept(framework->id()) ||
-                        !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-                      continue;
-                    }
-
-                    writer->element(FullFrameworkWriter(approvers, framework));
-                  }
-                });
+        [this, request](const Owned<ObjectApprovers>& approvers) {
+          return deferBatchedRequest(
+            &Master::ReadOnlyHandler::frameworks, request, approvers);
+        }));
+}
 
-            // Model all of the completed frameworks.
-            writer->field(
-                "completed_frameworks",
-                [this, &approvers, &selectFrameworkId](
-                    JSON::ArrayWriter* writer) {
-                  foreachvalue (const Owned<Framework>& framework,
-                                master->frameworks.completed) {
-                    // Skip unauthorized frameworks or frameworks
-                    // without a matching ID.
-                    if (!selectFrameworkId.accept(framework->id()) ||
-                        !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
-                      continue;
-                    }
-
-                    writer->element(
-                        FullFrameworkWriter(approvers, framework.get()));
-                  }
-                });
 
-            // Unregistered frameworks are no longer possible. We emit an
-            // empty array for the sake of backward compatibility.
-            writer->field("unregistered_frameworks", [](JSON::ArrayWriter*) {});
-          };
+process::http::Response Master::ReadOnlyHandler::frameworks(
+    const process::http::Request& request,
+    const process::Owned<ObjectApprovers>& approvers) const
+{
+  IDAcceptor<FrameworkID> selectFrameworkId(
+      request.url.query.get("framework_id"));
+  // This lambda is consumed before the outer lambda
+  // returns, hence capture by reference is fine here.
+  auto frameworks = [this, &approvers, &selectFrameworkId](
+      JSON::ObjectWriter* writer) {
+    // Model all of the frameworks.
+    writer->field(
+        "frameworks",
+        [this, &approvers, &selectFrameworkId](
+            JSON::ArrayWriter* writer) {
+          foreachvalue (
+              Framework* framework, master->frameworks.registered) {
+            // Skip unauthorized frameworks or frameworks
+            // without a matching ID.
+            if (!selectFrameworkId.accept(framework->id()) ||
+                !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+              continue;
+            }
 
-          return OK(jsonify(frameworks), request.url.query.get("jsonp"));
-        }));
+            writer->element(FullFrameworkWriter(approvers, framework));
+          }
+        });
+
+    // Model all of the completed frameworks.
+    writer->field(
+        "completed_frameworks",
+        [this, &approvers, &selectFrameworkId](
+            JSON::ArrayWriter* writer) {
+          foreachvalue (const Owned<Framework>& framework,
+                        master->frameworks.completed) {
+            // Skip unauthorized frameworks or frameworks
+            // without a matching ID.
+            if (!selectFrameworkId.accept(framework->id()) ||
+                !approvers->approved<VIEW_FRAMEWORK>(framework->info)) {
+              continue;
+            }
+
+            writer->element(
+                FullFrameworkWriter(approvers, framework.get()));
+          }
+        });
+
+    // Unregistered frameworks are no longer possible. We emit an
+    // empty array for the sake of backward compatibility.
+    writer->field("unregistered_frameworks", [](JSON::ArrayWriter*) {});
+  };
+
+  return OK(jsonify(frameworks), request.url.query.get("jsonp"));
 }
 
 
diff --git a/src/master/master.hpp b/src/master/master.hpp
index ac6e6d3..9b98771 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1416,6 +1416,11 @@ private:
         const process::http::Request& request,
         const process::Owned<ObjectApprovers>& approvers) const;
 
+    // /frameworks
+    process::http::Response frameworks(
+        const process::http::Request& request,
+        const process::Owned<ObjectApprovers>& approvers) const;
+
   private:
     const Master* master;
   };