You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by vi...@apache.org on 2016/04/22 23:11:52 UTC

[4/4] mesos git commit: Redirected some HTTP requests to the leading master.

Redirected some HTTP requests to the leading master.

HTTP requests to certain endpoints are redirected to the leading master
if the current master is not the leader. These endpoints do not contain
meaningful information at non-leading masters.

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


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

Branch: refs/heads/master
Commit: c9153336165b50cb140d4115ae85d2593a7b066f
Parents: 97bc9ca
Author: haosdent huang <ha...@gmail.com>
Authored: Fri Apr 22 14:08:03 2016 -0700
Committer: Vinod Kone <vi...@gmail.com>
Committed: Fri Apr 22 14:11:39 2016 -0700

----------------------------------------------------------------------
 src/master/http.cpp | 123 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 110 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/c9153336/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index 58f6a00..38fe498 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -342,14 +342,11 @@ Future<Response> Master::Http::scheduler(
 
   // TODO(vinod): Add support for rate limiting.
 
+  // When current master is not the leader, redirect to the leading master.
+  // Note that this could happen if the scheduler realizes this is the
+  // leading master before master itself realizes it (e.g., ZK watch delay).
   if (!master->elected()) {
-    // Note that this could happen if the scheduler realizes this is the
-    // leading master before master itself realizes it (e.g., ZK watch delay).
-    if (master->leader.isNone()) {
-      return ServiceUnavailable("No leader elected");
-    } else {
-      return redirect(request);
-    }
+    return redirect(request);
   }
 
   CHECK_SOME(master->recovered);
@@ -594,6 +591,11 @@ Future<Response> Master::Http::createVolumes(
     const Request& request,
     const Option<string>& principal) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   if (request.method != "POST") {
     return MethodNotAllowed(
         {"POST"}, "Expecting 'POST', received '" + request.method + "'");
@@ -696,6 +698,11 @@ Future<Response> Master::Http::destroyVolumes(
     const Request& request,
     const Option<string>& principal) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   if (request.method != "POST") {
     return MethodNotAllowed(
         {"POST"}, "Expecting 'POST', received '" + request.method + "'");
@@ -784,6 +791,11 @@ Future<Response> Master::Http::frameworks(
     const Request& request,
     const Option<string>& /*principal*/) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   auto frameworks = [this](JSON::ObjectWriter* writer) {
     // Model all of the frameworks.
     writer->field("frameworks", [this](JSON::ArrayWriter* writer) {
@@ -986,10 +998,15 @@ string Master::Http::REDIRECT_HELP()
 
 Future<Response> Master::Http::redirect(const Request& request) const
 {
-  // If there's no leader, redirect to this master's base url.
-  MasterInfo info = master->leader.isSome()
-    ? master->leader.get()
-    : master->info_;
+  // If there's no leader, return `ServiceUnavailable`.
+  if (master->leader.isNone()) {
+    LOG(WARNING) << "Current master is not elected as leader, and leader "
+                 << "information is unavailable. Failed to redirect the "
+                 << "request url: " << request.url;
+    return ServiceUnavailable("No leader elected");
+  }
+
+  MasterInfo info = master->leader.get();
 
   // NOTE: Currently, 'info.ip()' stores ip in network order, which
   // should be fixed. See MESOS-1201 for details.
@@ -1001,14 +1018,24 @@ Future<Response> Master::Http::redirect(const Request& request) const
     return InternalServerError(hostname.error());
   }
 
+  LOG(INFO) << "Redirecting request for " << request.url
+            << " to the leading master " << hostname.get();
+
   // NOTE: We can use a protocol-relative URL here in order to allow
   // the browser (or other HTTP client) to prefix with 'http:' or
   // 'https:' depending on the original request. See
   // https://tools.ietf.org/html/rfc7231#section-7.1.2 as well as
   // http://stackoverflow.com/questions/12436669/using-protocol-relative-uris-within-location-headers
   // which discusses this.
-  return TemporaryRedirect(
-    "//" + hostname.get() + ":" + stringify(info.port()) + request.url.path);
+  string basePath = "//" + hostname.get() + ":" + stringify(info.port());
+  if (request.url.path == "/redirect" ||
+      request.url.path == "/" + master->self().id + "/redirect") {
+    // When request url is '/redirect' or '/master/redirect', redirect to the
+    // base url of leading master to avoid infinite redirect loop.
+    return TemporaryRedirect(basePath);
+  } else {
+    return TemporaryRedirect(basePath + request.url.path);
+  }
 }
 
 
@@ -1035,6 +1062,11 @@ Future<Response> Master::Http::reserve(
     const Request& request,
     const Option<string>& principal) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   if (request.method != "POST") {
     return MethodNotAllowed(
         {"POST"}, "Expecting 'POST', received '" + request.method + "'");
@@ -1131,6 +1163,11 @@ Future<Response> Master::Http::slaves(
     const Request& request,
     const Option<string>& /*principal*/) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   auto slaves = [this](JSON::ObjectWriter* writer) {
     writer->field("slaves", [this](JSON::ArrayWriter* writer) {
       foreachvalue (const Slave* slave, master->slaves.registered) {
@@ -1205,6 +1242,11 @@ Future<Response> Master::Http::quota(
     const Request& request,
     const Option<string>& principal) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   // Dispatch based on HTTP method to separate `QuotaHandler`.
   if (request.method == "GET") {
     return quotaHandler.status(request);
@@ -1243,6 +1285,11 @@ Future<Response> Master::Http::weights(
     const Request& request,
     const Option<string>& principal) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   // TODO(Yongqiao Wang): `/roles` endpoint also shows the weights information,
   // consider erasing the duplicated information later.
   if (request.method == "GET") {
@@ -1346,6 +1393,11 @@ Future<Response> Master::Http::state(
     const Request& request,
     const Option<string>& /*principal*/) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   auto state = [this](JSON::ObjectWriter* writer) {
     writer->field("version", MESOS_VERSION);
 
@@ -1622,6 +1674,11 @@ Future<Response> Master::Http::stateSummary(
     const Request& request,
     const Option<string>& /*principal*/) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   auto stateSummary = [this](JSON::ObjectWriter* writer) {
     writer->field("hostname", master->info().hostname());
 
@@ -1783,6 +1840,11 @@ Future<Response> Master::Http::roles(
     const Request& request,
     const Option<string>& /*principal*/) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   JSON::Object object;
 
   // Compute the role names to return results for. When an explicit
@@ -1854,6 +1916,11 @@ Future<Response> Master::Http::teardown(
     const Request& request,
     const Option<string>& principal) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   if (request.method != "POST") {
     return MethodNotAllowed(
         {"POST"}, "Expecting 'POST', received '" + request.method + "'");
@@ -1993,6 +2060,11 @@ Future<Response> Master::Http::tasks(
     const Request& request,
     const Option<string>& /*principal*/) const
 {
+  // 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;
@@ -2068,6 +2140,11 @@ Future<Response> Master::Http::maintenanceSchedule(
     const Request& request,
     const Option<string>& /*principal*/) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   if (request.method != "GET" && request.method != "POST") {
     return MethodNotAllowed(
         {"GET", "POST"},
@@ -2206,6 +2283,11 @@ Future<Response> Master::Http::machineDown(
     const Request& request,
     const Option<string>& /*principal*/) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   if (request.method != "POST") {
     return MethodNotAllowed(
         {"POST"}, "Expecting 'POST', received '" + request.method + "'");
@@ -2312,6 +2394,11 @@ Future<Response> Master::Http::machineUp(
     const Request& request,
     const Option<string>& /*principal*/) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   if (request.method != "POST") {
     return MethodNotAllowed(
         {"POST"}, "Expecting 'POST', received '" + request.method + "'");
@@ -2419,6 +2506,11 @@ Future<Response> Master::Http::maintenanceStatus(
     const Request& request,
     const Option<string>& /*principal*/) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   if (request.method != "GET") {
     return MethodNotAllowed(
         {"GET"}, "Expecting 'GET', received '" + request.method + "'");
@@ -2501,6 +2593,11 @@ Future<Response> Master::Http::unreserve(
     const Request& request,
     const Option<string>& principal) const
 {
+  // When current master is not the leader, redirect to the leading master.
+  if (!master->elected()) {
+    return redirect(request);
+  }
+
   if (request.method != "POST") {
     return MethodNotAllowed(
         {"POST"}, "Expecting 'POST', received '" + request.method + "'");