You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by jo...@apache.org on 2015/09/24 06:18:33 UTC

[2/4] mesos git commit: Create and Start `mesos_executor.slice` in LinuxLauncher on Systemd.

Create and Start `mesos_executor.slice` in LinuxLauncher on Systemd.

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


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

Branch: refs/heads/master
Commit: 76a4e18dab3d5a342b24775cf64898a9b6df3ef4
Parents: ac76392
Author: Joris Van Remoortere <jo...@gmail.com>
Authored: Wed Sep 23 17:46:45 2015 -0700
Committer: Joris Van Remoortere <jo...@gmail.com>
Committed: Wed Sep 23 20:56:46 2015 -0700

----------------------------------------------------------------------
 src/linux/systemd.cpp                      | 117 ++++++++++++++++++++++++
 src/linux/systemd.hpp                      |  75 +++++++++++++++
 src/slave/containerizer/linux_launcher.cpp |  61 +++++++++++-
 src/slave/containerizer/linux_launcher.hpp |   3 +
 src/slave/flags.cpp                        |   5 +
 src/slave/flags.hpp                        |   1 +
 6 files changed, 261 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/76a4e18d/src/linux/systemd.cpp
----------------------------------------------------------------------
diff --git a/src/linux/systemd.cpp b/src/linux/systemd.cpp
index 7084e70..dde9e37 100644
--- a/src/linux/systemd.cpp
+++ b/src/linux/systemd.cpp
@@ -21,10 +21,14 @@
 #include <string>
 #include <vector>
 
+#include <process/once.hpp>
+
 #include <stout/os.hpp>
 #include <stout/strings.hpp>
 #include <stout/try.hpp>
 
+using process::Once;
+
 using std::string;
 using std::vector;
 
@@ -32,6 +36,52 @@ namespace systemd {
 
 int DELEGATE_MINIMUM_VERSION = 218;
 
+
+Flags::Flags()
+{
+  add(&Flags::runtime_directory,
+      "runtime_directory",
+      "The path to the systemd system run time directory\n",
+      "/run/systemd/system");
+
+  add(&Flags::cgroups_hierarchy,
+      "cgroups_hierarchy",
+      "The path to the cgroups hierarchy root\n",
+      "/sys/fs/cgroup");
+}
+
+
+static Flags* systemd_flags = NULL;
+
+
+const Flags& flags()
+{
+  return *CHECK_NOTNULL(systemd_flags);
+}
+
+
+Try<Nothing> initialize(const Flags& flags)
+{
+  static Once* initialized = new Once();
+
+  if (initialized->once()) {
+    return Nothing();
+  }
+
+  systemd_flags = new Flags(flags);
+
+  // If flags->runtime_directory doesn't exist, then we can't proceed.
+  if (!os::exists(CHECK_NOTNULL(systemd_flags)->runtime_directory)) {
+    return Error("Failed to locate systemd runtime directory: " +
+                 CHECK_NOTNULL(systemd_flags)->runtime_directory);
+  }
+
+  initialized->done();
+
+  return Nothing();
+}
+
+
 bool exists()
 {
   // This is static as the init system should not change while we are running.
@@ -97,4 +147,71 @@ bool exists()
   return exists;
 }
 
+
+Path runtimeDirectory()
+{
+  return Path(flags().runtime_directory);
+}
+
+
+Path hierarchy()
+{
+  return Path(path::join(flags().cgroups_hierarchy, "systemd"));
+}
+
+
+Try<Nothing> daemonReload()
+{
+  Try<std::string> daemonReload = os::shell("systemctl daemon-reload");
+  if (daemonReload.isError()) {
+    return Error("Failed to reload systemd daemon: " + daemonReload.error());
+  }
+
+  return Nothing();
+}
+
+namespace slices {
+
+bool exists(const Path& path)
+{
+  return os::exists(path);
+}
+
+
+Try<Nothing> create(const Path& path, const string& data)
+{
+  Try<Nothing> write = os::write(path, data);
+  if (write.isError()) {
+    return Error(
+        "Failed to write systemd slice `" + path.value + "`: " + write.error());
+  }
+
+  LOG(INFO) << "Created systemd slice: `" << path << "`";
+
+  Try<Nothing> reload = daemonReload();
+  if (reload.isError()) {
+    return Error("Failed to create systemd slice `" + path.value + "`: " +
+                 reload.error());
+  }
+
+  return Nothing();
+}
+
+
+Try<Nothing> start(const std::string& name)
+{
+  Try<std::string> start = os::shell("systemctl start " + name);
+
+  if (start.isError()) {
+    return Error(
+        "Failed to start systemd slice `" + name + "`: " + start.error());
+  }
+
+  LOG(INFO) << "Started systemd slice `" << name << "`";
+
+  return Nothing();
+}
+
+} // namespace slices {
+
 } // namespace systemd {

http://git-wip-us.apache.org/repos/asf/mesos/blob/76a4e18d/src/linux/systemd.hpp
----------------------------------------------------------------------
diff --git a/src/linux/systemd.hpp b/src/linux/systemd.hpp
index 81db822..7121967 100644
--- a/src/linux/systemd.hpp
+++ b/src/linux/systemd.hpp
@@ -19,9 +19,36 @@
 #ifndef __SYSTEMD_HPP__
 #define __SYSTEMD_HPP__
 
+#include <stout/flags.hpp>
+#include <stout/nothing.hpp>
+#include <stout/path.hpp>
+#include <stout/try.hpp>
+
 namespace systemd {
 
 /**
+ * Flags to initialize systemd state.
+ */
+class Flags : public virtual flags::FlagsBase
+{
+public:
+  Flags();
+
+  std::string runtime_directory;
+  std::string cgroups_hierarchy;
+};
+
+const Flags& flags();
+
+/**
+ * Initialized state for support of systemd functions in this file.
+ *
+ * @return Nothing if successful, otherwise Error.
+ */
+Try<Nothing> initialize(const Flags& flags);
+
+
+/**
  * 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.
@@ -35,6 +62,54 @@ namespace systemd {
  */
 bool exists();
 
+
+/**
+ * Returns the path to the runtime directory for systemd units.
+ */
+Path runtimeDirectory();
+
+
+/**
+ * Return the path to the systemd hierarchy.
+ */
+Path hierarchy();
+
+
+/**
+ * Runs systemctl daemon-reload.
+ *
+ * Used after updating configuration files.
+ *
+ * @return Nothing if successful, otherwise Error.
+ */
+Try<Nothing> daemonReload();
+
+namespace slices {
+
+/**
+ * Returns whether a systemd slice configuration file exists at the given path.
+ */
+bool exists(const Path& path);
+
+
+/**
+ * Creates a slice configuration with the provided contents at the given path.
+ *
+ * @param path The path at which to create the slice configurations file.
+ * @param data The contents of the configuration file.
+ *
+ * @return Nothing if successful, otherwise Error.
+ */
+Try<Nothing> create(const Path& path, const std::string& data);
+
+
+/**
+ * Starts the slice with the given name (via 'systemctl start <name>').
+ */
+Try<Nothing> start(const std::string& name);
+
+} // namespace slices {
+
 } // namespace systemd {
 
 #endif // __SYSTEMD_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/76a4e18d/src/slave/containerizer/linux_launcher.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/linux_launcher.cpp b/src/slave/containerizer/linux_launcher.cpp
index 55155ca..b746e54 100644
--- a/src/slave/containerizer/linux_launcher.cpp
+++ b/src/slave/containerizer/linux_launcher.cpp
@@ -110,11 +110,70 @@ Try<Launcher*> LinuxLauncher::create(const Flags& flags)
   // slice. It then migrates executor pids into this slice before it "unpauses"
   // the executor. This is the same pattern as the freezer.
 
+  // If this is a systemd environment, ensure that the
+  // `SYSTEMD_MESOS_EXECUTORS_SLICE` exists and is running.
+  // TODO(jmlvanre): Prevent racing between multiple agents for this creation
+  // logic.
+  if (systemd::exists()) {
+    systemd::Flags systemdFlags;
+    systemdFlags.runtime_directory = flags.systemd_runtime_directory;
+    systemdFlags.cgroups_hierarchy = flags.cgroups_hierarchy;
+    Try<Nothing> initialize = systemd::initialize(systemdFlags);
+    if (initialize.isError()) {
+      return Error("Failed to initialize systemd: " + initialize.error());
+    }
+
+    // Check whether the `SYSTEMD_MESOS_EXECUTORS_SLICE` already exists. Create
+    // it if it does not exist.
+    // We explicitly don't modify the file if it exists in case operators want
+    // to over-ride the settings for the slice that we provide when we create
+    // the `Unit` below.
+    const Path path(path::join(
+        systemd::runtimeDirectory(),
+        SYSTEMD_MESOS_EXECUTORS_SLICE));
+
+    if (!systemd::slices::exists(path)) {
+      // A simple systemd file to allow us to start a new slice.
+      string unit = "[Unit]\nDescription=Mesos Executors Slice\n";
+
+      Try<Nothing> create = systemd::slices::create(path, unit);
+
+      if (create.isError()) {
+        return Error("Failed to create systemd slice `" +
+                     stringify(SYSTEMD_MESOS_EXECUTORS_SLICE) + "`: " +
+                     create.error());
+      }
+    }
+
+    // Regardless of whether we created the file or it existed already, we
+    // `start` the executor slice. It is safe (a no-op) to `start` an already
+    // running slice.
+    Try<Nothing> start = systemd::slices::start(SYSTEMD_MESOS_EXECUTORS_SLICE);
+
+    if (start.isError()) {
+      return Error("Failed to start `" +
+                   stringify(SYSTEMD_MESOS_EXECUTORS_SLICE) +
+                   "`: " + start.error());
+    }
+
+    // Now the `SYSTEMD_MESOS_EXECUTORS_SLICE` is ready for us to assign any
+    // executors. We can verify that our cgroups assignments will work by
+    // testing the hierarchy.
+    Try<bool> exists = cgroups::exists(
+        systemd::hierarchy(),
+        SYSTEMD_MESOS_EXECUTORS_SLICE);
+
+    if (exists.isError() || !exists.get()) {
+      return Error("Failed to locate systemd cgroups hierarchy: " +
+                   (exists.isError() ? exists.error() : "does not exist"));
+    }
+  }
+
   return new LinuxLauncher(
       flags,
       freezerHierarchy.get(),
       systemd::exists() ?
-        Some(flags.cgroups_hierarchy + "/systemd") :
+        Some(systemd::hierarchy()) :
         Option<std::string>::none());
 }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/76a4e18d/src/slave/containerizer/linux_launcher.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/linux_launcher.hpp b/src/slave/containerizer/linux_launcher.hpp
index f3b666d..35b3315 100644
--- a/src/slave/containerizer/linux_launcher.hpp
+++ b/src/slave/containerizer/linux_launcher.hpp
@@ -25,6 +25,9 @@ namespace mesos {
 namespace internal {
 namespace slave {
 
+// TODO(jmlvanre): We may want to allow this to be configured.
+static const char SYSTEMD_MESOS_EXECUTORS_SLICE[] = "mesos_executors.slice";
+
 // Launcher for Linux systems with cgroups. Uses a freezer cgroup to
 // track pids.
 class LinuxLauncher : public Launcher

http://git-wip-us.apache.org/repos/asf/mesos/blob/76a4e18d/src/slave/flags.cpp
----------------------------------------------------------------------
diff --git a/src/slave/flags.cpp b/src/slave/flags.cpp
index 6164b4b..ab3b0e1 100644
--- a/src/slave/flags.cpp
+++ b/src/slave/flags.cpp
@@ -316,6 +316,11 @@ mesos::internal::slave::Flags::Flags()
       "normal containers (non-revocable cpu). Currently only\n"
       "supported by the cgroups/cpu isolator.",
       true);
+
+  add(&Flags::systemd_runtime_directory,
+      "systemd_runtime_directory",
+      "The path to the systemd system run time directory\n",
+      "/run/systemd/system");
 #endif
 
   add(&Flags::firewall_rules,

http://git-wip-us.apache.org/repos/asf/mesos/blob/76a4e18d/src/slave/flags.hpp
----------------------------------------------------------------------
diff --git a/src/slave/flags.hpp b/src/slave/flags.hpp
index b8d6bb4..bbf8171 100644
--- a/src/slave/flags.hpp
+++ b/src/slave/flags.hpp
@@ -88,6 +88,7 @@ public:
   Duration perf_interval;
   Duration perf_duration;
   bool revocable_cpu_low_priority;
+  std::string systemd_runtime_directory;
 #endif
   Option<Firewall> firewall_rules;
   Option<Path> credential;