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 2019/08/08 04:54:49 UTC

[mesos] 01/06: Propagate ephemeral volume information from rootfs.

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

commit 8a47fdd86c1ca9536eeca4f23b6cac5bd8ea4f2d
Author: James Peach <jp...@apache.org>
AuthorDate: Wed Aug 7 20:21:40 2019 -0700

    Propagate ephemeral volume information from rootfs.
    
    Propagate the overlayfs upperdir path to the containerization
    layer in a general form as a set of ephemeral volume paths.
    
    Review: https://reviews.apache.org/r/71192/
---
 include/mesos/slave/containerizer.proto                |  6 ++++++
 src/slave/containerizer/mesos/containerizer.cpp        | 18 +++++++++++++++++-
 src/slave/containerizer/mesos/provisioner/backend.hpp  |  7 ++++++-
 .../containerizer/mesos/provisioner/backends/aufs.cpp  |  8 ++++----
 .../containerizer/mesos/provisioner/backends/aufs.hpp  |  2 +-
 .../containerizer/mesos/provisioner/backends/bind.cpp  |  9 +++++----
 .../containerizer/mesos/provisioner/backends/bind.hpp  |  2 +-
 .../containerizer/mesos/provisioner/backends/copy.cpp  |  9 +++++----
 .../containerizer/mesos/provisioner/backends/copy.hpp  |  2 +-
 .../mesos/provisioner/backends/overlay.cpp             | 11 +++++++----
 .../mesos/provisioner/backends/overlay.hpp             |  2 +-
 .../containerizer/mesos/provisioner/provisioner.cpp    |  5 +++--
 .../containerizer/mesos/provisioner/provisioner.hpp    |  5 +++++
 13 files changed, 62 insertions(+), 24 deletions(-)

diff --git a/include/mesos/slave/containerizer.proto b/include/mesos/slave/containerizer.proto
index a60c963..3e5b667 100644
--- a/include/mesos/slave/containerizer.proto
+++ b/include/mesos/slave/containerizer.proto
@@ -79,6 +79,9 @@ message ContainerState {
 
   // The sandbox directory.
   required string directory = 4;
+
+  // Ephemeral path volumes subject to container disk quota.
+  repeated string ephemeral_volumes = 5;
 }
 
 
@@ -142,6 +145,9 @@ message ContainerConfig {
   // The work directory for the container in the host filesystem.
   required string directory = 3;
 
+  // Ephemeral path volumes subject to container disk quota.
+  repeated string ephemeral_volumes = 15;
+
   // The user that should be used to run the `command_info`.
   // The sandbox directory and any artifacts from the Mesos fetcher will
   // be made accessible to this user.
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index a01edc8..75e7cda 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -904,7 +904,7 @@ Future<Nothing> MesosContainerizerProcess::recover(
   }
 
   // Recover the containers from 'SlaveState'.
-  foreach (const ContainerState& state, recoverable) {
+  foreach (ContainerState& state, recoverable) {
     const ContainerID& containerId = state.container_id();
 
     // Contruct the structure for containers from the 'SlaveState'
@@ -931,6 +931,10 @@ Future<Nothing> MesosContainerizerProcess::recover(
 
     if (config.isSome()) {
       container->config = config.get();
+
+      // Copy the ephemeral volume paths to the ContainerState, since this
+      // information is otherwise only available to the prepare() callback.
+      *state.mutable_ephemeral_volumes() = config->ephemeral_volumes();
     } else {
       VLOG(1) << "No config is recovered for container " << containerId
               << ", this means image pruning will be disabled.";
@@ -1094,6 +1098,12 @@ Future<Nothing> MesosContainerizerProcess::recover(
             container->pid.get(),
             container->directory.get());
 
+      if (config.isSome()) {
+        // Copy the ephemeral volume paths to the ContainerState, since this
+        // information is otherwise only available to the prepare() callback.
+        *state.mutable_ephemeral_volumes() = config->ephemeral_volumes();
+      }
+
       recoverable.push_back(state);
       continue;
     }
@@ -1517,6 +1527,12 @@ Future<Nothing> MesosContainerizerProcess::prepare(
   if (provisionInfo.isSome()) {
     container->config->set_rootfs(provisionInfo->rootfs);
 
+    if (provisionInfo->ephemeralVolumes.isSome()) {
+      foreach (const Path& path, provisionInfo->ephemeralVolumes.get()) {
+        container->config->add_ephemeral_volumes(path);
+      }
+    }
+
     if (provisionInfo->dockerManifest.isSome() &&
         provisionInfo->appcManifest.isSome()) {
       return Failure("Container cannot have both Docker and Appc manifests");
diff --git a/src/slave/containerizer/mesos/provisioner/backend.hpp b/src/slave/containerizer/mesos/provisioner/backend.hpp
index 7257d3a..55f007f 100644
--- a/src/slave/containerizer/mesos/provisioner/backend.hpp
+++ b/src/slave/containerizer/mesos/provisioner/backend.hpp
@@ -24,6 +24,8 @@
 #include <process/owned.hpp>
 
 #include <stout/hashmap.hpp>
+#include <stout/option.hpp>
+#include <stout/path.hpp>
 #include <stout/try.hpp>
 
 #include "slave/flags.hpp"
@@ -48,7 +50,10 @@ public:
   // directory by applying the specified list of root filesystem layers in
   // the list order, i.e., files in a layer can overwrite/shadow those from
   // another layer earlier in the list.
-  virtual process::Future<Nothing> provision(
+  //
+  // Optionally returns a set of paths whose contents should be included
+  // in the ephemeral sandbox disk quota.
+  virtual process::Future<Option<std::vector<Path>>> provision(
       const std::vector<std::string>& layers,
       const std::string& rootfs,
       const std::string& backendDir) = 0;
diff --git a/src/slave/containerizer/mesos/provisioner/backends/aufs.cpp b/src/slave/containerizer/mesos/provisioner/backends/aufs.cpp
index 2eba552..e401e5b 100644
--- a/src/slave/containerizer/mesos/provisioner/backends/aufs.cpp
+++ b/src/slave/containerizer/mesos/provisioner/backends/aufs.cpp
@@ -51,7 +51,7 @@ public:
   AufsBackendProcess()
     : ProcessBase(process::ID::generate("aufs-provisioner-backend")) {}
 
-  Future<Nothing> provision(
+  Future<Option<vector<Path>>> provision(
       const vector<string>& layers,
       const string& rootfs,
       const string& backendDir);
@@ -87,7 +87,7 @@ AufsBackend::AufsBackend(Owned<AufsBackendProcess> _process)
 }
 
 
-Future<Nothing> AufsBackend::provision(
+Future<Option<vector<Path>>> AufsBackend::provision(
     const vector<string>& layers,
     const string& rootfs,
     const string& backendDir)
@@ -113,7 +113,7 @@ Future<bool> AufsBackend::destroy(
 }
 
 
-Future<Nothing> AufsBackendProcess::provision(
+Future<Option<vector<Path>>> AufsBackendProcess::provision(
     const vector<string>& layers,
     const string& rootfs,
     const string& backendDir)
@@ -236,7 +236,7 @@ Future<Nothing> AufsBackendProcess::provision(
         "' as a shared mount: " + mount.error());
   }
 
-  return Nothing();
+  return None();
 }
 
 
diff --git a/src/slave/containerizer/mesos/provisioner/backends/aufs.hpp b/src/slave/containerizer/mesos/provisioner/backends/aufs.hpp
index 2c25187..8a08339 100644
--- a/src/slave/containerizer/mesos/provisioner/backends/aufs.hpp
+++ b/src/slave/containerizer/mesos/provisioner/backends/aufs.hpp
@@ -48,7 +48,7 @@ public:
 
   static Try<process::Owned<Backend>> create(const Flags&);
 
-  process::Future<Nothing> provision(
+  process::Future<Option<std::vector<Path>>> provision(
       const std::vector<std::string>& layers,
       const std::string& rootfs,
       const std::string& backendDir) override;
diff --git a/src/slave/containerizer/mesos/provisioner/backends/bind.cpp b/src/slave/containerizer/mesos/provisioner/backends/bind.cpp
index 4cc4c52..e906a88 100644
--- a/src/slave/containerizer/mesos/provisioner/backends/bind.cpp
+++ b/src/slave/containerizer/mesos/provisioner/backends/bind.cpp
@@ -47,7 +47,8 @@ public:
   BindBackendProcess()
     : ProcessBase(process::ID::generate("bind-provisioner-backend")) {}
 
-  Future<Nothing> provision(const vector<string>& layers, const string& rootfs);
+  Future<Option<vector<Path>>> provision(
+      const vector<string>& layers, const string& rootfs);
 
   Future<bool> destroy(const string& rootfs);
 
@@ -86,7 +87,7 @@ BindBackend::BindBackend(Owned<BindBackendProcess> _process)
 }
 
 
-Future<Nothing> BindBackend::provision(
+Future<Option<std::vector<Path>>> BindBackend::provision(
     const vector<string>& layers,
     const string& rootfs,
     const string& backendDir)
@@ -104,7 +105,7 @@ Future<bool> BindBackend::destroy(
 }
 
 
-Future<Nothing> BindBackendProcess::provision(
+Future<Option<std::vector<Path>>> BindBackendProcess::provision(
     const vector<string>& layers,
     const string& rootfs)
 {
@@ -164,7 +165,7 @@ Future<Nothing> BindBackendProcess::provision(
         "' as a shared mount: " + mount.error());
   }
 
-  return Nothing();
+  return None();
 }
 
 
diff --git a/src/slave/containerizer/mesos/provisioner/backends/bind.hpp b/src/slave/containerizer/mesos/provisioner/backends/bind.hpp
index c4a1d5f..9c908fd 100644
--- a/src/slave/containerizer/mesos/provisioner/backends/bind.hpp
+++ b/src/slave/containerizer/mesos/provisioner/backends/bind.hpp
@@ -55,7 +55,7 @@ public:
   // BindBackend doesn't use any flag.
   static Try<process::Owned<Backend>> create(const Flags&);
 
-  process::Future<Nothing> provision(
+  process::Future<Option<std::vector<Path>>> provision(
       const std::vector<std::string>& layers,
       const std::string& rootfs,
       const std::string& backendDir) override;
diff --git a/src/slave/containerizer/mesos/provisioner/backends/copy.cpp b/src/slave/containerizer/mesos/provisioner/backends/copy.cpp
index 10516ca..4afef7f 100644
--- a/src/slave/containerizer/mesos/provisioner/backends/copy.cpp
+++ b/src/slave/containerizer/mesos/provisioner/backends/copy.cpp
@@ -52,7 +52,8 @@ public:
   CopyBackendProcess()
     : ProcessBase(process::ID::generate("copy-provisioner-backend")) {}
 
-  Future<Nothing> provision(const vector<string>& layers, const string& rootfs);
+  Future<Option<vector<Path>>> provision(
+      const vector<string>& layers, const string& rootfs);
 
   Future<bool> destroy(const string& rootfs);
 
@@ -82,7 +83,7 @@ CopyBackend::CopyBackend(Owned<CopyBackendProcess> _process)
 }
 
 
-Future<Nothing> CopyBackend::provision(
+Future<Option<vector<Path>>> CopyBackend::provision(
     const vector<string>& layers,
     const string& rootfs,
     const string& backendDir)
@@ -100,7 +101,7 @@ Future<bool> CopyBackend::destroy(
 }
 
 
-Future<Nothing> CopyBackendProcess::provision(
+Future<Option<vector<Path>>> CopyBackendProcess::provision(
     const vector<string>& layers,
     const string& rootfs)
 {
@@ -126,7 +127,7 @@ Future<Nothing> CopyBackendProcess::provision(
   }
 
   return collect(futures)
-    .then([]() -> Future<Nothing> { return Nothing(); });
+    .then([]() -> Future<Option<vector<Path>>> { return None(); });
 }
 
 
diff --git a/src/slave/containerizer/mesos/provisioner/backends/copy.hpp b/src/slave/containerizer/mesos/provisioner/backends/copy.hpp
index 5dc9a2f..9e8bd97 100644
--- a/src/slave/containerizer/mesos/provisioner/backends/copy.hpp
+++ b/src/slave/containerizer/mesos/provisioner/backends/copy.hpp
@@ -45,7 +45,7 @@ public:
 
   // Provisions a rootfs given the layers' paths and target rootfs
   // path.
-  process::Future<Nothing> provision(
+  process::Future<Option<std::vector<Path>>> provision(
       const std::vector<std::string>& layers,
       const std::string& rootfs,
       const std::string& backendDir) override;
diff --git a/src/slave/containerizer/mesos/provisioner/backends/overlay.cpp b/src/slave/containerizer/mesos/provisioner/backends/overlay.cpp
index f2040cf..77d6711 100644
--- a/src/slave/containerizer/mesos/provisioner/backends/overlay.cpp
+++ b/src/slave/containerizer/mesos/provisioner/backends/overlay.cpp
@@ -52,7 +52,7 @@ public:
   OverlayBackendProcess()
     : ProcessBase(process::ID::generate("overlay-provisioner-backend")) {}
 
-  Future<Nothing> provision(
+  Future<Option<vector<Path>>> provision(
       const vector<string>& layers,
       const string& rootfs,
       const string& backendDir);
@@ -88,7 +88,7 @@ OverlayBackend::OverlayBackend(Owned<OverlayBackendProcess> _process)
 }
 
 
-Future<Nothing> OverlayBackend::provision(
+Future<Option<vector<Path>>> OverlayBackend::provision(
     const vector<string>& layers,
     const string& rootfs,
     const string& backendDir)
@@ -114,7 +114,7 @@ Future<bool> OverlayBackend::destroy(
 }
 
 
-Future<Nothing> OverlayBackendProcess::provision(
+Future<Option<vector<Path>>> OverlayBackendProcess::provision(
     const vector<string>& layers,
     const string& rootfs,
     const string& backendDir)
@@ -237,7 +237,10 @@ Future<Nothing> OverlayBackendProcess::provision(
         "' as a shared mount: " + mount.error());
   }
 
-  return Nothing();
+  // Note that both upperdir and workdir are ephemeral. The `disk/xfs`
+  // isolator needs this because XFS will error with EXDEV when renaming
+  // a file into a tree with a different project ID (see xfs_rename).
+  return vector<Path>{Path(upperdir), Path(workdir)};
 }
 
 
diff --git a/src/slave/containerizer/mesos/provisioner/backends/overlay.hpp b/src/slave/containerizer/mesos/provisioner/backends/overlay.hpp
index 362e021..78896b6 100644
--- a/src/slave/containerizer/mesos/provisioner/backends/overlay.hpp
+++ b/src/slave/containerizer/mesos/provisioner/backends/overlay.hpp
@@ -49,7 +49,7 @@ public:
 
   static Try<process::Owned<Backend>> create(const Flags&);
 
-  process::Future<Nothing> provision(
+  process::Future<Option<std::vector<Path>>> provision(
       const std::vector<std::string>& layers,
       const std::string& rootfs,
       const std::string& backendDir) override;
diff --git a/src/slave/containerizer/mesos/provisioner/provisioner.cpp b/src/slave/containerizer/mesos/provisioner/provisioner.cpp
index a081fb0..bf3908d 100644
--- a/src/slave/containerizer/mesos/provisioner/provisioner.cpp
+++ b/src/slave/containerizer/mesos/provisioner/provisioner.cpp
@@ -574,7 +574,8 @@ Future<ProvisionInfo> ProvisionerProcess::_provision(
       imageInfo.layers,
       rootfs,
       backendDir)
-    .then(defer(self(), [=]() -> Future<ProvisionInfo> {
+    .then(defer(self(), [=](const Option<vector<Path>>& ephemeral)
+    -> Future<ProvisionInfo> {
       const string path =
         provisioner::paths::getLayersFilePath(rootDir, containerId);
 
@@ -596,7 +597,7 @@ Future<ProvisionInfo> ProvisionerProcess::_provision(
       }
 
       return ProvisionInfo{
-          rootfs, imageInfo.dockerManifest, imageInfo.appcManifest};
+          rootfs, ephemeral, imageInfo.dockerManifest, imageInfo.appcManifest};
     }));
 }
 
diff --git a/src/slave/containerizer/mesos/provisioner/provisioner.hpp b/src/slave/containerizer/mesos/provisioner/provisioner.hpp
index 7f84aa4..3866417 100644
--- a/src/slave/containerizer/mesos/provisioner/provisioner.hpp
+++ b/src/slave/containerizer/mesos/provisioner/provisioner.hpp
@@ -30,6 +30,7 @@
 #include <mesos/slave/isolator.hpp> // For ContainerState.
 
 #include <stout/nothing.hpp>
+#include <stout/path.hpp>
 #include <stout/try.hpp>
 
 #include <process/future.hpp>
@@ -61,6 +62,10 @@ struct ProvisionInfo
 {
   std::string rootfs;
 
+  // Ephemeral volumes are any additional paths the Provisioner backend
+  // may have created that should be counted towards the sandbox disk quota.
+  Option<std::vector<Path>> ephemeralVolumes;
+
   // Docker v1 image manifest.
   Option<::docker::spec::v1::ImageManifest> dockerManifest;