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/01/20 19:08:58 UTC

[2/5] mesos git commit: Implemented the CgroupsNetClsIsolatorProcess.

Implemented the CgroupsNetClsIsolatorProcess.

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


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

Branch: refs/heads/master
Commit: d42ff29303edfd110c42419e55a45849cf196b93
Parents: 157160b
Author: Avinash sridharan <av...@mesosphere.io>
Authored: Wed Jan 20 10:00:47 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Wed Jan 20 10:00:47 2016 -0800

----------------------------------------------------------------------
 .../mesos/isolators/cgroups/net_cls.cpp         | 191 ++++++++++++++++++-
 1 file changed, 183 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/d42ff293/src/slave/containerizer/mesos/isolators/cgroups/net_cls.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/cgroups/net_cls.cpp b/src/slave/containerizer/mesos/isolators/cgroups/net_cls.cpp
index 610d479..0160fe2 100644
--- a/src/slave/containerizer/mesos/isolators/cgroups/net_cls.cpp
+++ b/src/slave/containerizer/mesos/isolators/cgroups/net_cls.cpp
@@ -15,15 +15,21 @@
 // limitations under the License.
 
 #include <list>
+#include <vector>
 
-#include "slave/flags.hpp"
+#include <process/defer.hpp>
+#include <process/future.hpp>
+#include <process/pid.hpp>
 
-#include "slave/containerizer/mesos/isolators/cgroups/net_cls.hpp"
+#include <stout/os.hpp>
+#include <stout/path.hpp>
+#include <stout/try.hpp>
 
-using namespace process;
+#include "linux/cgroups.hpp"
 
-using std::string;
-using std::list;
+#include "slave/flags.hpp"
+
+#include "slave/containerizer/mesos/isolators/cgroups/net_cls.hpp"
 
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
@@ -31,6 +37,16 @@ using mesos::slave::ContainerLimitation;
 using mesos::slave::ContainerState;
 using mesos::slave::Isolator;
 
+using process::Failure;
+using process::Future;
+using process::Owned;
+using process::PID;
+
+using std::list;
+using std::set;
+using std::string;
+using std::vector;
+
 namespace mesos {
 namespace internal {
 namespace slave {
@@ -47,7 +63,31 @@ CgroupsNetClsIsolatorProcess::~CgroupsNetClsIsolatorProcess() {}
 
 Try<Isolator*> CgroupsNetClsIsolatorProcess::create(const Flags& flags)
 {
-  return nullptr;
+  Try<string> hierarchy = cgroups::prepare(
+      flags.cgroups_hierarchy,
+      "net_cls",
+      flags.cgroups_root);
+
+  if (hierarchy.isError()) {
+    return Error("Failed to create net_cls cgroup: " + hierarchy.error());
+  }
+
+  // Ensure that no other subsystem is attached to the hierarchy.
+  Try<set<string>> subsystems = cgroups::subsystems(hierarchy.get());
+  if (subsystems.isError()) {
+    return Error(
+        "Failed to get the list of attached subsystems for hierarchy " +
+        hierarchy.get());
+  } else if (subsystems.get().size() != 1) {
+    return Error(
+        "Unexpected subsystems found attached to the hierarchy " +
+        hierarchy.get());
+  }
+
+  process::Owned<MesosIsolatorProcess> process(
+      new CgroupsNetClsIsolatorProcess(flags, hierarchy.get()));
+
+  return new MesosIsolator(process);
 }
 
 
@@ -55,6 +95,64 @@ Future<Nothing> CgroupsNetClsIsolatorProcess::recover(
     const list<ContainerState>& states,
     const hashset<ContainerID>& orphans)
 {
+  foreach (const ContainerState& state, states) {
+    const ContainerID& containerId = state.container_id();
+    const string cgroup = path::join(flags.cgroups_root, containerId.value());
+
+    Try<bool> exists = cgroups::exists(hierarchy, cgroup);
+    if (exists.isError()) {
+      infos.clear();
+      return Failure("Failed to check cgroup for container '" +
+                     stringify(containerId) + "'");
+    }
+
+    if (!exists.get()) {
+      VLOG(1) << "Couldn't find cgroup for container " << containerId;
+      // This may occur if the executor has exited and the isolator
+      // has destroyed the cgroup but the slave dies before noticing
+      // this. This will be detected when the containerizer tries to
+      // monitor the executor's pid.
+      continue;
+    }
+
+    infos.emplace(containerId, Info(cgroup));
+  }
+
+  // Remove orphan cgroups.
+  Try<vector<string>> cgroups = cgroups::get(hierarchy, flags.cgroups_root);
+  if (cgroups.isError()) {
+    infos.clear();
+    return Failure(cgroups.error());
+  }
+
+  foreach (const string& cgroup, cgroups.get()) {
+    // Ignore the slave cgroup (see the --slave_subsystems flag).
+    // TODO(idownes): Remove this when the cgroups layout is updated,
+    // see MESOS-1185.
+    if (cgroup == path::join(flags.cgroups_root, "slave")) {
+      continue;
+    }
+
+    ContainerID containerId;
+    containerId.set_value(Path(cgroup).basename());
+
+    if (infos.contains(containerId)) {
+      continue;
+    }
+
+    // Known orphan cgroups will be destroyed by the containerizer
+    // using the normal cleanup path. See MESOS-2367 for details.
+    if (orphans.contains(containerId)) {
+      infos.emplace(containerId, Info(cgroup));
+      continue;
+    }
+
+    LOG(INFO) << "Removing unknown orphaned cgroup '" << cgroup << "'";
+
+    // We don't wait on the destroy as we don't want to block recovery.
+    cgroups::destroy(hierarchy, cgroup, cgroups::DESTROY_TIMEOUT);
+  }
+
   return Nothing();
 }
 
@@ -77,6 +175,10 @@ Future<Nothing> CgroupsNetClsIsolatorProcess::update(
 Future<ResourceStatistics> CgroupsNetClsIsolatorProcess::usage(
     const ContainerID& containerId)
 {
+  if (!infos.contains(containerId)) {
+    return Failure("Unknown container");
+  }
+
   return ResourceStatistics();
 }
 
@@ -86,7 +188,49 @@ Future<Option<ContainerLaunchInfo>> CgroupsNetClsIsolatorProcess::prepare(
     const ExecutorInfo& executorInfo,
     const ContainerConfig& containerConfig)
 {
-  return None();
+  if (infos.contains(containerId)) {
+    return Failure("Container has already been prepared");
+  }
+
+  // Use this info to create the cgroup, but do not insert it into
+  // infos till the cgroup has been created successfully.
+  Info info(path::join(flags.cgroups_root, containerId.value()));
+
+  // Create a cgroup for this container.
+  Try<bool> exists = cgroups::exists(hierarchy, info.cgroup);
+  if (exists.isError()) {
+    return Failure("Failed to check if the cgroup already exists: " +
+                   exists.error());
+  } else if (exists.get()) {
+    return Failure("The cgroup already exists");
+  }
+
+  Try<Nothing> create = cgroups::create(hierarchy, info.cgroup);
+  if (create.isError()) {
+    return Failure("Failed to create the cgroup: " + create.error());
+  }
+
+  // 'chown' the cgroup so the executor can create nested cgroups. Do
+  // not recurse so the control files are still owned by the slave
+  // user and thus cannot be changed by the executor.
+  if (containerConfig.has_user()) {
+    Try<Nothing> chown = os::chown(
+        containerConfig.user(),
+        path::join(hierarchy, info.cgroup),
+        false);
+
+    if (chown.isError()) {
+      return Failure("Failed to change ownership of cgroup hierarchy: " +
+                     chown.error());
+    }
+  }
+
+  infos.emplace(containerId, info);
+
+  return update(containerId, executorInfo.resources())
+    .then([]() -> Future<Option<ContainerLaunchInfo>> {
+      return None();
+    });
 }
 
 
@@ -94,6 +238,20 @@ Future<Nothing> CgroupsNetClsIsolatorProcess::isolate(
     const ContainerID& containerId,
     pid_t pid)
 {
+  if (!infos.contains(containerId)) {
+    return Failure("Unknown container");
+  }
+
+  const Info& info = infos.at(containerId);
+
+  Try<Nothing> assign = cgroups::assign(hierarchy, info.cgroup, pid);
+  if (assign.isError()) {
+    return Failure("Failed to assign container '" +
+                   stringify(containerId) + "' to its own cgroup '" +
+                   path::join(hierarchy, info.cgroup) +
+                   "': " + assign.error());
+  }
+
   return Nothing();
 }
 
@@ -104,6 +262,10 @@ Future<Nothing> CgroupsNetClsIsolatorProcess::isolate(
 Future<ContainerLimitation> CgroupsNetClsIsolatorProcess::watch(
     const ContainerID& containerId)
 {
+  if (!infos.contains(containerId)) {
+    return Failure("Unknown container");
+  }
+
   return Future<ContainerLimitation>();
 }
 
@@ -111,7 +273,20 @@ Future<ContainerLimitation> CgroupsNetClsIsolatorProcess::watch(
 Future<Nothing> CgroupsNetClsIsolatorProcess::cleanup(
     const ContainerID& containerId)
 {
-  return Nothing();
+  // Multiple calls may occur during test clean up.
+  if (!infos.contains(containerId)) {
+    VLOG(1) << "Ignoring cleanup request for unknown container: "
+            << containerId;
+    return Nothing();
+  }
+
+  const Info& info = infos.at(containerId);
+
+  return cgroups::destroy(hierarchy, info.cgroup, cgroups::DESTROY_TIMEOUT)
+    .then(defer(PID<CgroupsNetClsIsolatorProcess>(this), [=]() {
+      infos.erase(containerId);
+      return Nothing();
+    }));
 }
 
 } // namespace slave {