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 2016/08/28 15:04:09 UTC

[09/10] mesos git commit: Entered appropriate task's namespaces during health checking.

Entered appropriate task's namespaces during health checking.

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


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

Branch: refs/heads/master
Commit: bb084fb84cb59ed8eb1a554b17141d09ff0ed262
Parents: d2f8bfa
Author: haosdent huang <ha...@gmail.com>
Authored: Fri Aug 26 16:34:41 2016 +0200
Committer: Alexander Rukletsov <al...@apache.org>
Committed: Sun Aug 28 16:42:58 2016 +0200

----------------------------------------------------------------------
 src/docker/executor.cpp             | 15 ++++++-
 src/health-check/health_checker.cpp | 73 ++++++++++++++++++++++++++++----
 src/health-check/health_checker.hpp | 25 ++++++++++-
 src/launcher/executor.cpp           | 16 ++++++-
 4 files changed, 117 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/bb084fb8/src/docker/executor.cpp
----------------------------------------------------------------------
diff --git a/src/docker/executor.cpp b/src/docker/executor.cpp
index 5508819..f5981b0 100644
--- a/src/docker/executor.cpp
+++ b/src/docker/executor.cpp
@@ -181,6 +181,8 @@ public:
     inspect = docker->inspect(containerName, DOCKER_INSPECT_DELAY)
       .then(defer(self(), [=](const Docker::Container& container) {
         if (!killed) {
+          containerPid = container.pid;
+
           TaskStatus status;
           status.mutable_task_id()->CopyFrom(taskId.get());
           status.set_state(TASK_RUNNING);
@@ -510,10 +512,20 @@ private:
           strings::join(" ", commandArguments));
     }
 
+    vector<string> namespaces;
+    if (healthCheck.type() == HealthCheck::HTTP ||
+        healthCheck.type() == HealthCheck::TCP) {
+      // Make sure HTTP and TCP health checks are run
+      // from the container's network namespace.
+      namespaces.push_back("net");
+    }
+
     Try<Owned<health::HealthChecker>> _checker = health::HealthChecker::create(
         healthCheck,
         self(),
-        task.task_id());
+        task.task_id(),
+        containerPid,
+        namespaces);
 
     if (_checker.isError()) {
       // TODO(gilbert): Consider ABORT and return a TASK_FAILED here.
@@ -555,6 +567,7 @@ private:
   Option<TaskID> taskId;
   Owned<health::HealthChecker> checker;
   Option<NetworkInfo> containerNetworkInfo;
+  Option<pid_t> containerPid;
 };
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/bb084fb8/src/health-check/health_checker.cpp
----------------------------------------------------------------------
diff --git a/src/health-check/health_checker.cpp b/src/health-check/health_checker.cpp
index e5e7b94..f373df1 100644
--- a/src/health-check/health_checker.cpp
+++ b/src/health-check/health_checker.cpp
@@ -46,6 +46,10 @@
 
 #include "common/status_utils.hpp"
 
+#ifdef __linux__
+#include "linux/ns.hpp"
+#endif
+
 using process::delay;
 using process::Clock;
 using process::Failure;
@@ -73,10 +77,40 @@ static const string DEFAULT_HTTP_SCHEME = "http";
 static const string DEFAULT_DOMAIN = "127.0.0.1";
 
 
+#ifdef __linux__
+pid_t cloneWithSetns(
+    const lambda::function<int()>& func,
+    Option<pid_t> taskPid,
+    const vector<string>& namespaces)
+{
+  return process::defaultClone([=]() -> int {
+    if (taskPid.isSome()) {
+      foreach (const string& ns, namespaces) {
+        Try<Nothing> setns = ns::setns(taskPid.get(), ns);
+        if (setns.isError()) {
+          // This effectively aborts the health check.
+          LOG(FATAL) << "Failed to enter the " << ns << " namespace of "
+                     << "task (pid: '" << taskPid.get() << "'): "
+                     << setns.error();
+        }
+
+        VLOG(1) << "Entered the " << ns << " namespace of "
+                << "task (pid: '" << taskPid.get() << "') successfully";
+      }
+    }
+
+    return func();
+  });
+}
+#endif
+
+
 Try<Owned<HealthChecker>> HealthChecker::create(
     const HealthCheck& check,
     const UPID& executor,
-    const TaskID& taskID)
+    const TaskID& taskID,
+    Option<pid_t> taskPid,
+    const vector<string>& namespaces)
 {
   // Validate the 'HealthCheck' protobuf.
   Option<Error> error = validation::healthCheck(check);
@@ -87,7 +121,9 @@ Try<Owned<HealthChecker>> HealthChecker::create(
   Owned<HealthCheckerProcess> process(new HealthCheckerProcess(
       check,
       executor,
-      taskID));
+      taskID,
+      taskPid,
+      namespaces));
 
   return Owned<HealthChecker>(new HealthChecker(process));
 }
@@ -117,13 +153,24 @@ Future<Nothing> HealthChecker::healthCheck()
 HealthCheckerProcess::HealthCheckerProcess(
     const HealthCheck& _check,
     const UPID& _executor,
-    const TaskID& _taskID)
+    const TaskID& _taskID,
+    Option<pid_t> _taskPid,
+    const vector<string>& _namespaces)
   : ProcessBase(process::ID::generate("health-checker")),
     check(_check),
     initializing(true),
     executor(_executor),
     taskID(_taskID),
-    consecutiveFailures(0) {}
+    taskPid(_taskPid),
+    namespaces(_namespaces),
+    consecutiveFailures(0)
+{
+#ifdef __linux__
+  if (!namespaces.empty()) {
+    clone = lambda::bind(&cloneWithSetns, lambda::_1, taskPid, namespaces);
+  }
+#endif
+}
 
 
 Future<Nothing> HealthCheckerProcess::healthCheck()
@@ -264,7 +311,8 @@ Future<Nothing> HealthCheckerProcess::_commandHealthCheck()
         Subprocess::FD(STDERR_FILENO),
         Subprocess::FD(STDERR_FILENO),
         NO_SETSID,
-        environment);
+        environment,
+        clone);
   } else {
     // Use the exec variant.
     vector<string> argv;
@@ -283,7 +331,8 @@ Future<Nothing> HealthCheckerProcess::_commandHealthCheck()
         Subprocess::FD(STDERR_FILENO),
         NO_SETSID,
         nullptr,
-        environment);
+        environment,
+        clone);
   }
 
   if (external.isError()) {
@@ -353,7 +402,11 @@ Future<Nothing> HealthCheckerProcess::_httpHealthCheck()
       argv,
       Subprocess::PATH("/dev/null"),
       Subprocess::PIPE(),
-      Subprocess::PIPE());
+      Subprocess::PIPE(),
+      NO_SETSID,
+      nullptr,
+      None(),
+      clone);
 
   if (s.isError()) {
     return Failure("Failed to create the curl subprocess: " + s.error());
@@ -461,7 +514,11 @@ Future<Nothing> HealthCheckerProcess::_tcpHealthCheck()
       argv,
       Subprocess::PATH("/dev/null"),
       Subprocess::PIPE(),
-      Subprocess::PIPE());
+      Subprocess::PIPE(),
+      NO_SETSID,
+      nullptr,
+      None(),
+      clone);
 
   if (s.isError()) {
     return Failure("Failed to create the bash subprocess: " + s.error());

http://git-wip-us.apache.org/repos/asf/mesos/blob/bb084fb8/src/health-check/health_checker.hpp
----------------------------------------------------------------------
diff --git a/src/health-check/health_checker.hpp b/src/health-check/health_checker.hpp
index 52acdef..392b4d5 100644
--- a/src/health-check/health_checker.hpp
+++ b/src/health-check/health_checker.hpp
@@ -19,6 +19,7 @@
 
 #include <string>
 #include <tuple>
+#include <vector>
 
 #include <mesos/mesos.hpp>
 
@@ -43,10 +44,25 @@ class HealthCheckerProcess;
 class HealthChecker
 {
 public:
+  /**
+   * Attempts to create a `HealthChecker` object.
+   *
+   * @param check The protobuf message definition of health check.
+   * @param executor The executor UPID to which health check results will be
+   *     reported.
+   * @param taskID The TaskID of the target task.
+   * @param taskPid The target task's pid used to enter the specified
+   *     namespaces.
+   * @param namespaces The namespaces to enter prior performing a single health
+   *     check.
+   * @return A `HealthChecker` object or an error if `create` fails.
+   */
   static Try<process::Owned<HealthChecker>> create(
       const HealthCheck& check,
       const process::UPID& executor,
-      const TaskID& taskID);
+      const TaskID& taskID,
+      Option<pid_t> taskPid,
+      const std::vector<std::string>& namespaces);
 
   ~HealthChecker();
 
@@ -65,7 +81,9 @@ public:
   HealthCheckerProcess(
       const HealthCheck& _check,
       const process::UPID& _executor,
-      const TaskID& _taskID);
+      const TaskID& _taskID,
+      Option<pid_t> _taskPid,
+      const std::vector<std::string>& _namespaces);
 
   virtual ~HealthCheckerProcess() {}
 
@@ -104,6 +122,9 @@ private:
   bool initializing;
   process::UPID executor;
   TaskID taskID;
+  Option<pid_t> taskPid;
+  std::vector<std::string> namespaces;
+  Option<lambda::function<pid_t(const lambda::function<int()>&)>> clone;
   uint32_t consecutiveFailures;
   process::Time startTime;
 };

http://git-wip-us.apache.org/repos/asf/mesos/blob/bb084fb8/src/launcher/executor.cpp
----------------------------------------------------------------------
diff --git a/src/launcher/executor.cpp b/src/launcher/executor.cpp
index 71ede1e..5370634 100644
--- a/src/launcher/executor.cpp
+++ b/src/launcher/executor.cpp
@@ -418,11 +418,25 @@ protected:
     cout << "Forked command at " << pid << endl;
 
     if (task->has_health_check()) {
+      vector<string> namespaces;
+      if (rootfs.isSome() &&
+          task->health_check().type() == HealthCheck::COMMAND) {
+        // Make sure command health checks are run from the task's mount
+        // namespace. Otherwise if rootfs is specified the command binary
+        // may not be available in the executor.
+        //
+        // NOTE: The command executor shares the network namespace
+        // with its task, hence no need to enter it explicitly.
+        namespaces.push_back("mnt");
+      }
+
       Try<Owned<health::HealthChecker>> _checker =
         health::HealthChecker::create(
             task->health_check(),
             self(),
-            task->task_id());
+            task->task_id(),
+            pid,
+            namespaces);
 
       if (_checker.isError()) {
         // TODO(gilbert): Consider ABORT and return a TASK_FAILED here.