You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by id...@apache.org on 2014/10/28 20:23:40 UTC

[4/8] git commit: Add getns() for namespaces.

Add getns() for namespaces.

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


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

Branch: refs/heads/master
Commit: 36505730ac59d5255cd616618ce78e2ee88fca3d
Parents: 57447a7
Author: Ian Downes <id...@twitter.com>
Authored: Fri Oct 24 11:49:18 2014 -0700
Committer: Ian Downes <id...@twitter.com>
Committed: Tue Oct 28 12:04:16 2014 -0700

----------------------------------------------------------------------
 src/linux/ns.hpp       | 25 +++++++++++++++++++
 src/tests/ns_tests.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/36505730/src/linux/ns.hpp
----------------------------------------------------------------------
diff --git a/src/linux/ns.hpp b/src/linux/ns.hpp
index 53c95a4..60adaa4 100644
--- a/src/linux/ns.hpp
+++ b/src/linux/ns.hpp
@@ -198,6 +198,31 @@ inline Try<Nothing> setns(pid_t pid, const std::string& ns)
   return ns::setns(path, ns);
 }
 
+
+// Get the inode number of the specified namespace for the specified
+// pid. The inode number identifies the namespace and can be used for
+// comparisons, i.e., two processes with the same inode for a given
+// namespace type are in the same namespace.
+inline Try<ino_t> getns(pid_t pid, const std::string& ns)
+{
+  if (!os::exists(pid)) {
+    return Error("Pid " + stringify(pid) + " does not exist");
+  }
+
+  if (ns::namespaces().count(ns) < 1) {
+    return Error("Namespace '" + ns + "' is not supported");
+  }
+
+  std::string path = path::join("/proc", stringify(pid), "ns", ns);
+  struct stat s;
+  if (::stat(path.c_str(), &s) < 0) {
+    return ErrnoError("Failed to stat " + ns + " namespace handle"
+                      " for pid " + stringify(pid));
+  }
+
+  return s.st_ino;
+}
+
 } // namespace ns {
 
 #endif // __LINUX_NS_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/36505730/src/tests/ns_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/ns_tests.cpp b/src/tests/ns_tests.cpp
index c4cf9ab..30218cf 100644
--- a/src/tests/ns_tests.cpp
+++ b/src/tests/ns_tests.cpp
@@ -154,3 +154,63 @@ TEST(NsTest, ROOT_setnsMultipleThreads)
   EXPECT_EQ(0, pthread_cancel(pthread));
   EXPECT_EQ(0, pthread_join(pthread, NULL));
 }
+
+
+// Use a different child function for clone because it requires
+// int(*)(void*).
+static int childGetns(void* arg)
+{
+  // Sleep until killed.
+  while (true) { sleep(1); }
+
+  ABORT("Error, child should be killed before reaching here");
+}
+
+
+// Test that we can get the namespace inodes for a forked child.
+TEST(NsTest, ROOT_getns)
+{
+  set<string> namespaces = ns::namespaces();
+
+  // ns::setns() does not support "pid".
+  namespaces.erase("pid");
+
+  // Use the first other namespace available.
+  ASSERT_FALSE(namespaces.empty());
+  string ns = *(namespaces.begin());
+
+  ASSERT_SOME(ns::getns(::getpid(), ns));
+
+  Try<int> nstype = ns::nstype(ns);
+  ASSERT_SOME(nstype);
+
+  // 8 MiB stack for child.
+  static unsigned long long stack[(8*1024*1024)/sizeof(unsigned long long)];
+
+  pid_t pid = clone(
+      childGetns,
+      &stack[sizeof(stack)/sizeof(stack[0]) - 1], // Stack grows down.
+      SIGCHLD | nstype.get(),
+      NULL);
+
+  ASSERT_NE(-1, pid);
+
+  // Continue in parent.
+  Try<ino_t> nsParent = ns::getns(::getpid(), ns);
+  ASSERT_SOME(nsParent);
+
+  Try<ino_t> nsChild = ns::getns(pid, ns);
+  ASSERT_SOME(nsChild);
+
+  // Child should be in a different namespace.
+  EXPECT_NE(nsParent.get(), nsChild.get());
+
+  // Kill the child process.
+  ASSERT_NE(-1, ::kill(pid, SIGKILL));
+
+  // Wait for the child process.
+  int status;
+  EXPECT_NE(-1, ::waitpid((pid_t) -1, &status, 0));
+  ASSERT_TRUE(WIFSIGNALED(status));
+  EXPECT_EQ(SIGKILL, WTERMSIG(status));
+}