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/11/12 02:57:22 UTC

[01/11] mesos git commit: Added a default PATH environment variable when launching a container.

Repository: mesos
Updated Branches:
  refs/heads/master befac1cde -> 757d2804d


Added a default PATH environment variable when launching a container.

Having an environment set but no PATH variable set inside of it,
will trigger an `execvpe` call in launch.cpp on the command we are
trying to launch. Normally this doesn't casue problems because
`execvpe` with call `confstr(_CS_PATH)` under the hood to set up a
default path to use when lookiing up our command.

However, when provisioning a new filesystem for a container, its
possible that the `confstr(_CS_PATH)` called from the agent may not
return the same path as a `confstr(_CS_PATH)` call would return using
the libc installed inside the container. This can lead to problems
(for example) with finding the `sh` command in containers based on an
alpine linux image.

We observed this in our test setup with `confstr(_CS_PATH)` on the
agent returning `/usr/bin`, while alpine linux only has the `sh`
command installed in `/bin`.

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


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

Branch: refs/heads/master
Commit: b15b46ab00ebffa2b8247ac7c4210da538efcea5
Parents: befac1c
Author: Kevin Klues <kl...@gmail.com>
Authored: Fri Nov 11 16:03:04 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Nov 11 16:13:45 2016 -0800

----------------------------------------------------------------------
 src/slave/containerizer/mesos/launch.cpp | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/b15b46ab/src/slave/containerizer/mesos/launch.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/launch.cpp b/src/slave/containerizer/mesos/launch.cpp
index 377a9d9..181d833 100644
--- a/src/slave/containerizer/mesos/launch.cpp
+++ b/src/slave/containerizer/mesos/launch.cpp
@@ -658,7 +658,15 @@ int MesosContainerizerLaunch::execute()
   // specified, inherit the environment of the current process.
   Option<os::raw::Envp> envp;
   if (flags.environment.isSome()) {
-    envp = os::raw::Envp(flags.environment.get());
+    JSON::Object environment = flags.environment.get();
+
+    Result<JSON::String> path = flags.environment->find<JSON::String>("PATH");
+    if (path.isNone()) {
+      environment.values["PATH"] =
+          "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
+    }
+
+    envp = os::raw::Envp(environment);
   }
 
 #ifndef __WINDOWS__


[09/11] mesos git commit: Fixed nvidia gpu isolator tests.

Posted by ji...@apache.org.
Fixed nvidia gpu isolator tests.

Make sure to use filesystem/linux isolator for those tests. Otherwise,
the newly introduced check will fail the tests.


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

Branch: refs/heads/master
Commit: 781b96843a80a45667cd9a5c4f5132c81d4d37cb
Parents: c40765a
Author: Jie Yu <yu...@gmail.com>
Authored: Fri Nov 11 18:30:50 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Nov 11 18:54:11 2016 -0800

----------------------------------------------------------------------
 src/tests/containerizer/nvidia_gpu_isolator_tests.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/781b9684/src/tests/containerizer/nvidia_gpu_isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/nvidia_gpu_isolator_tests.cpp b/src/tests/containerizer/nvidia_gpu_isolator_tests.cpp
index fea1f9f..74e06f0 100644
--- a/src/tests/containerizer/nvidia_gpu_isolator_tests.cpp
+++ b/src/tests/containerizer/nvidia_gpu_isolator_tests.cpp
@@ -88,7 +88,7 @@ TEST_F(NvidiaGpuTest, ROOT_CGROUPS_NVIDIA_GPU_VerifyDeviceAccess)
   // Turn on Nvidia GPU isolation.
   // Assume at least one GPU is available for isolation.
   slave::Flags flags = CreateSlaveFlags();
-  flags.isolation = "cgroups/devices,gpu/nvidia";
+  flags.isolation = "filesystem/linux,cgroups/devices,gpu/nvidia";
   flags.nvidia_gpu_devices = vector<unsigned int>({0u});
   flags.resources = "gpus:1";
 
@@ -300,7 +300,7 @@ TEST_F(NvidiaGpuTest, ROOT_CGROUPS_NVIDIA_GPU_FractionalResources)
   // Turn on Nvidia GPU isolation.
   // Assume at least one GPU is available for isolation.
   slave::Flags flags = CreateSlaveFlags();
-  flags.isolation = "cgroups/devices,gpu/nvidia";
+  flags.isolation = "filesystem/linux,cgroups/devices,gpu/nvidia";
   flags.nvidia_gpu_devices = vector<unsigned int>({0u});
   flags.resources = "gpus:1";
 


[05/11] mesos git commit: Fixed a compile issue on OSX.

Posted by ji...@apache.org.
Fixed a compile issue on OSX.


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

Branch: refs/heads/master
Commit: c40765ad9f6ac6154f54f3b25842cad7b76a4cca
Parents: 0dafc55
Author: Jie Yu <yu...@gmail.com>
Authored: Fri Nov 11 18:20:41 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Nov 11 18:54:11 2016 -0800

----------------------------------------------------------------------
 src/tests/containerizer/mock_containerizer.hpp | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/c40765ad/src/tests/containerizer/mock_containerizer.hpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/mock_containerizer.hpp b/src/tests/containerizer/mock_containerizer.hpp
index 319b5c3..7a30b83 100644
--- a/src/tests/containerizer/mock_containerizer.hpp
+++ b/src/tests/containerizer/mock_containerizer.hpp
@@ -57,14 +57,15 @@ public:
           const std::map<std::string, std::string>&,
           bool));
 
-  MOCK_METHOD5(
+  MOCK_METHOD6(
       launch,
       process::Future<bool>(
-          const ContainerID& containerId,
-          const CommandInfo& commandInfo,
-          const Option<ContainerInfo>& containerInfo,
-          const Option<std::string>& user,
-          const SlaveID& slaveId));
+          const ContainerID&,
+          const CommandInfo&,
+          const Option<ContainerInfo>&,
+          const Option<std::string>&,
+          const SlaveID&,
+          const Option<mesos::slave::ContainerClass>&));
 
   MOCK_METHOD2(
       update,


[04/11] mesos git commit: Added 'ContainerClass' to help decide how best to launch a container.

Posted by ji...@apache.org.
Added 'ContainerClass' to help decide how best to launch a container.

A 'ContainerClass' must now be passed to all *nested*
containerizer->launch() calls in order to specify the class of
container being launched. For now, we simply have the default nested
container class (called 'NESTED') in a subsequent commit we will
introduce the 'DEBUG' class to help classify debug-based nested
containers that should be launched slightly differently than default
nested containers.

The 'ContainerClass' specified is passed through to each isolator in
'ContainerConfig' so they have a chance to custiomize their isolation
policies based on the class as well.

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


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

Branch: refs/heads/master
Commit: 727ce3d4f8b7c6b489a431983666f340398b0c97
Parents: ed1b4bc
Author: Kevin Klues <kl...@gmail.com>
Authored: Fri Nov 11 16:19:41 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Nov 11 18:54:10 2016 -0800

----------------------------------------------------------------------
 include/mesos/slave/containerizer.proto         | 15 +++++++++++++++
 src/slave/containerizer/composing.cpp           | 16 +++++++++++-----
 src/slave/containerizer/composing.hpp           |  3 ++-
 src/slave/containerizer/containerizer.hpp       |  3 ++-
 src/slave/containerizer/mesos/containerizer.cpp | 17 +++++++++++++----
 src/slave/containerizer/mesos/containerizer.hpp |  6 ++++--
 src/tests/api_tests.cpp                         |  2 +-
 src/tests/containerizer.cpp                     | 20 +++++++++++++-------
 src/tests/containerizer.hpp                     |  8 +++++---
 9 files changed, 66 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/727ce3d4/include/mesos/slave/containerizer.proto
----------------------------------------------------------------------
diff --git a/include/mesos/slave/containerizer.proto b/include/mesos/slave/containerizer.proto
index f4c4ad7..ee29468 100644
--- a/include/mesos/slave/containerizer.proto
+++ b/include/mesos/slave/containerizer.proto
@@ -23,6 +23,17 @@ import "mesos/appc/spec.proto";
 import "mesos/docker/v1.proto";
 
 /**
+ * Some containers are launched in conjunction with a specific
+ * `ContainerClass`. These classes allow an isolator to customize
+ * their functionality based on the class of container being isolated.
+ * The classes we currently define are below.
+ */
+enum ContainerClass {
+  DEFAULT = 1;
+}
+
+
+/**
  * Information when an executor is impacted by a resource limitation
  * and should be terminated. Intended to support resources like memory
  * where the Linux kernel may invoke the OOM killer, killing some/all
@@ -105,6 +116,10 @@ message ContainerConfig {
   // Resources associated with the container during launch.
   repeated Resource resources = 13;
 
+  // The class of container being launched. Used by isolators to
+  // perform different operations depending on the class.
+  optional ContainerClass container_class = 14;
+
   // The work directory for the container in the host filesystem.
   required string directory = 3;
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/727ce3d4/src/slave/containerizer/composing.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/composing.cpp b/src/slave/containerizer/composing.cpp
index 0c5489f..10bb618 100644
--- a/src/slave/containerizer/composing.cpp
+++ b/src/slave/containerizer/composing.cpp
@@ -41,6 +41,7 @@ using std::map;
 using std::string;
 using std::vector;
 
+using mesos::slave::ContainerClass;
 using mesos::slave::ContainerTermination;
 
 namespace mesos {
@@ -77,7 +78,8 @@ public:
       const CommandInfo& commandInfo,
       const Option<ContainerInfo>& containerInfo,
       const Option<string>& user,
-      const SlaveID& slaveId);
+      const SlaveID& slaveId,
+      const Option<ContainerClass>& containerClass);
 
   Future<Nothing> update(
       const ContainerID& containerId,
@@ -202,7 +204,8 @@ Future<bool> ComposingContainerizer::launch(
     const CommandInfo& commandInfo,
     const Option<ContainerInfo>& containerInfo,
     const Option<string>& user,
-    const SlaveID& slaveId)
+    const SlaveID& slaveId,
+    const Option<ContainerClass>& containerClass)
 {
   return dispatch(process,
                   &ComposingContainerizerProcess::launch,
@@ -210,7 +213,8 @@ Future<bool> ComposingContainerizer::launch(
                   commandInfo,
                   containerInfo,
                   user,
-                  slaveId);
+                  slaveId,
+                  containerClass);
 }
 
 
@@ -474,7 +478,8 @@ Future<bool> ComposingContainerizerProcess::launch(
           const CommandInfo& commandInfo,
           const Option<ContainerInfo>& containerInfo,
           const Option<std::string>& user,
-          const SlaveID& slaveId)
+          const SlaveID& slaveId,
+          const Option<ContainerClass>& containerClass)
 {
   ContainerID rootContainerId = getRootContainerId(containerId);
 
@@ -497,7 +502,8 @@ Future<bool> ComposingContainerizerProcess::launch(
       commandInfo,
       containerInfo,
       user,
-      slaveId)
+      slaveId,
+      containerClass)
     .then(defer(self(),
                 &Self::_launch,
                 containerId,

http://git-wip-us.apache.org/repos/asf/mesos/blob/727ce3d4/src/slave/containerizer/composing.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/composing.hpp b/src/slave/containerizer/composing.hpp
index 68c0523..3a2c9b4 100644
--- a/src/slave/containerizer/composing.hpp
+++ b/src/slave/containerizer/composing.hpp
@@ -67,7 +67,8 @@ public:
       const CommandInfo& commandInfo,
       const Option<ContainerInfo>& containerInfo,
       const Option<std::string>& user,
-      const SlaveID& slaveId);
+      const SlaveID& slaveId,
+      const Option<mesos::slave::ContainerClass>& containerClass = None());
 
   virtual process::Future<Nothing> update(
       const ContainerID& containerId,

http://git-wip-us.apache.org/repos/asf/mesos/blob/727ce3d4/src/slave/containerizer/containerizer.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/containerizer.hpp b/src/slave/containerizer/containerizer.hpp
index 7554446..73e74c9 100644
--- a/src/slave/containerizer/containerizer.hpp
+++ b/src/slave/containerizer/containerizer.hpp
@@ -100,7 +100,8 @@ public:
       const CommandInfo& commandInfo,
       const Option<ContainerInfo>& containerInfo,
       const Option<std::string>& user,
-      const SlaveID& slaveId)
+      const SlaveID& slaveId,
+      const Option<mesos::slave::ContainerClass>& containerClass = None())
   {
     return process::Failure("Unsupported");
   }

http://git-wip-us.apache.org/repos/asf/mesos/blob/727ce3d4/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index 44225eb..90f91b9 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -119,6 +119,7 @@ using mesos::internal::slave::state::RunState;
 
 using mesos::modules::ModuleManager;
 
+using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::ContainerLimitation;
@@ -478,7 +479,8 @@ Future<bool> MesosContainerizer::launch(
     const CommandInfo& commandInfo,
     const Option<ContainerInfo>& containerInfo,
     const Option<string>& user,
-    const SlaveID& slaveId)
+    const SlaveID& slaveId,
+    const Option<ContainerClass>& containerClass)
 {
   // Need to disambiguate for the compiler.
   Future<bool> (MesosContainerizerProcess::*launch)(
@@ -486,7 +488,8 @@ Future<bool> MesosContainerizer::launch(
       const CommandInfo&,
       const Option<ContainerInfo>&,
       const Option<string>&,
-      const SlaveID&) = &MesosContainerizerProcess::launch;
+      const SlaveID&,
+      const Option<ContainerClass>&) = &MesosContainerizerProcess::launch;
 
   return dispatch(process.get(),
                   launch,
@@ -494,7 +497,8 @@ Future<bool> MesosContainerizer::launch(
                   commandInfo,
                   containerInfo,
                   user,
-                  slaveId);
+                  slaveId,
+                  containerClass);
 }
 
 
@@ -1660,7 +1664,8 @@ Future<bool> MesosContainerizerProcess::launch(
     const CommandInfo& commandInfo,
     const Option<ContainerInfo>& containerInfo,
     const Option<string>& user,
-    const SlaveID& slaveId)
+    const SlaveID& slaveId,
+    const Option<ContainerClass>& containerClass)
 {
   CHECK(containerId.has_parent());
 
@@ -1732,6 +1737,10 @@ Future<bool> MesosContainerizerProcess::launch(
     containerConfig.mutable_container_info()->CopyFrom(containerInfo.get());
   }
 
+  if (containerClass.isSome()) {
+    containerConfig.set_container_class(containerClass.get());
+  }
+
   return launch(containerId,
                 containerConfig,
                 map<string, string>(),

http://git-wip-us.apache.org/repos/asf/mesos/blob/727ce3d4/src/slave/containerizer/mesos/containerizer.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.hpp b/src/slave/containerizer/mesos/containerizer.hpp
index c4fea8b..272052d 100644
--- a/src/slave/containerizer/mesos/containerizer.hpp
+++ b/src/slave/containerizer/mesos/containerizer.hpp
@@ -91,7 +91,8 @@ public:
       const CommandInfo& commandInfo,
       const Option<ContainerInfo>& containerInfo,
       const Option<std::string>& user,
-      const SlaveID& slaveId);
+      const SlaveID& slaveId,
+      const Option<mesos::slave::ContainerClass>& containerClass = None());
 
   virtual process::Future<Nothing> update(
       const ContainerID& containerId,
@@ -157,7 +158,8 @@ public:
       const CommandInfo& commandInfo,
       const Option<ContainerInfo>& containerInfo,
       const Option<std::string>& user,
-      const SlaveID& slaveId);
+      const SlaveID& slaveId,
+      const Option<mesos::slave::ContainerClass>& containerClass);
 
   virtual process::Future<Nothing> update(
       const ContainerID& containerId,

http://git-wip-us.apache.org/repos/asf/mesos/blob/727ce3d4/src/tests/api_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/api_tests.cpp b/src/tests/api_tests.cpp
index 57981f1..8889e78 100644
--- a/src/tests/api_tests.cpp
+++ b/src/tests/api_tests.cpp
@@ -3437,7 +3437,7 @@ TEST_P(AgentAPITest, NestedContainerLaunchFalse)
 
   {
     // Return false here to indicate "unsupported".
-    EXPECT_CALL(containerizer, launch(_, _, _, _, _))
+    EXPECT_CALL(containerizer, launch(_, _, _, _, _, _))
       .WillOnce(Return(Future<bool>(false)));
 
     v1::agent::Call call;

http://git-wip-us.apache.org/repos/asf/mesos/blob/727ce3d4/src/tests/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer.cpp b/src/tests/containerizer.cpp
index c3bcb85..6b7d3ed 100644
--- a/src/tests/containerizer.cpp
+++ b/src/tests/containerizer.cpp
@@ -33,6 +33,7 @@ using testing::_;
 using testing::Invoke;
 using testing::Return;
 
+using mesos::slave::ContainerClass;
 using mesos::slave::ContainerTermination;
 
 using mesos::v1::executor::Mesos;
@@ -191,7 +192,8 @@ public:
       const CommandInfo& commandInfo,
       const Option<ContainerInfo>& containerInfo,
       const Option<string>& user,
-      const SlaveID& slaveId)
+      const SlaveID& slaveId,
+      const Option<ContainerClass>& containerClass)
   {
     CHECK(!terminatedContainers.contains(containerId))
       << "Failed to launch nested container " << containerId
@@ -440,10 +442,10 @@ void TestContainerizer::setup()
       const CommandInfo& commandInfo,
       const Option<ContainerInfo>& containerInfo,
       const Option<string>& user,
-      const SlaveID& slaveId) =
-    &TestContainerizer::_launch;
+      const SlaveID& slaveId,
+      const Option<ContainerClass>&) = &TestContainerizer::_launch;
 
-  EXPECT_CALL(*this, launch(_, _, _, _, _))
+  EXPECT_CALL(*this, launch(_, _, _, _, _, _))
     .WillRepeatedly(Invoke(this, _launchNested));
 
   EXPECT_CALL(*this, wait(_))
@@ -504,7 +506,8 @@ Future<bool> TestContainerizer::_launch(
     const CommandInfo& commandInfo,
     const Option<ContainerInfo>& containerInfo,
     const Option<string>& user,
-    const SlaveID& slaveId)
+    const SlaveID& slaveId,
+    const Option<ContainerClass>& containerClass)
 {
   // Need to disambiguate for the compiler.
   Future<bool> (TestContainerizerProcess::*launch)(
@@ -512,7 +515,9 @@ Future<bool> TestContainerizer::_launch(
       const CommandInfo&,
       const Option<ContainerInfo>&,
       const Option<string>&,
-      const SlaveID&) = &TestContainerizerProcess::launch;
+      const SlaveID&,
+      const Option<ContainerClass>& containerClass) =
+        &TestContainerizerProcess::launch;
 
   return process::dispatch(
       process.get(),
@@ -521,7 +526,8 @@ Future<bool> TestContainerizer::_launch(
       commandInfo,
       containerInfo,
       user,
-      slaveId);
+      slaveId,
+      containerClass);
 }
 
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/727ce3d4/src/tests/containerizer.hpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer.hpp b/src/tests/containerizer.hpp
index 080b8fa..d799285 100644
--- a/src/tests/containerizer.hpp
+++ b/src/tests/containerizer.hpp
@@ -93,14 +93,15 @@ public:
           const std::map<std::string, std::string>&,
           bool checkpoint));
 
-  MOCK_METHOD5(
+  MOCK_METHOD6(
       launch,
       process::Future<bool>(
           const ContainerID& containerId,
           const CommandInfo& commandInfo,
           const Option<ContainerInfo>& containerInfo,
           const Option<std::string>& user,
-          const SlaveID& slaveId));
+          const SlaveID& slaveId,
+          const Option<mesos::slave::ContainerClass>& containerClass));
 
   MOCK_METHOD2(
       update,
@@ -154,7 +155,8 @@ private:
       const CommandInfo& commandInfo,
       const Option<ContainerInfo>& containerInfo,
       const Option<std::string>& user,
-      const SlaveID& slaveId);
+      const SlaveID& slaveId,
+      const Option<mesos::slave::ContainerClass>& containerClass = None());
 
   process::Future<Nothing> _update(
       const ContainerID& containerId,


[07/11] mesos git commit: Added proper dependencies on the 'filesystem/linux' isolator.

Posted by ji...@apache.org.
Added proper dependencies on the 'filesystem/linux' isolator.

For some isolators, this meant adding an explicit dependency on
'filesystem/linux' and then removing any of their local calls to
'set_clone_namespaces(CLONE_NEWNS)'. For others, this meant simply
removing their explicit 'set_clone_namespaces(CLONE_NEWNS)' calls
since they are redundant with the one made by 'filesystem/linux'.

The 'cni' isolator is a special case, however, because it may need to
call 'set_clone_namespaces(CLONE_NEWNS)' even if the
'filesystem/posix' isolator is enabled. For this we added a comment.

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


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

Branch: refs/heads/master
Commit: 09d42454c01398e0b7b6588aab4488b68cb82435
Parents: 329f3ea
Author: Kevin Klues <kl...@gmail.com>
Authored: Fri Nov 11 16:52:54 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Nov 11 18:54:11 2016 -0800

----------------------------------------------------------------------
 .../mesos/isolators/gpu/isolator.cpp              | 18 +++++++++++++++---
 .../mesos/isolators/namespaces/pid.cpp            |  9 ++++++++-
 .../mesos/isolators/volume/image.cpp              | 10 +++++++++-
 .../mesos/isolators/volume/sandbox_path.cpp       |  6 ------
 4 files changed, 32 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/09d42454/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp b/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
index 4bd3785..a3a140d 100644
--- a/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
+++ b/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
@@ -92,14 +92,17 @@ Try<Isolator*> NvidiaGpuIsolatorProcess::create(
     const Flags& flags,
     const NvidiaComponents& components)
 {
-  // Make sure the 'cgroups/devices' isolator is present and
-  // precedes the GPU isolator.
+  // Make sure both the 'cgroups/devices' isolator and the
+  // 'filesystem/linux' isolators are present and precede the GPU
+  // isolator.
   vector<string> tokens = strings::tokenize(flags.isolation, ",");
 
   auto gpuIsolator =
     std::find(tokens.begin(), tokens.end(), "gpu/nvidia");
   auto devicesIsolator =
     std::find(tokens.begin(), tokens.end(), "cgroups/devices");
+  auto filesystemIsolator =
+    std::find(tokens.begin(), tokens.end(), "filesystem/linux");
 
   CHECK(gpuIsolator != tokens.end());
 
@@ -108,11 +111,21 @@ Try<Isolator*> NvidiaGpuIsolatorProcess::create(
                  " order to use the 'gpu/nvidia' isolator");
   }
 
+  if (filesystemIsolator == tokens.end()) {
+    return Error("The 'filesystem/linux' isolator must be enabled in"
+                 " order to use the 'gpu/nvidia' isolator");
+  }
+
   if (devicesIsolator > gpuIsolator) {
     return Error("'cgroups/devices' must precede 'gpu/nvidia'"
                  " in the --isolation flag");
   }
 
+  if (filesystemIsolator > gpuIsolator) {
+    return Error("'filesystem/linux' must precede 'gpu/nvidia'"
+                 " in the --isolation flag");
+  }
+
   // Retrieve the cgroups devices hierarchy.
   Result<string> hierarchy = cgroups::hierarchy(CGROUP_SUBSYSTEM_DEVICES_NAME);
 
@@ -329,7 +342,6 @@ Future<Option<ContainerLaunchInfo>> NvidiaGpuIsolatorProcess::_prepare(
   }
 
   ContainerLaunchInfo launchInfo;
-  launchInfo.set_clone_namespaces(CLONE_NEWNS);
 
   // Inject the Nvidia volume into the container.
   //

http://git-wip-us.apache.org/repos/asf/mesos/blob/09d42454/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp b/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
index f3438b8..8ebf2e7 100644
--- a/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
+++ b/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
@@ -79,7 +79,14 @@ Future<Option<ContainerLaunchInfo>> NamespacesPidIsolatorProcess::prepare(
     const ContainerConfig& containerConfig)
 {
   ContainerLaunchInfo launchInfo;
-  launchInfo.set_clone_namespaces(CLONE_NEWPID | CLONE_NEWNS);
+
+  if (containerId.has_parent()) {
+    // If we are a nested container, then we want to enter our
+    // parent's pid namespace before cloning a new one.
+    launchInfo.set_enter_namespaces(CLONE_NEWPID);
+  }
+
+  launchInfo.set_clone_namespaces(CLONE_NEWPID);
 
   // Mount /proc with standard options for the container's pid
   // namespace to show the container's pids (and other /proc files),

http://git-wip-us.apache.org/repos/asf/mesos/blob/09d42454/src/slave/containerizer/mesos/isolators/volume/image.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/volume/image.cpp b/src/slave/containerizer/mesos/isolators/volume/image.cpp
index ee9bd35..e954182 100644
--- a/src/slave/containerizer/mesos/isolators/volume/image.cpp
+++ b/src/slave/containerizer/mesos/isolators/volume/image.cpp
@@ -72,6 +72,15 @@ Try<Isolator*> VolumeImageIsolatorProcess::create(
     const Flags& flags,
     const Shared<Provisioner>& provisioner)
 {
+  // Make sure 'filesystem/linux' isolator is used.
+  // NOTE: 'filesystem/linux' isolator will make sure mounts in the
+  // child mount namespace will not be propagated back to the host
+  // mount namespace.
+  if (!strings::contains(flags.isolation, "filesystem/linux")) {
+    return Error("'filesystem/linux' must be enabled"
+                 " to create the volume image isolator");
+  }
+
   process::Owned<MesosIsolatorProcess> process(
       new VolumeImageIsolatorProcess(flags, provisioner));
 
@@ -180,7 +189,6 @@ Future<Option<ContainerLaunchInfo>> VolumeImageIsolatorProcess::_prepare(
     const list<Future<ProvisionInfo>>& futures)
 {
   ContainerLaunchInfo launchInfo;
-  launchInfo.set_clone_namespaces(CLONE_NEWNS);
 
   vector<string> messages;
   vector<string> sources;

http://git-wip-us.apache.org/repos/asf/mesos/blob/09d42454/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
index a6f9794..cb7aa4f 100644
--- a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
+++ b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
@@ -120,12 +120,6 @@ Future<Option<ContainerLaunchInfo>> VolumeSandboxPathIsolatorProcess::prepare(
 
   ContainerLaunchInfo launchInfo;
 
-#ifdef __linux__
-  if (bindMountSupported) {
-    launchInfo.set_clone_namespaces(CLONE_NEWNS);
-  }
-#endif // __linux__
-
   foreach (const Volume& volume, containerInfo.volumes()) {
     if (!volume.has_source() ||
         !volume.source().has_type() ||


[02/11] mesos git commit: Removed unnecessary 'parentHooks' parameter from 'Launcher::fork()'.

Posted by ji...@apache.org.
Removed unnecessary 'parentHooks' parameter from 'Launcher::fork()'.

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


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

Branch: refs/heads/master
Commit: 0f3eabcfaed5e449988c239d312f17d3b25a04ca
Parents: b15b46a
Author: Kevin Klues <kl...@gmail.com>
Authored: Fri Nov 11 16:14:35 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Nov 11 16:14:35 2016 -0800

----------------------------------------------------------------------
 src/slave/containerizer/mesos/launcher.cpp       |  5 +++--
 src/slave/containerizer/mesos/launcher.hpp       |  6 ++----
 src/slave/containerizer/mesos/linux_launcher.cpp | 14 ++++++--------
 src/slave/containerizer/mesos/linux_launcher.hpp |  3 +--
 src/tests/containerizer/launcher.cpp             |  6 +++---
 src/tests/containerizer/launcher.hpp             |  5 ++---
 6 files changed, 17 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0f3eabcf/src/slave/containerizer/mesos/launcher.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/launcher.cpp b/src/slave/containerizer/mesos/launcher.cpp
index b45313f..bc33f19 100644
--- a/src/slave/containerizer/mesos/launcher.cpp
+++ b/src/slave/containerizer/mesos/launcher.cpp
@@ -87,8 +87,7 @@ Try<pid_t> PosixLauncher::fork(
     const Subprocess::IO& err,
     const flags::FlagsBase* flags,
     const Option<map<string, string>>& environment,
-    const Option<int>& namespaces,
-    vector<process::Subprocess::ParentHook> parentHooks)
+    const Option<int>& namespaces)
 {
   if (namespaces.isSome() && namespaces.get() != 0) {
     return Error("Posix launcher does not support namespaces");
@@ -101,6 +100,8 @@ Try<pid_t> PosixLauncher::fork(
 
   // If we are on systemd, then extend the life of the child. Any
   // grandchildren's lives will also be extended.
+  vector<process::Subprocess::ParentHook> parentHooks;
+
 #ifdef __linux__
   if (systemd::enabled()) {
     parentHooks.emplace_back(Subprocess::ParentHook(

http://git-wip-us.apache.org/repos/asf/mesos/blob/0f3eabcf/src/slave/containerizer/mesos/launcher.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/launcher.hpp b/src/slave/containerizer/mesos/launcher.hpp
index 6ceb02d..c1a390a 100644
--- a/src/slave/containerizer/mesos/launcher.hpp
+++ b/src/slave/containerizer/mesos/launcher.hpp
@@ -69,8 +69,7 @@ public:
       const process::Subprocess::IO& err,
       const flags::FlagsBase* flags,
       const Option<std::map<std::string, std::string>>& environment,
-      const Option<int>& namespaces,
-      std::vector<process::Subprocess::ParentHook> parentHooks = {}) = 0;
+      const Option<int>& namespaces) = 0;
 
   // Kill all processes in the containerized context.
   virtual process::Future<Nothing> destroy(const ContainerID& containerId) = 0;
@@ -105,8 +104,7 @@ public:
       const process::Subprocess::IO& err,
       const flags::FlagsBase* flags,
       const Option<std::map<std::string, std::string>>& environment,
-      const Option<int>& namespaces,
-      std::vector<process::Subprocess::ParentHook> parentHooks = {});
+      const Option<int>& namespaces);
 
   virtual process::Future<Nothing> destroy(const ContainerID& containerId);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/0f3eabcf/src/slave/containerizer/mesos/linux_launcher.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/linux_launcher.cpp b/src/slave/containerizer/mesos/linux_launcher.cpp
index 0305d14..e96090f 100644
--- a/src/slave/containerizer/mesos/linux_launcher.cpp
+++ b/src/slave/containerizer/mesos/linux_launcher.cpp
@@ -79,8 +79,7 @@ public:
       const process::Subprocess::IO& err,
       const flags::FlagsBase* flags,
       const Option<std::map<std::string, std::string>>& environment,
-      const Option<int>& namespaces,
-      std::vector<process::Subprocess::ParentHook> parentHooks);
+      const Option<int>& namespaces);
 
   virtual process::Future<Nothing> destroy(const ContainerID& containerId);
 
@@ -211,8 +210,7 @@ Try<pid_t> LinuxLauncher::fork(
     const process::Subprocess::IO& err,
     const flags::FlagsBase* flags,
     const Option<map<string, string>>& environment,
-    const Option<int>& namespaces,
-    vector<Subprocess::ParentHook> parentHooks)
+    const Option<int>& namespaces)
 {
   return dispatch(
       process.get(),
@@ -225,8 +223,7 @@ Try<pid_t> LinuxLauncher::fork(
       err,
       flags,
       environment,
-      namespaces,
-      parentHooks).get();
+      namespaces).get();
 }
 
 
@@ -388,8 +385,7 @@ Try<pid_t> LinuxLauncherProcess::fork(
     const process::Subprocess::IO& err,
     const flags::FlagsBase* flags,
     const Option<map<string, string>>& environment,
-    const Option<int>& namespaces,
-    vector<Subprocess::ParentHook> parentHooks)
+    const Option<int>& namespaces)
 {
   // Make sure this container (nested or not) is unique.
   if (containers.contains(containerId)) {
@@ -434,6 +430,8 @@ Try<pid_t> LinuxLauncherProcess::fork(
 
   // Hook to extend the life of the child (and all of its
   // descendants) using a systemd slice.
+  vector<Subprocess::ParentHook> parentHooks;
+
   if (systemdHierarchy.isSome()) {
     parentHooks.emplace_back(Subprocess::ParentHook([](pid_t child) {
       return systemd::mesos::extendLifetime(child);

http://git-wip-us.apache.org/repos/asf/mesos/blob/0f3eabcf/src/slave/containerizer/mesos/linux_launcher.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/linux_launcher.hpp b/src/slave/containerizer/mesos/linux_launcher.hpp
index d235305..356d4de 100644
--- a/src/slave/containerizer/mesos/linux_launcher.hpp
+++ b/src/slave/containerizer/mesos/linux_launcher.hpp
@@ -51,8 +51,7 @@ public:
       const process::Subprocess::IO& err,
       const flags::FlagsBase* flags,
       const Option<std::map<std::string, std::string>>& environment,
-      const Option<int>& namespaces,
-      std::vector<process::Subprocess::ParentHook> parentHooks);
+      const Option<int>& namespaces);
 
   virtual process::Future<Nothing> destroy(const ContainerID& containerId);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/0f3eabcf/src/tests/containerizer/launcher.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/launcher.cpp b/src/tests/containerizer/launcher.cpp
index a92d989..51ae4f9 100644
--- a/src/tests/containerizer/launcher.cpp
+++ b/src/tests/containerizer/launcher.cpp
@@ -30,7 +30,7 @@ ACTION_P(InvokeRecover, launcher)
 ACTION_P(InvokeFork, launcher)
 {
   return launcher->real->fork(
-      arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+      arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
 }
 
 
@@ -51,9 +51,9 @@ TestLauncher::TestLauncher(const process::Owned<slave::Launcher>& _real)
   EXPECT_CALL(*this, recover(_))
     .WillRepeatedly(DoDefault());
 
-  ON_CALL(*this, fork(_, _, _, _, _, _, _, _, _, _))
+  ON_CALL(*this, fork(_, _, _, _, _, _, _, _, _))
     .WillByDefault(InvokeFork(this));
-  EXPECT_CALL(*this, fork(_, _, _, _, _, _, _, _, _, _))
+  EXPECT_CALL(*this, fork(_, _, _, _, _, _, _, _, _))
     .WillRepeatedly(DoDefault());
 
   ON_CALL(*this, destroy(_))

http://git-wip-us.apache.org/repos/asf/mesos/blob/0f3eabcf/src/tests/containerizer/launcher.hpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/launcher.hpp b/src/tests/containerizer/launcher.hpp
index 773b458..5dcc391 100644
--- a/src/tests/containerizer/launcher.hpp
+++ b/src/tests/containerizer/launcher.hpp
@@ -56,7 +56,7 @@ public:
       process::Future<hashset<ContainerID>>(
           const std::list<mesos::slave::ContainerState>& states));
 
-  MOCK_METHOD10(
+  MOCK_METHOD9(
       fork,
       Try<pid_t>(
           const ContainerID& containerId,
@@ -67,8 +67,7 @@ public:
           const process::Subprocess::IO& err,
           const flags::FlagsBase* flags,
           const Option<std::map<std::string, std::string>>& env,
-          const Option<int>& namespaces,
-          std::vector<process::Subprocess::ParentHook> parentHooks));
+          const Option<int>& namespaces));
 
   MOCK_METHOD1(
       destroy,


[03/11] mesos git commit: Added a flag to optionally skip the multithreaded check in setns().

Posted by ji...@apache.org.
Added a flag to optionally skip the multithreaded check in setns().

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


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

Branch: refs/heads/master
Commit: ed1b4bc62486e06a5e76922bcc2f9bd494ab01e8
Parents: 0f3eabc
Author: Kevin Klues <kl...@gmail.com>
Authored: Fri Nov 11 16:14:51 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Nov 11 18:54:07 2016 -0800

----------------------------------------------------------------------
 src/linux/ns.hpp | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/ed1b4bc6/src/linux/ns.hpp
----------------------------------------------------------------------
diff --git a/src/linux/ns.hpp b/src/linux/ns.hpp
index 76db0dc..010a1fa 100644
--- a/src/linux/ns.hpp
+++ b/src/linux/ns.hpp
@@ -154,16 +154,21 @@ inline std::set<int> nstypes()
 // allow a process with multiple threads to call this function because
 // it will lead to some weird situations where different threads of a
 // process are in different namespaces.
-inline Try<Nothing> setns(const std::string& path, const std::string& ns)
+inline Try<Nothing> setns(
+    const std::string& path,
+    const std::string& ns,
+    bool checkMultithreaded = true)
 {
-  // Return error if there're multiple threads in the calling process.
-  Try<std::set<pid_t>> threads = proc::threads(::getpid());
-  if (threads.isError()) {
-    return Error(
-        "Failed to get the threads of the current process: " +
-        threads.error());
-  } else if (threads.get().size() > 1) {
-    return Error("Multiple threads exist in the current process");
+  if (checkMultithreaded) {
+    // Return error if there're multiple threads in the calling process.
+    Try<std::set<pid_t>> threads = proc::threads(::getpid());
+    if (threads.isError()) {
+      return Error(
+          "Failed to get the threads of the current process: " +
+          threads.error());
+    } else if (threads.get().size() > 1) {
+      return Error("Multiple threads exist in the current process");
+    }
   }
 
   if (ns::namespaces().count(ns) == 0) {


[08/11] mesos git commit: Updated namespace isolators to customize based on 'ContainerClass'.

Posted by ji...@apache.org.
Updated namespace isolators to customize based on 'ContainerClass'.

The namespace-related isolators now do different things depending on
whether they are launching a "normal" nested container or a "debug"
nested container. Normal nested containers clone a new mount namespace
as well as a new pid namespace. Debug nested cotnainers do not -- they
simply inherit these namespaces from their parent.

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


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

Branch: refs/heads/master
Commit: 0dafc55529e386e97e6384e1b8e5a19a84899b63
Parents: a012efa
Author: Kevin Klues <kl...@gmail.com>
Authored: Fri Nov 11 17:01:23 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Nov 11 18:54:11 2016 -0800

----------------------------------------------------------------------
 src/slave/containerizer/mesos/containerizer.cpp |   6 -
 .../mesos/isolators/filesystem/linux.cpp        |  24 ++++
 .../mesos/isolators/gpu/isolator.cpp            |  21 +++-
 .../mesos/isolators/namespaces/pid.cpp          |   9 ++
 .../mesos/isolators/network/cni/cni.cpp         |  56 ++++++---
 .../mesos/isolators/volume/image.cpp            |   6 +
 .../mesos/isolators/volume/sandbox_path.cpp     |   7 ++
 .../containerizer/mesos/linux_launcher.cpp      |   6 +
 .../nested_mesos_containerizer_tests.cpp        | 117 +++++++++++++++++++
 9 files changed, 225 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0dafc555/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index 3c3bee4..2741497 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -1230,12 +1230,6 @@ Future<bool> MesosContainerizerProcess::_launch(
   Option<int> enterNamespaces = None();
   Option<int> cloneNamespaces = None();
 
-  // TODO(klueska): Remove the following once we update
-  // isolators to fill enterNamespaces for us.
-  if (containerId.has_parent()) {
-    enterNamespaces = CLONE_NEWUTS | CLONE_NEWNET | CLONE_NEWPID;
-  }
-
   CHECK_READY(container->launchInfos);
 
   foreach (const Option<ContainerLaunchInfo>& launchInfo,

http://git-wip-us.apache.org/repos/asf/mesos/blob/0dafc555/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 6535375..8f024d0 100644
--- a/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
+++ b/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
@@ -53,6 +53,7 @@ using std::ostringstream;
 using std::string;
 using std::vector;
 
+using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerState;
 using mesos::slave::ContainerLaunchInfo;
@@ -307,6 +308,29 @@ Future<Option<ContainerLaunchInfo>> LinuxFilesystemIsolatorProcess::prepare(
     const ContainerID& containerId,
     const ContainerConfig& containerConfig)
 {
+  // If we are a nested container in the `DEBUG` class, then we only
+  // use this isolator to indicate that we should enter our parent's
+  // MOUNT namespace. We don't want to clone a new MOUNT namespace or
+  // run any new pre-exec commands in it. For now, we also don't
+  // support provisioning a new filesystem or setting a `rootfs` for
+  // the container. We also don't support mounting any volumes.
+  if (containerId.has_parent() &&
+      containerConfig.has_container_class() &&
+      containerConfig.container_class() == ContainerClass::DEBUG) {
+    if (containerConfig.has_rootfs()) {
+      return Failure("A 'rootfs' cannot be set for DEBUG containers");
+    }
+
+    if (containerConfig.has_container_info() &&
+        containerConfig.container_info().volumes().size() > 0) {
+      return Failure("Volumes not supported for DEBUG containers");
+    }
+
+    ContainerLaunchInfo launchInfo;
+    launchInfo.set_enter_namespaces(CLONE_NEWNS);
+    return launchInfo;
+  }
+
   if (infos.contains(containerId)) {
     return Failure("Container has already been prepared");
   }

http://git-wip-us.apache.org/repos/asf/mesos/blob/0dafc555/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp b/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
index a3a140d..a3b9fe7 100644
--- a/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
+++ b/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
@@ -53,6 +53,7 @@ using cgroups::devices::Entry;
 
 using docker::spec::v1::ImageManifest;
 
+using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::ContainerLimitation;
@@ -283,13 +284,21 @@ Future<Option<ContainerLaunchInfo>> NvidiaGpuIsolatorProcess::prepare(
     const ContainerID& containerId,
     const mesos::slave::ContainerConfig& containerConfig)
 {
-  // If we are a nested container, we don't need to maintain an `Info()`
-  // struct about the container since we don't allocate GPUs to it
-  // directly (we only allocate GPUs to top-level containers, and they
-  // automatically get shared by nested containers).  However, we do
-  // still need to mount the necessary Nvidia libraries into the
-  // container. We call `_prepare()` directly to do this for us.
   if (containerId.has_parent()) {
+    // If we are a nested container in the `DEBUG` class, then we
+    // don't need to do anything special to prepare ourselves for GPU
+    // support. All Nvidia volumes will be inherited from our parent.
+    if (containerConfig.has_container_class() &&
+        containerConfig.container_class() == ContainerClass::DEBUG) {
+      return None();
+    }
+
+    // If we are a nested container in a different class, we don't
+    // need to maintain an `Info()` struct about the container (since
+    // we don't directly allocate any GPUs to it), but we do need to
+    // mount the necessary Nvidia libraries into the container (since
+    // we live in a different mount namespace than our parent). We
+    // directly call `_prepare()` to do this for us.
     return _prepare(containerConfig);
   }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/0dafc555/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp b/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
index 8ebf2e7..5bf5ffb 100644
--- a/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
+++ b/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
@@ -25,6 +25,7 @@
 using process::Future;
 using process::Owned;
 
+using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::Isolator;
@@ -84,6 +85,14 @@ Future<Option<ContainerLaunchInfo>> NamespacesPidIsolatorProcess::prepare(
     // If we are a nested container, then we want to enter our
     // parent's pid namespace before cloning a new one.
     launchInfo.set_enter_namespaces(CLONE_NEWPID);
+
+    // However, if we are a nested container in the `DEBUG` class,
+    // then we don't want to clone a new PID namespace at all, so we
+    // short cirucuit here.
+    if (containerConfig.has_container_class() &&
+        containerConfig.container_class() == ContainerClass::DEBUG) {
+      return launchInfo;
+    }
   }
 
   launchInfo.set_clone_namespaces(CLONE_NEWPID);

http://git-wip-us.apache.org/repos/asf/mesos/blob/0dafc555/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp b/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
index 74bb6eb..3b2d4db 100644
--- a/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
+++ b/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
@@ -54,6 +54,7 @@ using process::Owned;
 using process::PID;
 using process::Subprocess;
 
+using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::ContainerLimitation;
@@ -590,6 +591,8 @@ Future<Option<ContainerLaunchInfo>> NetworkCniIsolatorProcess::prepare(
   // * Cases where the containers don't need a new mount namespace:
   //    a) Containers (nested or stand alone) join the host network
   //       without an image.
+  //    b) Nested DEBUG containers join the same mount namespace as
+  //       their parent.
   // * Cases where the container needs a new mount namespace:
   //    a) Containers (nested or stand alone) join the host network
   //       with an image.
@@ -610,19 +613,40 @@ Future<Option<ContainerLaunchInfo>> NetworkCniIsolatorProcess::prepare(
       infos.put(containerId, info);
     }
 
-    // NOTE: No additional namespace needed. The container shares the
-    // same network and UTS namesapces with the host. If container has
-    // a rootfs, the filesystem/linux isolator will put the container
-    // in a new mount namespace.
+    // NOTE: No additional namespaces needed. The container shares the
+    // same network and UTS namespaces with the host. If the container
+    // has a rootfs, the filesystem/linux isolator will put the
+    // container in a new mount namespace. If the *parent* container
+    // has a rootfs, the filesystem/linux isolator will properly set
+    // the MNT namespace to enter. If the parent does not have a
+    // rootfs, it will join the host network and there are no
+    // namespaces it needs to enter.
     return None();
   } else {
     // This is the case where the container is joining a non-host
-    // network namespace.
-    if (containerConfig.has_rootfs()) {
-      Owned<Info> info(new Info(containerNetworks, containerConfig.rootfs()));
-      infos.put(containerId, info);
+    // network namespace. Non-DEBUG containers will need a new mount
+    // namespaces to bind mount their network files (/etc/hosts,
+    // /etc/hostname, /etc/resolv.conf) which will be different than
+    // those on the host file system.
+    //
+    // Unlike other isolators, we can't simply rely on the
+    // `filesystem/linux` isolator to give this container a new
+    // mount namespace (because we allow the `filesystem/posix`
+    // isolator to be used here). We must set the clone flags
+    // ourselves explicitly.
+
+    if (containerId.has_parent() &&
+        containerConfig.has_container_class() &&
+        containerConfig.container_class() == ContainerClass::DEBUG) {
+      // Nested DEBUG containers never need a new MOUNT namespace, so
+      // we don't mantain information about them in the `infos` map.
     } else {
-      infos.put(containerId, Owned<Info>(new Info(containerNetworks)));
+      if (containerConfig.has_rootfs()) {
+        Owned<Info> info(new Info(containerNetworks, containerConfig.rootfs()));
+        infos.put(containerId, info);
+      } else {
+        infos.put(containerId, Owned<Info>(new Info(containerNetworks)));
+      }
     }
 
     ContainerLaunchInfo launchInfo;
@@ -659,12 +683,14 @@ Future<Option<ContainerLaunchInfo>> NetworkCniIsolatorProcess::prepare(
       }
     } else {
       // This is a nested container. This shares the parent's network
-      // and UTS namespace. We still need to give this container a new
-      // mount namespace since its joining a non-host network and
-      // therefore we will need to bind mount its network files
-      // (/etc/hosts, /etc/hostname, /etc/resolv.conf) which will be
-      // different than those on the host file system.
-      launchInfo.set_clone_namespaces(CLONE_NEWNS);
+      // and UTS namespace. For non-DEBUG containers it also needs a
+      // new mount namespace.
+      launchInfo.set_enter_namespaces(CLONE_NEWNET | CLONE_NEWUTS);
+
+      if (!containerConfig.has_container_class() ||
+          containerConfig.container_class() != ContainerClass::DEBUG) {
+        launchInfo.set_clone_namespaces(CLONE_NEWNS);
+      }
     }
 
     return launchInfo;

http://git-wip-us.apache.org/repos/asf/mesos/blob/0dafc555/src/slave/containerizer/mesos/isolators/volume/image.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/volume/image.cpp b/src/slave/containerizer/mesos/isolators/volume/image.cpp
index e954182..c89af3e 100644
--- a/src/slave/containerizer/mesos/isolators/volume/image.cpp
+++ b/src/slave/containerizer/mesos/isolators/volume/image.cpp
@@ -43,6 +43,7 @@ using process::Owned;
 using process::PID;
 using process::Shared;
 
+using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::Isolator;
@@ -110,6 +111,11 @@ Future<Option<ContainerLaunchInfo>> VolumeImageIsolatorProcess::prepare(
       continue;
     }
 
+    if (containerConfig.has_container_class() &&
+        containerConfig.container_class() == ContainerClass::DEBUG) {
+      return Failure("Image volume is not supported for DEBUG containers");
+    }
+
     // Determine the target of the mount. The mount target
     // is determined by 'container_path'.
     string target;

http://git-wip-us.apache.org/repos/asf/mesos/blob/0dafc555/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
index cb7aa4f..6f7304d 100644
--- a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
+++ b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
@@ -36,6 +36,7 @@ using process::Failure;
 using process::Future;
 using process::Owned;
 
+using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::ContainerState;
@@ -127,6 +128,12 @@ Future<Option<ContainerLaunchInfo>> VolumeSandboxPathIsolatorProcess::prepare(
       continue;
     }
 
+    if (containerConfig.has_container_class() &&
+        containerConfig.container_class() == ContainerClass::DEBUG) {
+      return Failure(
+          "SANDBOX_PATH volume is not supported for DEBUG containers");
+    }
+
     if (!volume.source().has_sandbox_path()) {
       return Failure("volume.source.sandbox_path is not specified");
     }

http://git-wip-us.apache.org/repos/asf/mesos/blob/0dafc555/src/slave/containerizer/mesos/linux_launcher.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/linux_launcher.cpp b/src/slave/containerizer/mesos/linux_launcher.cpp
index 2c55d7b..a3409dc 100644
--- a/src/slave/containerizer/mesos/linux_launcher.cpp
+++ b/src/slave/containerizer/mesos/linux_launcher.cpp
@@ -416,6 +416,12 @@ Try<pid_t> LinuxLauncherProcess::fork(
     target = container->pid.get();
   }
 
+  // Ensure we didn't pass `enterNamespaces`
+  // if we aren't forking a nested contiainer.
+  if (!containerId.has_parent() && enterNamespaces.isSome()) {
+    return Error("Cannot enter parent namespaces for non-nested container");
+  }
+
   int enterFlags = enterNamespaces.isSome() ? enterNamespaces.get() : 0;
 
   int cloneFlags = cloneNamespaces.isSome() ? cloneNamespaces.get() : 0;

http://git-wip-us.apache.org/repos/asf/mesos/blob/0dafc555/src/tests/containerizer/nested_mesos_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/nested_mesos_containerizer_tests.cpp b/src/tests/containerizer/nested_mesos_containerizer_tests.cpp
index e6c690c..20bc9d5 100644
--- a/src/tests/containerizer/nested_mesos_containerizer_tests.cpp
+++ b/src/tests/containerizer/nested_mesos_containerizer_tests.cpp
@@ -58,6 +58,7 @@ using mesos::internal::slave::state::FrameworkState;
 using mesos::internal::slave::state::RunState;
 using mesos::internal::slave::state::SlaveState;
 
+using mesos::slave::ContainerClass;
 using mesos::slave::ContainerState;
 using mesos::slave::ContainerTermination;
 
@@ -232,6 +233,122 @@ TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_LaunchNested)
 }
 
 
+TEST_F(NestedMesosContainerizerTest,
+       ROOT_CGROUPS_LaunchNestedDebugCheckPidNamespace)
+{
+  slave::Flags flags = CreateSlaveFlags();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> create = MesosContainerizer::create(
+      flags,
+      true,
+      &fetcher);
+
+  ASSERT_SOME(create);
+
+  Owned<MesosContainerizer> containerizer(create.get());
+
+  SlaveState state;
+  state.id = SlaveID();
+
+  AWAIT_READY(containerizer->recover(state));
+
+  ContainerID containerId;
+  containerId.set_value(UUID::random().toString());
+
+  Try<string> directory = environment->mkdtemp();
+  ASSERT_SOME(directory);
+
+  Future<bool> launch = containerizer->launch(
+      containerId,
+      None(),
+      createExecutorInfo("executor", "sleep 1000", "cpus:1"),
+      directory.get(),
+      None(),
+      state.id,
+      map<string, string>(),
+      true); // TODO(benh): Ever want to test not checkpointing?
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  // Now launch nested container.
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(containerId);
+  nestedContainerId.set_value(UUID::random().toString());
+
+  // Launch the nested container with the `ps | wc -l` command and
+  // launch the container without a `ContainerClass`.  With this
+  // default setting, we should request to clone a new PID namespace.
+  //
+  // We expect to see exactly 6 lines of output from `ps`.
+  //
+  // 1) The 'ps' header
+  // 2) The init process of the container (i.e. `mesos-containerizer`).
+  // 3) The executor of the container (i.e. `mesos-executor`).
+  // 4) `sh`
+  // 5) `wc -l`
+  // 6) `ps`
+  launch = containerizer->launch(
+      nestedContainerId,
+      createCommandInfo(
+          "PS_LINES=`ps | wc -l`;"
+          "if [ ${PS_LINES} -ne 6 ]; then"
+          "  exit ${PS_LINES};"
+          "fi;"),
+      None(),
+      None(),
+      state.id);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<Option<ContainerTermination>> wait = containerizer->wait(
+      nestedContainerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WEXITSTATUS_EQ(0, wait.get()->status());
+
+  // Relaunch the nested container with the `ps | wc -l` command and
+  // set the container class as `DEBUG`.  In this class, we don't
+  // clone a new PID namespace.
+  //
+  // We expect to see much more than 6 lines of output from `ps`.
+  launch = containerizer->launch(
+      nestedContainerId,
+      createCommandInfo(
+          "PS_LINES=`ps | wc -l`;"
+          "if [ ${PS_LINES} -le 6 ]; then"
+          "  exit ${PS_LINES};"
+          "fi;"),
+      None(),
+      None(),
+      state.id,
+      ContainerClass::DEBUG);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  wait = containerizer->wait(nestedContainerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WEXITSTATUS_EQ(0, wait.get()->status());
+
+  wait = containerizer->wait(containerId);
+
+  containerizer->destroy(containerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WTERMSIG_EQ(SIGKILL, wait.get()->status());
+}
+
+
 TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_DestroyNested)
 {
   slave::Flags flags = CreateSlaveFlags();


[11/11] mesos git commit: Added special case for entering "mnt" namespaces for DEBUG containers.

Posted by ji...@apache.org.
Added special case for entering "mnt" namespaces for DEBUG containers.

Until we switch over to the default (a.k.a. "pod" executor) for
launching command tasks, we need to special case which `pid` we use
for entering the `mnt` namespace of a parent container.  Specifically,
we need to enter the `mnt` namespace of the process representing the
command task itself, not the `mnt` namespace of the `init` process of
the container or the `executor` of the container because these run in
the same `mnt` namespace as the agent (not the task).

Unfortunately, there is no easy way to get the `pid` of tasks launched
with the command executor because we only checkpoint the `pid` of the
`init` process of these containers. For now, we compensate for this by
simply walking the process tree from the container's `init` process up
to 2-levels down (where the task process would exist) and look to see
if any process along the way has a different `mnt` namespace. If it
does, we return a reference to its `pid` as the `pid` for entering the
`mnt` namespace of the container.  Otherwise, we return the `init`
process's `pid`.

We then pass this pid to the `mesos-containerizer launch` binary and
have it set the namespace, rather than letting the `ns::clone()` call
do it for us. This is important because otherwise we wouldn't be able
to find the `mesos-containerizer launch` itself (it only exists in the
host mount namespace!).

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


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

Branch: refs/heads/master
Commit: 757d2804d09da457103e67c843fdcebf52016097
Parents: 781b968
Author: Kevin Klues <kl...@gmail.com>
Authored: Fri Nov 11 18:32:07 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Nov 11 18:54:11 2016 -0800

----------------------------------------------------------------------
 src/slave/containerizer/mesos/containerizer.cpp |  68 +++++++++--
 src/slave/containerizer/mesos/launch.cpp        |  20 ++++
 src/slave/containerizer/mesos/launch.hpp        |   1 +
 src/slave/containerizer/mesos/utils.cpp         |  90 ++++++++++++++
 src/slave/containerizer/mesos/utils.hpp         |   7 ++
 .../nested_mesos_containerizer_tests.cpp        | 119 +++++++++++++++++++
 6 files changed, 293 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/757d2804/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index 2741497..ec4ae32 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -1201,16 +1201,21 @@ Future<bool> MesosContainerizerProcess::_launch(
     environment.values[key] = value;
   }
 
-  // TODO(jieyu): Consider moving this to 'executorEnvironment' and
-  // consolidating with docker containerizer.
-  //
-  // NOTE: For the command executor case, although it uses the host
-  // filesystem for itself, we still set 'MESOS_SANDBOX' according to
-  // the root filesystem of the task (if specified). Command executor
-  // itself does not use this environment variable.
-  environment.values["MESOS_SANDBOX"] = container->config.has_rootfs()
-    ? flags.sandbox_directory
-    : container->config.directory();
+  // TODO(klueska): Remove the check below once we have a good way of
+  // setting the sandbox directory for DEBUG containers.
+  if (!container->config.has_container_class() ||
+       container->config.container_class() != ContainerClass::DEBUG) {
+    // TODO(jieyu): Consider moving this to 'executorEnvironment' and
+    // consolidating with docker containerizer.
+    //
+    // NOTE: For the command executor case, although it uses the host
+    // filesystem for itself, we still set 'MESOS_SANDBOX' according to
+    // the root filesystem of the task (if specified). Command executor
+    // itself does not use this environment variable.
+    environment.values["MESOS_SANDBOX"] = container->config.has_rootfs()
+      ? flags.sandbox_directory
+      : container->config.directory();
+  }
 
   // NOTE: Command task is a special case. Even if the container
   // config has a root filesystem, the executor container still uses
@@ -1428,7 +1433,15 @@ Future<bool> MesosContainerizerProcess::_launch(
                      << "host filesystem";
       }
 
-      launchFlags.working_directory = container->config.directory();
+      // TODO(klueska): Debug containers should set their working
+      // directory to their sandbox directory (once we know how to set
+      // that properly).
+      if (container->config.has_container_class() &&
+          container->config.container_class() == ContainerClass::DEBUG) {
+        launchFlags.working_directory = None();
+      } else {
+        launchFlags.working_directory = container->config.directory();
+      }
     } else {
       launchFlags.working_directory = workingDirectory.isSome()
         ? workingDirectory
@@ -1493,6 +1506,37 @@ Future<bool> MesosContainerizerProcess::_launch(
     VLOG(1) << "Launching '" << MESOS_CONTAINERIZER << "' with flags '"
             << launchFlags << "'";
 
+    // For now we need to special case entering a parent container's
+    // mount namespace. We do this to ensure that we have access to
+    // the binary we launch with `launcher->fork()`.
+    //
+    // TODO(klueska): Remove this special case once we pull
+    // the container's `init` process out of its container.
+    Option<int> _enterNamespaces = enterNamespaces;
+
+#ifdef __linux__
+    if (enterNamespaces.isSome() && (enterNamespaces.get() & CLONE_NEWNS)) {
+      CHECK(containerId.has_parent());
+      if (!containers_.contains(containerId.parent())) {
+        return Failure("Unknown parent container");
+      }
+      if (containers_.at(containerId.parent())->pid.isNone()) {
+        return Failure("Unknown parent container pid");
+      }
+
+      pid_t parentPid = containers_.at(containerId.parent())->pid.get();
+
+      Try<pid_t> mountNamespaceTarget = getMountNamespaceTarget(parentPid);
+      if (mountNamespaceTarget.isError()) {
+        return Failure("Cannot get target mount namespace from process"
+                       " '" + stringify(parentPid) + "'");
+      }
+
+      launchFlags.namespace_mnt_target = mountNamespaceTarget.get();
+      _enterNamespaces = enterNamespaces.get() & ~CLONE_NEWNS;
+    }
+#endif // __linux__
+
     // Fork the child using launcher.
     vector<string> argv(2);
     argv[0] = MESOS_CONTAINERIZER;
@@ -1510,7 +1554,7 @@ Future<bool> MesosContainerizerProcess::_launch(
         &launchFlags,
         launchEnvironment,
         // 'enterNamespaces' will be ignored by PosixLauncher.
-        enterNamespaces,
+        _enterNamespaces,
         // 'cloneNamespaces' will be ignored by PosixLauncher.
         cloneNamespaces);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/757d2804/src/slave/containerizer/mesos/launch.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/launch.cpp b/src/slave/containerizer/mesos/launch.cpp
index 181d833..320e427 100644
--- a/src/slave/containerizer/mesos/launch.cpp
+++ b/src/slave/containerizer/mesos/launch.cpp
@@ -146,6 +146,11 @@ MesosContainerizerLaunch::Flags::Flags()
       "capabilities",
       "Capabilities the command can use.");
 
+  add(&Flags::namespace_mnt_target,
+      "namespace_mnt_target",
+      "The target 'pid' of the process whose mount namespace we'd like\n"
+      "to enter before executing the command.");
+
   add(&Flags::unshare_namespace_mnt,
       "unshare_namespace_mnt",
       "Whether to launch the command in a new mount namespace.",
@@ -391,6 +396,21 @@ int MesosContainerizerLaunch::execute()
   }
 
 #ifdef __linux__
+  if (flags.namespace_mnt_target.isSome()) {
+    string path = path::join(
+        "/proc",
+        stringify(flags.namespace_mnt_target.get()),
+        "ns",
+        "mnt");
+
+    Try<Nothing> setns = ns::setns(path, "mnt", false);
+    if (setns.isError()) {
+      cerr << "Failed to enter mount namespace: "
+           << setns.error() << endl;
+      exitWithStatus(EXIT_FAILURE);
+    }
+  }
+
   if (flags.unshare_namespace_mnt) {
     if (unshare(CLONE_NEWNS) != 0) {
       cerr << "Failed to unshare mount namespace: "

http://git-wip-us.apache.org/repos/asf/mesos/blob/757d2804/src/slave/containerizer/mesos/launch.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/launch.hpp b/src/slave/containerizer/mesos/launch.hpp
index 8b23c1b..155e3c5 100644
--- a/src/slave/containerizer/mesos/launch.hpp
+++ b/src/slave/containerizer/mesos/launch.hpp
@@ -52,6 +52,7 @@ public:
     Option<JSON::Array> pre_exec_commands;
 #ifdef __linux__
     Option<CapabilityInfo> capabilities;
+    Option<pid_t> namespace_mnt_target;
     bool unshare_namespace_mnt;
 #endif // __linux__
   };

http://git-wip-us.apache.org/repos/asf/mesos/blob/757d2804/src/slave/containerizer/mesos/utils.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/utils.cpp b/src/slave/containerizer/mesos/utils.cpp
index 237aea4..4e2a014 100644
--- a/src/slave/containerizer/mesos/utils.cpp
+++ b/src/slave/containerizer/mesos/utils.cpp
@@ -14,8 +14,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <set>
+
+#include <stout/os.hpp>
+#include <stout/try.hpp>
+
+#ifdef __linux__
+#include "linux/ns.hpp"
+#endif // __linux__
+
 #include "slave/containerizer/mesos/utils.hpp"
 
+using std::set;
+
 namespace mesos {
 namespace internal {
 namespace slave {
@@ -35,6 +46,85 @@ ContainerID getRootContainerId(const ContainerID& containerId)
   return rootContainerId;
 }
 
+
+#ifdef __linux__
+// This function can be used to find a new target `pid` for entering
+// the `mnt` namespace of a container (if necessary).
+//
+// Until we switch over to the default (a.k.a. "pod" executor) for
+// launching command tasks, we need to special case which `pid` we
+// use for entering the `mnt` namespace of a parent container.
+// Specifically, we need to enter the `mnt` namespace of the
+// process representing the command task itself, not the `mnt`
+// namespace of the `init` process of the container or the
+// `executor` of the container because these run in the same `mnt`
+// namespace as the agent (not the task).
+//
+// Unfortunately, there is no easy way to get the `pid` of tasks
+// launched with the command executor because we only checkpoint the
+// `pid` of the `init` process of these containers. For now, we
+// compensate for this by simply walking the process tree from the
+// container's `init` process up to 2-levels down (where the task
+// process would exist) and look to see if any process along the way
+// has a different `mnt` namespace. If it does, we return a reference
+// to its `pid` as the `pid` for entering the `mnt` namespace of the
+// container.  Otherwise, we return the `init` process's `pid`.
+//
+// TODO(klueska): Remove this function once we start launching command
+// tasks with the default (a.k.a. "pod" executor).
+Try<pid_t> getMountNamespaceTarget(pid_t parent)
+{
+  Try<ino_t> parentNamespace = ns::getns(parent, "mnt");
+  if (parentNamespace.isError()) {
+    return Error("Cannot get 'mnt' namespace for"
+                 " process '" + stringify(parent) + "'");
+  }
+
+  // Search for a new mount namespace in all direct children.
+  Try<set<pid_t>> children = os::children(parent, false);
+  if (children.isError()) {
+    return Error("Cannot get children for process"
+                 " '" + stringify(parent) + "'");
+  }
+
+  foreach (pid_t child, children.get()) {
+    Try<ino_t> childNamespace = ns::getns(child, "mnt");
+    if (childNamespace.isError()) {
+      return Error("Cannot get 'mnt' namespace for"
+                   " child process '" + stringify(child) + "'");
+    }
+
+    if (parentNamespace.get() != childNamespace.get()) {
+      return child;
+    }
+  }
+
+  // Search for a new mount namespace in all 2nd-level children.
+  foreach (pid_t child, children.get()) {
+    Try<set<pid_t>> children2 = os::children(child, false);
+    if (children2.isError()) {
+      return Error("Cannot get 2nd-level children for process"
+                   " '" + stringify(parent) + "' with child"
+                   " '" + stringify(child) + "'");
+    }
+
+    foreach (pid_t child2, children2.get()) {
+      Try<ino_t> child2Namespace = ns::getns(child2, "mnt");
+      if (child2Namespace.isError()) {
+        return Error("Cannot get 'mnt' namespace for 2nd-level"
+                     " child process '" + stringify(child2) + "'");
+      }
+
+      if (parentNamespace.get() != child2Namespace.get()) {
+        return child2;
+      }
+    }
+  }
+
+  return parent;
+}
+#endif // __linux__
+
 } // namespace slave {
 } // namespace internal {
 } // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/757d2804/src/slave/containerizer/mesos/utils.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/utils.hpp b/src/slave/containerizer/mesos/utils.hpp
index f24215b..a54106d 100644
--- a/src/slave/containerizer/mesos/utils.hpp
+++ b/src/slave/containerizer/mesos/utils.hpp
@@ -19,12 +19,19 @@
 
 #include <mesos/mesos.hpp>
 
+#include <stout/os.hpp>
+#include <stout/try.hpp>
+
 namespace mesos {
 namespace internal {
 namespace slave {
 
 ContainerID getRootContainerId(const ContainerID& containerId);
 
+#ifdef __linux__
+Try<pid_t> getMountNamespaceTarget(pid_t parent);
+#endif // __linux__
+
 } // namespace slave {
 } // namespace internal {
 } // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/757d2804/src/tests/containerizer/nested_mesos_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/nested_mesos_containerizer_tests.cpp b/src/tests/containerizer/nested_mesos_containerizer_tests.cpp
index 20bc9d5..6c341e1 100644
--- a/src/tests/containerizer/nested_mesos_containerizer_tests.cpp
+++ b/src/tests/containerizer/nested_mesos_containerizer_tests.cpp
@@ -58,6 +58,8 @@ using mesos::internal::slave::state::FrameworkState;
 using mesos::internal::slave::state::RunState;
 using mesos::internal::slave::state::SlaveState;
 
+using mesos::master::detector::MasterDetector;
+
 using mesos::slave::ContainerClass;
 using mesos::slave::ContainerState;
 using mesos::slave::ContainerTermination;
@@ -349,6 +351,123 @@ TEST_F(NestedMesosContainerizerTest,
 }
 
 
+TEST_F(NestedMesosContainerizerTest,
+       ROOT_CGROUPS_CURL_INTERNET_LaunchNestedDebugCheckMntNamespace)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "docker/runtime,filesystem/linux,namespaces/pid";
+  flags.image_providers = "docker";
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Fetcher fetcher;
+
+  Try<MesosContainerizer*> _containerizer =
+    MesosContainerizer::create(flags, true, &fetcher);
+  ASSERT_SOME(_containerizer);
+
+  Owned<MesosContainerizer> containerizer(_containerizer.get());
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(
+      detector.get(),
+      containerizer.get());
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
+
+  Future<Nothing> schedRegistered;
+  EXPECT_CALL(sched, registered(_, _, _))
+    .WillOnce(FutureSatisfy(&schedRegistered));
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(_, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return());      // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(schedRegistered);
+
+  AWAIT_READY(offers);
+  ASSERT_EQ(1u, offers->size());
+
+  // Use a pipe to synchronize with the top-level container.
+  int pipes[2] = {-1, -1};
+  ASSERT_SOME(os::pipe(pipes));
+
+  // Launch a command task within the `alpine` docker image and
+  // synchronize its launch with the launch of a debug container below.
+  TaskInfo task = createTask(
+      offers->front().slave_id(),
+      offers->front().resources(),
+      "echo running >&" + stringify(pipes[1]) + ";" + "sleep 1000");
+
+  task.mutable_container()->CopyFrom(createContainerInfo("alpine"));
+
+  Future<TaskStatus> statusRunning;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillOnce(FutureArg<1>(&statusRunning));
+
+  driver.launchTasks(offers->at(0).id(), {task});
+
+  // We wait wait up to 120 seconds
+  // to download the docker image.
+  AWAIT_READY_FOR(statusRunning, Seconds(120));
+  ASSERT_EQ(TASK_RUNNING, statusRunning->state());
+
+  close(pipes[1]);
+
+  // Wait for the parent container to start running its task
+  // before launching a debug container inside it.
+  AWAIT_READY(process::io::poll(pipes[0], process::io::READ));
+  close(pipes[0]);
+
+  ASSERT_TRUE(statusRunning->has_slave_id());
+  ASSERT_TRUE(statusRunning->has_container_status());
+  ASSERT_TRUE(statusRunning->container_status().has_container_id());
+
+  // Launch a nested debug container.
+  ContainerID nestedContainerId;
+  nestedContainerId.mutable_parent()->CopyFrom(
+      statusRunning->container_status().container_id());
+  nestedContainerId.set_value(UUID::random().toString());
+
+  // Launch a debug container inside the command task and check for
+  // the existence of a file we know to be inside the `alpine` docker
+  // image (but not on the host filesystem).
+  Future<bool> launch = containerizer->launch(
+      nestedContainerId,
+      createCommandInfo(
+          "LINES=`ls -la /etc/alpine-release | wc -l`;"
+          "if [ ${LINES} -ne 1 ]; then"
+          "  exit 1;"
+          "fi;"),
+      None(),
+      None(),
+      statusRunning->slave_id(),
+      ContainerClass::DEBUG);
+
+  AWAIT_ASSERT_TRUE(launch);
+
+  Future<Option<ContainerTermination>> wait =
+    containerizer->wait(nestedContainerId);
+
+  AWAIT_READY(wait);
+  ASSERT_SOME(wait.get());
+  ASSERT_TRUE(wait.get()->has_status());
+  EXPECT_WEXITSTATUS_EQ(0, wait.get()->status());
+
+  driver.stop();
+  driver.join();
+}
+
+
 TEST_F(NestedMesosContainerizerTest, ROOT_CGROUPS_DestroyNested)
 {
   slave::Flags flags = CreateSlaveFlags();


[10/11] mesos git commit: Introduced a new 'DEBUG' container class.

Posted by ji...@apache.org.
Introduced a new 'DEBUG' container class.

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


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

Branch: refs/heads/master
Commit: a012efa0b57f0199b7ed54b12e9c522d695e09aa
Parents: 09d4245
Author: Kevin Klues <kl...@gmail.com>
Authored: Fri Nov 11 16:53:07 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Nov 11 18:54:11 2016 -0800

----------------------------------------------------------------------
 include/mesos/slave/containerizer.proto | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/a012efa0/include/mesos/slave/containerizer.proto
----------------------------------------------------------------------
diff --git a/include/mesos/slave/containerizer.proto b/include/mesos/slave/containerizer.proto
index c9fcc24..2621522 100644
--- a/include/mesos/slave/containerizer.proto
+++ b/include/mesos/slave/containerizer.proto
@@ -30,6 +30,7 @@ import "mesos/docker/v1.proto";
  */
 enum ContainerClass {
   DEFAULT = 1;
+  DEBUG = 2;
 }
 
 


[06/11] mesos git commit: Updated 'LinuxLauncher->fork()` with *enter* and *clone* namespaces.

Posted by ji...@apache.org.
Updated 'LinuxLauncher->fork()` with *enter* and *clone* namespaces.

Instead of only taking the namespaces to *clone* inside a newly forked
container, 'LinuxLauncher->fork()' now takes a list of namespaces to
enter inside a parent container before forking. When both an *enter*
and a *clone* for the same namespace are passed, we will first enter
the namespace of the parent, and then clone a new one.

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


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

Branch: refs/heads/master
Commit: 329f3ea90ee9b4c49f7a35af76065b19dadedceb
Parents: 727ce3d
Author: Kevin Klues <kl...@gmail.com>
Authored: Fri Nov 11 16:20:25 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Nov 11 18:54:11 2016 -0800

----------------------------------------------------------------------
 include/mesos/slave/containerizer.proto         |  8 ++++--
 src/slave/containerizer/mesos/containerizer.cpp | 30 ++++++++++++++++----
 .../mesos/isolators/docker/volume/isolator.cpp  |  2 +-
 .../mesos/isolators/filesystem/linux.cpp        |  2 +-
 .../mesos/isolators/filesystem/shared.cpp       |  2 +-
 .../mesos/isolators/gpu/isolator.cpp            |  2 +-
 .../mesos/isolators/namespaces/pid.cpp          |  2 +-
 .../mesos/isolators/network/cni/cni.cpp         |  9 ++++--
 .../mesos/isolators/network/port_mapping.cpp    |  2 +-
 .../mesos/isolators/volume/image.cpp            |  2 +-
 .../mesos/isolators/volume/sandbox_path.cpp     |  2 +-
 src/slave/containerizer/mesos/launcher.cpp      | 11 +++++--
 src/slave/containerizer/mesos/launcher.hpp      |  6 ++--
 .../containerizer/mesos/linux_launcher.cpp      | 23 ++++++++-------
 .../containerizer/mesos/linux_launcher.hpp      |  3 +-
 src/tests/containerizer/isolator_tests.cpp      | 10 ++++---
 src/tests/containerizer/launcher.cpp            |  6 ++--
 src/tests/containerizer/launcher.hpp            |  5 ++--
 .../containerizer/mesos_containerizer_tests.cpp |  1 +
 src/tests/containerizer/port_mapping_tests.cpp  |  1 +
 20 files changed, 85 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/include/mesos/slave/containerizer.proto
----------------------------------------------------------------------
diff --git a/include/mesos/slave/containerizer.proto b/include/mesos/slave/containerizer.proto
index ee29468..c9fcc24 100644
--- a/include/mesos/slave/containerizer.proto
+++ b/include/mesos/slave/containerizer.proto
@@ -166,9 +166,13 @@ message ContainerLaunchInfo {
   // since 1.0.1.
   optional string rootfs = 3 [deprecated = true]; // Since 1.0.1.
 
-  // (Linux only) The namespaces required for the container.
+  // (Linux only) The namespaces a nested container
+  // should enter in its parent before cloning.
+  optional uint32 enter_namespaces = 9 [default = 0];
+
+  // (Linux only) The namespaces that should be cloned for the container.
   // The namespaces are created while launching the executor.
-  optional uint32 namespaces = 4 [default = 0];
+  optional uint32 clone_namespaces = 4 [default = 0];
 
   // If specified, it'll become the launch command for the custom
   // executor, or the launch command for the user task in the case of

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index 90f91b9..3c3bee4 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -1227,9 +1227,14 @@ Future<bool> MesosContainerizerProcess::_launch(
   Option<CapabilityInfo> capabilities;
   Option<RLimitInfo> rlimits;
 
-  // TODO(jieyu): We should use Option here. If no namespace is
-  // required, we should pass None() to 'launcher->fork'.
-  int namespaces = 0;
+  Option<int> enterNamespaces = None();
+  Option<int> cloneNamespaces = None();
+
+  // TODO(klueska): Remove the following once we update
+  // isolators to fill enterNamespaces for us.
+  if (containerId.has_parent()) {
+    enterNamespaces = CLONE_NEWUTS | CLONE_NEWNET | CLONE_NEWPID;
+  }
 
   CHECK_READY(container->launchInfos);
 
@@ -1285,8 +1290,18 @@ Future<bool> MesosContainerizerProcess::_launch(
       preExecCommands.values.emplace_back(JSON::protobuf(command));
     }
 
-    if (launchInfo->has_namespaces()) {
-      namespaces |= launchInfo->namespaces();
+    if (launchInfo->has_enter_namespaces()) {
+      if (enterNamespaces.isNone()) {
+        enterNamespaces = 0;
+      }
+      enterNamespaces = enterNamespaces.get() | launchInfo->enter_namespaces();
+    }
+
+    if (launchInfo->has_clone_namespaces()) {
+      if (cloneNamespaces.isNone()) {
+        cloneNamespaces = 0;
+      }
+      cloneNamespaces = cloneNamespaces.get() | launchInfo->clone_namespaces();
     }
 
     if (launchInfo->has_capabilities()) {
@@ -1500,7 +1515,10 @@ Future<bool> MesosContainerizerProcess::_launch(
                : Subprocess::IO(subprocessInfo.err)),
         &launchFlags,
         launchEnvironment,
-        namespaces); // 'namespaces' will be ignored by PosixLauncher.
+        // 'enterNamespaces' will be ignored by PosixLauncher.
+        enterNamespaces,
+        // 'cloneNamespaces' will be ignored by PosixLauncher.
+        cloneNamespaces);
 
     if (forked.isError()) {
       return Failure("Failed to fork: " + forked.error());

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp b/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
index af9f373..6f0d6b0 100644
--- a/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
+++ b/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
@@ -467,7 +467,7 @@ Future<Option<ContainerLaunchInfo>> DockerVolumeIsolatorProcess::_prepare(
     const list<Future<string>>& futures)
 {
   ContainerLaunchInfo launchInfo;
-  launchInfo.set_namespaces(CLONE_NEWNS);
+  launchInfo.set_clone_namespaces(CLONE_NEWNS);
 
   vector<string> messages;
   vector<string> sources;

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/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 df16b8f..6535375 100644
--- a/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
+++ b/src/slave/containerizer/mesos/isolators/filesystem/linux.cpp
@@ -323,7 +323,7 @@ Future<Option<ContainerLaunchInfo>> LinuxFilesystemIsolatorProcess::prepare(
       executorInfo)));
 
   ContainerLaunchInfo launchInfo;
-  launchInfo.set_namespaces(CLONE_NEWNS);
+  launchInfo.set_clone_namespaces(CLONE_NEWNS);
 
   // Prepare the commands that will be run in the container's mount
   // namespace right after forking the executor process. We use these

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/isolators/filesystem/shared.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/filesystem/shared.cpp b/src/slave/containerizer/mesos/isolators/filesystem/shared.cpp
index a1283e5..d16b42f 100644
--- a/src/slave/containerizer/mesos/isolators/filesystem/shared.cpp
+++ b/src/slave/containerizer/mesos/isolators/filesystem/shared.cpp
@@ -101,7 +101,7 @@ Future<Option<ContainerLaunchInfo>> SharedFilesystemIsolatorProcess::prepare(
   containerPaths.insert(containerConfig.directory());
 
   ContainerLaunchInfo launchInfo;
-  launchInfo.set_namespaces(CLONE_NEWNS);
+  launchInfo.set_clone_namespaces(CLONE_NEWNS);
 
   foreach (const Volume& volume, executorInfo.container().volumes()) {
     // Because the filesystem is shared we require the container path

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp b/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
index e3756c9..4bd3785 100644
--- a/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
+++ b/src/slave/containerizer/mesos/isolators/gpu/isolator.cpp
@@ -329,7 +329,7 @@ Future<Option<ContainerLaunchInfo>> NvidiaGpuIsolatorProcess::_prepare(
   }
 
   ContainerLaunchInfo launchInfo;
-  launchInfo.set_namespaces(CLONE_NEWNS);
+  launchInfo.set_clone_namespaces(CLONE_NEWNS);
 
   // Inject the Nvidia volume into the container.
   //

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp b/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
index 0d9ec57..f3438b8 100644
--- a/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
+++ b/src/slave/containerizer/mesos/isolators/namespaces/pid.cpp
@@ -79,7 +79,7 @@ Future<Option<ContainerLaunchInfo>> NamespacesPidIsolatorProcess::prepare(
     const ContainerConfig& containerConfig)
 {
   ContainerLaunchInfo launchInfo;
-  launchInfo.set_namespaces(CLONE_NEWPID | CLONE_NEWNS);
+  launchInfo.set_clone_namespaces(CLONE_NEWPID | CLONE_NEWNS);
 
   // Mount /proc with standard options for the container's pid
   // namespace to show the container's pids (and other /proc files),

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp b/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
index 50b4377..74bb6eb 100644
--- a/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
+++ b/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
@@ -650,9 +650,12 @@ Future<Option<ContainerLaunchInfo>> NetworkCniIsolatorProcess::prepare(
         // NOTE: There is an implicit assumption here that when used
         // for testing, '__MESOS_TEST__' is the only network the
         // container is going to join.
-        launchInfo.set_namespaces(CLONE_NEWNS | CLONE_NEWUTS);
+        launchInfo.set_clone_namespaces(CLONE_NEWNS | CLONE_NEWUTS);
       } else {
-        launchInfo.set_namespaces(CLONE_NEWNET | CLONE_NEWNS | CLONE_NEWUTS);
+        launchInfo.set_clone_namespaces(
+            CLONE_NEWNET |
+            CLONE_NEWNS |
+            CLONE_NEWUTS);
       }
     } else {
       // This is a nested container. This shares the parent's network
@@ -661,7 +664,7 @@ Future<Option<ContainerLaunchInfo>> NetworkCniIsolatorProcess::prepare(
       // therefore we will need to bind mount its network files
       // (/etc/hosts, /etc/hostname, /etc/resolv.conf) which will be
       // different than those on the host file system.
-      launchInfo.set_namespaces(CLONE_NEWNS);
+      launchInfo.set_clone_namespaces(CLONE_NEWNS);
     }
 
     return launchInfo;

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/isolators/network/port_mapping.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/network/port_mapping.cpp b/src/slave/containerizer/mesos/isolators/network/port_mapping.cpp
index 48202fb..a994adf 100644
--- a/src/slave/containerizer/mesos/isolators/network/port_mapping.cpp
+++ b/src/slave/containerizer/mesos/isolators/network/port_mapping.cpp
@@ -2522,7 +2522,7 @@ Future<Option<ContainerLaunchInfo>> PortMappingIsolatorProcess::prepare(
   // other isolators, we need to set mount sharing accordingly for
   // PORT_MAPPING_BIND_MOUNT_ROOT to avoid races described in
   // MESOS-1558. So we turn on mount namespace here for consistency.
-  launchInfo.set_namespaces(CLONE_NEWNET | CLONE_NEWNS);
+  launchInfo.set_clone_namespaces(CLONE_NEWNET | CLONE_NEWNS);
 
   return launchInfo;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/isolators/volume/image.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/volume/image.cpp b/src/slave/containerizer/mesos/isolators/volume/image.cpp
index 210e67a..ee9bd35 100644
--- a/src/slave/containerizer/mesos/isolators/volume/image.cpp
+++ b/src/slave/containerizer/mesos/isolators/volume/image.cpp
@@ -180,7 +180,7 @@ Future<Option<ContainerLaunchInfo>> VolumeImageIsolatorProcess::_prepare(
     const list<Future<ProvisionInfo>>& futures)
 {
   ContainerLaunchInfo launchInfo;
-  launchInfo.set_namespaces(CLONE_NEWNS);
+  launchInfo.set_clone_namespaces(CLONE_NEWNS);
 
   vector<string> messages;
   vector<string> sources;

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
index 7b976d2..a6f9794 100644
--- a/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
+++ b/src/slave/containerizer/mesos/isolators/volume/sandbox_path.cpp
@@ -122,7 +122,7 @@ Future<Option<ContainerLaunchInfo>> VolumeSandboxPathIsolatorProcess::prepare(
 
 #ifdef __linux__
   if (bindMountSupported) {
-    launchInfo.set_namespaces(CLONE_NEWNS);
+    launchInfo.set_clone_namespaces(CLONE_NEWNS);
   }
 #endif // __linux__
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/launcher.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/launcher.cpp b/src/slave/containerizer/mesos/launcher.cpp
index bc33f19..a6a8c01 100644
--- a/src/slave/containerizer/mesos/launcher.cpp
+++ b/src/slave/containerizer/mesos/launcher.cpp
@@ -87,10 +87,15 @@ Try<pid_t> PosixLauncher::fork(
     const Subprocess::IO& err,
     const flags::FlagsBase* flags,
     const Option<map<string, string>>& environment,
-    const Option<int>& namespaces)
+    const Option<int>& enterNamespaces,
+    const Option<int>& cloneNamespaces)
 {
-  if (namespaces.isSome() && namespaces.get() != 0) {
-    return Error("Posix launcher does not support namespaces");
+  if (enterNamespaces.isSome() && enterNamespaces.get() != 0) {
+    return Error("Posix launcher does not support entering namespaces");
+  }
+
+  if (cloneNamespaces.isSome() && cloneNamespaces.get() != 0) {
+    return Error("Posix launcher does not support cloning namespaces");
   }
 
   if (pids.contains(containerId)) {

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/launcher.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/launcher.hpp b/src/slave/containerizer/mesos/launcher.hpp
index c1a390a..79f6eea 100644
--- a/src/slave/containerizer/mesos/launcher.hpp
+++ b/src/slave/containerizer/mesos/launcher.hpp
@@ -69,7 +69,8 @@ public:
       const process::Subprocess::IO& err,
       const flags::FlagsBase* flags,
       const Option<std::map<std::string, std::string>>& environment,
-      const Option<int>& namespaces) = 0;
+      const Option<int>& enterNamespaces,
+      const Option<int>& cloneNamespaces) = 0;
 
   // Kill all processes in the containerized context.
   virtual process::Future<Nothing> destroy(const ContainerID& containerId) = 0;
@@ -104,7 +105,8 @@ public:
       const process::Subprocess::IO& err,
       const flags::FlagsBase* flags,
       const Option<std::map<std::string, std::string>>& environment,
-      const Option<int>& namespaces);
+      const Option<int>& enterNamespaces,
+      const Option<int>& cloneNamespaces);
 
   virtual process::Future<Nothing> destroy(const ContainerID& containerId);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/linux_launcher.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/linux_launcher.cpp b/src/slave/containerizer/mesos/linux_launcher.cpp
index e96090f..2c55d7b 100644
--- a/src/slave/containerizer/mesos/linux_launcher.cpp
+++ b/src/slave/containerizer/mesos/linux_launcher.cpp
@@ -79,7 +79,8 @@ public:
       const process::Subprocess::IO& err,
       const flags::FlagsBase* flags,
       const Option<std::map<std::string, std::string>>& environment,
-      const Option<int>& namespaces);
+      const Option<int>& enterNamespaces,
+      const Option<int>& cloneNamespaces);
 
   virtual process::Future<Nothing> destroy(const ContainerID& containerId);
 
@@ -210,7 +211,8 @@ Try<pid_t> LinuxLauncher::fork(
     const process::Subprocess::IO& err,
     const flags::FlagsBase* flags,
     const Option<map<string, string>>& environment,
-    const Option<int>& namespaces)
+    const Option<int>& enterNamespaces,
+    const Option<int>& cloneNamespaces)
 {
   return dispatch(
       process.get(),
@@ -223,7 +225,8 @@ Try<pid_t> LinuxLauncher::fork(
       err,
       flags,
       environment,
-      namespaces).get();
+      enterNamespaces,
+      cloneNamespaces).get();
 }
 
 
@@ -385,7 +388,8 @@ Try<pid_t> LinuxLauncherProcess::fork(
     const process::Subprocess::IO& err,
     const flags::FlagsBase* flags,
     const Option<map<string, string>>& environment,
-    const Option<int>& namespaces)
+    const Option<int>& enterNamespaces,
+    const Option<int>& cloneNamespaces)
 {
   // Make sure this container (nested or not) is unique.
   if (containers.contains(containerId)) {
@@ -412,7 +416,9 @@ Try<pid_t> LinuxLauncherProcess::fork(
     target = container->pid.get();
   }
 
-  int cloneFlags = namespaces.isSome() ? namespaces.get() : 0;
+  int enterFlags = enterNamespaces.isSome() ? enterNamespaces.get() : 0;
+
+  int cloneFlags = cloneNamespaces.isSome() ? cloneNamespaces.get() : 0;
 
   LOG(INFO) << "Launching " << (target.isSome() ? "nested " : "")
             << "container " << containerId << " and cloning with namespaces "
@@ -454,14 +460,11 @@ Try<pid_t> LinuxLauncherProcess::fork(
       err,
       flags,
       environment,
-      [target, cloneFlags](const lambda::function<int()>& child) {
+      [target, enterFlags, cloneFlags](const lambda::function<int()>& child) {
         if (target.isSome()) {
-          // TODO(benh): Factor out this set of namespaces that we
-          // enter and give a healthy comment for why these are the
-          // only ones we enter.
           Try<pid_t> pid = ns::clone(
               target.get(),
-              CLONE_NEWUTS | CLONE_NEWNET | CLONE_NEWPID,
+              enterFlags,
               child,
               cloneFlags);
           if (pid.isError()) {

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/slave/containerizer/mesos/linux_launcher.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/linux_launcher.hpp b/src/slave/containerizer/mesos/linux_launcher.hpp
index 356d4de..e152523 100644
--- a/src/slave/containerizer/mesos/linux_launcher.hpp
+++ b/src/slave/containerizer/mesos/linux_launcher.hpp
@@ -51,7 +51,8 @@ public:
       const process::Subprocess::IO& err,
       const flags::FlagsBase* flags,
       const Option<std::map<std::string, std::string>>& environment,
-      const Option<int>& namespaces);
+      const Option<int>& enterNamespaces,
+      const Option<int>& cloneNamespaces);
 
   virtual process::Future<Nothing> destroy(const ContainerID& containerId);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/tests/containerizer/isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/isolator_tests.cpp b/src/tests/containerizer/isolator_tests.cpp
index 8fefeef..9766aaf 100644
--- a/src/tests/containerizer/isolator_tests.cpp
+++ b/src/tests/containerizer/isolator_tests.cpp
@@ -154,7 +154,7 @@ TEST_F(SharedFilesystemIsolatorTest, DISABLED_ROOT_RelativeVolume)
   AWAIT_READY(prepare);
   ASSERT_SOME(prepare.get());
   ASSERT_EQ(1, prepare.get().get().pre_exec_commands().size());
-  EXPECT_TRUE(prepare.get().get().has_namespaces());
+  EXPECT_TRUE(prepare.get().get().has_clone_namespaces());
 
   // The test will touch a file in container path.
   const string file = path::join(containerPath, UUID::random().toString());
@@ -178,7 +178,8 @@ TEST_F(SharedFilesystemIsolatorTest, DISABLED_ROOT_RelativeVolume)
       Subprocess::FD(STDERR_FILENO),
       nullptr,
       None(),
-      prepare.get().get().namespaces());
+      None(),
+      prepare.get().get().clone_namespaces());
   ASSERT_SOME(pid);
 
   // Set up the reaper to wait on the forked child.
@@ -260,7 +261,7 @@ TEST_F(SharedFilesystemIsolatorTest, DISABLED_ROOT_AbsoluteVolume)
   AWAIT_READY(prepare);
   ASSERT_SOME(prepare.get());
   ASSERT_EQ(1, prepare.get().get().pre_exec_commands().size());
-  EXPECT_TRUE(prepare.get().get().has_namespaces());
+  EXPECT_TRUE(prepare.get().get().has_clone_namespaces());
 
   // Test the volume mounting by touching a file in the container's
   // /tmp, which should then be in flags.work_dir.
@@ -284,7 +285,8 @@ TEST_F(SharedFilesystemIsolatorTest, DISABLED_ROOT_AbsoluteVolume)
       Subprocess::FD(STDERR_FILENO),
       nullptr,
       None(),
-      prepare.get().get().namespaces());
+      None(),
+      prepare.get().get().clone_namespaces());
   ASSERT_SOME(pid);
 
   // Set up the reaper to wait on the forked child.

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/tests/containerizer/launcher.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/launcher.cpp b/src/tests/containerizer/launcher.cpp
index 51ae4f9..a92d989 100644
--- a/src/tests/containerizer/launcher.cpp
+++ b/src/tests/containerizer/launcher.cpp
@@ -30,7 +30,7 @@ ACTION_P(InvokeRecover, launcher)
 ACTION_P(InvokeFork, launcher)
 {
   return launcher->real->fork(
-      arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+      arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
 }
 
 
@@ -51,9 +51,9 @@ TestLauncher::TestLauncher(const process::Owned<slave::Launcher>& _real)
   EXPECT_CALL(*this, recover(_))
     .WillRepeatedly(DoDefault());
 
-  ON_CALL(*this, fork(_, _, _, _, _, _, _, _, _))
+  ON_CALL(*this, fork(_, _, _, _, _, _, _, _, _, _))
     .WillByDefault(InvokeFork(this));
-  EXPECT_CALL(*this, fork(_, _, _, _, _, _, _, _, _))
+  EXPECT_CALL(*this, fork(_, _, _, _, _, _, _, _, _, _))
     .WillRepeatedly(DoDefault());
 
   ON_CALL(*this, destroy(_))

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/tests/containerizer/launcher.hpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/launcher.hpp b/src/tests/containerizer/launcher.hpp
index 5dcc391..a8e436f 100644
--- a/src/tests/containerizer/launcher.hpp
+++ b/src/tests/containerizer/launcher.hpp
@@ -56,7 +56,7 @@ public:
       process::Future<hashset<ContainerID>>(
           const std::list<mesos::slave::ContainerState>& states));
 
-  MOCK_METHOD9(
+  MOCK_METHOD10(
       fork,
       Try<pid_t>(
           const ContainerID& containerId,
@@ -67,7 +67,8 @@ public:
           const process::Subprocess::IO& err,
           const flags::FlagsBase* flags,
           const Option<std::map<std::string, std::string>>& env,
-          const Option<int>& namespaces));
+          const Option<int>& enterNamespaces,
+          const Option<int>& cloneNamespaces));
 
   MOCK_METHOD1(
       destroy,

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/tests/containerizer/mesos_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/mesos_containerizer_tests.cpp b/src/tests/containerizer/mesos_containerizer_tests.cpp
index 16d7f12..5aae23b 100644
--- a/src/tests/containerizer/mesos_containerizer_tests.cpp
+++ b/src/tests/containerizer/mesos_containerizer_tests.cpp
@@ -1434,6 +1434,7 @@ TEST_F(MesosLauncherStatusTest, ExecutorPIDTest)
       Subprocess::FD(STDERR_FILENO),
       nullptr,
       None(),
+      None(),
       None());
 
   ASSERT_SOME(forked);

http://git-wip-us.apache.org/repos/asf/mesos/blob/329f3ea9/src/tests/containerizer/port_mapping_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/port_mapping_tests.cpp b/src/tests/containerizer/port_mapping_tests.cpp
index fbdc0db..79b0a60 100644
--- a/src/tests/containerizer/port_mapping_tests.cpp
+++ b/src/tests/containerizer/port_mapping_tests.cpp
@@ -347,6 +347,7 @@ protected:
         Subprocess::FD(STDERR_FILENO),
         &launchFlags,
         None(),
+        None(),
         CLONE_NEWNET | CLONE_NEWNS);
 
     return pid;