This is an automated email from the ASF dual-hosted git repository. gilbert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mesos.git
commit e3b2edb1f3226e9f84e22383153314dc4a212edc Author: Qian Zhang <[email protected]> AuthorDate: Sat Jul 13 10:07:58 2019 -0700 Updated the test `NamespacesIsolatorTest.ROOT_IPCNamespace`. This test is updated to verify the backward compatibility is kept after we implement the configurable IPC namespaces and /dev/shm. Review: https://reviews.apache.org/r/70859/ --- src/tests/containerizer/isolator_tests.cpp | 105 ++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 18 deletions(-) diff --git a/src/tests/containerizer/isolator_tests.cpp b/src/tests/containerizer/isolator_tests.cpp index 8668088..47debaa 100644 --- a/src/tests/containerizer/isolator_tests.cpp +++ b/src/tests/containerizer/isolator_tests.cpp @@ -268,17 +268,20 @@ TEST_F(NamespacesIsolatorTest, ROOT_SharePidNamespaceWhenDisallow) } -// The IPC namespace has its own copy of the svipc(7) tunables. We verify -// that we are correctly entering the IPC namespace by verifying that we -// can set shmmax some different value than that of the host namespace. -TEST_F(NamespacesIsolatorTest, ROOT_IPCNamespace) +// This test verifies that when `namespaces/ipc` isolator is enabled and +// container's IPC mode is not set, for backward compatibility we will +// keep the previous behavior: Top level container will have its own IPC +// namespace and nested container will share the IPC namespace with its +// parent container. If the container does not have its own rootfs, it +// will share agent's /dev/shm, otherwise it will have its own /dev/shm. +TEST_F(NamespacesIsolatorTest, ROOT_IPCNamespaceWithIPCModeUnset) { Try<Owned<MesosContainerizer>> containerizer = createContainerizer("filesystem/linux,namespaces/ipc"); ASSERT_SOME(containerizer); - // Value we will set the child namespace shmmax to. + // Value we will set the top-level container's IPC namespace shmmax to. uint64_t shmmaxValue = static_cast<uint64_t>(::getpid()); Try<uint64_t> hostShmmax = readValue("/proc/sys/kernel/shmmax"); @@ -287,10 +290,13 @@ TEST_F(NamespacesIsolatorTest, ROOT_IPCNamespace) // Verify that the host namespace shmmax is different. ASSERT_NE(hostShmmax.get(), shmmaxValue); - const string command = - "stat -Lc %i /proc/self/ns/ipc > ns;" - "echo " + stringify(shmmaxValue) + " > /proc/sys/kernel/shmmax;" - "cp /proc/sys/kernel/shmmax shmmax"; + // Launch a top-level container with IPC mode + // unset and it does not have its own rootfs. + string command = + "stat -Lc %i /proc/self/ns/ipc > ns && " + "echo " + stringify(shmmaxValue) + " > /proc/sys/kernel/shmmax && " + "cp /proc/sys/kernel/shmmax /dev/shm/shmmax && " + "sleep 1000"; process::Future<Containerizer::LaunchResult> launch = containerizer.get()->launch( @@ -304,36 +310,99 @@ TEST_F(NamespacesIsolatorTest, ROOT_IPCNamespace) AWAIT_ASSERT_EQ(Containerizer::LaunchResult::SUCCESS, launch); - // Wait on the container. + // Since the top-level container does not have its own + // rootfs, it will share host's /dev/shm, so let's wait + // until /dev/shm/shmmax is created in the host. + Duration waited = Duration::zero(); + + do { + if (os::exists("/dev/shm/shmmax")) { + break; + } + + os::sleep(Seconds(1)); + waited += Seconds(1); + } while (waited < process::TEST_AWAIT_TIMEOUT); + + EXPECT_LT(waited, process::TEST_AWAIT_TIMEOUT); + + // Launch a nested container with IPC mode unset and it has its own rootfs. + ContainerID nestedContainerId; + nestedContainerId.mutable_parent()->CopyFrom(containerId); + nestedContainerId.set_value(id::UUID::random().toString()); + + mesos::Image image; + image.set_type(mesos::Image::DOCKER); + image.mutable_docker()->set_name("alpine"); + + ContainerInfo containerInfo; + containerInfo.set_type(ContainerInfo::MESOS); + containerInfo.mutable_mesos()->mutable_image()->CopyFrom(image); + + command = + "stat -Lc %i /proc/self/ns/ipc > ns && " + "test `cat /proc/sys/kernel/shmmax` = " + stringify(shmmaxValue) + " && " + "touch /dev/shm/file"; + + launch = containerizer.get()->launch( + nestedContainerId, + createContainerConfig(createCommandInfo(command), containerInfo), + std::map<string, string>(), + None()); + + AWAIT_ASSERT_EQ(Containerizer::LaunchResult::SUCCESS, launch); + + // Wait on the nested container. Future<Option<ContainerTermination>> wait = - containerizer.get()->wait(containerId); + containerizer.get()->wait(nestedContainerId); AWAIT_READY(wait); ASSERT_SOME(wait.get()); - - // Check the executor exited correctly. EXPECT_TRUE(wait->get().has_status()); EXPECT_EQ(0, wait->get().status()); - // Check that the command was run in a different IPC namespace. + // Check that top-level container and the nested container are in the + // same IPC namespace but not in the same IPC namespace with host. Result<ino_t> testIPCNamespace = ns::getns(::getpid(), "ipc"); ASSERT_SOME(testIPCNamespace); Try<string> containerIPCNamespace = os::read(path::join(directory, "ns")); ASSERT_SOME(containerIPCNamespace); + Try<string> nestedcontainerIPCNamespace = + os::read(path::join(getSandboxPath(directory, nestedContainerId), "ns")); + + ASSERT_SOME(nestedcontainerIPCNamespace); + EXPECT_NE(stringify(testIPCNamespace.get()), strings::trim(containerIPCNamespace.get())); + EXPECT_EQ(strings::trim(containerIPCNamespace.get()), + strings::trim(nestedcontainerIPCNamespace.get())); + + // The nested container will have its own /dev/shm since it has its own + // rootfs, so the file it created should not exist in the host. + ASSERT_FALSE(os::exists("/dev/shm/file")); + // Check that we modified the IPC shmmax of the namespace, not the host. - Try<uint64_t> childShmmax = readValue("shmmax"); - ASSERT_SOME(childShmmax); + Try<uint64_t> containerShmmax = readValue("/dev/shm/shmmax"); + ASSERT_SOME(containerShmmax); // Verify that we didn't modify shmmax in the host namespace. ASSERT_EQ(hostShmmax.get(), readValue("/proc/sys/kernel/shmmax").get()); - EXPECT_NE(hostShmmax.get(), childShmmax.get()); - EXPECT_EQ(shmmaxValue, childShmmax.get()); + EXPECT_NE(hostShmmax.get(), containerShmmax.get()); + EXPECT_EQ(shmmaxValue, containerShmmax.get()); + + Future<Option<ContainerTermination>> termination = + containerizer.get()->destroy(containerId); + + AWAIT_READY(termination); + ASSERT_SOME(termination.get()); + ASSERT_TRUE(termination.get()->has_status()); + EXPECT_WTERMSIG_EQ(SIGKILL, termination.get()->status()); + + ASSERT_SOME(os::rm("/dev/shm/shmmax")); }
