You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2016/09/28 23:21:17 UTC

mesos git commit: Made 'filesystem/linux' isolator nesting aware.

Repository: mesos
Updated Branches:
  refs/heads/master cd4596180 -> 81461dcf2


Made 'filesystem/linux' isolator nesting aware.

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


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

Branch: refs/heads/master
Commit: 81461dcf22270b2a10362a4e3b500d817446f22a
Parents: cd45961
Author: Jie Yu <yu...@gmail.com>
Authored: Wed Sep 28 15:56:39 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Wed Sep 28 16:20:47 2016 -0700

----------------------------------------------------------------------
 .../mesos/isolators/filesystem/linux.cpp        | 119 +++++++++++++++----
 .../mesos/isolators/filesystem/linux.hpp        |   4 +-
 src/slave/containerizer/mesos/paths.cpp         |  40 +++++++
 src/slave/containerizer/mesos/paths.hpp         |   8 ++
 4 files changed, 144 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/81461dcf/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp b/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
index ea41825..e55f3d1 100644
--- a/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
+++ b/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
@@ -42,6 +42,7 @@
 #include "slave/paths.hpp"
 
 #include "slave/containerizer/mesos/mount.hpp"
+#include "slave/containerizer/mesos/paths.hpp"
 
 #include "slave/containerizer/mesos/isolators/filesystem/linux.hpp"
 
@@ -209,14 +210,25 @@ LinuxFilesystemIsolatorProcess::LinuxFilesystemIsolatorProcess(
 LinuxFilesystemIsolatorProcess::~LinuxFilesystemIsolatorProcess() {}
 
 
+bool LinuxFilesystemIsolatorProcess::supportsNesting()
+{
+    return true;
+}
+
+
 Future<Nothing> LinuxFilesystemIsolatorProcess::recover(
     const list<ContainerState>& states,
     const hashset<ContainerID>& orphans)
 {
   foreach (const ContainerState& state, states) {
+    Option<ExecutorInfo> executorInfo;
+    if (state.has_executor_info()) {
+      executorInfo = state.executor_info();
+    }
+
     Owned<Info> info(new Info(
         state.directory(),
-        state.executor_info()));
+        executorInfo));
 
     infos.put(state.container_id(), info);
   }
@@ -227,37 +239,67 @@ Future<Nothing> LinuxFilesystemIsolatorProcess::recover(
     return Failure("Failed to get mount table: " + table.error());
   }
 
+  list<Future<Nothing>> cleanups;
+
   foreach (const fs::MountInfoTable::Entry& entry, table->entries) {
     // Check for mounts inside an executor's run path. These are
     // persistent volumes mounts.
     Try<paths::ExecutorRunPath> runPath =
-      paths::parseExecutorRunPath(flags.work_dir, entry.target);
+      slave::paths::parseExecutorRunPath(flags.work_dir, entry.target);
 
     if (runPath.isError()) {
       continue;
     }
 
-    if (infos.contains(runPath->containerId)) {
+    const string rootSandboxPath = paths::getExecutorRunPath(
+        flags.work_dir,
+        runPath->slaveId,
+        runPath->frameworkId,
+        runPath->executorId,
+        runPath->containerId);
+
+    Try<ContainerID> containerId =
+      containerizer::paths::parseSandboxPath(
+          runPath->containerId,
+          rootSandboxPath,
+          entry.target);
+
+    // Since we pass the same 'entry.target' to 'parseSandboxPath' and
+    // 'parseSandboxPath', we should not see an error here.
+    if (containerId.isError()) {
+      return Failure("Parsing sandbox path failed: " + containerId.error());
+    }
+
+    if (infos.contains(containerId.get())) {
       continue;
     }
 
-    // TODO(josephw): We only track persistent volumes for known
-    // orphans as these orphans were presumably created by an earlier
-    // `MesosContainerizer`. Other persistent volumes may have been
-    // created by other actors, such as the `DockerContainerizer`.
-    if (orphans.contains(runPath->containerId)) {
-      Owned<Info> info(new Info(paths::getExecutorRunPath(
-          flags.work_dir,
-          runPath->slaveId,
-          runPath->frameworkId,
-          runPath->executorId,
-          runPath->containerId)));
-
-      infos.put(runPath->containerId, info);
+    // TODO(josephw): We only track persistent volumes for containers
+    // launched by MesosContainerizer. Nested containers or containers
+    // that are listed in 'orphans' were presumably created by an
+    // earlier `MesosContainerizer`. Other persistent volumes may have
+    // been created by other actors, such as the
+    // `DockerContainerizer`.
+    if (orphans.contains(containerId.get())) {
+      infos.put(containerId.get(), Owned<Info>(new Info(
+          containerizer::paths::getSandboxPath(
+              rootSandboxPath,
+              containerId.get()))));
+    } else if (containerId->has_parent()) {
+      infos.put(containerId.get(), Owned<Info>(new Info(
+          containerizer::paths::getSandboxPath(
+              rootSandboxPath,
+              containerId.get()))));
+
+      LOG(INFO) << "Cleaning up unknown orphaned nested container "
+                << containerId.get();
+
+      cleanups.push_back(cleanup(containerId.get()));
     }
   }
 
-  return Nothing();
+  return collect(cleanups)
+    .then([]() { return Nothing(); });
 }
 
 
@@ -265,17 +307,20 @@ Future<Option<ContainerLaunchInfo>> LinuxFilesystemIsolatorProcess::prepare(
     const ContainerID& containerId,
     const ContainerConfig& containerConfig)
 {
-  const string& directory = containerConfig.directory();
-
   if (infos.contains(containerId)) {
     return Failure("Container has already been prepared");
   }
 
-  Owned<Info> info(new Info(
-      directory,
-      containerConfig.executor_info()));
+  const string& directory = containerConfig.directory();
+
+  Option<ExecutorInfo> executorInfo;
+  if (containerConfig.has_executor_info()) {
+    executorInfo = containerConfig.executor_info();
+  }
 
-  infos.put(containerId, info);
+  infos.put(containerId, Owned<Info>(new Info(
+      directory,
+      executorInfo)));
 
   ContainerLaunchInfo launchInfo;
   launchInfo.set_namespaces(CLONE_NEWNS);
@@ -295,6 +340,11 @@ Future<Option<ContainerLaunchInfo>> LinuxFilesystemIsolatorProcess::prepare(
     launchInfo.add_pre_exec_commands()->CopyFrom(command);
   }
 
+  // Currently, we only need to update resources for top level containers.
+  if (containerId.has_parent()) {
+    return launchInfo;
+  }
+
   return update(containerId, containerConfig.executor_info().resources())
     .then([launchInfo]() -> Future<Option<ContainerLaunchInfo>> {
       return launchInfo;
@@ -332,7 +382,7 @@ Try<vector<CommandInfo>> LinuxFilesystemIsolatorProcess::getPreExecCommands(
 
   commands.push_back(command);
 
-  if (!containerConfig.executor_info().has_container()) {
+  if (!containerConfig.has_container_info()) {
     return commands;
   }
 
@@ -364,8 +414,7 @@ Try<vector<CommandInfo>> LinuxFilesystemIsolatorProcess::getPreExecCommands(
     commands.push_back(command);
   }
 
-  foreach (const Volume& volume,
-           containerConfig.executor_info().container().volumes()) {
+  foreach (const Volume& volume, containerConfig.container_info().volumes()) {
     // NOTE: Volumes with source will be handled by the corresponding
     // isolators (e.g., docker/volume).
     if (volume.has_source()) {
@@ -538,6 +587,10 @@ Future<Nothing> LinuxFilesystemIsolatorProcess::update(
     const ContainerID& containerId,
     const Resources& resources)
 {
+  if (containerId.has_parent()) {
+    return Failure("Not supported for nested containers");
+  }
+
   // Mount persistent volumes. We do this in the host namespace and
   // rely on mount propagation for them to be visible inside the
   // container.
@@ -696,6 +749,17 @@ Future<Nothing> LinuxFilesystemIsolatorProcess::cleanup(
     return Nothing();
   }
 
+  // Make sure the container we are cleaning up doesn't have any
+  // children (they should have already been cleaned up by a previous
+  // call if it had any).
+  foreachkey (const ContainerID& _containerId, infos) {
+    if (_containerId.has_parent() && _containerId.parent() == containerId) {
+      return Failure(
+          "Container " + stringify(containerId) + " has non terminated "
+          "child container " + stringify(_containerId));
+    }
+  }
+
   const Owned<Info>& info = infos[containerId];
 
   // NOTE: We don't need to cleanup mounts in the container's mount
@@ -755,6 +819,9 @@ LinuxFilesystemIsolatorProcess::Metrics::~Metrics()
 }
 
 
+// TODO(gilbert): Currently, this only supports counting rootfses for
+// top level containers. We should figure out another way to collect
+// this information if necessary.
 double LinuxFilesystemIsolatorProcess::_containers_new_rootfs()
 {
   double count = 0.0;

http://git-wip-us.apache.org/repos/asf/mesos/blob/81461dcf/src/slave/containerizer/mesos/isolators/filesystem/linux.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/filesystem/linux.hpp b/src/slave/containerizer/mesos/isolators/filesystem/linux.hpp
index 0a85935..c7fbda5 100644
--- a/src/slave/containerizer/mesos/isolators/filesystem/linux.hpp
+++ b/src/slave/containerizer/mesos/isolators/filesystem/linux.hpp
@@ -46,6 +46,8 @@ public:
 
   virtual ~LinuxFilesystemIsolatorProcess();
 
+  virtual bool supportsNesting();
+
   virtual process::Future<Nothing> recover(
       const std::list<mesos::slave::ContainerState>& states,
       const hashset<ContainerID>& orphans);
@@ -75,7 +77,7 @@ private:
     Info(const std::string& _directory) : directory(_directory) {}
 
     Info(const std::string& _directory,
-         const ExecutorInfo& _executor)
+         const Option<ExecutorInfo>& _executor)
       : directory(_directory),
         executor(_executor) {}
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/81461dcf/src/slave/containerizer/mesos/paths.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/paths.cpp b/src/slave/containerizer/mesos/paths.cpp
index 7635228..6c6b4dc 100644
--- a/src/slave/containerizer/mesos/paths.cpp
+++ b/src/slave/containerizer/mesos/paths.cpp
@@ -193,6 +193,46 @@ string getSandboxPath(
     : rootSandboxPath;
 }
 
+
+Try<ContainerID> parseSandboxPath(
+    const ContainerID& rootContainerId,
+    const string& _rootSandboxPath,
+    const string& path)
+{
+  // Make sure there's a separator at the end of the `rootdir` so that
+  // we don't accidentally slice off part of a directory.
+  const string rootSandboxPath = path::join(_rootSandboxPath, "");
+
+  if (!strings::startsWith(path, rootSandboxPath)) {
+    return Error(
+        "Directory '" + path + "' does not fall under "
+        "the root sandbox directory '" + rootSandboxPath + "'");
+  }
+
+  ContainerID currentContainerId = rootContainerId;
+
+  vector<string> tokens = strings::tokenize(
+      path.substr(rootSandboxPath.size()),
+      "/");
+
+  for (size_t i = 0; i < tokens.size(); i++) {
+    // For a nested container x.y.z, the sandbox layout is the
+    // following: '.../runs/x/containers/y/containers/z'.
+    if (i % 2 == 0) {
+      if (tokens[i] != CONTAINER_DIRECTORY) {
+        break;
+      }
+    } else {
+      ContainerID id;
+      id.set_value(tokens[i]);
+      id.mutable_parent()->CopyFrom(currentContainerId);
+      currentContainerId = id;
+    }
+  }
+
+  return currentContainerId;
+}
+
 } // namespace paths {
 } // namespace containerizer {
 } // namespace slave {

http://git-wip-us.apache.org/repos/asf/mesos/blob/81461dcf/src/slave/containerizer/mesos/paths.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/paths.hpp b/src/slave/containerizer/mesos/paths.hpp
index 8d8bcb4..1051c21 100644
--- a/src/slave/containerizer/mesos/paths.hpp
+++ b/src/slave/containerizer/mesos/paths.hpp
@@ -88,6 +88,14 @@ std::string getSandboxPath(
     const std::string& rootSandboxPath,
     const ContainerID& containerId);
 
+
+// The helper method parses a given 'path' and returns the container
+// ID of the container whose sandbox contains 'path'.
+Try<ContainerID> parseSandboxPath(
+    const ContainerID& rootContainerId,
+    const std::string& rootSandboxPath,
+    const std::string& path);
+
 } // namespace paths {
 } // namespace containerizer {
 } // namespace slave {