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

[07/11] mesos git commit: Optionally isolate only the agent network ports.

Optionally isolate only the agent network ports.

Normally, the `network/ports` isolator will kill any task that
listens on a port that it does not have resources for. However,
executors that are based on the libprocess API will always
listen on a port in the ephemeral range, and we want to make
it possible to use libprocess-based executors.

Added the `--check_agent_port_range_only` option to only kill
tasks when they listen on un-allocated ports within the port
range published by the agent resources. This still prevents
port collisions between tasks, but doesn't kill them just
because the executor is listening on a port.

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


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

Branch: refs/heads/master
Commit: 2fc779bfcdcf511563d7c57a6ee02d8ac5382c5e
Parents: 4868d0b
Author: James Peach <jp...@apache.org>
Authored: Thu Oct 19 15:35:54 2017 -0700
Committer: James Peach <jp...@apache.org>
Committed: Thu Oct 19 16:33:35 2017 -0700

----------------------------------------------------------------------
 .../mesos/isolators/network/ports.cpp           | 84 +++++++++++++++++++-
 .../mesos/isolators/network/ports.hpp           |  5 +-
 src/slave/flags.cpp                             |  8 ++
 src/slave/flags.hpp                             |  1 +
 4 files changed, 93 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/2fc779bf/src/slave/containerizer/mesos/isolators/network/ports.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/network/ports.cpp b/src/slave/containerizer/mesos/isolators/network/ports.cpp
index 5a58d07..243ba01 100644
--- a/src/slave/containerizer/mesos/isolators/network/ports.cpp
+++ b/src/slave/containerizer/mesos/isolators/network/ports.cpp
@@ -36,6 +36,8 @@
 
 #include "linux/cgroups.hpp"
 
+#include "slave/constants.hpp"
+
 #include "slave/containerizer/mesos/linux_launcher.hpp"
 
 using std::list;
@@ -72,6 +74,7 @@ static hashmap<ContainerID, IntervalSet<uint16_t>>
 collectContainerListeners(
     const string& cgroupsRoot,
     const string& freezerHierarchy,
+    const Option<IntervalSet<uint16_t>>& agentPorts,
     const hashset<ContainerID>& containerIds)
 {
   hashmap<ContainerID, IntervalSet<uint16_t>> listeners;
@@ -144,7 +147,11 @@ collectContainerListeners(
           }
         }
 
-        listeners[containerId].add(address.port);
+        // If we are filtering by agent ports, then we only collect this
+        // listen socket if it falls within the agent port range.
+        if (agentPorts.isNone() || agentPorts->contains(address.port)) {
+          listeners[containerId].add(address.port);
+        }
       }
     }
   }
@@ -250,6 +257,23 @@ Try<vector<uint32_t>> NetworkPortsIsolatorProcess::getProcessSockets(pid_t pid)
 }
 
 
+// Return true if any "ports" resources are specified in the flags. This
+// is later used to distinguish between empty an unspecified ports.
+static bool havePortsResource(const Flags& flags)
+{
+  vector<Resource> resourceList = Resources::fromString(
+      flags.resources.getOrElse(""), flags.default_role).get();
+
+  foreach(const auto& resource, resourceList) {
+    if (resource.name() == "ports") {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
 Try<Isolator*> NetworkPortsIsolatorProcess::create(const Flags& flags)
 {
   if (flags.launcher != "linux") {
@@ -267,22 +291,73 @@ Try<Isolator*> NetworkPortsIsolatorProcess::create(const Flags& flags)
         freezerHierarchy.error());
   }
 
+
+  Option<IntervalSet<uint16_t>> agentPorts = None();
+
+  // If we are only watching the ports in the agent resources, figure
+  // out what the agent ports will be by checking the resources flag
+  // and falling back to the default.
+  if (flags.check_agent_port_range_only) {
+    Try<Resources> resources = Resources::parse(
+        flags.resources.getOrElse(""),
+        flags.default_role);
+
+    if (resources.isError()) {
+      return Error(
+          "Failed to parse agent resources: " + resources.error());
+    }
+
+    // Mirroring the logic in Containerizer::resources(), we need
+    // to distinguish between an empty ports resource and a missing
+    // ports resource.
+    if (!havePortsResource(flags)) {
+      // Apply the defaults, if no ports were specified.
+      resources = Resources(
+          Resources::parse(
+              "ports",
+              stringify(DEFAULT_PORTS),
+              flags.default_role).get());
+
+      agentPorts =
+        rangesToIntervalSet<uint16_t>(resources->ports().get()).get();
+    } else if (resources->ports().isSome()) {
+      // Use the given non-empty ports resource.
+      Try<IntervalSet<uint16_t>> ports =
+        rangesToIntervalSet<uint16_t>(resources->ports().get());
+
+      if (ports.isError()) {
+        return Error(
+            "Invalid ports resource '" +
+            stringify(resources->ports().get()) +
+            "': " + ports.error());
+      }
+
+      agentPorts = ports.get();
+    } else {
+      // An empty ports resource was specified.
+      agentPorts = IntervalSet<uint16_t>{};
+    }
+  }
+
   return new MesosIsolator(process::Owned<MesosIsolatorProcess>(
       new NetworkPortsIsolatorProcess(
           flags.container_ports_watch_interval,
           flags.cgroups_root,
-          freezerHierarchy.get())));
+          freezerHierarchy.get(),
+          agentPorts)));
 }
 
 
 NetworkPortsIsolatorProcess::NetworkPortsIsolatorProcess(
     const Duration& _watchInterval,
     const string& _cgroupsRoot,
-    const string& _freezerHierarchy)
+    const string& _freezerHierarchy,
+    const Option<IntervalSet<uint16_t>>& _agentPorts)
   : ProcessBase(process::ID::generate("network-ports-isolator")),
     watchInterval(_watchInterval),
     cgroupsRoot(_cgroupsRoot),
-    freezerHierarchy(_freezerHierarchy)
+    freezerHierarchy(_freezerHierarchy),
+    agentPorts(_agentPorts)
 {
 }
 
@@ -458,6 +533,7 @@ void NetworkPortsIsolatorProcess::initialize()
             &collectContainerListeners,
             cgroupsRoot,
             freezerHierarchy,
+            agentPorts,
             infos.keys())
           .then(defer(self, &NetworkPortsIsolatorProcess::check, lambda::_1))
           .then([]() -> ControlFlow<Nothing> { return Continue(); });

http://git-wip-us.apache.org/repos/asf/mesos/blob/2fc779bf/src/slave/containerizer/mesos/isolators/network/ports.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/network/ports.hpp b/src/slave/containerizer/mesos/isolators/network/ports.hpp
index 5a1e0e3..6ce35e7 100644
--- a/src/slave/containerizer/mesos/isolators/network/ports.hpp
+++ b/src/slave/containerizer/mesos/isolators/network/ports.hpp
@@ -27,6 +27,7 @@
 #include <stout/duration.hpp>
 #include <stout/hashmap.hpp>
 #include <stout/interval.hpp>
+#include <stout/option.hpp>
 
 #include "linux/routing/diagnosis/diagnosis.hpp"
 
@@ -84,7 +85,8 @@ private:
   NetworkPortsIsolatorProcess(
       const Duration& _watchInterval,
       const std::string& _cgroupsRoot,
-      const std::string& _freezerHierarchy);
+      const std::string& _freezerHierarchy,
+      const Option<IntervalSet<uint16_t>>& agentPorts);
 
   struct Info
   {
@@ -95,6 +97,7 @@ private:
   const Duration watchInterval;
   const std::string cgroupsRoot;
   const std::string freezerHierarchy;
+  const Option<IntervalSet<uint16_t>> agentPorts;
 
   hashmap<ContainerID, process::Owned<Info>> infos;
 };

http://git-wip-us.apache.org/repos/asf/mesos/blob/2fc779bf/src/slave/flags.cpp
----------------------------------------------------------------------
diff --git a/src/slave/flags.cpp b/src/slave/flags.cpp
index d9116de..789b45b 100644
--- a/src/slave/flags.cpp
+++ b/src/slave/flags.cpp
@@ -1009,6 +1009,14 @@ mesos::internal::slave::Flags::Flags()
       "Interval at which the `network/ports` isolator should check for\n"
       "containers listening on ports they don't have resources for.",
       Seconds(30));
+
+  add(&Flags::check_agent_port_range_only,
+      "check_agent_port_range_only",
+      "When this is true, the `network/ports` isolator allows tasks to\n"
+      "listen on additional ports provided they fall outside the range\n"
+      "published by the agent's resources. Otherwise tasks are restricted\n"
+      "to only listen on ports for which they have been assigned resources.",
+      false);
 #endif // ENABLE_NETWORK_PORTS_ISOLATOR
 
   add(&Flags::network_cni_plugins_dir,

http://git-wip-us.apache.org/repos/asf/mesos/blob/2fc779bf/src/slave/flags.hpp
----------------------------------------------------------------------
diff --git a/src/slave/flags.hpp b/src/slave/flags.hpp
index a038e9d..d02edbf 100644
--- a/src/slave/flags.hpp
+++ b/src/slave/flags.hpp
@@ -147,6 +147,7 @@ public:
 
 #ifdef ENABLE_NETWORK_PORTS_ISOLATOR
   Duration container_ports_watch_interval;
+  bool check_agent_port_range_only;
 #endif // ENABLE_NETWORK_PORTS_ISOLATOR
 
   Option<std::string> network_cni_plugins_dir;