Implemented handling AUFS whiteouts for copy backend.

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


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

Branch: refs/heads/master
Commit: 0f4c15ad735e437a8e8b9bb6846025aea02c765b
Parents: 3800cfd
Author: Qian Zhang <zhang...@cn.ibm.com>
Authored: Sat Oct 22 21:45:44 2016 +0800
Committer: Qian Zhang <zhq527...@gmail.com>
Committed: Sat Nov 5 16:18:30 2016 +0800

----------------------------------------------------------------------
 .../mesos/provisioner/backends/copy.cpp         | 103 ++++++++++++++++++-
 1 file changed, 98 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0f4c15ad/src/slave/containerizer/mesos/provisioner/backends/copy.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/provisioner/backends/copy.cpp 
b/src/slave/containerizer/mesos/provisioner/backends/copy.cpp
index 9c5354e..7e98110 100644
--- a/src/slave/containerizer/mesos/provisioner/backends/copy.cpp
+++ b/src/slave/containerizer/mesos/provisioner/backends/copy.cpp
@@ -16,6 +16,8 @@
 
 #include <list>
 
+#include <mesos/docker/spec.hpp>
+
 #include <process/collect.hpp>
 #include <process/defer.hpp>
 #include <process/dispatch.hpp>
@@ -24,7 +26,6 @@
 #include <process/process.hpp>
 #include <process/subprocess.hpp>
 
-
 #include <stout/foreach.hpp>
 #include <stout/os.hpp>
 
@@ -32,7 +33,6 @@
 
 #include "slave/containerizer/mesos/provisioner/backends/copy.hpp"
 
-
 using namespace process;
 
 using std::string;
@@ -128,9 +128,92 @@ Future<Nothing> CopyBackendProcess::provision(
 
 
 Future<Nothing> CopyBackendProcess::_provision(
-  string layer,
-  const string& rootfs)
+    string layer,
+    const string& rootfs)
 {
+  // Traverse the layer to check if there is any whiteout files, if
+  // yes, remove the corresponding files/directories from the rootfs.
+  // Note: We assume all image types use AUFS whiteout format.
+  char* source[] = {const_cast<char*>(layer.c_str()), nullptr};
+
+  FTS* tree = ::fts_open(source, FTS_NOCHDIR | FTS_PHYSICAL, nullptr);
+  if (tree == nullptr) {
+    return Failure("Failed to open '" + layer + "': " + os::strerror(errno));
+  }
+
+  vector<string> whiteouts;
+  for (FTSENT *node = ::fts_read(tree);
+       node != nullptr; node = ::fts_read(tree)) {
+    if (node->fts_info != FTS_F) {
+      continue;
+    }
+
+    if (!strings::startsWith(node->fts_name, docker::spec::WHITEOUT_PREFIX)) {
+      continue;
+    }
+
+    string ftsPath = string(node->fts_path);
+    Path whiteout = Path(ftsPath.substr(layer.length() + 1));
+
+    // Keep the relative paths of the whiteout files, we will
+    // remove them from rootfs after layer is copied to rootfs.
+    whiteouts.push_back(whiteout.string());
+
+    if (node->fts_name == string(docker::spec::WHITEOUT_OPAQUE_PREFIX)) {
+      const string path = path::join(rootfs, Path(whiteout).dirname());
+
+      // Remove the entries under the directory labeled
+      // as opaque whiteout from rootfs.
+      Try<Nothing> rmdir = os::rmdir(path, true, false);
+      if (rmdir.isError()) {
+        ::fts_close(tree);
+        return Failure(
+            "Failed to remove the entries under the directory labeled as"
+            " opaque whiteout '" + path + "': " + rmdir.error());
+      }
+    } else {
+      const string path = path::join(
+          rootfs,
+          whiteout.dirname(),
+          whiteout.basename().substr(strlen(docker::spec::WHITEOUT_PREFIX)));
+
+      // The file/directory labeled as whiteout may have already been
+      // removed with the code above due to its parent directory labeled
+      // as opaque whiteout, so here we need to check if it still exists
+      // before trying to remove it.
+      if (os::exists(path)) {
+        if (os::stat::isdir(path)) {
+          Try<Nothing> rmdir = os::rmdir(path);
+          if (rmdir.isError()) {
+            ::fts_close(tree);
+            return Failure(
+                "Failed to remove the directory labeled as whiteout '" +
+                path + "': " + rmdir.error());
+          }
+        } else {
+          Try<Nothing> rm = os::rm(path);
+          if (rm.isError()) {
+            ::fts_close(tree);
+            return Failure(
+                "Failed to remove the file labeled as whiteout '" +
+                path + "': " + rm.error());
+          }
+        }
+      }
+    }
+  }
+
+  if (errno != 0) {
+    Error error = ErrnoError();
+    ::fts_close(tree);
+    return Failure(error);
+  }
+
+  if (::fts_close(tree) != 0) {
+    return Failure(
+        "Failed to stop traversing file system: " + os::strerror(errno));
+  }
+
   VLOG(1) << "Copying layer path '" << layer << "' to rootfs '" << rootfs
           << "'";
 
@@ -160,7 +243,7 @@ Future<Nothing> CopyBackendProcess::_provision(
   Subprocess cp = s.get();
 
   return cp.status()
-    .then([cp](const Option<int>& status) -> Future<Nothing> {
+    .then([=](const Option<int>& status) -> Future<Nothing> {
       if (status.isNone()) {
         return Failure("Failed to reap subprocess to copy image");
       } else if (status.get() != 0) {
@@ -170,6 +253,16 @@ Future<Nothing> CopyBackendProcess::_provision(
           });
       }
 
+      // Remove the whiteout files from rootfs.
+      foreach (const string whiteout, whiteouts) {
+        Try<Nothing> rm = os::rm(path::join(rootfs, whiteout));
+        if (rm.isError()) {
+          return Failure(
+              "Failed to remove whiteout file '" +
+              whiteout + "': " + rm.error());
+        }
+      }
+
       return Nothing();
     });
 }

Reply via email to