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 2014/06/06 19:07:01 UTC
git commit: Added setns utilities to stout.
Repository: mesos
Updated Branches:
refs/heads/master 1920efdd8 -> 5cbdbf2a5
Added setns utilities to stout.
Review: https://reviews.apache.org/r/22160
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/5cbdbf2a
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/5cbdbf2a
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/5cbdbf2a
Branch: refs/heads/master
Commit: 5cbdbf2a5923a04beadf0e812131ca05602c59c3
Parents: 1920efd
Author: Jie Yu <yu...@gmail.com>
Authored: Mon Jun 2 13:43:29 2014 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Jun 6 10:06:37 2014 -0700
----------------------------------------------------------------------
3rdparty/libprocess/3rdparty/Makefile.am | 1 +
3rdparty/libprocess/3rdparty/stout/Makefile.am | 2 +
.../3rdparty/stout/include/stout/os/setns.hpp | 200 +++++++++++++++++++
.../3rdparty/stout/tests/os/setns_tests.cpp | 53 +++++
4 files changed, 256 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/5cbdbf2a/3rdparty/libprocess/3rdparty/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/Makefile.am b/3rdparty/libprocess/3rdparty/Makefile.am
index 1474bbc..3359907 100644
--- a/3rdparty/libprocess/3rdparty/Makefile.am
+++ b/3rdparty/libprocess/3rdparty/Makefile.am
@@ -161,6 +161,7 @@ stout_tests_SOURCES = \
if OS_LINUX
stout_tests_SOURCES += $(STOUT)/tests/proc_tests.cpp
+ stout_tests_SOURCES += $(STOUT)/tests/os/setns_tests.cpp
endif
stout_tests_CPPFLAGS = \
http://git-wip-us.apache.org/repos/asf/mesos/blob/5cbdbf2a/3rdparty/libprocess/3rdparty/stout/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/Makefile.am b/3rdparty/libprocess/3rdparty/stout/Makefile.am
index 8f32a66..00d8c61 100644
--- a/3rdparty/libprocess/3rdparty/stout/Makefile.am
+++ b/3rdparty/libprocess/3rdparty/stout/Makefile.am
@@ -52,6 +52,7 @@ EXTRA_DIST = \
include/stout/os/process.hpp \
include/stout/os/read.hpp \
include/stout/os/sendfile.hpp \
+ include/stout/os/setns.hpp \
include/stout/os/shell.hpp \
include/stout/os/signals.hpp \
include/stout/os/permissions.hpp \
@@ -93,6 +94,7 @@ EXTRA_DIST = \
tests/option_tests.cpp \
tests/os_tests.cpp \
tests/os/sendfile_tests.cpp \
+ tests/os/setns_tests.cpp \
tests/os/signals_tests.cpp \
tests/proc_tests.cpp \
tests/protobuf_tests.cpp \
http://git-wip-us.apache.org/repos/asf/mesos/blob/5cbdbf2a/3rdparty/libprocess/3rdparty/stout/include/stout/os/setns.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/os/setns.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/os/setns.hpp
new file mode 100644
index 0000000..5ec2602
--- /dev/null
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/os/setns.hpp
@@ -0,0 +1,200 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __STOUT_OS_SETNS_HPP__
+#define __STOUT_OS_SETNS_HPP__
+
+// This file contains Linux-only OS utilities.
+#ifndef __linux__
+#error "stout/os/setns.hpp is only available on Linux systems."
+#endif
+
+#include <sched.h>
+#include <unistd.h>
+
+#include <sys/syscall.h>
+
+#include <set>
+#include <string>
+
+#include <stout/error.hpp>
+#include <stout/hashmap.hpp>
+#include <stout/nothing.hpp>
+#include <stout/os.hpp>
+#include <stout/path.hpp>
+#include <stout/proc.hpp>
+#include <stout/stringify.hpp>
+#include <stout/try.hpp>
+
+#include <stout/os/exists.hpp>
+#include <stout/os/ls.hpp>
+
+namespace os {
+
+// Returns all the supported namespaces by the kernel.
+inline std::set<std::string> namespaces()
+{
+ std::set<std::string> result;
+ foreach (const std::string& ns, os::ls("/proc/self/ns")) {
+ result.insert(ns);
+ }
+ return result;
+}
+
+
+// Returns the nstype (e.g., CLONE_NEWNET, CLONE_NEWNS, etc.) for the
+// given namespace which will be used when calling ::setns.
+inline Try<int> nstype(const std::string& ns)
+{
+ hashmap<std::string, int> nstypes;
+
+#ifdef CLONE_NEWNS
+ nstypes["mnt"] = CLONE_NEWNS;
+#else
+ nstypes["mnt"] = 0x00020000;
+#endif
+
+#ifdef CLONE_NEWUTS
+ nstypes["uts"] = CLONE_NEWUTS;
+#else
+ nstypes["uts"] = 0x04000000;
+#endif
+
+#ifdef CLONE_NEWIPC
+ nstypes["ipc"] = CLONE_NEWIPC;
+#else
+ nstypes["ipc"] = 0x08000000;
+#endif
+
+#ifdef CLONE_NEWNET
+ nstypes["net"] = CLONE_NEWNET;
+#else
+ nstypes["net"] = 0x40000000;
+#endif
+
+#ifdef CLONE_NEWUSER
+ nstypes["user"] = CLONE_NEWUSER;
+#else
+ nstypes["user"] = 0x10000000;
+#endif
+
+#ifndef CLONE_NEWPID
+ nstypes["pid"] = CLONE_NEWPID;
+#else
+ nstypes["pid"] = 0x20000000;
+#endif
+
+ if (!nstypes.contains(ns)) {
+ return Error("Unknown namespace '" + ns + "'");
+ }
+
+ return nstypes[ns];
+}
+
+
+// Re-associate the calling process with the specified namespace. The
+// path refers to one of the corresponding namespace entries in the
+// /proc/[pid]/ns/ directory (or bind mounted elsewhere). We do not
+// 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)
+{
+ // 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 (os::namespaces().count(ns) == 0) {
+ return Error("Namespace '" + ns + "' is not supported");
+ }
+
+ // Currently, we don't support pid namespace as its semantics is
+ // different from other namespaces (instead of re-associating the
+ // calling thread, it re-associates the *children* of the calling
+ // thread with the specified namespace).
+ if (ns == "pid") {
+ return Error("Pid namespace is not supported");
+ }
+
+#ifdef O_CLOEXEC
+ Try<int> fd = os::open(path, O_RDONLY | O_CLOEXEC);
+#else
+ Try<int> fd = os::open(path, O_RDONLY);
+#endif
+
+ if (fd.isError()) {
+ return Error("Failed to open '" + path + "': " + fd.error());
+ }
+
+#ifndef O_CLOEXEC
+ Try<Nothing> cloexec = os::cloexec(fd.get());
+ if (cloexec.isError()) {
+ os::close(fd.get());
+ return Error("Failed to cloexec: " + cloexec.error());
+ }
+#endif
+
+ Try<int> nstype = os::nstype(ns);
+ if (nstype.isError()) {
+ return Error(nstype.error());
+ }
+
+#ifdef SYS_setns
+ int ret = ::syscall(SYS_setns, fd.get(), nstype.get());
+#elif __x86_64__
+ // A workaround for those hosts that have an old glibc (older than
+ // 2.14) but have a new kernel. The magic number '308' here is the
+ // syscall number for 'setns' on x86_64 architecture.
+ int ret = ::syscall(308, fd.get(), nstype.get());
+#else
+#error "setns is not available"
+#endif
+
+ if (ret == -1) {
+ // Save the errno as it might be overwritten by 'os::close' below.
+ ErrnoError error;
+ os::close(fd.get());
+ return error;
+ }
+
+ os::close(fd.get());
+ return Nothing();
+}
+
+
+// Re-associate the calling process with the specified namespace. The
+// pid specifies the process whose namespace we will associate.
+inline Try<Nothing> setns(pid_t pid, const std::string& ns)
+{
+ if (!os::exists(pid)) {
+ return Error("Pid " + stringify(pid) + " does not exist");
+ }
+
+ std::string path = path::join("/proc", stringify(pid), "ns", ns);
+ if (!os::exists(path)) {
+ return Error("Namespace '" + ns + "' is not supported");
+ }
+
+ return os::setns(path, ns);
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_SETNS_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/5cbdbf2a/3rdparty/libprocess/3rdparty/stout/tests/os/setns_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/tests/os/setns_tests.cpp b/3rdparty/libprocess/3rdparty/stout/tests/os/setns_tests.cpp
new file mode 100644
index 0000000..f6d79b1
--- /dev/null
+++ b/3rdparty/libprocess/3rdparty/stout/tests/os/setns_tests.cpp
@@ -0,0 +1,53 @@
+#include <pthread.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <stout/gtest.hpp>
+#include <stout/os.hpp>
+
+#include <stout/os/setns.hpp>
+
+using std::set;
+using std::string;
+
+
+static void* child(void* arg)
+{
+ // Newly created threads have PTHREAD_CANCEL_ENABLE and
+ // PTHREAD_CANCEL_DEFERRED so they can be cancelled.
+ while (true) { os::sleep(Seconds(1)); }
+}
+
+
+TEST(OsSetnsTest, setns)
+{
+ if (os::user() != "root") {
+ return;
+ }
+
+ // Get all the available namespaces.
+ set<string> namespaces = os::namespaces();
+
+ foreach (const string& ns, namespaces) {
+ if (ns == "pid") {
+ EXPECT_ERROR(os::setns(::getpid(), ns));
+ } else {
+ EXPECT_SOME(os::setns(::getpid(), ns));
+ }
+ }
+
+ // Do not allow multi-threaded environment.
+ pthread_t pthread;
+ ASSERT_EQ(0, pthread_create(&pthread, NULL, child, NULL));
+
+ foreach (const string& ns, namespaces) {
+ EXPECT_ERROR(os::setns(::getpid(), ns));
+ }
+
+ // Terminate the threads.
+ EXPECT_EQ(0, pthread_cancel(pthread));
+ EXPECT_EQ(0, pthread_join(pthread, NULL));
+}