You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2015/09/17 00:54:36 UTC
[2/6] mesos git commit: Moved files to prepare for unifying
provisioners.
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/appc/store.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/appc/store.cpp b/src/slave/containerizer/provisioners/appc/store.cpp
deleted file mode 100644
index 33f692c..0000000
--- a/src/slave/containerizer/provisioners/appc/store.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-/**
- * 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 <list>
-
-#include <glog/logging.h>
-
-#include <process/defer.hpp>
-#include <process/dispatch.hpp>
-
-#include <stout/check.hpp>
-#include <stout/hashmap.hpp>
-#include <stout/os.hpp>
-#include <stout/path.hpp>
-
-#include "slave/containerizer/provisioners/appc/paths.hpp"
-#include "slave/containerizer/provisioners/appc/spec.hpp"
-#include "slave/containerizer/provisioners/appc/store.hpp"
-
-using namespace process;
-
-using std::list;
-using std::string;
-using std::vector;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace appc {
-
-// Defines a locally cached image (which has passed validation).
-struct CachedImage
-{
- CachedImage(
- const AppcImageManifest& _manifest,
- const string& _id,
- const string& _path)
- : manifest(_manifest), id(_id), path(_path) {}
-
- string rootfs() const
- {
- return path::join(path, "rootfs");
- }
-
- const AppcImageManifest manifest;
-
- // Image ID of the format "sha512-value" where "value" is the hex
- // encoded string of the sha512 digest of the uncompressed tar file
- // of the image.
- const string id;
-
- // Absolute path to the extracted image.
- const string path;
-};
-
-
-// Helper that implements this:
-// https://github.com/appc/spec/blob/master/spec/aci.md#dependency-matching
-static bool matches(Image::Appc requirements, const CachedImage& candidate)
-{
- // The name must match.
- if (candidate.manifest.name() != requirements.name()) {
- return false;
- }
-
- // If an id is specified the candidate must match.
- if (requirements.has_id() && (candidate.id != requirements.id())) {
- return false;
- }
-
- // Extract labels for easier comparison, this also weeds out duplicates.
- // TODO(xujyan): Detect duplicate labels in image manifest validation
- // and Image::Appc validation.
- hashmap<string, string> requiredLabels;
- foreach (const Label& label, requirements.labels().labels()) {
- requiredLabels[label.key()] = label.value();
- }
-
- hashmap<string, string> candidateLabels;
- foreach (const AppcImageManifest::Label& label,
- candidate.manifest.labels()) {
- candidateLabels[label.name()] = label.value();
- }
-
- // Any label specified must be present and match in the candidate.
- foreachpair (const string& name,
- const string& value,
- requiredLabels) {
- if (!candidateLabels.contains(name) ||
- candidateLabels.get(name).get() != value) {
- return false;
- }
- }
-
- return true;
-}
-
-
-class StoreProcess : public Process<StoreProcess>
-{
-public:
- StoreProcess(const string& root);
-
- ~StoreProcess() {}
-
- Future<Nothing> recover();
-
- Future<vector<string>> get(const Image::Appc& image);
-
-private:
- // Absolute path to the root directory of the store as defined by
- // --appc_store_dir.
- const string root;
-
- // Mappings: name -> id -> image.
- hashmap<string, hashmap<string, CachedImage>> images;
-};
-
-
-Try<Owned<Store>> Store::create(const Flags& flags)
-{
- Try<Nothing> mkdir = os::mkdir(paths::getImagesDir(flags.appc_store_dir));
- if (mkdir.isError()) {
- return Error("Failed to create the images directory: " + mkdir.error());
- }
-
- // Make sure the root path is canonical so all image paths derived
- // from it are canonical too.
- Result<string> root = os::realpath(flags.appc_store_dir);
- if (!root.isSome()) {
- // The above mkdir call recursively creates the store directory
- // if necessary so it cannot be None here.
- CHECK_ERROR(root);
- return Error(
- "Failed to get the realpath of the store directory: " + root.error());
- }
-
- return Owned<Store>(new Store(
- Owned<StoreProcess>(new StoreProcess(root.get()))));
-}
-
-
-Store::Store(Owned<StoreProcess> _process)
- : process(_process)
-{
- spawn(CHECK_NOTNULL(process.get()));
-}
-
-
-Store::~Store()
-{
- terminate(process.get());
- wait(process.get());
-}
-
-
-Future<Nothing> Store::recover()
-{
- return dispatch(process.get(), &StoreProcess::recover);
-}
-
-
-Future<vector<string>> Store::get(const Image::Appc& image)
-{
- return dispatch(process.get(), &StoreProcess::get, image);
-}
-
-
-StoreProcess::StoreProcess(const string& _root) : root(_root) {}
-
-
-// Implemented as a helper function because it's going to be used for a
-// newly downloaded image too.
-static Try<CachedImage> createImage(const string& imagePath)
-{
- Option<Error> error = spec::validateLayout(imagePath);
- if (error.isSome()) {
- return Error("Invalid image layout: " + error.get().message);
- }
-
- string imageId = Path(imagePath).basename();
-
- error = spec::validateImageID(imageId);
- if (error.isSome()) {
- return Error("Invalid image ID: " + error.get().message);
- }
-
- Try<string> read = os::read(paths::getImageManifestPath(imagePath));
- if (read.isError()) {
- return Error("Failed to read manifest: " + read.error());
- }
-
- Try<AppcImageManifest> manifest = spec::parse(read.get());
- if (manifest.isError()) {
- return Error("Failed to parse manifest: " + manifest.error());
- }
-
- return CachedImage(manifest.get(), imageId, imagePath);
-}
-
-
-Future<vector<string>> StoreProcess::get(const Image::Appc& image)
-{
- if (!images.contains(image.name())) {
- return Failure("No image named '" + image.name() + "' can be found");
- }
-
- // Get local candidates.
- vector<CachedImage> candidates;
- foreach (const CachedImage& candidate, images[image.name()].values()) {
- // The first match is returned.
- // TODO(xujyan): Some tie-breaking rules are necessary.
- if (matches(image, candidate)) {
- LOG(INFO) << "Found match for image '" << image.name()
- << "' in the store";
-
- // The Appc store current doesn't support dependencies and this is
- // enforced by manifest validation: if the image's manifest contains
- // dependencies it would fail the validation and wouldn't be stored
- // in the store.
- return vector<string>({candidate.rootfs()});
- }
- }
-
- return Failure("No image named '" + image.name() +
- "' can match the requirements");
-}
-
-
-Future<Nothing> StoreProcess::recover()
-{
- // Recover everything in the store.
- Try<list<string>> imageIds = os::ls(paths::getImagesDir(root));
- if (imageIds.isError()) {
- return Failure(
- "Failed to list images under '" +
- paths::getImagesDir(root) + "': " +
- imageIds.error());
- }
-
- foreach (const string& imageId, imageIds.get()) {
- string path = paths::getImagePath(root, imageId);
- if (!os::stat::isdir(path)) {
- LOG(WARNING) << "Unexpected entry in storage: " << imageId;
- continue;
- }
-
- Try<CachedImage> image = createImage(path);
- if (image.isError()) {
- LOG(WARNING) << "Unexpected entry in storage: " << image.error();
- continue;
- }
-
- LOG(INFO) << "Restored image '" << image.get().manifest.name() << "'";
-
- images[image.get().manifest.name()].put(image.get().id, image.get());
- }
-
- return Nothing();
-}
-
-} // namespace appc {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/appc/store.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/appc/store.hpp b/src/slave/containerizer/provisioners/appc/store.hpp
deleted file mode 100644
index c4ce4b9..0000000
--- a/src/slave/containerizer/provisioners/appc/store.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * 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_APPC_STORE_HPP__
-#define __MESOS_APPC_STORE_HPP__
-
-#include <string>
-#include <vector>
-
-#include <mesos/mesos.hpp>
-
-#include <process/future.hpp>
-#include <process/owned.hpp>
-
-#include <stout/try.hpp>
-
-#include "slave/flags.hpp"
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace appc {
-
-// Forward declaration.
-class StoreProcess;
-
-
-// An image store abstraction that "stores" images. It serves as a read-through
-// cache (cache misses are fetched remotely and transparently) for images.
-// TODO(xujyan): The store currently keeps cached images indefinitely and we
-// should introduce cache eviction policies.
-class Store
-{
-public:
- static Try<process::Owned<Store>> create(const Flags& flags);
-
- ~Store();
-
- process::Future<Nothing> recover();
-
- // Get the specified image (and all its recursive dependencies) as a list
- // of rootfs layers in the topological order (dependencies go before
- // dependents in the list). The images required to build this list are
- // either retrieved from the local cache or fetched remotely.
- // NOTE: The returned list should not have duplicates. e.g., in the
- // following scenario the result should be [C, B, D, A] (B before D in this
- // example is decided by the order in which A specifies its dependencies).
- //
- // A --> B --> C
- // | ^
- // |---> D ----|
- //
- // The returned future fails if the requested image or any of its
- // dependencies cannot be found or failed to be fetched.
- // TODO(xujyan): Fetching remotely is not implemented for now and until
- // then the future fails directly if the image is not in the local cache.
- // TODO(xujyan): The store currently doesn't support images that have
- // dependencies and we should add it later.
- process::Future<std::vector<std::string>> get(const Image::Appc& image);
-
-private:
- Store(process::Owned<StoreProcess> process);
-
- Store(const Store&); // Not copyable.
- Store& operator=(const Store&); // Not assignable.
-
- process::Owned<StoreProcess> process;
-};
-
-} // namespace appc {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __MESOS_APPC_STORE_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/backend.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/backend.cpp b/src/slave/containerizer/provisioners/backend.cpp
deleted file mode 100644
index 6560ece..0000000
--- a/src/slave/containerizer/provisioners/backend.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * 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 <glog/logging.h>
-
-#include <stout/os.hpp>
-
-#include "slave/containerizer/provisioners/backend.hpp"
-
-#include "slave/containerizer/provisioners/backends/bind.hpp"
-#include "slave/containerizer/provisioners/backends/copy.hpp"
-
-using namespace process;
-
-using std::string;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-hashmap<string, Owned<Backend>> Backend::create(const Flags& flags)
-{
- hashmap<string, Try<Owned<Backend>>(*)(const Flags&)> creators;
-
-#ifdef __linux__
- creators.put("bind", &BindBackend::create);
-#endif // __linux__
- creators.put("copy", &CopyBackend::create);
-
- hashmap<string, Owned<Backend>> backends;
-
- foreachkey (const string& name, creators) {
- Try<Owned<Backend>> backend = creators[name](flags);
- if (backend.isError()) {
- LOG(WARNING) << "Failed to create '" << name << "' backend: "
- << backend.error();
- continue;
- }
- backends.put(name, backend.get());
- }
-
- return backends;
-}
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/backend.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/backend.hpp b/src/slave/containerizer/provisioners/backend.hpp
deleted file mode 100644
index a25b4ea..0000000
--- a/src/slave/containerizer/provisioners/backend.hpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * 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_BACKEND_HPP__
-#define __MESOS_PROVISIONER_BACKEND_HPP__
-
-#include <string>
-#include <vector>
-
-#include <process/future.hpp>
-#include <process/owned.hpp>
-
-#include <stout/hashmap.hpp>
-#include <stout/try.hpp>
-
-#include "slave/flags.hpp"
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-// Provision a root filesystem for a container.
-class Backend
-{
-public:
- virtual ~Backend() {}
-
- // Return a map of all supported backends keyed by their names. Note
- // that Backends that failed to be created due to incorrect flags are
- // simply not added to the result.
- static hashmap<std::string, process::Owned<Backend>> create(
- const Flags& flags);
-
- // Provision a root filesystem for a container into the specified 'rootfs'
- // 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(
- const std::vector<std::string>& layers,
- const std::string& rootfs) = 0;
-
- // Destroy the root filesystem provisioned at the specified 'rootfs'
- // directory. Return false if there is no provisioned root filesystem
- // to destroy for the given directory.
- virtual process::Future<bool> destroy(const std::string& rootfs) = 0;
-};
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __MESOS_PROVISIONER_BACKEND_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/backends/bind.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/backends/bind.cpp b/src/slave/containerizer/provisioners/backends/bind.cpp
deleted file mode 100644
index 71861a9..0000000
--- a/src/slave/containerizer/provisioners/backends/bind.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/**
- * 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 <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <process/dispatch.hpp>
-#include <process/process.hpp>
-
-#include <stout/foreach.hpp>
-#include <stout/os.hpp>
-
-#include "linux/fs.hpp"
-
-#include "slave/containerizer/provisioners/backends/bind.hpp"
-
-using namespace process;
-
-using std::string;
-using std::vector;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-class BindBackendProcess : public Process<BindBackendProcess>
-{
-public:
- Future<Nothing> provision(const vector<string>& layers, const string& rootfs);
-
- Future<bool> destroy(const string& rootfs);
-};
-
-
-Try<Owned<Backend>> BindBackend::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("BindBackend requires root privileges");
- }
-
- return Owned<Backend>(new BindBackend(
- Owned<BindBackendProcess>(new BindBackendProcess())));
-}
-
-
-BindBackend::~BindBackend()
-{
- terminate(process.get());
- wait(process.get());
-}
-
-
-BindBackend::BindBackend(Owned<BindBackendProcess> _process)
- : process(_process)
-{
- spawn(CHECK_NOTNULL(process.get()));
-}
-
-
-Future<Nothing> BindBackend::provision(
- const vector<string>& layers,
- const string& rootfs)
-{
- return dispatch(
- process.get(), &BindBackendProcess::provision, layers, rootfs);
-}
-
-
-Future<bool> BindBackend::destroy(const string& rootfs)
-{
- return dispatch(process.get(), &BindBackendProcess::destroy, rootfs);
-}
-
-
-Future<Nothing> BindBackendProcess::provision(
- const vector<string>& layers,
- const string& rootfs)
-{
- if (layers.size() > 1) {
- return Failure(
- "Multiple layers are not supported by the bind backend");
- }
-
- 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);
- }
-
- // TODO(xujyan): Use MS_REC? Does any provisioner use mounts within
- // its image store in a single layer?
- Try<Nothing> mount = fs::mount(
- layers.front(),
- rootfs,
- None(),
- MS_BIND,
- NULL);
-
- if (mount.isError()) {
- return Failure(
- "Failed to bind mount rootfs '" + layers.front() +
- "' to '" + rootfs + "': " + mount.error());
- }
-
- // And remount it read-only.
- mount = fs::mount(
- None(), // Ignored.
- rootfs,
- None(),
- MS_BIND | MS_RDONLY | MS_REMOUNT,
- NULL);
-
- if (mount.isError()) {
- return Failure(
- "Failed to remount rootfs '" + rootfs + "' read-only: " +
- mount.error());
- }
-
- return Nothing();
-}
-
-
-Future<bool> BindBackendProcess::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.get().entries) {
- // TODO(xujyan): If MS_REC was used in 'provision()' we would need
- // to check `strings::startsWith(entry.target, rootfs)` here to
- // unmount all nested mounts.
- 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 bind-mounted rootfs '" + rootfs + "': " +
- unmount.error());
- }
-
- // TODO(jieyu): If 'rmdir' here returns EBUSY, we still returns
- // a success. This is currently possible because the parent
- // mount of 'rootfs' might not be a shared mount. Thus,
- // containers in different mount namespaces might hold extra
- // references to this mount. It is OK to ignore the EBUSY error
- // because the provisioner will later try to delete all the
- // rootfses for the terminated containers.
- if (::rmdir(rootfs.c_str()) != 0) {
- string message =
- "Failed to remove rootfs mount point '" + rootfs +
- "': " + strerror(errno);
-
- if (errno == EBUSY) {
- LOG(ERROR) << message;
- } else {
- return Failure(message);
- }
- }
-
- return true;
- }
- }
-
- return false;
-}
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/backends/bind.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/backends/bind.hpp b/src/slave/containerizer/provisioners/backends/bind.hpp
deleted file mode 100644
index 61a8838..0000000
--- a/src/slave/containerizer/provisioners/backends/bind.hpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * 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_BIND_HPP__
-#define __MESOS_PROVISIONER_BIND_HPP__
-
-#include "slave/containerizer/provisioners/backend.hpp"
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-// Forward declaration.
-class BindBackendProcess;
-
-
-// This is a specialized backend that may be useful for deployments
-// using large (multi-GB) single-layer images *and* where more recent
-// kernel features such as overlayfs are not available (overlayfs-based
-// backend tracked by MESOS-2971). For small images (10's to 100's of MB)
-// the copy backend may be sufficient. NOTE:
-// 1) BindBackend supports only a single layer. Multi-layer images will
-// fail to provision and the container will fail to launch!
-// 2) The filesystem is read-only because all containers using this
-// image share the source. Select writable areas can be achieved by
-// mounting read-write volumes to places like /tmp, /var/tmp,
-// /home, etc. using the ContainerInfo. These can be relative to
-// the executor work directory.
-// N.B. Since the filesystem is read-only, '--sandbox_directory' must
-// already exist within the filesystem because the filesystem isolator
-// is unable to create it!
-// 3) It's fast because the bind mount requires (nearly) zero IO.
-class BindBackend : public Backend
-{
-public:
- virtual ~BindBackend();
-
- // BindBackend doesn't use any flag.
- static Try<process::Owned<Backend>> create(const Flags&);
-
- virtual process::Future<Nothing> provision(
- const std::vector<std::string>& layers,
- const std::string& rootfs);
-
- virtual process::Future<bool> destroy(const std::string& rootfs);
-
-private:
- explicit BindBackend(process::Owned<BindBackendProcess> process);
-
- BindBackend(const BindBackend&); // Not copyable.
- BindBackend& operator=(const BindBackend&); // Not assignable.
-
- process::Owned<BindBackendProcess> process;
-};
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __MESOS_PROVISIONER_BIND_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/backends/copy.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/backends/copy.cpp b/src/slave/containerizer/provisioners/backends/copy.cpp
deleted file mode 100644
index b569465..0000000
--- a/src/slave/containerizer/provisioners/backends/copy.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/**
- * 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 <list>
-
-#include <process/collect.hpp>
-#include <process/defer.hpp>
-#include <process/dispatch.hpp>
-#include <process/io.hpp>
-#include <process/process.hpp>
-#include <process/subprocess.hpp>
-
-
-#include <stout/foreach.hpp>
-#include <stout/os.hpp>
-
-#include "common/status_utils.hpp"
-
-#include "slave/containerizer/provisioners/backends/copy.hpp"
-
-
-using namespace process;
-
-using std::string;
-using std::list;
-using std::vector;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-class CopyBackendProcess : public Process<CopyBackendProcess>
-{
-public:
- Future<Nothing> provision(const vector<string>& layers, const string& rootfs);
-
- Future<bool> destroy(const string& rootfs);
-
-private:
- Future<Nothing> _provision(string layer, const string& rootfs);
-};
-
-
-Try<Owned<Backend>> CopyBackend::create(const Flags&)
-{
- return Owned<Backend>(new CopyBackend(
- Owned<CopyBackendProcess>(new CopyBackendProcess())));
-}
-
-
-CopyBackend::~CopyBackend()
-{
- terminate(process.get());
- wait(process.get());
-}
-
-
-CopyBackend::CopyBackend(Owned<CopyBackendProcess> _process)
- : process(_process)
-{
- spawn(CHECK_NOTNULL(process.get()));
-}
-
-
-Future<Nothing> CopyBackend::provision(
- const vector<string>& layers,
- const string& rootfs)
-{
- return dispatch(
- process.get(), &CopyBackendProcess::provision, layers, rootfs);
-}
-
-
-Future<bool> CopyBackend::destroy(const string& rootfs)
-{
- return dispatch(process.get(), &CopyBackendProcess::destroy, rootfs);
-}
-
-
-Future<Nothing> CopyBackendProcess::provision(
- const vector<string>& layers,
- const string& rootfs)
-{
- if (layers.size() == 0) {
- return Failure("No filesystem layers provided");
- }
-
- if (os::exists(rootfs)) {
- return Failure("Rootfs is already provisioned");
- }
-
- Try<Nothing> mkdir = os::mkdir(rootfs);
- if (mkdir.isError()) {
- return Failure("Failed to create rootfs directory: " + mkdir.error());
- }
-
- list<Future<Nothing>> futures{Nothing()};
-
- foreach (const string layer, layers) {
- futures.push_back(
- futures.back().then(
- defer(self(), &Self::_provision, layer, rootfs)));
- }
-
- return collect(futures)
- .then([]() -> Future<Nothing> { return Nothing(); });
-}
-
-
-Future<Nothing> CopyBackendProcess::_provision(
- string layer,
- const string& rootfs)
-{
- VLOG(1) << "Copying layer path '" << layer << "' to rootfs '" << rootfs
- << "'";
-
-#ifdef __APPLE__
- if (!strings::endsWith(layer, "/")) {
- layer += "/";
- }
-
- // OSX cp doesn't support -T flag, but supports source trailing
- // slash so we only copy the content but not the folder.
- vector<string> args{"cp", "-a", layer, rootfs};
-#else
- vector<string> args{"cp", "-aT", layer, rootfs};
-#endif // __APPLE__
-
- Try<Subprocess> s = subprocess(
- "cp",
- args,
- Subprocess::PATH("/dev/null"),
- Subprocess::PATH("/dev/null"),
- Subprocess::PIPE());
-
- if (s.isError()) {
- return Failure("Failed to create 'cp' subprocess: " + s.error());
- }
-
- Subprocess cp = s.get();
-
- return cp.status()
- .then([cp](const Option<int>& status) -> Future<Nothing> {
- if (status.isNone()) {
- return Failure("Failed to reap subprocess to copy image");
- } else if (status.get() != 0) {
- return io::read(cp.err().get())
- .then([](const string& err) -> Future<Nothing> {
- return Failure("Failed to copy layer: " + err);
- });
- }
-
- return Nothing();
- });
-}
-
-
-Future<bool> CopyBackendProcess::destroy(const string& rootfs)
-{
- vector<string> argv{"rm", "-rf", rootfs};
-
- Try<Subprocess> s = subprocess(
- "rm",
- argv,
- Subprocess::PATH("/dev/null"),
- Subprocess::FD(STDOUT_FILENO),
- Subprocess::FD(STDERR_FILENO));
-
- if (s.isError()) {
- return Failure("Failed to create 'rm' subprocess: " + s.error());
- }
-
- return s.get().status()
- .then([](const Option<int>& status) -> Future<bool> {
- if (status.isNone()) {
- return Failure("Failed to reap subprocess to destroy rootfs");
- } else if (status.get() != 0) {
- return Failure("Failed to destroy rootfs, exit status: " +
- WSTRINGIFY(status.get()));
- }
-
- return true;
- });
-}
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/backends/copy.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/backends/copy.hpp b/src/slave/containerizer/provisioners/backends/copy.hpp
deleted file mode 100644
index 2abca37..0000000
--- a/src/slave/containerizer/provisioners/backends/copy.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * 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_COPY_HPP__
-#define __MESOS_PROVISIONER_COPY_HPP__
-
-#include "slave/containerizer/provisioners/backend.hpp"
-
-namespace mesos {
-namespace internal {
-namespace slave {
-
-// Forward declaration.
-class CopyBackendProcess;
-
-
-class CopyBackend : public Backend
-{
-public:
- virtual ~CopyBackend();
-
- // CopyBackend doesn't use any flag.
- static Try<process::Owned<Backend>> create(const Flags&);
-
- // Provisions a rootfs given the layers' paths and target rootfs
- // path.
- virtual process::Future<Nothing> provision(
- const std::vector<std::string>& layers,
- const std::string& rootfs);
-
- virtual process::Future<bool> destroy(const std::string& rootfs);
-
-private:
- explicit CopyBackend(process::Owned<CopyBackendProcess> process);
-
- CopyBackend(const CopyBackend&); // Not copyable.
- CopyBackend& operator=(const CopyBackend&); // Not assignable.
-
- process::Owned<CopyBackendProcess> process;
-};
-
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __MESOS_PROVISIONER_COPY_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/docker/registry_client.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/docker/registry_client.cpp b/src/slave/containerizer/provisioners/docker/registry_client.cpp
deleted file mode 100644
index b262ef0..0000000
--- a/src/slave/containerizer/provisioners/docker/registry_client.cpp
+++ /dev/null
@@ -1,575 +0,0 @@
-/**
- * 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 <vector>
-
-#include <process/defer.hpp>
-#include <process/dispatch.hpp>
-#include <process/io.hpp>
-
-#include "slave/containerizer/provisioners/docker/registry_client.hpp"
-#include "slave/containerizer/provisioners/docker/token_manager.hpp"
-
-using std::string;
-using std::vector;
-
-using process::Failure;
-using process::Future;
-using process::Owned;
-using process::Process;
-
-using process::http::Request;
-using process::http::Response;
-using process::http::URL;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace docker {
-namespace registry {
-
-using FileSystemLayerInfo = RegistryClient::FileSystemLayerInfo;
-
-using ManifestResponse = RegistryClient::ManifestResponse;
-
-const Duration RegistryClient::DEFAULT_MANIFEST_TIMEOUT_SECS = Seconds(10);
-
-const size_t RegistryClient::DEFAULT_MANIFEST_MAXSIZE_BYTES = 4096;
-
-static const uint16_t DEFAULT_SSL_PORT = 443;
-
-class RegistryClientProcess : public Process<RegistryClientProcess>
-{
-public:
- static Try<Owned<RegistryClientProcess>> create(
- const URL& authServer,
- const URL& registry,
- const Option<RegistryClient::Credentials>& creds);
-
- Future<RegistryClient::ManifestResponse> getManifest(
- const string& path,
- const Option<string>& tag,
- const Duration& timeout);
-
- Future<size_t> getBlob(
- const string& path,
- const Option<string>& digest,
- const Path& filePath,
- const Duration& timeout,
- size_t maxSize);
-
-private:
- RegistryClientProcess(
- const Owned<TokenManager>& tokenMgr,
- const URL& registryServer,
- const Option<RegistryClient::Credentials>& creds);
-
- Future<Response> doHttpGet(
- const URL& url,
- const Option<hashmap<string, string>>& headers,
- const Duration& timeout,
- bool resend,
- const Option<string>& lastResponse) const;
-
- Try<hashmap<string, string>> getAuthenticationAttributes(
- const Response& httpResponse) const;
-
- Owned<TokenManager> tokenManager_;
- const URL registryServer_;
- const Option<RegistryClient::Credentials> credentials_;
-
- RegistryClientProcess(const RegistryClientProcess&) = delete;
- RegistryClientProcess& operator = (const RegistryClientProcess&) = delete;
-};
-
-
-Try<Owned<RegistryClient>> RegistryClient::create(
- const URL& authServer,
- const URL& registryServer,
- const Option<Credentials>& creds)
-{
- Try<Owned<RegistryClientProcess>> process =
- RegistryClientProcess::create(authServer, registryServer, creds);
-
- if (process.isError()) {
- return Error(process.error());
- }
-
- return Owned<RegistryClient>(
- new RegistryClient(authServer, registryServer, creds, process.get()));
-}
-
-
-RegistryClient::RegistryClient(
- const URL& authServer,
- const URL& registryServer,
- const Option<Credentials>& creds,
- const Owned<RegistryClientProcess>& process)
- : authServer_(authServer),
- registryServer_(registryServer),
- credentials_(creds),
- process_(process)
-{
- spawn(CHECK_NOTNULL(process_.get()));
-}
-
-
-RegistryClient::~RegistryClient()
-{
- terminate(process_.get());
- process::wait(process_.get());
-}
-
-
-Future<ManifestResponse> RegistryClient::getManifest(
- const string& _path,
- const Option<string>& _tag,
- const Option<Duration>& _timeout)
-{
- Duration timeout = _timeout.getOrElse(DEFAULT_MANIFEST_TIMEOUT_SECS);
-
- return dispatch(
- process_.get(),
- &RegistryClientProcess::getManifest,
- _path,
- _tag,
- timeout);
-}
-
-
-Future<size_t> RegistryClient::getBlob(
- const string& _path,
- const Option<string>& _digest,
- const Path& _filePath,
- const Option<Duration>& _timeout,
- const Option<size_t>& _maxSize)
-{
- Duration timeout = _timeout.getOrElse(DEFAULT_MANIFEST_TIMEOUT_SECS);
- size_t maxSize = _maxSize.getOrElse(DEFAULT_MANIFEST_MAXSIZE_BYTES);
-
- return dispatch(
- process_.get(),
- &RegistryClientProcess::getBlob,
- _path,
- _digest,
- _filePath,
- timeout,
- maxSize);
-}
-
-
-Try<Owned<RegistryClientProcess>> RegistryClientProcess::create(
- const URL& authServer,
- const URL& registryServer,
- const Option<RegistryClient::Credentials>& creds)
-{
- Try<Owned<TokenManager>> tokenMgr = TokenManager::create(authServer);
- if (tokenMgr.isError()) {
- return Error("Failed to create token manager: " + tokenMgr.error());
- }
-
- return Owned<RegistryClientProcess>(
- new RegistryClientProcess(tokenMgr.get(), registryServer, creds));
-}
-
-
-RegistryClientProcess::RegistryClientProcess(
- const Owned<TokenManager>& tokenMgr,
- const URL& registryServer,
- const Option<RegistryClient::Credentials>& creds)
- : tokenManager_(tokenMgr),
- registryServer_(registryServer),
- credentials_(creds) {}
-
-
-Try<hashmap<string, string>>
-RegistryClientProcess::getAuthenticationAttributes(
- const Response& httpResponse) const
-{
- if (httpResponse.headers.find("WWW-Authenticate") ==
- httpResponse.headers.end()) {
- return Error("Failed to find WWW-Authenticate header value");
- }
-
- const string& authString = httpResponse.headers.at("WWW-Authenticate");
-
- const vector<string> authStringTokens = strings::tokenize(authString, " ");
- if ((authStringTokens.size() != 2) || (authStringTokens[0] != "Bearer")) {
- // TODO(jojy): Look at various possibilities of auth response. We currently
- // assume that the string will have realm information.
- return Error("Invalid authentication header value: " + authString);
- }
-
- const vector<string> authParams = strings::tokenize(authStringTokens[1], ",");
-
- hashmap<string, string> authAttributes;
- auto addAttribute = [&authAttributes](
- const string& param) -> Try<Nothing> {
- const vector<string> paramTokens =
- strings::tokenize(param, "=\"");
-
- if (paramTokens.size() != 2) {
- return Error(
- "Failed to get authentication attribute from response parameter " +
- param);
- }
-
- authAttributes.insert({paramTokens[0], paramTokens[1]});
-
- return Nothing();
- };
-
- foreach (const string& param, authParams) {
- Try<Nothing> addRes = addAttribute(param);
- if (addRes.isError()) {
- return Error(addRes.error());
- }
- }
-
- return authAttributes;
-}
-
-
-Future<Response>
-RegistryClientProcess::doHttpGet(
- const URL& url,
- const Option<hashmap<string, string>>& headers,
- const Duration& timeout,
- bool resend,
- const Option<string>& lastResponseStatus) const
-{
- return process::http::get(url, headers)
- .after(timeout, [](
- const Future<Response>& httpResponseFuture) -> Future<Response> {
- return Failure("Response timeout");
- })
- .then(defer(self(), [=](
- const Response& httpResponse) -> Future<Response> {
- VLOG(1) << "Response status: " + httpResponse.status;
-
- // Set the future if we get a OK response.
- if (httpResponse.status == "200 OK") {
- return httpResponse;
- } else if (httpResponse.status == "400 Bad Request") {
- Try<JSON::Object> errorResponse =
- JSON::parse<JSON::Object>(httpResponse.body);
-
- if (errorResponse.isError()) {
- return Failure("Failed to parse bad request response JSON: " +
- errorResponse.error());
- }
-
- std::ostringstream out;
- bool first = true;
- Result<JSON::Array> errorObjects =
- errorResponse.get().find<JSON::Array>("errors");
-
- if (errorObjects.isError()) {
- return Failure("Failed to find 'errors' in bad request response: " +
- errorObjects.error());
- } else if (errorObjects.isNone()) {
- return Failure("Errors not found in bad request response");
- }
-
- foreach (const JSON::Value& error, errorObjects.get().values) {
- Result<JSON::String> message =
- error.as<JSON::Object>().find<JSON::String>("message");
- if (message.isError()) {
- return Failure("Failed to parse bad request error message: " +
- message.error());
- } else if (message.isNone()) {
- continue;
- }
-
- if (first) {
- out << message.get().value;
- first = false;
- } else {
- out << ", " << message.get().value;
- }
- }
- return Failure("Received Bad request, errors: [" + out.str() + "]");
- }
-
- // Prevent infinite recursion.
- if (lastResponseStatus.isSome() &&
- (lastResponseStatus.get() == httpResponse.status)) {
- return Failure("Invalid response: " + httpResponse.status);
- }
-
- // If resend is not set, we dont try again and stop here.
- if (!resend) {
- return Failure("Bad response: " + httpResponse.status);
- }
-
- // Handle 401 Unauthorized.
- if (httpResponse.status == "401 Unauthorized") {
- Try<hashmap<string, string>> authAttributes =
- getAuthenticationAttributes(httpResponse);
-
- if (authAttributes.isError()) {
- return Failure(
- "Failed to get authentication attributes: " +
- authAttributes.error());
- }
-
- // TODO(jojy): Currently only handling TLS/cert authentication.
- Future<Token> tokenResponse = tokenManager_->getToken(
- authAttributes.get().at("service"),
- authAttributes.get().at("scope"),
- None());
-
- return tokenResponse
- .after(timeout, [=](
- Future<Token> tokenResponse) -> Future<Token> {
- tokenResponse.discard();
- return Failure("Token response timeout");
- })
- .then(defer(self(), [=](
- const Future<Token>& tokenResponse) {
- // Send request with acquired token.
- hashmap<string, string> authHeaders = {
- {"Authorization", "Bearer " + tokenResponse.get().raw}
- };
-
- return doHttpGet(
- url,
- authHeaders,
- timeout,
- true,
- httpResponse.status);
- }));
- } else if (httpResponse.status == "307 Temporary Redirect") {
- // Handle redirect.
-
- // TODO(jojy): Add redirect functionality in http::get.
-
- auto toURL = [](
- const string& urlString) -> Try<URL> {
- // TODO(jojy): Need to add functionality to URL class that parses a
- // string to its URL components. For now, assuming:
- // - scheme is https
- // - path always ends with /
-
- static const string schemePrefix = "https://";
-
- if (!strings::contains(urlString, schemePrefix)) {
- return Error(
- "Failed to find expected token '" + schemePrefix +
- "' in redirect url");
- }
-
- const string schemeSuffix = urlString.substr(schemePrefix.length());
-
- const vector<string> components =
- strings::tokenize(schemeSuffix, "/");
-
- const string path = schemeSuffix.substr(components[0].length());
-
- const vector<string> addrComponents =
- strings::tokenize(components[0], ":");
-
- uint16_t port = DEFAULT_SSL_PORT;
- string domain = components[0];
-
- // Parse the port.
- if (addrComponents.size() == 2) {
- domain = addrComponents[0];
-
- Try<uint16_t> tryPort = numify<uint16_t>(addrComponents[1]);
- if (tryPort.isError()) {
- return Error(
- "Failed to parse location: " + urlString + " for port.");
- }
-
- port = tryPort.get();
- }
-
- return URL("https", domain, port, path);
- };
-
- if (httpResponse.headers.find("Location") ==
- httpResponse.headers.end()) {
- return Failure(
- "Invalid redirect response: 'Location' not found in headers.");
- }
-
- const string& location = httpResponse.headers.at("Location");
- Try<URL> tryUrl = toURL(location);
- if (tryUrl.isError()) {
- return Failure(
- "Failed to parse '" + location + "': " + tryUrl.error());
- }
-
- return doHttpGet(
- tryUrl.get(),
- headers,
- timeout,
- false,
- httpResponse.status);
- } else {
- return Failure("Invalid response: " + httpResponse.status);
- }
- }));
-}
-
-
-Future<ManifestResponse> RegistryClientProcess::getManifest(
- const string& path,
- const Option<string>& tag,
- const Duration& timeout)
-{
- //TODO(jojy): These validations belong in the URL class.
- if (strings::contains(path, " ")) {
- return Failure("Invalid repository path: " + path);
- }
-
- string repoTag = tag.getOrElse("latest");
- if (strings::contains(repoTag, " ")) {
- return Failure("Invalid repository tag: " + repoTag);
- }
-
- URL manifestURL(registryServer_);
- manifestURL.path =
- "v2/" + path + "/manifests/" + repoTag;
-
- auto getManifestResponse = [](
- const Response& httpResponse) -> Try<ManifestResponse> {
- if (!httpResponse.headers.contains("Docker-Content-Digest")) {
- return Error("Docker-Content-Digest header missing in response");
- }
-
- Try<JSON::Object> responseJSON =
- JSON::parse<JSON::Object>(httpResponse.body);
-
- if (responseJSON.isError()) {
- return Error(responseJSON.error());
- }
-
- Result<JSON::String> name = responseJSON.get().find<JSON::String>("name");
- if (name.isNone()) {
- return Error("Failed to find \"name\" in manifest response");
- }
-
- Result<JSON::Array> fsLayers =
- responseJSON.get().find<JSON::Array>("fsLayers");
-
- if (fsLayers.isNone()) {
- return Error("Failed to find \"fsLayers\" in manifest response");
- }
-
- vector<FileSystemLayerInfo> fsLayerInfoList;
- foreach (const JSON::Value& layer, fsLayers.get().values) {
- const JSON::Object& layerInfoJSON = layer.as<JSON::Object>();
- Result<JSON::String> blobSumInfo =
- layerInfoJSON.find<JSON::String>("blobSum");
-
- if (blobSumInfo.isNone()) {
- return Error("Failed to find \"blobSum\" in manifest response");
- }
-
- fsLayerInfoList.emplace_back(
- FileSystemLayerInfo{blobSumInfo.get().value});
- }
-
- return ManifestResponse {
- name.get().value,
- httpResponse.headers.at("Docker-Content-Digest"),
- fsLayerInfoList,
- };
- };
-
- return doHttpGet(manifestURL, None(), timeout, true, None())
- .then([getManifestResponse] (
- const Response& response) -> Future<ManifestResponse> {
- Try<ManifestResponse> manifestResponse = getManifestResponse(response);
-
- if (manifestResponse.isError()) {
- return Failure(
- "Failed to parse manifest response: " + manifestResponse.error());
- }
-
- return manifestResponse.get();
- });
-}
-
-
-Future<size_t> RegistryClientProcess::getBlob(
- const string& path,
- const Option<string>& digest,
- const Path& filePath,
- const Duration& timeout,
- size_t maxSize)
-{
- auto prepare = ([&filePath]() -> Try<Nothing> {
- const string dirName = filePath.dirname();
-
- //TODO(jojy): Return more state, for example - if the directory is new.
- Try<Nothing> dirResult = os::mkdir(dirName, true);
- if (dirResult.isError()) {
- return Error(
- "Failed to create directory to download blob: " +
- dirResult.error());
- }
-
- return dirResult;
- })();
-
- // TODO(jojy): This currently leaves a residue in failure cases. Would be
- // ideal if we can completely rollback.
- if (prepare.isError()) {
- return Failure(prepare.error());
- }
-
- if (strings::contains(path, " ")) {
- return Failure("Invalid repository path: " + path);
- }
-
- URL blobURL(registryServer_);
- blobURL.path =
- "v2/" + path + "/blobs/" + digest.getOrElse("");
-
- auto saveBlob = [filePath](
- const Response& httpResponse) -> Future<size_t> {
- // TODO(jojy): Add verification step.
- // TODO(jojy): Add check for max size.
- size_t size = httpResponse.body.length();
- Try<int> fd = os::open(
- filePath.value,
- O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
- if (fd.isError()) {
- return Failure("Failed to open file '" + filePath.value + "': " +
- fd.error());
- }
-
- return process::io::write(fd.get(), httpResponse.body)
- .then([size](const Future<Nothing>&) { return size; })
- .onAny([fd]() { os::close(fd.get()); } );
- };
-
- return doHttpGet(blobURL, None(), timeout, true, None())
- .then([saveBlob](const Response& response) { return saveBlob(response); });
-}
-
-} // namespace registry {
-} // namespace docker {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/docker/registry_client.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/docker/registry_client.hpp b/src/slave/containerizer/provisioners/docker/registry_client.hpp
deleted file mode 100644
index 3ec3741..0000000
--- a/src/slave/containerizer/provisioners/docker/registry_client.hpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/**
- * 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 __PROVISIONERS_DOCKER_REGISTRY_CLIENT_HPP__
-#define __PROVISIONERS_DOCKER_REGISTRY_CLIENT_HPP__
-
-#include <string>
-#include <vector>
-
-#include <stout/duration.hpp>
-#include <stout/hashmap.hpp>
-#include <stout/json.hpp>
-#include <stout/path.hpp>
-
-#include <process/future.hpp>
-#include <process/http.hpp>
-#include <process/process.hpp>
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace docker {
-namespace registry {
-
-// Forward declarations.
-class RegistryClientProcess;
-
-
-class RegistryClient
-{
-public:
- /**
- * Encapsulates information about a file system layer.
- */
- struct FileSystemLayerInfo {
- //TODO(jojy): This string includes the checksum type also now. Need to
- //separate this into checksum method and checksum.
- std::string checksumInfo;
- };
-
- /**
- * Encapsulates response of "GET Manifest" request.
- *
- * Reference: https://docs.docker.com/registry/spec/api
- */
- struct ManifestResponse {
- const std::string name;
- const std::string digest;
- const std::vector<FileSystemLayerInfo> fsLayerInfoList;
- };
-
- /**
- * Encapsulates auth credentials for the client sessions.
- * TODO(jojy): Secure heap to protect the credentials.
- */
- struct Credentials {
- /**
- * UserId for basic authentication.
- */
- const Option<std::string> userId;
- /**
- * Password for basic authentication.
- */
- const Option<std::string> password;
- /**
- * Account for fetching data from registry.
- */
- const Option<std::string> account;
- };
-
- /**
- * Factory method for creating RegistryClient objects.
- *
- * @param authServer URL of authorization server.
- * @param registryServer URL of docker registry server.
- * @param credentials credentials for client session (optional).
- * @return RegistryClient on Success.
- * Error on failure.
- */
- static Try<process::Owned<RegistryClient>> create(
- const process::http::URL& authServer,
- const process::http::URL& registryServer,
- const Option<Credentials>& credentials);
-
- /**
- * Fetches manifest for a repository from the client's remote registry server.
- *
- * @param path path of the repository on the registry.
- * @param tag unique tag that identifies the repository. Will default to
- * latest.
- * @param timeout Maximum time ater which the request will timeout and return
- * a failure. Will default to RESPONSE_TIMEOUT.
- * @return JSON object on success.
- * Failure on process failure.
- */
- process::Future<ManifestResponse> getManifest(
- const std::string& path,
- const Option<std::string>& tag,
- const Option<Duration>& timeout);
-
- /**
- * Fetches blob for a repository from the client's remote registry server.
- *
- * @param path path of the repository on the registry.
- * @param digest digest of the blob (from manifest).
- * @param filePath file path to store the fetched blob.
- * @param timeout Maximum time ater which the request will timeout and return
- * a failure. Will default to RESPONSE_TIMEOUT.
- * @param maxSize Maximum size of the response thats acceptable. Will default
- * to MAX_RESPONSE_SIZE.
- * @return size of downloaded blob on success.
- * Failure in case of any errors.
- */
- process::Future<size_t> getBlob(
- const std::string& path,
- const Option<std::string>& digest,
- const Path& filePath,
- const Option<Duration>& timeout,
- const Option<size_t>& maxSize);
-
- ~RegistryClient();
-
-private:
- RegistryClient(
- const process::http::URL& authServer,
- const process::http::URL& registryServer,
- const Option<Credentials>& credentials,
- const process::Owned<RegistryClientProcess>& process);
-
- static const Duration DEFAULT_MANIFEST_TIMEOUT_SECS;
- static const size_t DEFAULT_MANIFEST_MAXSIZE_BYTES;
-
- const process::http::URL authServer_;
- const process::http::URL registryServer_;
- const Option<Credentials> credentials_;
- process::Owned<RegistryClientProcess> process_;
-
- RegistryClient(const RegistryClient&) = delete;
- RegistryClient& operator=(const RegistryClient&) = delete;
-};
-
-} // namespace registry {
-} // namespace docker {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __PROVISIONERS_DOCKER_REGISTRY_CLIENT_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/docker/token_manager.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/docker/token_manager.cpp b/src/slave/containerizer/provisioners/docker/token_manager.cpp
deleted file mode 100644
index aec915f..0000000
--- a/src/slave/containerizer/provisioners/docker/token_manager.cpp
+++ /dev/null
@@ -1,361 +0,0 @@
-/**
- * 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/defer.hpp>
-#include <process/dispatch.hpp>
-
-#include "slave/containerizer/provisioners/docker/token_manager.hpp"
-
-using std::hash;
-using std::string;
-using std::vector;
-
-using process::Clock;
-using process::Failure;
-using process::Future;
-using process::Owned;
-using process::Process;
-using process::Time;
-
-using process::http::Request;
-using process::http::Response;
-using process::http::URL;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace docker {
-namespace registry {
-
-class TokenManagerProcess : public Process<TokenManagerProcess>
-{
-public:
- static Try<Owned<TokenManagerProcess>> create(const URL& realm);
-
- Future<Token> getToken(
- const string& service,
- const string& scope,
- const Option<string>& account);
-
-private:
- static const string TOKEN_PATH_PREFIX;
- static const Duration RESPONSE_TIMEOUT;
-
- TokenManagerProcess(const URL& realm)
- : realm_(realm) {}
-
- Try<Token> getTokenFromResponse(const Response& response) const;
-
- /**
- * Key for the token cache.
- */
- struct TokenCacheKey
- {
- string service;
- string scope;
- };
-
- struct TokenCacheKeyHash
- {
- size_t operator()(const TokenCacheKey& key) const
- {
- hash<string> hashFn;
-
- return (hashFn(key.service) ^
- (hashFn(key.scope) << 1));
- }
- };
-
- struct TokenCacheKeyEqual
- {
- bool operator()(
- const TokenCacheKey& left,
- const TokenCacheKey& right) const
- {
- return ((left.service == right.service) &&
- (left.scope == right.scope));
- }
- };
-
- typedef hashmap<
- const TokenCacheKey,
- Token,
- TokenCacheKeyHash,
- TokenCacheKeyEqual> TokenCacheType;
-
- const URL realm_;
- TokenCacheType tokenCache_;
-
- TokenManagerProcess(const TokenManagerProcess&) = delete;
- TokenManagerProcess& operator=(const TokenManagerProcess&) = delete;
-};
-
-const Duration TokenManagerProcess::RESPONSE_TIMEOUT = Seconds(10);
-const string TokenManagerProcess::TOKEN_PATH_PREFIX = "/v2/token/";
-
-
-Token::Token(
- const string& _raw,
- const JSON::Object& _header,
- const JSON::Object& _claims,
- const Option<Time>& _expiration,
- const Option<Time>& _notBefore)
- : raw(_raw),
- header(_header),
- claims(_claims),
- expiration(_expiration),
- notBefore(_notBefore) {}
-
-
-Try<Token> Token::create(const string& raw)
-{
- auto decode = [](
- const string& segment) -> Try<JSON::Object> {
- const auto padding = segment.length() % 4;
- string paddedSegment(segment);
-
- if (padding) {
- paddedSegment.append(padding, '=');
- }
-
- Try<string> decoded = base64::decode(paddedSegment);
- if (decoded.isError()) {
- return Error(decoded.error());
- }
-
- return JSON::parse<JSON::Object>(decoded.get());
- };
-
- const vector<string> tokens = strings::tokenize(raw, ".");
-
- if (tokens.size() != 3) {
- return Error("Invalid raw token string");
- }
-
- Try<JSON::Object> header = decode(tokens[0]);
- if (header.isError()) {
- return Error("Failed to decode 'header' segment: " + header.error());
- }
-
- Try<JSON::Object> claims = decode(tokens[1]);
- if (claims.isError()) {
- return Error("Failed to decode 'claims' segment: " + claims.error());
- }
-
- Result<Time> expirationTime = getTimeValue(claims.get(), "exp");
- if (expirationTime.isError()) {
- return Error("Failed to decode expiration time: " + expirationTime.error());
- }
-
- Option<Time> expiration;
- if (expirationTime.isSome()) {
- expiration = expirationTime.get();
- }
-
- Result<Time> notBeforeTime = getTimeValue(claims.get(), "nbf");
- if (notBeforeTime.isError()) {
- return Error("Failed to decode not-before time: " + notBeforeTime.error());
- }
-
- Option<Time> notBefore;
- if (notBeforeTime.isSome()) {
- notBefore = notBeforeTime.get();
- }
-
- Token token(raw, header.get(), claims.get(), expiration, notBefore);
-
- if (token.isExpired()) {
- return Error("Token has expired");
- }
-
- // TODO(jojy): Add signature validation.
- return token;
-}
-
-
-Result<Time> Token::getTimeValue(const JSON::Object& object, const string& key)
-{
- Result<JSON::Number> jsonValue = object.find<JSON::Number>(key);
-
- Option<Time> timeValue;
-
- // If expiration is provided, we will process it for future validations.
- if (jsonValue.isSome()) {
- Try<Time> time = Time::create(jsonValue.get().value);
- if (time.isError()) {
- return Error("Failed to decode time: " + time.error());
- }
-
- timeValue = time.get();
- }
-
- return timeValue;
-}
-
-
-bool Token::isExpired() const
-{
- if (expiration.isSome()) {
- return (Clock::now() >= expiration.get());
- }
-
- return false;
-}
-
-
-bool Token::isValid() const
-{
- if (!isExpired()) {
- if (notBefore.isSome()) {
- return (Clock::now() >= notBefore.get());
- }
-
- return true;
- }
-
- // TODO(jojy): Add signature validation.
- return false;
-}
-
-
-Try<Owned<TokenManager>> TokenManager::create(
- const URL& realm)
-{
- Try<Owned<TokenManagerProcess>> process = TokenManagerProcess::create(realm);
- if (process.isError()) {
- return Error(process.error());
- }
-
- return Owned<TokenManager>(new TokenManager(process.get()));
-}
-
-
-TokenManager::TokenManager(Owned<TokenManagerProcess>& process)
- : process_(process)
-{
- spawn(CHECK_NOTNULL(process_.get()));
-}
-
-
-TokenManager::~TokenManager()
-{
- terminate(process_.get());
- process::wait(process_.get());
-}
-
-
-Future<Token> TokenManager::getToken(
- const string& service,
- const string& scope,
- const Option<string>& account)
-{
- return dispatch(
- process_.get(),
- &TokenManagerProcess::getToken,
- service,
- scope,
- account);
-}
-
-
-Try<Owned<TokenManagerProcess>> TokenManagerProcess::create(const URL& realm)
-{
- return Owned<TokenManagerProcess>(new TokenManagerProcess(realm));
-}
-
-
-Try<Token> TokenManagerProcess::getTokenFromResponse(
- const Response& response) const
-{
- Try<JSON::Object> tokenJSON = JSON::parse<JSON::Object>(response.body);
- if (tokenJSON.isError()) {
- return Error(tokenJSON.error());
- }
-
- Result<JSON::String> tokenString =
- tokenJSON.get().find<JSON::String>("token");
-
- if (tokenString.isError()) {
- return Error(tokenString.error());
- }
-
- Try<Token> result = Token::create(tokenString.get().value);
- if (result.isError()) {
- return Error(result.error());
- }
-
- return result.get();;
-}
-
-
-Future<Token> TokenManagerProcess::getToken(
- const string& service,
- const string& scope,
- const Option<string>& account)
-{
- const TokenCacheKey tokenKey = {service, scope};
-
- if (tokenCache_.contains(tokenKey)) {
- Token token = tokenCache_.at(tokenKey);
-
- if (token.isValid()) {
- return token;
- } else {
- LOG(WARNING) << "Cached token was invalid. Will fetch once again";
- }
- }
-
- URL tokenUrl = realm_;
- tokenUrl.path = TOKEN_PATH_PREFIX;
-
- tokenUrl.query = {
- {"service", service},
- {"scope", scope},
- };
-
- if (account.isSome()) {
- tokenUrl.query.insert({"account", account.get()});
- }
-
- return process::http::get(tokenUrl, None())
- .after(RESPONSE_TIMEOUT, [] (Future<Response> resp) -> Future<Response> {
- resp.discard();
- return Failure("Timeout waiting for response to token request");
- })
- .then(defer(self(), [this, tokenKey](
- const Future<Response>& response) -> Future<Token> {
- Try<Token> token = getTokenFromResponse(response.get());
- if (token.isError()) {
- return Failure(
- "Failed to parse JSON Web Token object from response: " +
- token.error());
- }
-
- tokenCache_.insert({tokenKey, token.get()});
-
- return token.get();
- }));
-}
-
-// TODO(jojy): Add implementation for basic authentication based getToken API.
-
-} // namespace registry {
-} // namespace docker {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/docker/token_manager.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/docker/token_manager.hpp b/src/slave/containerizer/provisioners/docker/token_manager.hpp
deleted file mode 100644
index 879269d..0000000
--- a/src/slave/containerizer/provisioners/docker/token_manager.hpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/**
- * 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 __PROVISIONERS_DOCKER_TOKEN_MANAGER_HPP__
-#define __PROVISIONERS_DOCKER_TOKEN_MANAGER_HPP__
-
-#include <functional>
-#include <string>
-
-#include <stout/base64.hpp>
-#include <stout/duration.hpp>
-#include <stout/hashmap.hpp>
-#include <stout/strings.hpp>
-
-#include <process/future.hpp>
-#include <process/http.hpp>
-#include <process/process.hpp>
-#include <process/time.hpp>
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace docker {
-namespace registry {
-
-
-/**
- * Encapsulates JSON Web Token.
- *
- * Reference: https://tools.ietf.org/html/rfc7519.
- */
-struct Token
-{
- /**
- * Factory method for Token object.
- *
- * Parses the raw token string and validates for token's expiration.
- *
- * @returns Token if parsing and validation succeeds.
- * Error if parsing or validation fails.
- */
- static Try<Token> create(const std::string& rawString);
-
- /**
- * Compares token's expiration time(expressed in seconds) with current time.
- *
- * @returns True if token's expiration time is greater than current time.
- * False if token's expiration time is less than or equal to current
- * time.
- */
- bool isExpired() const;
-
- /**
- * Validates the token if its "exp" "nbf" values are in range.
- *
- * @returns True if current time is within token's "exp" and "nbf" values.
- * False if current time is not within token's "exp" and "nbf"
- * values.
- */
- bool isValid() const;
-
- const std::string raw;
- const JSON::Object header;
- const JSON::Object claims;
- // TODO(jojy): Add signature information.
-
-private:
- Token(
- const std::string& raw,
- const JSON::Object& headerJson,
- const JSON::Object& claimsJson,
- const Option<process::Time>& expireTime,
- const Option<process::Time>& notBeforeTime);
-
- static Result<process::Time> getTimeValue(
- const JSON::Object& object,
- const std::string& key);
-
- const Option<process::Time> expiration;
- const Option<process::Time> notBefore;
-};
-
-
-// Forward declaration.
-class TokenManagerProcess;
-
-
-/**
- * Acquires and manages docker registry tokens. It keeps the tokens in its
- * cache to server any future request for the same token.
- * The cache grows unbounded.
- * TODO(jojy): The cache can be optimized to prune based on the expiry time of
- * the token and server's issue time.
- */
-class TokenManager
-{
-public:
- /**
- * Factory method for creating TokenManager object.
- *
- * TokenManager and registry authorization realm has a 1:1 relationship.
- *
- * @param realm URL of the authorization server from where token will be
- * requested by this TokenManager.
- * @returns Owned<TokenManager> if success.
- * Error on failure.
- */
- static Try<process::Owned<TokenManager>> create(
- const process::http::URL& realm);
-
- /**
- * Returns JSON Web Token from cache or from remote server using "Basic
- * authorization".
- *
- * @param service Name of the service that hosts the resource for which
- * token is being requested.
- * @param scope unique scope returned by the 401 Unauthorized response
- * from the registry.
- * @param account Name of the account which the client is acting as.
- * @param user base64 encoded userid for basic authorization.
- * @param password base64 encoded password for basic authorization.
- * @returns Token struct that encapsulates JSON Web Token.
- */
- process::Future<Token> getToken(
- const std::string& service,
- const std::string& scope,
- const Option<std::string>& account,
- const std::string& user,
- const Option<std::string>& password);
-
- /**
- * Returns JSON Web Token from cache or from remote server using "TLS/Cert"
- * based authorization.
- *
- * @param service Name of the service that hosts the resource for which
- * token is being requested.
- * @param scope unique scope returned by the 401 Unauthorized response
- * from the registry.
- * @param account Name of the account which the client is acting as.
- * @returns Token struct that encapsulates JSON Web Token.
- */
- process::Future<Token> getToken(
- const std::string& service,
- const std::string& scope,
- const Option<std::string>& account);
-
- ~TokenManager();
-
-private:
- TokenManager(process::Owned<TokenManagerProcess>& process);
-
- TokenManager(const TokenManager&) = delete;
- TokenManager& operator=(const TokenManager&) = delete;
-
- process::Owned<TokenManagerProcess> process_;
-};
-
-} // namespace registry {
-} // namespace docker {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __PROVISIONERS_DOCKER_TOKEN_MANAGER_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/paths.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/paths.cpp b/src/slave/containerizer/provisioners/paths.cpp
deleted file mode 100644
index 4293dd2..0000000
--- a/src/slave/containerizer/provisioners/paths.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-/**
- * 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 <list>
-
-#include <glog/logging.h>
-
-#include <mesos/type_utils.hpp>
-
-#include <stout/os.hpp>
-#include <stout/path.hpp>
-
-#include <stout/os/stat.hpp>
-
-#include "slave/containerizer/provisioners/paths.hpp"
-#include "slave/paths.hpp"
-
-using std::list;
-using std::string;
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace provisioners {
-namespace paths {
-
-static string getContainersDir(const string& provisionerDir)
-{
- return path::join(provisionerDir, "containers");
-}
-
-
-static string getBackendsDir(const string& containerDir)
-{
- return path::join(containerDir, "backends");
-}
-
-
-static string getBackendDir(const string& backendsDir, const string& backend)
-{
- return path::join(backendsDir, backend);
-}
-
-
-static string getRootfsesDir(const string& backendDir)
-{
- return path::join(backendDir, "rootfses");
-}
-
-
-static string getRootfsDir(const string& rootfsesDir, const string& roofsId)
-{
- return path::join(rootfsesDir, roofsId);
-}
-
-
-string getContainerDir(
- const string& provisionerDir,
- const ContainerID& containerId)
-{
- return path::join(getContainersDir(provisionerDir), containerId.value());
-}
-
-
-string getContainerRootfsDir(
- const string& provisionerDir,
- const ContainerID& containerId,
- const string& backend,
- const string& rootfsId)
-{
- return getRootfsDir(
- getRootfsesDir(
- getBackendDir(
- getBackendsDir(
- getContainerDir(
- provisionerDir,
- containerId)),
- backend)),
- rootfsId);
-}
-
-
-Try<hashmap<ContainerID, string>> listContainers(
- const string& provisionerDir)
-{
- hashmap<ContainerID, string> results;
-
- string containersDir = getContainersDir(provisionerDir);
- if (!os::exists(containersDir)) {
- // No container has been created yet.
- return results;
- }
-
- Try<list<string>> containerIds = os::ls(containersDir);
- if (containerIds.isError()) {
- return Error("Unable to list the containers directory: " +
- containerIds.error());
- }
-
- foreach (const string& entry, containerIds.get()) {
- string containerPath = path::join(containersDir, entry);
-
- if (!os::stat::isdir(containerPath)) {
- LOG(WARNING) << "Ignoring unexpected container entry at: "
- << containerPath;
- continue;
- }
-
- ContainerID containerId;
- containerId.set_value(entry);
- results.put(containerId, containerPath);
- }
-
- return results;
-}
-
-
-Try<hashmap<string, hashmap<string, string>>> listContainerRootfses(
- const string& provisionerDir,
- const ContainerID& containerId)
-{
- hashmap<string, hashmap<string, string>> results;
-
- string backendsDir = getBackendsDir(
- getContainerDir(
- provisionerDir,
- containerId));
-
- Try<list<string>> backends = os::ls(backendsDir);
- if (backends.isError()) {
- return Error("Unable to list the container directory: " + backends.error());
- }
-
- foreach (const string& backend, backends.get()) {
- string backendDir = getBackendDir(backendsDir, backend);
- if (!os::stat::isdir(backendDir)) {
- LOG(WARNING) << "Ignoring unexpected backend entry at: " << backendDir;
- continue;
- }
-
- Try<list<string>> rootfses = os::ls(getRootfsesDir(backendDir));
- if (rootfses.isError()) {
- return Error("Unable to list the backend directory: " + rootfses.error());
- }
-
- hashmap<string, string> backendResults;
-
- foreach (const string& rootfsId, rootfses.get()) {
- string rootfs = getRootfsDir(getRootfsesDir(backendDir), rootfsId);
-
- if (!os::stat::isdir(rootfs)) {
- LOG(WARNING) << "Ignoring unexpected rootfs entry at: " << backendDir;
- continue;
- }
-
- backendResults.put(rootfsId, rootfs);
- }
-
- if (backendResults.empty()) {
- LOG(WARNING) << "Ignoring a backend directory with no rootfs in it: "
- << backendDir;
- continue;
- }
-
- // The rootfs directory has passed validation.
- results.put(backend, backendResults);
- }
-
- return results;
-}
-
-} // namespace paths {
-} // namespace provisioners {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/cc1f8f54/src/slave/containerizer/provisioners/paths.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/provisioners/paths.hpp b/src/slave/containerizer/provisioners/paths.hpp
deleted file mode 100644
index 5b82591..0000000
--- a/src/slave/containerizer/provisioners/paths.hpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * 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_PROVISIONERS_PATHS_HPP__
-#define __MESOS_PROVISIONERS_PATHS_HPP__
-
-#include <string>
-
-#include <mesos/mesos.hpp>
-
-#include <stout/hashmap.hpp>
-#include <stout/try.hpp>
-
-namespace mesos {
-namespace internal {
-namespace slave {
-namespace provisioners {
-namespace paths {
-
-// The provisioner rootfs directory is as follows:
-// <work_dir> ('--work_dir' flag)
-// |-- provisioners
-// |-- <provisioner_type> (APPC, DOCKER, etc.)
-// |-- containers
-// |-- <container_id>
-// |-- backends
-// |-- <backend> (copy, bind, etc.)
-// |-- rootfses
-// |-- <rootfs_id> (the rootfs)
-//
-// NOTE: Each container could have multiple image types, therefore there
-// can be the same <container_id> directory under other provisioners e.g.,
-// <work_dir>/provisioners/DOCKER, <work_dir>/provisioners/APPC, etc.
-// Under each provisioner + container there can be multiple backends
-// due to the change of backend flags. Under each backend a rootfs is
-// identified by the 'rootfs_id' which is a UUID.
-
-std::string getContainerDir(
- const std::string& provisionerDir,
- const ContainerID& containerId);
-
-
-std::string getContainerRootfsDir(
- const std::string& provisionerDir,
- const ContainerID& containerId,
- const std::string& backend,
- const std::string& rootfsId);
-
-
-// Recursively "ls" the container directory and return a map of
-// backend -> rootfsId -> rootfsPath.
-Try<hashmap<std::string, hashmap<std::string, std::string>>>
-listContainerRootfses(
- const std::string& provisionerDir,
- const ContainerID& containerId);
-
-
-// Return a map of containerId -> containerPath;
-Try<hashmap<ContainerID, std::string>> listContainers(
- const std::string& provisionerDir);
-
-} // namespace paths {
-} // namespace provisioners {
-} // namespace slave {
-} // namespace internal {
-} // namespace mesos {
-
-#endif // __MESOS_PROVISIONERS_PATHS__