Can you update the documentation for this change, please?

Thanks,
Neil

On Tue, Jun 7, 2016 at 6:14 PM,  <ji...@apache.org> wrote:
> Repository: mesos
> Updated Branches:
>   refs/heads/master 90871a48f -> e5358ed1c
>
>
> Added aufs provisioning backend.
>
> Review: https://reviews.apache.org/r/47396/
>
>
> Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
> Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/e5358ed1
> Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/e5358ed1
> Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/e5358ed1
>
> Branch: refs/heads/master
> Commit: e5358ed1c132923d5fa357d1e337e037d1f29c8a
> Parents: ca09304
> Author: Shuai Lin <linshuai2...@gmail.com>
> Authored: Mon Jun 6 18:05:15 2016 -0700
> Committer: Jie Yu <yujie....@gmail.com>
> Committed: Tue Jun 7 09:14:22 2016 -0700
>
> ----------------------------------------------------------------------
>  src/Makefile.am                                 |   2 +
>  .../containerizer/mesos/provisioner/backend.cpp |   9 +
>  .../mesos/provisioner/backends/aufs.cpp         | 227 +++++++++++++++++++
>  .../mesos/provisioner/backends/aufs.hpp         |  70 ++++++
>  .../containerizer/provisioner_backend_tests.cpp |  51 +++++
>  src/tests/environment.cpp                       |  13 ++
>  6 files changed, 372 insertions(+)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/mesos/blob/e5358ed1/src/Makefile.am
> ----------------------------------------------------------------------
> diff --git a/src/Makefile.am b/src/Makefile.am
> index a08ea40..b02b901 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -1001,6 +1001,7 @@ MESOS_LINUX_FILES =                                     
>                   \
>    slave/containerizer/mesos/isolators/filesystem/shared.cpp            \
>    slave/containerizer/mesos/isolators/namespaces/pid.cpp               \
>    slave/containerizer/mesos/isolators/network/cni/cni.cpp              \
> +  slave/containerizer/mesos/provisioner/backends/aufs.cpp              \
>    slave/containerizer/mesos/provisioner/backends/bind.cpp              \
>    slave/containerizer/mesos/provisioner/backends/overlay.cpp
>
> @@ -1024,6 +1025,7 @@ MESOS_LINUX_FILES +=                                    
>                   \
>    slave/containerizer/mesos/isolators/filesystem/shared.hpp            \
>    slave/containerizer/mesos/isolators/namespaces/pid.hpp               \
>    slave/containerizer/mesos/isolators/network/cni/cni.hpp              \
> +  slave/containerizer/mesos/provisioner/backends/aufs.hpp              \
>    slave/containerizer/mesos/provisioner/backends/bind.hpp              \
>    slave/containerizer/mesos/provisioner/backends/overlay.hpp
>
>
> http://git-wip-us.apache.org/repos/asf/mesos/blob/e5358ed1/src/slave/containerizer/mesos/provisioner/backend.cpp
> ----------------------------------------------------------------------
> diff --git a/src/slave/containerizer/mesos/provisioner/backend.cpp 
> b/src/slave/containerizer/mesos/provisioner/backend.cpp
> index b2a20b7..93a2c3a 100644
> --- a/src/slave/containerizer/mesos/provisioner/backend.cpp
> +++ b/src/slave/containerizer/mesos/provisioner/backend.cpp
> @@ -25,6 +25,7 @@
>  #include "slave/containerizer/mesos/provisioner/backend.hpp"
>
>  #ifdef __linux__
> +#include "slave/containerizer/mesos/provisioner/backends/aufs.hpp"
>  #include "slave/containerizer/mesos/provisioner/backends/bind.hpp"
>  #endif
>  #include "slave/containerizer/mesos/provisioner/backends/copy.hpp"
> @@ -47,6 +48,14 @@ hashmap<string, Owned<Backend>> Backend::create(const 
> Flags& flags)
>  #ifdef __linux__
>    creators.put("bind", &BindBackend::create);
>
> +  Try<bool> aufsSupported = fs::aufs::supported();
> +  if (aufsSupported.isError()) {
> +    LOG(WARNING) << "Failed to check aufs availability: '"
> +                 << aufsSupported.error();
> +  } else if (aufsSupported.get()) {
> +    creators.put("aufs", &AufsBackend::create);
> +  }
> +
>    Try<bool> overlayfsSupported = fs::overlay::supported();
>    if (overlayfsSupported.isError()) {
>      LOG(WARNING) << "Failed to check overlayfs availability: '"
>
> http://git-wip-us.apache.org/repos/asf/mesos/blob/e5358ed1/src/slave/containerizer/mesos/provisioner/backends/aufs.cpp
> ----------------------------------------------------------------------
> diff --git a/src/slave/containerizer/mesos/provisioner/backends/aufs.cpp 
> b/src/slave/containerizer/mesos/provisioner/backends/aufs.cpp
> new file mode 100644
> index 0000000..54c0057
> --- /dev/null
> +++ b/src/slave/containerizer/mesos/provisioner/backends/aufs.cpp
> @@ -0,0 +1,227 @@
> +// Licensed to the Apache Software Foundation (ASF) under one
> +// or more contributor license agreements.  See the NOTICE file
> +// distributed with this work for additional information
> +// regarding copyright ownership.  The ASF licenses this file
> +// to you under the Apache License, Version 2.0 (the
> +// "License"); you may not use this file except in compliance
> +// with the License.  You may obtain a copy of the License at
> +//
> +//     http://www.apache.org/licenses/LICENSE-2.0
> +//
> +// Unless required by applicable law or agreed to in writing, software
> +// distributed under the License is distributed on an "AS IS" BASIS,
> +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> +// See the License for the specific language governing permissions and
> +// limitations under the License.
> +
> +#include <process/dispatch.hpp>
> +#include <process/process.hpp>
> +
> +#include <stout/adaptor.hpp>
> +#include <stout/foreach.hpp>
> +#include <stout/os.hpp>
> +
> +#include "linux/fs.hpp"
> +
> +#include "slave/containerizer/mesos/provisioner/backends/aufs.hpp"
> +
> +using process::Failure;
> +using process::Future;
> +using process::Owned;
> +using process::Process;
> +using process::Shared;
> +
> +using process::dispatch;
> +using process::spawn;
> +using process::wait;
> +
> +using std::string;
> +using std::vector;
> +
> +namespace mesos {
> +namespace internal {
> +namespace slave {
> +
> +class AufsBackendProcess : public Process<AufsBackendProcess>
> +{
> +public:
> +  Future<Nothing> provision(
> +      const vector<string>& layers,
> +      const string& rootfs,
> +      const string& backendDir);
> +
> +  Future<bool> destroy(const string& rootfs);
> +};
> +
> +
> +Try<Owned<Backend>> AufsBackend::create(const Flags&)
> +{
> +  Result<string> user = os::user();
> +  if (!user.isSome()) {
> +    return Error(
> +        "Failed to determine user: " +
> +        (user.isError() ? user.error() : "username not found"));
> +  }
> +
> +  if (user.get() != "root") {
> +    return Error(
> +      "AufsBackend requires root privileges, "
> +      "but is running as user " + user.get());
> +  }
> +
> +  return Owned<Backend>(new AufsBackend(
> +      Owned<AufsBackendProcess>(new AufsBackendProcess())));
> +}
> +
> +
> +AufsBackend::~AufsBackend()
> +{
> +  terminate(process.get());
> +  wait(process.get());
> +}
> +
> +
> +AufsBackend::AufsBackend(Owned<AufsBackendProcess> _process)
> +  : process(_process)
> +{
> +  spawn(CHECK_NOTNULL(process.get()));
> +}
> +
> +
> +Future<Nothing> AufsBackend::provision(
> +    const vector<string>& layers,
> +    const string& rootfs,
> +    const string& backendDir)
> +{
> +  return dispatch(
> +      process.get(),
> +      &AufsBackendProcess::provision,
> +      layers,
> +      rootfs,
> +      backendDir);
> +}
> +
> +Future<bool> AufsBackend::destroy(const string& rootfs)
> +{
> +  return dispatch(process.get(), &AufsBackendProcess::destroy, rootfs);
> +}
> +
> +
> +Future<Nothing> AufsBackendProcess::provision(
> +    const vector<string>& layers,
> +    const string& rootfs,
> +    const string& backendDir)
> +{
> +  if (layers.size() == 0) {
> +    return Failure("No filesystem layer provided");
> +  }
> +
> +  Try<Nothing> mkdir = os::mkdir(rootfs);
> +  if (mkdir.isError()) {
> +    return Failure(
> +        "Failed to create container rootfs at '" +
> +        rootfs + "': " + mkdir.error());
> +  }
> +
> +  const string scratchDirId = Path(rootfs).basename();
> +  const string scratchDir = path::join(backendDir, "scratch", scratchDirId);
> +
> +  // The top writable directory for aufs.
> +  const string workdir = path::join(scratchDir, "workdir");
> +
> +  mkdir = os::mkdir(workdir);
> +  if (mkdir.isError()) {
> +    return Failure(
> +        "Failed to create aufs workdir at '" +
> +        workdir + "': " + mkdir.error());
> +  }
> +
> +  // See http://aufs.sourceforge.net/aufs2/man.html
> +  // for the mount syntax for aufs.
> +  string options = "dirs=" + workdir + ":";
> +
> +  // For aufs, the specified lower directories will be stacked
> +  // beginning from the rightmost one and going left. But we need the
> +  // first layer in the vector to be the bottom most layer.
> +  options += strings::join(":", adaptor::reverse(layers));
> +
> +  VLOG(1) << "Provisioning image rootfs with aufs: '" << options << "'";
> +
> +  Try<Nothing> mount = fs::mount(
> +      "aufs",
> +      rootfs,
> +      "aufs",
> +      0,
> +      options);
> +
> +  if (mount.isError()) {
> +    return Failure(
> +        "Failed to mount rootfs '" + rootfs +
> +        "' with aufs: " + mount.error());
> +  }
> +
> +  // Mark the mount as shared+slave.
> +  mount = fs::mount(
> +      None(),
> +      rootfs,
> +      None(),
> +      MS_SLAVE,
> +      nullptr);
> +
> +  if (mount.isError()) {
> +    return Failure(
> +        "Failed to mark mount '" + rootfs +
> +        "' as a slave mount: " + mount.error());
> +  }
> +
> +  mount = fs::mount(
> +      None(),
> +      rootfs,
> +      None(),
> +      MS_SHARED,
> +      nullptr);
> +
> +  if (mount.isError()) {
> +    return Failure(
> +        "Failed to mark mount '" + rootfs +
> +        "' as a shared mount: " + mount.error());
> +  }
> +
> +  return Nothing();
> +}
> +
> +
> +Future<bool> AufsBackendProcess::destroy(const string& rootfs)
> +{
> +  Try<fs::MountInfoTable> mountTable = fs::MountInfoTable::read();
> +  if (mountTable.isError()) {
> +    return Failure("Failed to read mount table: " + mountTable.error());
> +  }
> +
> +  foreach (const fs::MountInfoTable::Entry& entry, mountTable->entries) {
> +    if (entry.target == rootfs) {
> +      // NOTE: This would fail if the rootfs is still in use.
> +      Try<Nothing> unmount = fs::unmount(entry.target);
> +      if (unmount.isError()) {
> +        return Failure(
> +            "Failed to destroy aufs-mounted rootfs '" + rootfs + "': " +
> +            unmount.error());
> +      }
> +
> +      Try<Nothing> rmdir = os::rmdir(rootfs);
> +      if (rmdir.isError()) {
> +        return Failure(
> +            "Failed to remove rootfs mount point '" + rootfs + "': " +
> +            rmdir.error());
> +      }
> +
> +      return true;
> +    }
> +  }
> +
> +  return false;
> +}
> +
> +} // namespace slave {
> +} // namespace internal {
> +} // namespace mesos {
>
> http://git-wip-us.apache.org/repos/asf/mesos/blob/e5358ed1/src/slave/containerizer/mesos/provisioner/backends/aufs.hpp
> ----------------------------------------------------------------------
> diff --git a/src/slave/containerizer/mesos/provisioner/backends/aufs.hpp 
> b/src/slave/containerizer/mesos/provisioner/backends/aufs.hpp
> new file mode 100644
> index 0000000..a5ac13b
> --- /dev/null
> +++ b/src/slave/containerizer/mesos/provisioner/backends/aufs.hpp
> @@ -0,0 +1,70 @@
> +// Licensed to the Apache Software Foundation (ASF) under one
> +// or more contributor license agreements.  See the NOTICE file
> +// distributed with this work for additional information
> +// regarding copyright ownership.  The ASF licenses this file
> +// to you under the Apache License, Version 2.0 (the
> +// "License"); you may not use this file except in compliance
> +// with the License.  You may obtain a copy of the License at
> +//
> +//     http://www.apache.org/licenses/LICENSE-2.0
> +//
> +// Unless required by applicable law or agreed to in writing, software
> +// distributed under the License is distributed on an "AS IS" BASIS,
> +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> +// See the License for the specific language governing permissions and
> +// limitations under the License.
> +
> +#ifndef __MESOS_PROVISIONER_AUFS_HPP__
> +#define __MESOS_PROVISIONER_AUFS_HPP__
> +
> +#include "slave/containerizer/mesos/provisioner/backend.hpp"
> +
> +namespace mesos {
> +namespace internal {
> +namespace slave {
> +
> +// Forward declaration.
> +class AufsBackendProcess;
> +
> +
> +// This backend mounts the images layers to the rootfs using the aufs file
> +// system. The directory layout is as follows:
> +// <work_dir> ('--work_dir' flag)
> +// |-- provisioner
> +//     |-- containers
> +//         |-- <container-id>
> +//             |-- backends
> +//                 |-- aufs
> +//                    |-- rootfses
> +//                        |-- <rootfs_id> (the rootfs)
> +//                    |-- scratch
> +//                        |-- <rootfs_id> (the scratch space)
> +//                            |-- workdir
> +class AufsBackend : public Backend
> +{
> +public:
> +  virtual ~AufsBackend();
> +
> +  static Try<process::Owned<Backend>> create(const Flags&);
> +
> +  virtual process::Future<Nothing> provision(
> +      const std::vector<std::string>& layers,
> +      const std::string& rootfs,
> +      const std::string& backendDir);
> +
> +  virtual process::Future<bool> destroy(const std::string& rootfs);
> +
> +private:
> +  explicit AufsBackend(process::Owned<AufsBackendProcess> process);
> +
> +  AufsBackend(const AufsBackend&);
> +  AufsBackend& operator=(const AufsBackend&);
> +
> +  process::Owned<AufsBackendProcess> process;
> +};
> +
> +} // namespace slave {
> +} // namespace internal {
> +} // namespace mesos {
> +
> +#endif // __MESOS_PROVISIONER_AUFS_HPP__
>
> http://git-wip-us.apache.org/repos/asf/mesos/blob/e5358ed1/src/tests/containerizer/provisioner_backend_tests.cpp
> ----------------------------------------------------------------------
> diff --git a/src/tests/containerizer/provisioner_backend_tests.cpp 
> b/src/tests/containerizer/provisioner_backend_tests.cpp
> index bc04760..f18cc3f 100644
> --- a/src/tests/containerizer/provisioner_backend_tests.cpp
> +++ b/src/tests/containerizer/provisioner_backend_tests.cpp
> @@ -200,6 +200,57 @@ TEST_F(CopyBackendTest, ROOT_CopyBackend)
>    EXPECT_FALSE(os::exists(rootfs));
>  }
>
> +
> +class AufsBackendTest : public MountBackendTest {};
> +
> +
> +// Provision a rootfs using multiple layers with the aufs backend.
> +TEST_F(AufsBackendTest, ROOT_AUFS_AufsBackend)
> +{
> +  string layer1 = path::join(os::getcwd(), "source1");
> +  ASSERT_SOME(os::mkdir(layer1));
> +  ASSERT_SOME(os::mkdir(path::join(layer1, "dir1")));
> +  ASSERT_SOME(os::write(path::join(layer1, "dir1", "1"), "1"));
> +  ASSERT_SOME(os::write(path::join(layer1, "file"), "test1"));
> +
> +  string layer2 = path::join(os::getcwd(), "source2");
> +  ASSERT_SOME(os::mkdir(layer2));
> +  ASSERT_SOME(os::mkdir(path::join(layer2, "dir2")));
> +  ASSERT_SOME(os::write(path::join(layer2, "dir2", "2"), "2"));
> +  ASSERT_SOME(os::write(path::join(layer2, "file"), "test2"));
> +
> +  string rootfs = path::join(os::getcwd(), "rootfs");
> +
> +  hashmap<string, Owned<Backend>> backends = Backend::create(slave::Flags());
> +  ASSERT_TRUE(backends.contains("aufs"));
> +
> +  AWAIT_READY(backends["aufs"]->provision(
> +      {layer1, layer2},
> +      rootfs,
> +      sandbox.get()));
> +
> +  EXPECT_TRUE(os::exists(path::join(rootfs, "dir1", "1")));
> +  EXPECT_SOME_EQ("1", os::read(path::join(rootfs, "dir1", "1")));
> +
> +  EXPECT_TRUE(os::exists(path::join(rootfs, "dir2", "2")));
> +  EXPECT_SOME_EQ("2", os::read(path::join(rootfs, "dir2", "2")));
> +
> +  // Last layer should overwrite existing file of earlier layers.
> +  EXPECT_TRUE(os::exists(path::join(rootfs, "file")));
> +  EXPECT_SOME_EQ("test2", os::read(path::join(rootfs, "file")));
> +
> +  // Rootfs should be writable.
> +  ASSERT_SOME(os::write(path::join(rootfs, "file"), "test3"));
> +
> +  // Files created in rootfs should shadow the files of lower dirs.
> +  EXPECT_SOME_EQ("test3", os::read(path::join(rootfs, "file")));
> +  EXPECT_SOME_EQ("test2", os::read(path::join(layer2, "file")));
> +
> +  AWAIT_READY(backends["aufs"]->destroy(rootfs));
> +
> +  EXPECT_FALSE(os::exists(rootfs));
> +}
> +
>  } // namespace tests {
>  } // namespace internal {
>  } // namespace mesos {
>
> http://git-wip-us.apache.org/repos/asf/mesos/blob/e5358ed1/src/tests/environment.cpp
> ----------------------------------------------------------------------
> diff --git a/src/tests/environment.cpp b/src/tests/environment.cpp
> index 849e9ce..ebfacc3 100644
> --- a/src/tests/environment.cpp
> +++ b/src/tests/environment.cpp
> @@ -517,6 +517,18 @@ public:
>  };
>
>
> +class AufsFilter : public SupportedFilesystemTestFilter
> +{
> +public:
> +  AufsFilter() : SupportedFilesystemTestFilter("aufs") {}
> +
> +  bool disable(const ::testing::TestInfo* test) const
> +  {
> +    return fsSupportError.isSome() && matches(test, "AUFS_");
> +  }
> +};
> +
> +
>  class OverlayFSFilter : public SupportedFilesystemTestFilter
>  {
>  public:
> @@ -738,6 +750,7 @@ Environment::Environment(const Flags& _flags) : 
> flags(_flags)
>
>    vector<Owned<TestFilter> > filters;
>
> +  filters.push_back(Owned<TestFilter>(new AufsFilter()));
>    filters.push_back(Owned<TestFilter>(new BenchmarkFilter()));
>    filters.push_back(Owned<TestFilter>(new CfsFilter()));
>    filters.push_back(Owned<TestFilter>(new CgroupsFilter()));
>

Reply via email to