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/09/06 14:34:31 UTC

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

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 0c5f300aa9cbe6043498d586c1150ba7483b08f1
Author: Benno Evers <be...@mesosphere.com>
AuthorDate: Thu Sep 6 14:08:29 2018 +0200

    Added '/roles' to the set of batched master endpoints.
    
    For improved consistency, the '/roles' endpoint on the
    master is now marked as read-only and uses the batching
    mechanism shared by the other read-only endpoints.
    
    Review: https://reviews.apache.org/r/68568/
---
 src/master/http.cpp             | 126 +++-------------------------------------
 src/master/master.cpp           |  43 ++++++++++++++
 src/master/master.hpp           |  13 ++++-
 src/master/readonly_handler.cpp |  85 +++++++++++++++++++++++++++
 4 files changed, 145 insertions(+), 122 deletions(-)

diff --git a/src/master/http.cpp b/src/master/http.cpp
index 8a37349..deb65af 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -2565,49 +2565,6 @@ Future<Response> Master::Http::stateSummary(
 }
 
 
-// Returns a JSON object modeled after a role.
-JSON::Object model(
-    const string& name,
-    Option<double> weight,
-    Option<Quota> quota,
-    Option<Role*> _role)
-{
-  JSON::Object object;
-  object.values["name"] = name;
-
-  if (weight.isSome()) {
-    object.values["weight"] = weight.get();
-  } else {
-    object.values["weight"] = 1.0; // Default weight.
-  }
-
-  if (quota.isSome()) {
-    object.values["quota"] = model(quota->info);
-  }
-
-  if (_role.isNone()) {
-    object.values["resources"] = model(Resources());
-    object.values["frameworks"] = JSON::Array();
-  } else {
-    Role* role = _role.get();
-
-    object.values["resources"] = model(role->allocatedResources());
-
-    {
-      JSON::Array array;
-
-      foreachkey (const FrameworkID& frameworkId, role->frameworks) {
-        array.values.push_back(frameworkId.value());
-      }
-
-      object.values["frameworks"] = std::move(array);
-    }
-  }
-
-  return object;
-}
-
-
 string Master::Http::ROLES_HELP()
 {
   return HELP(
@@ -2631,49 +2588,6 @@ string Master::Http::ROLES_HELP()
 }
 
 
-vector<string> Master::Http::_filterRoles(
-    const Owned<ObjectApprovers>& approvers) const
-{
-  JSON::Object object;
-
-  // Compute the role names to return results for. When an explicit
-  // role whitelist has been configured, we use that list of names.
-  // When using implicit roles, the right behavior is a bit more
-  // subtle. There are no constraints on possible role names, so we
-  // instead list all the "interesting" roles: all roles with one or
-  // more registered frameworks, and all roles with a non-default
-  // weight or quota.
-  //
-  // NOTE: we use a `std::set` to store the role names to ensure a
-  // deterministic output order.
-  set<string> roleList;
-  if (master->roleWhitelist.isSome()) {
-    const hashset<string>& whitelist = master->roleWhitelist.get();
-    roleList.insert(whitelist.begin(), whitelist.end());
-  } else {
-    hashset<string> roles = master->roles.keys();
-    roleList.insert(roles.begin(), roles.end());
-
-    hashset<string> weights = master->weights.keys();
-    roleList.insert(weights.begin(), weights.end());
-
-    hashset<string> quotas = master->quotas.keys();
-    roleList.insert(quotas.begin(), quotas.end());
-  }
-
-  vector<string> filteredRoleList;
-  filteredRoleList.reserve(roleList.size());
-
-  foreach (const string& role, roleList) {
-    if (approvers->approved<VIEW_ROLE>(role)) {
-      filteredRoleList.push_back(role);
-    }
-  }
-
-  return filteredRoleList;
-}
-
-
 Future<Response> Master::Http::roles(
     const Request& request,
     const Option<Principal>& principal) const
@@ -2694,38 +2608,12 @@ Future<Response> Master::Http::roles(
 
   return ObjectApprovers::create(master->authorizer, principal, {VIEW_ROLE})
     .then(defer(master->self(),
-        [this, request](const Owned<ObjectApprovers>& approvers)
-          -> Response {
-      JSON::Object object;
-      const vector<string> filteredRoles = _filterRoles(approvers);
-
-      {
-        JSON::Array array;
-
-        foreach (const string& name, filteredRoles) {
-          Option<double> weight = None();
-          if (master->weights.contains(name)) {
-            weight = master->weights[name];
-          }
-
-          Option<Quota> quota = None();
-          if (master->quotas.contains(name)) {
-            quota = master->quotas.at(name);
-          }
-
-          Option<Role*> role = None();
-          if (master->roles.contains(name)) {
-            role = master->roles.at(name);
-          }
-
-          array.values.push_back(model(name, weight, quota, role));
-        }
-
-        object.values["roles"] = std::move(array);
-      }
-
-      return OK(object, request.url.query.get("jsonp"));
-    }));
+        [this, request](const Owned<ObjectApprovers>& approvers) {
+            return deferBatchedRequest(
+                &Master::ReadOnlyHandler::roles,
+                request,
+                approvers);
+          }));
 }
 
 
@@ -2791,7 +2679,7 @@ Future<Response> Master::Http::getRoles(
     .then(defer(master->self(),
         [this, contentType](const Owned<ObjectApprovers>& approvers)
           -> Response {
-      const vector<string> filteredRoles = _filterRoles(approvers);
+      const vector<string> filteredRoles = master->filterRoles(approvers);
 
       mesos::master::Response response;
       response.set_type(mesos::master::Response::GET_ROLES);
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 3277b57..982bfcc 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -3403,6 +3403,49 @@ void Master::suppress(
 }
 
 
+vector<string> Master::filterRoles(
+    const Owned<ObjectApprovers>& approvers) const
+{
+  JSON::Object object;
+
+  // Compute the role names to return results for. When an explicit
+  // role whitelist has been configured, we use that list of names.
+  // When using implicit roles, the right behavior is a bit more
+  // subtle. There are no constraints on possible role names, so we
+  // instead list all the "interesting" roles: all roles with one or
+  // more registered frameworks, and all roles with a non-default
+  // weight or quota.
+  //
+  // NOTE: we use a `std::set` to store the role names to ensure a
+  // deterministic output order.
+  set<string> roleList;
+  if (roleWhitelist.isSome()) {
+    const hashset<string>& whitelist = roleWhitelist.get();
+    roleList.insert(whitelist.begin(), whitelist.end());
+  } else {
+    hashset<string> roles = this->roles.keys();
+    roleList.insert(roles.begin(), roles.end());
+
+    hashset<string> weights = this->weights.keys();
+    roleList.insert(weights.begin(), weights.end());
+
+    hashset<string> quotas = this->quotas.keys();
+    roleList.insert(quotas.begin(), quotas.end());
+  }
+
+  vector<string> filteredRoleList;
+  filteredRoleList.reserve(roleList.size());
+
+  foreach (const string& role, roleList) {
+    if (approvers->approved<VIEW_ROLE>(role)) {
+      filteredRoleList.push_back(role);
+    }
+  }
+
+  return filteredRoleList;
+}
+
+
 bool Master::isWhitelistedRole(const string& name) const
 {
   if (roleWhitelist.isNone()) {
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 5d01de4..ec2ae01 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1181,6 +1181,9 @@ private:
   process::Future<bool> authorizeLogAccess(
       const Option<process::http::authentication::Principal>& principal);
 
+  std::vector<std::string> filterRoles(
+      const process::Owned<ObjectApprovers>& approvers) const;
+
   /**
    * Returns whether the given role is on the whitelist.
    *
@@ -1401,6 +1404,11 @@ private:
         const process::http::Request& request,
         const process::Owned<ObjectApprovers>& approvers) const;
 
+    // /roles
+    process::http::Response roles(
+        const process::http::Request& request,
+        const process::Owned<ObjectApprovers>& approvers) const;
+
     // /slaves
     process::http::Response slaves(
         const process::http::Request& request,
@@ -1488,6 +1496,8 @@ private:
             principal) const;
 
     // /master/roles
+    //
+    // NOTE: Requests to this endpoint are batched.
     process::Future<process::http::Response> roles(
         const process::http::Request& request,
         const Option<process::http::authentication::Principal>&
@@ -1695,9 +1705,6 @@ private:
         Resources required,
         const Offer::Operation& operation) const;
 
-    std::vector<std::string> _filterRoles(
-        const process::Owned<ObjectApprovers>& approvers) const;
-
     // Master API handlers.
 
     process::Future<process::http::Response> getAgents(
diff --git a/src/master/readonly_handler.cpp b/src/master/readonly_handler.cpp
index 47d7de5..8895374 100644
--- a/src/master/readonly_handler.cpp
+++ b/src/master/readonly_handler.cpp
@@ -53,6 +53,9 @@ namespace mesos {
 namespace internal {
 namespace master {
 
+// Pull in model overrides from common.
+using mesos::internal::model;
+
 // The summary representation of `T` to support the `/state-summary` endpoint.
 // e.g., `Summary<Slave>`.
 template <typename T>
@@ -74,6 +77,9 @@ struct Full : Representation<T>
 // Filtered representation of Full<Framework>.
 // Executors and Tasks are filtered based on whether the
 // user is authorized to view them.
+//
+// TODO(bevers): Consider moving writers and other json-related
+// code into a separate file.
 struct FullFrameworkWriter {
   FullFrameworkWriter(
       const process::Owned<ObjectApprovers>& approvers,
@@ -688,6 +694,85 @@ process::http::Response Master::ReadOnlyHandler::frameworks(
 }
 
 
+// Returns a JSON object modeled after a role.
+JSON::Object model(
+    const string& name,
+    Option<double> weight,
+    Option<Quota> quota,
+    Option<Role*> _role)
+{
+  JSON::Object object;
+  object.values["name"] = name;
+
+  if (weight.isSome()) {
+    object.values["weight"] = weight.get();
+  } else {
+    object.values["weight"] = 1.0; // Default weight.
+  }
+
+  if (quota.isSome()) {
+    object.values["quota"] = model(quota->info);
+  }
+
+  if (_role.isNone()) {
+    object.values["resources"] = model(Resources());
+    object.values["frameworks"] = JSON::Array();
+  } else {
+    Role* role = _role.get();
+
+    object.values["resources"] = model(role->allocatedResources());
+
+    {
+      JSON::Array array;
+
+      foreachkey (const FrameworkID& frameworkId, role->frameworks) {
+        array.values.push_back(frameworkId.value());
+      }
+
+      object.values["frameworks"] = std::move(array);
+    }
+  }
+
+  return object;
+}
+
+
+process::http::Response Master::ReadOnlyHandler::roles(
+    const process::http::Request& request,
+    const process::Owned<ObjectApprovers>& approvers) const
+{
+  JSON::Object object;
+  const vector<string> filteredRoles = master->filterRoles(approvers);
+
+  {
+    JSON::Array array;
+
+    foreach (const string& name, filteredRoles) {
+      Option<double> weight = None();
+      if (master->weights.contains(name)) {
+        weight = master->weights.at(name);
+      }
+
+      Option<Quota> quota = None();
+      if (master->quotas.contains(name)) {
+        quota = master->quotas.at(name);
+      }
+
+      Option<Role*> role = None();
+      if (master->roles.contains(name)) {
+        role = master->roles.at(name);
+      }
+
+      array.values.push_back(model(name, weight, quota, role));
+    }
+
+    object.values["roles"] = std::move(array);
+  }
+
+  return OK(object, request.url.query.get("jsonp"));
+}
+
+
 process::http::Response Master::ReadOnlyHandler::slaves(
     const process::http::Request& request,
     const process::Owned<ObjectApprovers>& approvers) const