This is an automated email from the ASF dual-hosted git repository.

jieyu pushed a commit to branch 1.6.x
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit 416d50d1d395e147ca10bc4ff46db992305883b1
Author: Deepak Goel <deepak.go...@gmail.com>
AuthorDate: Tue Dec 18 22:04:06 2018 -0800

    Allowed CNI root directory to be in a persistent location.
    
    This patch added the support to configure the CNI root directory to be
    under `work_dir` so that the network related information persist across
    reboot which will allow cni isolator to do proper cleanup post reboot.
    
    A new agent flag `--network_cni_root_dir_persist` has been introduced.
    
    Review: https://reviews.apache.org/r/69590/
    (cherry picked from commit 5ab822cfce6d27c86832645cbc007eee8791db5f)
    
    *** Modified for 1.6.x ***
---
 docs/cni.md                                        |  7 +++
 docs/configuration/agent.md                        |  9 ++++
 .../mesos/isolators/network/cni/cni.cpp            | 30 ++++++++-----
 .../mesos/isolators/network/cni/paths.cpp          | 10 +++++
 .../mesos/isolators/network/cni/paths.hpp          |  9 +++-
 src/slave/flags.cpp                                |  6 +++
 src/slave/flags.hpp                                |  1 +
 src/tests/containerizer/cni_isolator_tests.cpp     | 51 +++++++++++++++++++---
 8 files changed, 103 insertions(+), 20 deletions(-)

diff --git a/docs/cni.md b/docs/cni.md
index 73b0e64..3769272 100644
--- a/docs/cni.md
+++ b/docs/cni.md
@@ -103,6 +103,13 @@ after Agent startup, the Agent needs to be restarted. The
 and hence restarting the Agent (and therefore the `network/cni`
 isolator) will not affect container orchestration.
 
+Optionally, the operator could specify the
+`--network_cni_root_dir_persist` flag. This flag would allow
+`network/cni` isolator to persist the network related information
+across reboot and allow `network/cni` isolator to carry out network
+cleanup post reboot. This is useful for the CNI networks that depend
+on the isolator to clean their network state.
+
 #### <a name="adding-modifying-deleting"></a>Adding/Deleting/Modifying CNI 
networks
 
 The `network/cni` isolator learns about all the CNI networks by
diff --git a/docs/configuration/agent.md b/docs/configuration/agent.md
index c130cca..3978c95 100644
--- a/docs/configuration/agent.md
+++ b/docs/configuration/agent.md
@@ -1059,6 +1059,15 @@ a network configuration file in JSON format in the 
specified directory.
 </tr>
 <tr>
   <td>
+    --[no-]network_cni_root_dir_persist
+  </td>
+  <td>
+This setting controls whether the CNI root directory persists across
+reboot or not.
+  </td>
+</tr>
+<tr>
+  <td>
     --oversubscribed_resources_interval=VALUE
   </td>
   <td>
diff --git a/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp 
b/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
index 55ecc9c..1ad3e2a 100644
--- a/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
+++ b/src/slave/containerizer/mesos/isolators/network/cni/cni.cpp
@@ -134,19 +134,21 @@ Try<Isolator*> NetworkCniIsolatorProcess::create(const 
Flags& flags)
     return Error("Unable to load CNI config: " + networkConfigs.error());
   }
 
+  const string cniRootDir = paths::getCniRootDir(flags);
+
   // Create the CNI network information root directory if it does not exist.
-  Try<Nothing> mkdir = os::mkdir(paths::ROOT_DIR);
+  Try<Nothing> mkdir = os::mkdir(cniRootDir);
   if (mkdir.isError()) {
     return Error(
         "Failed to create CNI network information root directory at '" +
-        string(paths::ROOT_DIR) + "': " + mkdir.error());
+        cniRootDir + "': " + mkdir.error());
   }
 
-  Result<string> rootDir = os::realpath(paths::ROOT_DIR);
+  Result<string> rootDir = os::realpath(cniRootDir);
   if (!rootDir.isSome()) {
     return Error(
         "Failed to determine canonical path of CNI network information root"
-        " directory '" + string(paths::ROOT_DIR) + "': " +
+        " directory '" + cniRootDir + "': " +
         (rootDir.isError() ? rootDir.error() : "No such file or directory"));
   }
 
@@ -1275,11 +1277,13 @@ Future<Nothing> NetworkCniIsolatorProcess::attach(
         stringify(networkConfigJSON.get()) + "': " + checkpoint.error());
   }
 
-  VLOG(1) << "Invoking CNI plugin '" << plugin.get()
-          << "' with network configuration '"
+  LOG(INFO) << "Invoking CNI plugin '" << plugin.get()
+            << "' to attach container " << containerId
+            << " to network '" << networkName << "'";
+
+  VLOG(1) << "Using network configuration '"
           << stringify(networkConfigJSON.get())
-          << "' to attach container " << containerId << " to network '"
-          << networkName << "'";
+          << "' for container " << containerId;
 
   Try<Subprocess> s = subprocess(
       plugin.get(),
@@ -1654,10 +1658,12 @@ Future<Nothing> NetworkCniIsolatorProcess::detach(
         " to network '" + networkName + "'");
   }
 
-  VLOG(1) << "Invoking CNI plugin '" << plugin.get()
-          << "' with network configuration '" << networkConfigPath
-          << "' to detach container " << containerId << " from network '"
-          << networkName << "'";
+  LOG(INFO) << "Invoking CNI plugin '" << plugin.get()
+            << "' to detach container " << containerId
+            << " from network '" << networkName << "'";
+
+  VLOG(1) << "Using network configuration at '" << networkConfigPath
+          << "' for container " << containerId;
 
   Try<Subprocess> s = subprocess(
       plugin.get(),
diff --git a/src/slave/containerizer/mesos/isolators/network/cni/paths.cpp 
b/src/slave/containerizer/mesos/isolators/network/cni/paths.cpp
index c1cb4f7..5598b7d 100644
--- a/src/slave/containerizer/mesos/isolators/network/cni/paths.cpp
+++ b/src/slave/containerizer/mesos/isolators/network/cni/paths.cpp
@@ -31,6 +31,16 @@ namespace slave {
 namespace cni {
 namespace paths {
 
+string getCniRootDir(const Flags& flags)
+{
+  string workDir = flags.network_cni_root_dir_persist
+    ? flags.work_dir
+    : flags.runtime_dir;
+
+  return path::join(workDir, paths::CNI_DIR);
+}
+
+
 string getContainerDir(
     const string& rootDir,
     const ContainerID& containerId)
diff --git a/src/slave/containerizer/mesos/isolators/network/cni/paths.hpp 
b/src/slave/containerizer/mesos/isolators/network/cni/paths.hpp
index 3b06fb1..135a359 100644
--- a/src/slave/containerizer/mesos/isolators/network/cni/paths.hpp
+++ b/src/slave/containerizer/mesos/isolators/network/cni/paths.hpp
@@ -24,6 +24,8 @@
 
 #include <stout/try.hpp>
 
+#include "slave/flags.hpp"
+
 namespace mesos {
 namespace internal {
 namespace slave {
@@ -32,7 +34,7 @@ namespace paths {
 
 // The root directory where we keep the information of CNI networks that each
 // container joins. The layout is as follows:
-//   /var/run/mesos/isolators/network/cni/
+//   /<work_dir|runtime_dir>/isolators/network/cni/
 //    |- <ID of Container1>/
 //    |  |-- ns -> /proc/<pid>/ns/net (bind mount)
 //    |  |-- <Name of CNI network 1>/
@@ -45,7 +47,10 @@ namespace paths {
 //    |          |-- network.info
 //    |-- <ID of ContainerID 2>/
 //    | ...
-constexpr char ROOT_DIR[] = "/var/run/mesos/isolators/network/cni";
+constexpr char CNI_DIR[] = "isolators/network/cni";
+
+
+std::string getCniRootDir(const Flags& flags);
 
 
 std::string getContainerDir(
diff --git a/src/slave/flags.cpp b/src/slave/flags.cpp
index 294ccb7..683aa4a 100644
--- a/src/slave/flags.cpp
+++ b/src/slave/flags.cpp
@@ -1148,6 +1148,12 @@ mesos::internal::slave::Flags::Flags()
       "the operator should install a network configuration file in JSON\n"
       "format in the specified directory.");
 
+  add(&Flags::network_cni_root_dir_persist,
+      "network_cni_root_dir_persist",
+      "This setting controls whether the CNI root directory\n"
+      "persists across reboot or not.",
+      false);
+
   add(&Flags::container_disk_watch_interval,
       "container_disk_watch_interval",
       "The interval between disk quota checks for containers. This flag is\n"
diff --git a/src/slave/flags.hpp b/src/slave/flags.hpp
index b80a631..9627435 100644
--- a/src/slave/flags.hpp
+++ b/src/slave/flags.hpp
@@ -158,6 +158,7 @@ public:
 
   Option<std::string> network_cni_plugins_dir;
   Option<std::string> network_cni_config_dir;
+  bool network_cni_root_dir_persist;
   Duration container_disk_watch_interval;
   bool enforce_container_disk_quota;
   Option<Modules> modules;
diff --git a/src/tests/containerizer/cni_isolator_tests.cpp 
b/src/tests/containerizer/cni_isolator_tests.cpp
index b282e10..4c204a8 100644
--- a/src/tests/containerizer/cni_isolator_tests.cpp
+++ b/src/tests/containerizer/cni_isolator_tests.cpp
@@ -375,24 +375,25 @@ TEST_F(CniIsolatorTest, ROOT_VerifyCheckpointedInfo)
   ContainerID containerId = *(containers->begin());
 
   // Check if the CNI related information is checkpointed successfully.
+  const string cniRootDir = paths::getCniRootDir(flags);
   const string containerDir =
-    paths::getContainerDir(paths::ROOT_DIR, containerId);
+    paths::getContainerDir(cniRootDir, containerId);
 
   EXPECT_TRUE(os::exists(containerDir));
   EXPECT_TRUE(os::exists(paths::getNetworkDir(
-      paths::ROOT_DIR, containerId, "__MESOS_TEST__")));
+      cniRootDir, containerId, "__MESOS_TEST__")));
 
   EXPECT_TRUE(os::exists(paths::getNetworkConfigPath(
-      paths::ROOT_DIR, containerId, "__MESOS_TEST__")));
+      cniRootDir, containerId, "__MESOS_TEST__")));
 
   EXPECT_TRUE(os::exists(paths::getInterfaceDir(
-      paths::ROOT_DIR, containerId, "__MESOS_TEST__", "eth0")));
+      cniRootDir, containerId, "__MESOS_TEST__", "eth0")));
 
   EXPECT_TRUE(os::exists(paths::getNetworkInfoPath(
-      paths::ROOT_DIR, containerId, "__MESOS_TEST__", "eth0")));
+      cniRootDir, containerId, "__MESOS_TEST__", "eth0")));
 
   EXPECT_TRUE(os::exists(paths::getNamespacePath(
-      paths::ROOT_DIR, containerId)));
+      cniRootDir, containerId)));
 
   EXPECT_TRUE(os::exists(path::join(containerDir, "hostname")));
   EXPECT_TRUE(os::exists(path::join(containerDir, "hosts")));
@@ -2196,6 +2197,44 @@ TEST_P(DefaultContainerDNSCniTest, ROOT_VerifyDefaultDNS)
   driver.join();
 }
 
+
+// This test verifies CNI root directory path.
+TEST_F(CniIsolatorTest, ROOT_VerifyCniRootDir)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "network/cni";
+
+  flags.network_cni_plugins_dir = cniPluginDir;
+  flags.network_cni_config_dir = cniConfigDir;
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), flags);
+  ASSERT_SOME(slave);
+
+  string cniRootDir = paths::getCniRootDir(flags);
+
+  ASSERT_EQ(path::join(flags.runtime_dir, paths::CNI_DIR), cniRootDir);
+  EXPECT_TRUE(os::exists(cniRootDir));
+
+  slave.get()->terminate();
+
+  // Enable the flag to test whether the directory
+  // has moved to a persistent location.
+  flags.network_cni_root_dir_persist = true;
+
+  slave = StartSlave(detector.get(), flags);
+  ASSERT_SOME(slave);
+
+  cniRootDir = paths::getCniRootDir(flags);
+
+  ASSERT_EQ(path::join(flags.work_dir, paths::CNI_DIR), cniRootDir);
+  EXPECT_TRUE(os::exists(cniRootDir));
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {

Reply via email to