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

jpeach pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git


The following commit(s) were added to refs/heads/master by this push:
     new bc5a571  Adopted container file operations for secrets volumes.
bc5a571 is described below

commit bc5a57122635700f3943d73f1df13820aef202e2
Author: James Peach <[email protected]>
AuthorDate: Thu Jun 6 13:18:18 2019 -0700

    Adopted container file operations for secrets volumes.
    
    Switched the `volumes/secrets` isolator from using container
    pre-exec commands to using file operations. This allows us to
    reduce the number of forked child processes, consolidate code
    and leaves the `network/port_mapping` isolator as the last
    consumer of pre-exec commands.
    
    Review: https://reviews.apache.org/r/70741/
---
 include/mesos/slave/containerizer.proto            | 23 ++++++
 src/common/protobuf_utils.cpp                      | 40 ++++++++++
 src/common/protobuf_utils.hpp                      | 14 ++++
 .../mesos/isolators/volume/secret.cpp              | 64 ++++++----------
 src/slave/containerizer/mesos/launch.cpp           | 87 ++++++++++++++++++----
 5 files changed, 172 insertions(+), 56 deletions(-)

diff --git a/include/mesos/slave/containerizer.proto 
b/include/mesos/slave/containerizer.proto
index b2e35cb..2d04f3c 100644
--- a/include/mesos/slave/containerizer.proto
+++ b/include/mesos/slave/containerizer.proto
@@ -200,6 +200,16 @@ message ContainerFileOperation {
   enum Operation {
     // Create a symlink that points to `source` at `target`.
     SYMLINK = 1;
+
+    // Perform a container mount. This can be used when a mount is part
+    // of a sequence of steps involving other filesystem operations.
+    MOUNT = 2;
+
+    // Rename a path;
+    RENAME = 3;
+
+    // Create a directory.
+    MKDIR = 4;
   };
 
   message Symlink {
@@ -207,10 +217,23 @@ message ContainerFileOperation {
     optional string target = 2;
   }
 
+  message Rename {
+    optional string source = 1;
+    optional string target = 2;
+  }
+
+  message Mkdir {
+    optional string target = 1;
+    optional bool recursive = 2;
+  }
+
   optional Operation operation = 1;
 
   oneof parameters {
     Symlink symlink = 2;
+    Mkdir mkdir = 3;
+    Rename rename = 4;
+    ContainerMountInfo mount = 5;
   }
 }
 
diff --git a/src/common/protobuf_utils.cpp b/src/common/protobuf_utils.cpp
index 870859d..9ff0cf5 100644
--- a/src/common/protobuf_utils.cpp
+++ b/src/common/protobuf_utils.cpp
@@ -1256,6 +1256,46 @@ mesos::slave::ContainerFileOperation 
containerSymlinkOperation(
   return op;
 }
 
+
+mesos::slave::ContainerFileOperation containerRenameOperation(
+    const std::string& source,
+    const std::string& target)
+{
+  ContainerFileOperation op;
+
+  op.set_operation(ContainerFileOperation::RENAME);
+  op.mutable_rename()->set_source(source);
+  op.mutable_rename()->set_target(target);
+
+  return op;
+}
+
+
+mesos::slave::ContainerFileOperation containerMkdirOperation(
+    const std::string& target,
+    const bool recursive)
+{
+  ContainerFileOperation op;
+
+  op.set_operation(ContainerFileOperation::MKDIR);
+  op.mutable_mkdir()->set_target(target);
+  op.mutable_mkdir()->set_recursive(recursive);
+
+  return op;
+}
+
+
+mesos::slave::ContainerFileOperation containerMountOperation(
+    const ContainerMountInfo& mnt)
+{
+  ContainerFileOperation op;
+
+  op.set_operation(ContainerFileOperation::MOUNT);
+  *op.mutable_mount() = mnt;
+
+  return op;
+}
+
 } // namespace slave {
 
 namespace maintenance {
diff --git a/src/common/protobuf_utils.hpp b/src/common/protobuf_utils.hpp
index 8aa9aff..ecaf8ea 100644
--- a/src/common/protobuf_utils.hpp
+++ b/src/common/protobuf_utils.hpp
@@ -419,6 +419,20 @@ mesos::slave::ContainerFileOperation 
containerSymlinkOperation(
     const std::string& source,
     const std::string& target);
 
+
+mesos::slave::ContainerFileOperation containerRenameOperation(
+    const std::string& source,
+    const std::string& target);
+
+
+mesos::slave::ContainerFileOperation containerMkdirOperation(
+    const std::string& target,
+    const bool recursive);
+
+
+mesos::slave::ContainerFileOperation containerMountOperation(
+    const mesos::slave::ContainerMountInfo& mnt);
+
 } // namespace slave {
 
 namespace maintenance {
diff --git a/src/slave/containerizer/mesos/isolators/volume/secret.cpp 
b/src/slave/containerizer/mesos/isolators/volume/secret.cpp
index 7a9bb82..4bbcc7a 100644
--- a/src/slave/containerizer/mesos/isolators/volume/secret.cpp
+++ b/src/slave/containerizer/mesos/isolators/volume/secret.cpp
@@ -16,6 +16,8 @@
 
 #include "slave/containerizer/mesos/isolators/volume/secret.hpp"
 
+#include <sys/mount.h>
+
 #include <string>
 #include <vector>
 
@@ -38,6 +40,7 @@
 #include "linux/ns.hpp"
 #endif // __linux__
 
+#include "common/protobuf_utils.hpp"
 #include "common/validation.hpp"
 
 using std::string;
@@ -47,12 +50,18 @@ using process::Failure;
 using process::Future;
 using process::Owned;
 
+using mesos::internal::protobuf::slave::containerMkdirOperation;
+using mesos::internal::protobuf::slave::containerMountOperation;
+using mesos::internal::protobuf::slave::containerRenameOperation;
+using mesos::internal::protobuf::slave::createContainerMount;
+
 using mesos::slave::ContainerClass;
 using mesos::slave::ContainerConfig;
 using mesos::slave::ContainerLaunchInfo;
 using mesos::slave::ContainerState;
 using mesos::slave::Isolator;
 
+
 namespace mesos {
 namespace internal {
 namespace slave {
@@ -135,15 +144,8 @@ Future<Option<ContainerLaunchInfo>> 
VolumeSecretIsolatorProcess::prepare(
   }
 
   // Mount ramfs in the container.
-  CommandInfo* command = launchInfo.add_pre_exec_commands();
-  command->set_shell(false);
-  command->set_value("mount");
-  command->add_arguments("mount");
-  command->add_arguments("-n");
-  command->add_arguments("-t");
-  command->add_arguments("ramfs");
-  command->add_arguments("ramfs");
-  command->add_arguments(sandboxSecretRootDir);
+  *launchInfo.add_file_operations() = containerMountOperation(
+      createContainerMount("ramfs", sandboxSecretRootDir, "ramfs", 0));
 
   vector<Future<Nothing>> futures;
   foreach (const Volume& volume, containerInfo.volumes()) {
@@ -250,44 +252,20 @@ Future<Option<ContainerLaunchInfo>> 
VolumeSecretIsolatorProcess::prepare(
     }
 
     // Create directory tree inside sandbox secret root dir.
-    command = launchInfo.add_pre_exec_commands();
-    command->set_shell(false);
-    command->set_value("mkdir");
-    command->add_arguments("mkdir");
-    command->add_arguments("-p");
-    command->add_arguments(Path(sandboxSecretPath).dirname());
+    *launchInfo.add_file_operations() = containerMkdirOperation(
+        Path(sandboxSecretPath).dirname(), true /* recursive */);
 
     // Move secret from hostSecretPath to sandboxSecretPath.
-    command = launchInfo.add_pre_exec_commands();
-    command->set_shell(false);
-    command->set_value("mv");
-    command->add_arguments("mv");
-    command->add_arguments("-f");
-    command->add_arguments(hostSecretPath);
-    command->add_arguments(sandboxSecretPath);
+    *launchInfo.add_file_operations() = containerRenameOperation(
+        hostSecretPath, sandboxSecretPath);
+
+    const unsigned long flags =
+      volume.mode() == Volume::RO ? (MS_BIND | MS_REC | MS_RDONLY)
+                                  : (MS_BIND | MS_REC);
 
     // Bind mount sandboxSecretPath to targetContainerPath
-    command = launchInfo.add_pre_exec_commands();
-    command->set_shell(false);
-    command->set_value("mount");
-    command->add_arguments("mount");
-    command->add_arguments("-n");
-    command->add_arguments("--rbind");
-    command->add_arguments(sandboxSecretPath);
-    command->add_arguments(targetContainerPath);
-
-    // If the mount needs to be read-only, do a remount.
-    if (volume.mode() == Volume::RO) {
-      command = launchInfo.add_pre_exec_commands();
-      command->set_shell(false);
-      command->set_value("mount");
-      command->add_arguments("mount");
-      command->add_arguments("-n");
-      command->add_arguments("-o");
-      command->add_arguments("bind,ro,remount");
-      command->add_arguments(sandboxSecretPath);
-      command->add_arguments(targetContainerPath);
-    }
+    *launchInfo.add_file_operations() = containerMountOperation(
+        createContainerMount(sandboxSecretPath, targetContainerPath, flags));
 
     Future<Nothing> future = secretResolver->resolve(secret)
       .then([hostSecretPath](const Secret::Value& value) -> Future<Nothing> {
diff --git a/src/slave/containerizer/mesos/launch.cpp 
b/src/slave/containerizer/mesos/launch.cpp
index 0c482f4..a69a688 100644
--- a/src/slave/containerizer/mesos/launch.cpp
+++ b/src/slave/containerizer/mesos/launch.cpp
@@ -259,6 +259,19 @@ static void exitWithStatus(int status)
 }
 
 
+#ifdef __linux__
+static Try<Nothing> mountContainerFilesystem(const ContainerMountInfo& mount)
+{
+  return fs::mount(
+      mount.has_source() ? Option<string>(mount.source()) : None(),
+      mount.target(),
+      mount.has_type() ? Option<string>(mount.type()) : None(),
+      mount.has_flags() ? mount.flags() : 0,
+      mount.has_options() ? Option<string>(mount.options()) : None());
+}
+#endif // __linux__
+
+
 static Try<Nothing> prepareMounts(const ContainerLaunchInfo& launchInfo)
 {
 #ifdef __linux__
@@ -435,13 +448,7 @@ static Try<Nothing> prepareMounts(const 
ContainerLaunchInfo& launchInfo)
       }
     }
 
-    Try<Nothing> mnt = fs::mount(
-        (mount.has_source() ? Option<string>(mount.source()) : None()),
-        mount.target(),
-        (mount.has_type() ? Option<string>(mount.type()) : None()),
-        (mount.has_flags() ? mount.flags() : 0),
-        (mount.has_options() ? Option<string>(mount.options()) : None()));
-
+    Try<Nothing> mnt = mountContainerFilesystem(mount);
     if (mnt.isError()) {
       return Error(
           "Failed to mount '" + stringify(JSON::protobuf(mount)) +
@@ -476,20 +483,74 @@ static Try<Nothing> maskPath(const string& target)
 
 static Try<Nothing> executeFileOperation(const ContainerFileOperation& op)
 {
-  Try<Nothing> result = Nothing();
-
   switch (op.operation()) {
-    case ContainerFileOperation::SYMLINK:
-      result = ::fs::symlink(op.symlink().source(), op.symlink().target());
+    case ContainerFileOperation::SYMLINK: {
+      Try<Nothing> result =
+        ::fs::symlink(op.symlink().source(), op.symlink().target());
       if (result.isError()) {
         return Error(
             "Failed to link '" + op.symlink().source() + "' as '" +
             op.symlink().target() + "': " + result.error());
       }
-      break;
+
+      return Nothing();
+    }
+
+#ifdef __linux__
+    case ContainerFileOperation::MOUNT: {
+      Try<Nothing> result = mountContainerFilesystem(op.mount());
+      if (result.isError()) {
+        return Error(
+            "Failed to mount '" + stringify(JSON::protobuf(op.mount())) +
+            "': " + result.error());
+      }
+
+      return Nothing();
+    }
+#endif // __linux__
+
+    case ContainerFileOperation::RENAME: {
+      Try<Nothing> result =
+        os::rename(op.rename().source(), op.rename().target());
+
+      // TODO(jpeach): We should only fall back to `mv` if the error
+      // is EXDEV, in which case a rename is a copy+unlink.
+      if (result.isError()) {
+        Option<int> status = os::spawn(
+            "mv", {"mv", "-f", op.rename().source(), op.rename().target()});
+
+        if (status.isNone()) {
+          return Error(
+              "Failed to rename '" + op.rename().source() + "' to '" +
+              op.rename().target() + "':  spawn failed");
+        }
+
+        if (!WSUCCEEDED(status.get())) {
+          return Error(
+              "Failed to rename '" + op.rename().source() + "' to '" +
+              op.rename().target() + "': " + WSTRINGIFY(status.get()));
+        }
+
+        result = Nothing();
+      }
+
+      return Nothing();
   }
 
-  return result;
+    case ContainerFileOperation::MKDIR: {
+      Try<Nothing> result =
+        os::mkdir(op.mkdir().target(), op.mkdir().recursive());
+      if (result.isError()) {
+        return Error(
+            "Failed to create directory '" + op.mkdir().target() + "': " +
+            result.error());
+      }
+
+      return result;
+    }
+  }
+
+  return Nothing();
 }
 
 

Reply via email to