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 2016/10/13 00:52:50 UTC

mesos git commit: Implemented `delegate` method.

Repository: mesos
Updated Branches:
  refs/heads/master 8b4d83aec -> 99cbe69eb


Implemented `delegate` method.

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


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

Branch: refs/heads/master
Commit: 99cbe69eb4dd7e5bcac7a5df4134d1af9e4a00b8
Parents: 8b4d83a
Author: Avinash sridharan <av...@mesosphere.io>
Authored: Wed Oct 12 16:04:43 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Wed Oct 12 17:52:46 2016 -0700

----------------------------------------------------------------------
 .../cni/plugins/port_mapper/port_mapper.cpp     | 154 ++++++++++++++++++-
 1 file changed, 148 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/99cbe69e/src/slave/containerizer/mesos/isolators/network/cni/plugins/port_mapper/port_mapper.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/network/cni/plugins/port_mapper/port_mapper.cpp b/src/slave/containerizer/mesos/isolators/network/cni/plugins/port_mapper/port_mapper.cpp
index 0473645..2ff8b0e 100644
--- a/src/slave/containerizer/mesos/isolators/network/cni/plugins/port_mapper/port_mapper.cpp
+++ b/src/slave/containerizer/mesos/isolators/network/cni/plugins/port_mapper/port_mapper.cpp
@@ -25,11 +25,19 @@
 #include "slave/containerizer/mesos/isolators/network/cni/spec.hpp"
 #include "slave/containerizer/mesos/isolators/network/cni/plugins/port_mapper/port_mapper.hpp"
 
+namespace io = process::io;
+
+using std::cerr;
+using std::endl;
+using std::map;
 using std::string;
+using std::tuple;
 using std::vector;
 
+using process::Failure;
 using process::Future;
 using process::Owned;
+using process::Subprocess;
 
 using mesos::NetworkInfo;
 
@@ -180,19 +188,23 @@ Try<Owned<PortMapper>, PluginError> PortMapper::create(const string& _cniConfig)
   // 'delegate' as it should be a valid CNI config JSON.
 
   // Make sure the 'delegate' plugin exists.
-  Result<JSON::String> delegatePlugin =
+  Result<JSON::String> _delegatePlugin =
     _delegateConfig->find<JSON::String>("type");
 
-  if (!delegatePlugin.isSome()) {
+  if (!_delegatePlugin.isSome()) {
     return PluginError(
         "Failed to get the delegate plugin 'type'" +
-        (delegatePlugin.isError() ? delegatePlugin.error() : "Not found"),
+        (_delegatePlugin.isError() ? _delegatePlugin.error() : "Not found"),
         ERROR_BAD_ARGS);
   }
 
-  if (os::which(delegatePlugin->value, cniPath.get()).isNone()) {
+  Option<string> delegatePlugin = os::which(
+      _delegatePlugin->value,
+      cniPath.get());
+
+  if (delegatePlugin.isNone()) {
     return PluginError(
-        "Could not find the delegate plugin '" + delegatePlugin->value +
+        "Could not find the delegate plugin '" + _delegatePlugin->value +
         "' in '" + cniPath.get() + "'",
         ERROR_BAD_ARGS);
   }
@@ -211,7 +223,7 @@ Try<Owned<PortMapper>, PluginError> PortMapper::create(const string& _cniConfig)
           cniArgs,
           cniPath.get(),
           networkInfo.get(),
-          delegatePlugin->value,
+          delegatePlugin.get(),
           delegateConfig,
           chain->value,
           excludeDevices));
@@ -226,6 +238,136 @@ Try<Option<string>, PluginError> PortMapper::execute()
 
 Result<spec::NetworkInfo> PortMapper::delegate(const string& command)
 {
+  map<std::string, std::string> environment;
+
+  environment["CNI_COMMAND"] = command;
+  environment["CNI_IFNAME"] = cniIfName;
+  environment["CNI_NETNS"] = cniNetNs;
+  environment["CNI_PATH"] = cniPath;
+
+  if (cniContainerId.isSome()) {
+    environment["CNI_CONTAINERID"] = cniContainerId.get();
+  }
+
+  if (cniArgs.isSome()) {
+    environment["CNI_ARGS"] = cniArgs.get();
+  }
+
+  // Some CNI plugins need to run "iptables" to set up IP Masquerade,
+  // so we need to set the "PATH" environment variable so that the
+  // plugin can locate the "iptables" executable file.
+  Option<string> value = os::getenv("PATH");
+  if (value.isSome()) {
+    environment["PATH"] = value.get();
+  } else {
+    environment["PATH"] =
+      "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
+  }
+
+  Try<string> temp = os::mktemp();
+  if (temp.isError()) {
+    return Error("Failed to create the temp file: " + temp.error());
+  }
+
+  Try<Nothing> write = os::write(
+      temp.get(),
+      stringify(delegateConfig));
+
+  if (write.isError()) {
+    os::rm(temp.get());
+    return Error("Failed to write the temp file: " + write.error());
+  }
+
+  Try<Subprocess> s = process::subprocess(
+      delegatePlugin,
+      {delegatePlugin},
+      Subprocess::PATH(temp.get()),
+      Subprocess::PIPE(),
+      Subprocess::PIPE(),
+      nullptr,
+      environment);
+
+  if (s.isError()) {
+    return Error(
+        "Failed to exec the '" + delegatePlugin +
+        "' subprocess: " + s.error());
+  }
+
+  auto result = await(
+      s->status(),
+      io::read(s->out().get()),
+      io::read(s->err().get()));
+
+  result.await();
+
+  // At this point the subprocess has completed and hence we need to
+  // remove the `temp` file that we created.
+  os::rm(temp.get());
+
+  if (!result.isReady()) {
+    return Error(
+        "Failed to wait for exec of delegate CNI plugin '" +
+        delegatePlugin + "': " +
+        (result.isDiscarded() ? "discarded" : result.failure()));
+  }
+
+  Future<Option<int>> status = std::get<0>(result.get());
+  if (!status.isReady()) {
+    return Error(
+        "Failed to get the exit status of the delegate CNI plugin '" +
+        delegatePlugin + "' subprocess: " +
+        (status.isFailed() ? status.failure() : "discarded"));
+  }
+
+  if (status->isNone()) {
+    return Error(
+        "Failed to reap the delegate CNI plugin '" +
+        delegatePlugin + "' subprocess");
+  }
+
+  // CNI plugin will print result or error to stdout.
+  Future<string> output = std::get<1>(result.get());
+  if (!output.isReady()) {
+    return Error(
+        "Failed to read stdout from the delegate CNI plugin '" +
+        delegatePlugin + "' subprocess: " +
+        (output.isFailed() ? output.failure() : "discarded"));
+  }
+
+  // We are reading stderr of the plugin since any log messages from
+  // the CNI plugin would be thrown on stderr. This can be useful for
+  // debugging issues when the plugin throws a `spec::Error`.
+  Future<string> err = std::get<2>(result.get());
+  if (!err.isReady()) {
+    return Error(
+        "Failed to read STDERR from the delegate CNI plugin '" +
+        delegatePlugin + "' subprocess: " +
+        (err.isFailed() ? err.failure() : "discarded"));
+  }
+
+  if (status.get() != 0) {
+    cerr << "Delegate plugin reported error: " << err.get() << endl;
+
+    return Error(
+        "The delegate CNI plugin '" + delegatePlugin +
+        "' return status " + stringify(status->get()) +
+        ". Could not attach container: " + output.get());
+  }
+
+  if (command == spec::CNI_CMD_ADD) {
+    // Parse the output of CNI plugin.
+    Try<spec::NetworkInfo> parse = spec::parseNetworkInfo(output.get());
+    if (parse.isError()) {
+      return Error(
+          "Failed to parse the output of the delegate CNI plugin '" +
+          delegatePlugin + "': " + parse.error());
+    }
+
+    return parse.get();
+  }
+
+  // For `spec::CNI_CMD_DEL` CNI plugins don't return a result. They
+  // will report an error if any, which should be captured above.
   return None();
 }