Repository: mesos Updated Branches: refs/heads/master 721ea1145 -> 69393f77d
Added Systemd environment check to LinuxLauncher. This will be used to perform Systemd specific actions. Review: https://reviews.apache.org/r/38634 Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/ac76392b Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/ac76392b Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/ac76392b Branch: refs/heads/master Commit: ac76392bc64a8a570e3519e875fce91ea4064d56 Parents: 721ea11 Author: Joris Van Remoortere <[email protected]> Authored: Tue Sep 22 10:51:39 2015 -0400 Committer: Joris Van Remoortere <[email protected]> Committed: Wed Sep 23 20:56:39 2015 -0700 ---------------------------------------------------------------------- src/Makefile.am | 3 + src/linux/systemd.cpp | 100 ++++++++++++++++++++++++ src/linux/systemd.hpp | 40 ++++++++++ src/slave/containerizer/linux_launcher.cpp | 56 ++++++++----- src/slave/containerizer/linux_launcher.hpp | 6 +- 5 files changed, 184 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/ac76392b/src/Makefile.am ---------------------------------------------------------------------- diff --git a/src/Makefile.am b/src/Makefile.am index 74c1154..776483b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -682,6 +682,7 @@ if OS_LINUX libmesos_no_3rdparty_la_SOURCES += linux/cgroups.cpp libmesos_no_3rdparty_la_SOURCES += linux/fs.cpp libmesos_no_3rdparty_la_SOURCES += linux/perf.cpp + libmesos_no_3rdparty_la_SOURCES += linux/systemd.cpp libmesos_no_3rdparty_la_SOURCES += slave/containerizer/isolators/cgroups/cpushare.cpp libmesos_no_3rdparty_la_SOURCES += slave/containerizer/isolators/cgroups/mem.cpp libmesos_no_3rdparty_la_SOURCES += slave/containerizer/isolators/cgroups/perf_event.cpp @@ -693,6 +694,7 @@ if OS_LINUX else EXTRA_DIST += linux/cgroups.cpp EXTRA_DIST += linux/fs.cpp + EXTRA_DIST += linux/systemd.cpp endif if WITH_NETWORK_ISOLATOR @@ -763,6 +765,7 @@ libmesos_no_3rdparty_la_SOURCES += \ linux/ns.hpp \ linux/perf.hpp \ linux/sched.hpp \ + linux/systemd.hpp \ local/flags.hpp \ local/local.hpp \ logging/flags.hpp \ http://git-wip-us.apache.org/repos/asf/mesos/blob/ac76392b/src/linux/systemd.cpp ---------------------------------------------------------------------- diff --git a/src/linux/systemd.cpp b/src/linux/systemd.cpp new file mode 100644 index 0000000..7084e70 --- /dev/null +++ b/src/linux/systemd.cpp @@ -0,0 +1,100 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +#include "linux/systemd.hpp" + +#include <string> +#include <vector> + +#include <stout/os.hpp> +#include <stout/strings.hpp> +#include <stout/try.hpp> + +using std::string; +using std::vector; + +namespace systemd { + +int DELEGATE_MINIMUM_VERSION = 218; + +bool exists() +{ + // This is static as the init system should not change while we are running. + static const bool exists = []() -> bool { + // (1) Test whether `/sbin/init` links to systemd. + const Result<string> realpath = os::realpath("/sbin/init"); + if (realpath.isError() || realpath.isNone()) { + LOG(WARNING) << "Failed to test /sbin/init for systemd environment: " + << realpath.error(); + + return false; + } + + CHECK_SOME(realpath); + + // (2) Testing whether we have a systemd version. + const string command = realpath.get() + " --version"; + Try<string> versionCommand = os::shell(command); + + if (versionCommand.isError()) { + LOG(WARNING) << "Failed to test command '" << command << "': " + << versionCommand.error(); + + return false; + } + + vector<string> tokens = strings::tokenize(versionCommand.get(), " \n"); + + // We need at least a name and a version number to match systemd. + if (tokens.size() < 2) { + return false; + } + + if (tokens[0] != "systemd") { + return false; + } + + Try<int> version = numify<int>(tokens[1]); + if (version.isError()) { + LOG(WARNING) << "Failed to parse systemd version '" << tokens[1] << "'"; + return false; + } + + LOG(INFO) << "systemd version `" << version.get() << "` detected"; + + // We log a warning if the version is below 218. This is because the + // `Delegate` flag was introduced in version 218. Some systems, like RHEL 7, + // have patched versions that are below 218 but still have the `Delegate` + // flag. This is why we warn / inform users rather than failing. See + // MESOS-3352. + if (version.get() < DELEGATE_MINIMUM_VERSION) { + LOG(WARNING) + << "Required functionality `Delegate` was introduced in Version `" + << DELEGATE_MINIMUM_VERSION << "`. Your system may not function" + << " properly; however since some distributions have patched systemd" + << " packages, your system may still be functional. This is why we keep" + << " running. See MESOS-3352 for more information"; + } + + return true; + }(); + + return exists; +} + +} // namespace systemd { http://git-wip-us.apache.org/repos/asf/mesos/blob/ac76392b/src/linux/systemd.hpp ---------------------------------------------------------------------- diff --git a/src/linux/systemd.hpp b/src/linux/systemd.hpp new file mode 100644 index 0000000..81db822 --- /dev/null +++ b/src/linux/systemd.hpp @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 __SYSTEMD_HPP__ +#define __SYSTEMD_HPP__ + +namespace systemd { + +/** + * Check if we are on a systemd environment by: + * (1) Testing whether `/sbin/init` links to systemd. + * (2) Testing whether we have a systemd version. + * TODO(jmlvanre): This logic can be made more robust, but there does not seem + * to be a standardized way to test the executing init system in a + * cross-platform way. The task is made slightly easier because we are only + * interested in identifying if we are running on systemd, not which specific + * init system is running. + * + * @return Whether running on a systemd environment. + */ +bool exists(); + +} // namespace systemd { + +#endif // __SYSTEMD_HPP__ http://git-wip-us.apache.org/repos/asf/mesos/blob/ac76392b/src/slave/containerizer/linux_launcher.cpp ---------------------------------------------------------------------- diff --git a/src/slave/containerizer/linux_launcher.cpp b/src/slave/containerizer/linux_launcher.cpp index 459af1b..55155ca 100644 --- a/src/slave/containerizer/linux_launcher.cpp +++ b/src/slave/containerizer/linux_launcher.cpp @@ -34,6 +34,7 @@ #include "linux/cgroups.hpp" #include "linux/ns.hpp" +#include "linux/systemd.hpp" #include "mesos/resources.hpp" @@ -65,42 +66,56 @@ static ContainerID container(const string& cgroup) } +// `_systemdHierarchy` is only set if running on a systemd environment. LinuxLauncher::LinuxLauncher( const Flags& _flags, - const string& _hierarchy) + const string& _freezerHierarchy, + const Option<string>& _systemdHierarchy) : flags(_flags), - hierarchy(_hierarchy) {} + freezerHierarchy(_freezerHierarchy), + systemdHierarchy(_systemdHierarchy) {} Try<Launcher*> LinuxLauncher::create(const Flags& flags) { - Try<string> hierarchy = cgroups::prepare( + Try<string> freezerHierarchy = cgroups::prepare( flags.cgroups_hierarchy, "freezer", flags.cgroups_root); - if (hierarchy.isError()) { - return Error("Failed to create Linux launcher: " + hierarchy.error()); + if (freezerHierarchy.isError()) { + return Error( + "Failed to create Linux launcher: " + freezerHierarchy.error()); } - // Ensure that no other subsystem is attached to the hierarchy. - Try<set<string>> subsystems = cgroups::subsystems(hierarchy.get()); + // Ensure that no other subsystem is attached to the freezer hierarchy. + Try<set<string>> subsystems = cgroups::subsystems(freezerHierarchy.get()); if (subsystems.isError()) { return Error( "Failed to get the list of attached subsystems for hierarchy " + - hierarchy.get()); + freezerHierarchy.get()); } else if (subsystems.get().size() != 1) { return Error( "Unexpected subsystems found attached to the hierarchy " + - hierarchy.get()); + freezerHierarchy.get()); } - LOG(INFO) << "Using " << hierarchy.get() + LOG(INFO) << "Using " << freezerHierarchy.get() << " as the freezer hierarchy for the Linux launcher"; + // On systemd environments we currently migrate executor pids into a separate + // executor slice. This allows the life-time of the executor to be extended + // past the life-time of the slave. See MESOS-3352. + // The LinuxLauncher takes responsibility for creating and starting this + // slice. It then migrates executor pids into this slice before it "unpauses" + // the executor. This is the same pattern as the freezer. + return new LinuxLauncher( flags, - hierarchy.get()); + freezerHierarchy.get(), + systemd::exists() ? + Some(flags.cgroups_hierarchy + "/systemd") : + Option<std::string>::none()); } @@ -131,7 +146,7 @@ Future<hashset<ContainerID>> LinuxLauncher::recover( // destroy() when we clean up. pids.put(containerId, pid); - Try<bool> exists = cgroups::exists(hierarchy, cgroup(containerId)); + Try<bool> exists = cgroups::exists(freezerHierarchy, cgroup(containerId)); if (!exists.get()) { // This may occur if the freezer cgroup was destroyed but the @@ -147,7 +162,9 @@ Future<hashset<ContainerID>> LinuxLauncher::recover( } // Return the set of orphan containers. - Try<vector<string>> cgroups = cgroups::get(hierarchy, flags.cgroups_root); + Try<vector<string>> cgroups = + cgroups::get(freezerHierarchy, flags.cgroups_root); + if (cgroups.isError()) { return Failure(cgroups.error()); } @@ -215,14 +232,15 @@ Try<pid_t> LinuxLauncher::fork( const Option<int>& namespaces) { // Create a freezer cgroup for this container if necessary. - Try<bool> exists = cgroups::exists(hierarchy, cgroup(containerId)); + Try<bool> exists = cgroups::exists(freezerHierarchy, cgroup(containerId)); if (exists.isError()) { return Error("Failed to check existence of freezer cgroup: " + exists.error()); } if (!exists.get()) { - Try<Nothing> created = cgroups::create(hierarchy, cgroup(containerId)); + Try<Nothing> created = + cgroups::create(freezerHierarchy, cgroup(containerId)); if (created.isError()) { return Error("Failed to create freezer cgroup: " + created.error()); @@ -266,7 +284,7 @@ Try<pid_t> LinuxLauncher::fork( // TODO(jieyu): Move this logic to the subprocess (i.e., // mesos-containerizer launch). Try<Nothing> assign = cgroups::assign( - hierarchy, + freezerHierarchy, cgroup(containerId), child.get().pid()); @@ -313,7 +331,7 @@ Future<Nothing> LinuxLauncher::destroy(const ContainerID& containerId) // Just return if the cgroup was destroyed and the slave didn't receive the // notification. See comment in recover(). - Try<bool> exists = cgroups::exists(hierarchy, cgroup(containerId)); + Try<bool> exists = cgroups::exists(freezerHierarchy, cgroup(containerId)); if (exists.isError()) { return Failure("Failed to check existence of freezer cgroup: " + exists.error()); @@ -334,14 +352,14 @@ Future<Nothing> LinuxLauncher::destroy(const ContainerID& containerId) (Future<Nothing>(*)(const string&, const string&, const Duration&))(&cgroups::destroy), - hierarchy, + freezerHierarchy, cgroup(containerId), cgroups::DESTROY_TIMEOUT)); } // Try to clean up using just the freezer cgroup. return cgroups::destroy( - hierarchy, + freezerHierarchy, cgroup(containerId), cgroups::DESTROY_TIMEOUT); } http://git-wip-us.apache.org/repos/asf/mesos/blob/ac76392b/src/slave/containerizer/linux_launcher.hpp ---------------------------------------------------------------------- diff --git a/src/slave/containerizer/linux_launcher.hpp b/src/slave/containerizer/linux_launcher.hpp index f6112c9..f3b666d 100644 --- a/src/slave/containerizer/linux_launcher.hpp +++ b/src/slave/containerizer/linux_launcher.hpp @@ -54,11 +54,13 @@ public: private: LinuxLauncher( const Flags& flags, - const std::string& hierarchy); + const std::string& freezerHierarchy, + const Option<std::string>& systemdHierarchy); static const std::string subsystem; const Flags flags; - const std::string hierarchy; + const std::string freezerHierarchy; + const Option<std::string> systemdHierarchy; std::string cgroup(const ContainerID& containerId);
