Added a test `DefaultExecutorTest.ROOT_MultiTaskgroupSharePidNamespace`.

Added a test `DefaultExecutorTest.ROOT_MultiTaskgroupSharePidNamespace`.

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


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

Branch: refs/heads/master
Commit: 2e3a5b1347e5ff8c3bfa6d80d14c1f9e883887d3
Parents: 63e848a
Author: Qian Zhang <zhq527...@gmail.com>
Authored: Sun Aug 13 19:52:03 2017 -0700
Committer: Gilbert Song <songzihao1...@gmail.com>
Committed: Mon Aug 14 20:49:14 2017 -0700

----------------------------------------------------------------------
 src/tests/default_executor_tests.cpp | 174 +++++++++++++++++++++++++++++-
 1 file changed, 173 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/2e3a5b13/src/tests/default_executor_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/default_executor_tests.cpp 
b/src/tests/default_executor_tests.cpp
index 3ac9f29..afe0afa 100644
--- a/src/tests/default_executor_tests.cpp
+++ b/src/tests/default_executor_tests.cpp
@@ -1373,6 +1373,178 @@ TEST_P(DefaultExecutorTest, ReservedResources)
 }
 
 
+#ifdef __linux__
+// This test verifies that tasks from two different
+// task groups can share the same pid namespace.
+TEST_P(DefaultExecutorTest, ROOT_MultiTaskgroupSharePidNamespace)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.containerizers = GetParam();
+  flags.launcher = "linux";
+  flags.isolation = "cgroups/cpu,filesystem/linux,namespaces/pid";
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), flags);
+  ASSERT_SOME(slave);
+
+  auto scheduler = std::make_shared<v1::MockHTTPScheduler>();
+
+  v1::FrameworkInfo frameworkInfo = v1::DEFAULT_FRAMEWORK_INFO;
+
+  Future<Nothing> connected;
+  EXPECT_CALL(*scheduler, connected(_))
+    .WillOnce(DoAll(v1::scheduler::SendSubscribe(frameworkInfo),
+                    FutureSatisfy(&connected)));
+
+  v1::scheduler::TestMesos mesos(
+      master.get()->pid,
+      ContentType::PROTOBUF,
+      scheduler);
+
+  AWAIT_READY(connected);
+
+  Future<v1::scheduler::Event::Subscribed> subscribed;
+  EXPECT_CALL(*scheduler, subscribed(_, _))
+    .WillOnce(FutureArg<1>(&subscribed));
+
+  Future<v1::scheduler::Event::Offers> offers1;
+  EXPECT_CALL(*scheduler, offers(_, _))
+    .WillOnce(FutureArg<1>(&offers1));
+
+  EXPECT_CALL(*scheduler, heartbeat(_))
+    .WillRepeatedly(Return()); // Ignore heartbeats.
+
+  AWAIT_READY(subscribed);
+
+  v1::FrameworkID frameworkId(subscribed->framework_id());
+  v1::ExecutorInfo executorInfo = v1::createExecutorInfo(
+      "test_default_executor",
+      None(),
+      "cpus:0.1;mem:32;disk:32",
+      v1::ExecutorInfo::DEFAULT);
+
+  // Update `executorInfo` with the subscribed `frameworkId`.
+  executorInfo.mutable_framework_id()->CopyFrom(frameworkId);
+
+  AWAIT_READY(offers1);
+  EXPECT_FALSE(offers1->offers().empty());
+
+  const v1::Offer& offer1 = offers1->offers(0);
+  const v1::AgentID& agentId = offer1.agent_id();
+
+  // Create the first task which will share pid namespace with its parent.
+  v1::TaskInfo taskInfo1 = v1::createTask(
+      agentId,
+      v1::Resources::parse("cpus:0.1;mem:32;disk:32").get(),
+      "stat -Lc %i /proc/self/ns/pid > ns && sleep 1000");
+
+  mesos::v1::ContainerInfo* containerInfo = taskInfo1.mutable_container();
+  containerInfo->set_type(mesos::v1::ContainerInfo::MESOS);
+  containerInfo->mutable_linux_info()->set_share_pid_namespace(true);
+
+  Future<v1::scheduler::Event::Update> update1;
+  EXPECT_CALL(*scheduler, update(_, _))
+    .WillOnce(FutureArg<1>(&update1));
+
+  Future<v1::scheduler::Event::Offers> offers2;
+  EXPECT_CALL(*scheduler, offers(_, _))
+    .WillOnce(FutureArg<1>(&offers2))
+    .WillRepeatedly(Return());
+
+  // Launch the first task group.
+  v1::Offer::Operation launchGroup = v1::LAUNCH_GROUP(
+      executorInfo,
+      v1::createTaskGroupInfo({taskInfo1}));
+
+  mesos.send(v1::createCallAccept(frameworkId, offer1, {launchGroup}));
+
+  AWAIT_READY(update1);
+
+  ASSERT_EQ(TASK_RUNNING, update1->status().state());
+  EXPECT_EQ(taskInfo1.task_id(), update1->status().task_id());
+  EXPECT_TRUE(update1->status().has_timestamp());
+
+  AWAIT_READY(offers2);
+  EXPECT_FALSE(offers2->offers().empty());
+
+  const v1::Offer& offer2 = offers2->offers(0);
+
+  // Create the second task which will share pid namespace with its parent.
+  v1::TaskInfo taskInfo2 = v1::createTask(
+      agentId,
+      v1::Resources::parse("cpus:0.1;mem:32;disk:32").get(),
+      "stat -Lc %i /proc/self/ns/pid > ns && sleep 1000");
+
+  containerInfo = taskInfo2.mutable_container();
+  containerInfo->set_type(mesos::v1::ContainerInfo::MESOS);
+  containerInfo->mutable_linux_info()->set_share_pid_namespace(true);
+
+  Future<v1::scheduler::Event::Update> update2;
+  EXPECT_CALL(*scheduler, update(_, _))
+    .WillOnce(FutureArg<1>(&update2));
+
+  // Launch the second task group.
+  launchGroup = v1::LAUNCH_GROUP(
+      executorInfo,
+      v1::createTaskGroupInfo({taskInfo2}));
+
+  mesos.send(v1::createCallAccept(frameworkId, offer2, {launchGroup}));
+
+  AWAIT_READY(update2);
+
+  ASSERT_EQ(TASK_RUNNING, update2->status().state());
+  EXPECT_EQ(taskInfo2.task_id(), update2->status().task_id());
+  EXPECT_TRUE(update2->status().has_timestamp());
+
+  string executorSandbox = slave::paths::getExecutorLatestRunPath(
+      flags.work_dir,
+      devolve(agentId),
+      devolve(frameworkId),
+      devolve(executorInfo.executor_id()));
+
+  string pidNamespacePath1 = path::join(
+      executorSandbox,
+      "tasks",
+      taskInfo1.task_id().value(),
+      "ns");
+
+  string pidNamespacePath2 = path::join(
+      executorSandbox,
+      "tasks",
+      taskInfo2.task_id().value(),
+      "ns");
+
+  // Wait up to 5 seconds for each of the two tasks to
+  // write its pid namespace inode into its sandbox.
+  Duration waited = Duration::zero();
+  do {
+    if (os::exists(pidNamespacePath1) && os::exists(pidNamespacePath2)) {
+      break;
+    }
+
+    os::sleep(Seconds(1));
+    waited += Seconds(1);
+  } while (waited < Seconds(5));
+
+  EXPECT_TRUE(os::exists(pidNamespacePath1));
+  EXPECT_TRUE(os::exists(pidNamespacePath2));
+
+  Try<string> pidNamespace1 = os::read(pidNamespacePath1);
+  ASSERT_SOME(pidNamespace1);
+
+  Try<string> pidNamespace2 = os::read(pidNamespacePath2);
+  ASSERT_SOME(pidNamespace2);
+
+  // Check the two tasks share the same pid namespace.
+  EXPECT_EQ(strings::trim(pidNamespace1.get()),
+            strings::trim(pidNamespace2.get()));
+}
+#endif // __linux__
+
+
 struct LauncherAndIsolationParam
 {
   LauncherAndIsolationParam(const string& _launcher, const string& _isolation)
@@ -1508,7 +1680,7 @@ TEST_P_TEMP_DISABLED_ON_WINDOWS(
       "echo abc > task_volume_path/file");
 
   // TODO(gilbert): Refactor the following code once the helper
-  // to create a 'sandbox_path' volume is suppported.
+  // to create a 'sandbox_path' volume is supported.
   mesos::v1::ContainerInfo* containerInfo = taskInfo.mutable_container();
   containerInfo->set_type(mesos::v1::ContainerInfo::MESOS);
 

Reply via email to