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 2016/04/24 19:27:33 UTC
mesos git commit: Implemented prepare() for volume isolator.
Repository: mesos
Updated Branches:
refs/heads/master 3d2d3edb9 -> e8e65535c
Implemented prepare() for volume isolator.
Review: https://reviews.apache.org/r/45370/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/e8e65535
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/e8e65535
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/e8e65535
Branch: refs/heads/master
Commit: e8e65535c8ee105e262662fde95aef2d93b289a5
Parents: 3d2d3ed
Author: Guangya Liu <gy...@gmail.com>
Authored: Sat Apr 23 22:30:23 2016 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Sun Apr 24 10:17:33 2016 -0700
----------------------------------------------------------------------
.../mesos/isolators/docker/volume/isolator.cpp | 192 ++++++++++++++++++-
.../mesos/isolators/docker/volume/isolator.hpp | 24 +++
.../mesos/isolators/docker/volume/state.hpp | 36 ++++
3 files changed, 250 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/e8e65535/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp b/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
index 915e5ae..7c147cf 100644
--- a/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
+++ b/src/slave/containerizer/mesos/isolators/docker/volume/isolator.cpp
@@ -14,11 +14,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <list>
+#include <process/collect.hpp>
#include <stout/os.hpp>
#include "slave/flags.hpp"
+#include "slave/state.hpp"
#include "slave/containerizer/mesos/isolators/docker/volume/isolator.hpp"
@@ -26,6 +27,7 @@ namespace paths = mesos::internal::slave::docker::volume::paths;
using std::list;
using std::string;
+using std::vector;
using process::Failure;
using process::Future;
@@ -121,7 +123,193 @@ Future<Option<ContainerLaunchInfo>> DockerVolumeIsolatorProcess::prepare(
const ContainerID& containerId,
const ContainerConfig& containerConfig)
{
- return None();
+ const ExecutorInfo& executorInfo = containerConfig.executor_info();
+
+ if (!executorInfo.has_container()) {
+ return None();
+ }
+
+ if (executorInfo.container().type() != ContainerInfo::MESOS) {
+ return Failure(
+ "Can only prepare docker volume driver for a MESOS container");
+ }
+
+ // The hashset is used to check if there are duplicated docker
+ // volume for the same container.
+ hashset<DockerVolume> volumes;
+
+ // Represents mounts that will be sent to the driver client.
+ struct Mount
+ {
+ DockerVolume volume;
+ hashmap<string, string> options;
+ };
+
+ vector<Mount> mounts;
+
+ // The mount points in the container.
+ vector<string> targets;
+
+ foreach (const Volume& _volume, executorInfo.container().volumes()) {
+ if (!_volume.has_source()) {
+ continue;
+ }
+
+ if (_volume.source().type() != Volume::Source::DOCKER_VOLUME) {
+ VLOG(1) << "Ignored volume type '" << _volume.source().type()
+ << "' for container " << containerId << " as only "
+ << "'DOCKER_VOLUME' was supported by the docker "
+ << "volume isolator";
+ continue;
+ }
+
+ const string driver = _volume.source().docker_volume().driver();
+ const string name = _volume.source().docker_volume().name();
+
+ DockerVolume volume;
+ volume.set_driver(driver);
+ volume.set_name(name);
+
+ if (volumes.contains(volume)) {
+ return Failure(
+ "Found duplicate docker volume with driver '" +
+ driver + "' and name '" + name + "'");
+ }
+
+ // Determine driver options.
+ hashmap<string, string> options;
+ if (_volume.source().docker_volume().has_driver_options()) {
+ foreach (const Parameter& parameter,
+ _volume.source().docker_volume().driver_options().parameter()) {
+ options[parameter.key()] = parameter.value();
+ }
+ }
+
+ // Determine the mount point.
+ string target;
+
+ if (containerConfig.has_rootfs()) {
+ target = path::join(
+ containerConfig.rootfs(),
+ _volume.container_path());
+ } else {
+ target = path::join(
+ containerConfig.directory(),
+ _volume.container_path());
+ }
+
+ Mount mount;
+ mount.volume = volume;
+ mount.options = options;
+
+ volumes.insert(volume);
+ mounts.push_back(mount);
+ targets.push_back(target);
+ }
+
+ // Create the container directory.
+ const string containerDir =
+ paths::getContainerDir(rootDir, containerId.value());
+
+ Try<Nothing> mkdir = os::mkdir(containerDir);
+ if (mkdir.isError()) {
+ return Failure(
+ "Failed to create the container directory at '" +
+ containerDir + "': " + mkdir.error());
+ }
+
+ // Create DockerVolumes protobuf message to checkpoint.
+ DockerVolumes state;
+ foreach (const DockerVolume& volume, volumes) {
+ state.add_volumes()->CopyFrom(volume);
+ }
+
+ const string volumesPath =
+ paths::getVolumesPath(rootDir, containerId.value());
+
+ Try<Nothing> checkpoint = state::checkpoint(
+ volumesPath,
+ stringify(JSON::protobuf(state)));
+
+ if (checkpoint.isError()) {
+ return Failure(
+ "Failed to checkpoint docker volumes at '" +
+ volumesPath + "': " + checkpoint.error());
+ }
+
+ VLOG(1) << "Successfully created checkpoint at '" << volumesPath << "'";
+
+ infos.put(containerId, Owned<Info>(new Info(volumes)));
+
+ // Invoke driver client to create the mount.
+ list<Future<string>> futures;
+ foreach (const Mount& mount, mounts) {
+ futures.push_back(client->mount(
+ mount.volume.driver(),
+ mount.volume.name(),
+ mount.options));
+ }
+
+ // NOTE: Wait for all `mount()` to finish before returning to make
+ // sure `unmount()` is not called (via 'cleanup()') if some mount on
+ // is still pending.
+ return await(futures)
+ .then(defer(
+ PID<DockerVolumeIsolatorProcess>(this),
+ &DockerVolumeIsolatorProcess::_prepare,
+ containerId,
+ targets,
+ lambda::_1));
+}
+
+
+Future<Option<ContainerLaunchInfo>> DockerVolumeIsolatorProcess::_prepare(
+ const ContainerID& containerId,
+ const vector<string>& targets,
+ const list<Future<string>>& futures)
+{
+ ContainerLaunchInfo launchInfo;
+ launchInfo.set_namespaces(CLONE_NEWNS);
+
+ vector<string> messages;
+ vector<string> sources;
+ foreach (const Future<string>& future, futures) {
+ if (!future.isReady()) {
+ messages.push_back(future.isFailed() ? future.failure() : "discarded");
+ continue;
+ }
+
+ sources.push_back(strings::trim(future.get()));
+ }
+
+ if (!messages.empty()) {
+ return Failure(strings::join("\n", messages));
+ }
+
+ CHECK_EQ(sources.size(), targets.size());
+
+ for (size_t i = 0; i < sources.size(); i++) {
+ const string source = sources[i];
+ const string target = targets[i];
+
+ VLOG(1) << "Mounting docker volume mount point '" << source
+ << "' to '" << target << "' for container '"
+ << containerId << "'";
+
+ // Create the mount point if it does not exist.
+ Try<Nothing> mkdir = os::mkdir(target);
+ if (mkdir.isError()) {
+ return Failure(
+ "Failed to create mount point at '" +
+ target + "': " + mkdir.error());
+ }
+
+ const string command = "mount -n --rbind " + source + " " + target;
+
+ launchInfo.add_commands()->set_value(command);
+ }
+
+ return launchInfo;
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/e8e65535/src/slave/containerizer/mesos/isolators/docker/volume/isolator.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/docker/volume/isolator.hpp b/src/slave/containerizer/mesos/isolators/docker/volume/isolator.hpp
index bedc687..02e1cff 100644
--- a/src/slave/containerizer/mesos/isolators/docker/volume/isolator.hpp
+++ b/src/slave/containerizer/mesos/isolators/docker/volume/isolator.hpp
@@ -17,10 +17,19 @@
#ifndef __DOCKER_VOLUME_ISOLATOR_HPP__
#define __DOCKER_VOLUME_ISOLATOR_HPP__
+#include <list>
+#include <string>
+#include <vector>
+
+#include <process/owned.hpp>
+
+#include <stout/hashmap.hpp>
+
#include "slave/containerizer/mesos/isolator.hpp"
#include "slave/containerizer/mesos/isolators/docker/volume/driver.hpp"
#include "slave/containerizer/mesos/isolators/docker/volume/paths.hpp"
+#include "slave/containerizer/mesos/isolators/docker/volume/state.hpp"
namespace mesos {
namespace internal {
@@ -61,14 +70,29 @@ public:
const ContainerID& containerId);
private:
+ struct Info
+ {
+ Info (const hashset<DockerVolume>& _volumes)
+ : volumes(_volumes) {}
+
+ hashset<DockerVolume> volumes;
+ };
+
DockerVolumeIsolatorProcess(
const Flags& flags,
const std::string& rootDir,
const process::Owned<docker::volume::DriverClient>& client);
+ process::Future<Option<mesos::slave::ContainerLaunchInfo>> _prepare(
+ const ContainerID& containerId,
+ const std::vector<std::string>& targets,
+ const std::list<process::Future<std::string>>& futures);
+
const Flags flags;
const std::string rootDir;
const process::Owned<docker::volume::DriverClient> client;
+
+ hashmap<ContainerID, process::Owned<Info>> infos;
};
} // namespace slave {
http://git-wip-us.apache.org/repos/asf/mesos/blob/e8e65535/src/slave/containerizer/mesos/isolators/docker/volume/state.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/docker/volume/state.hpp b/src/slave/containerizer/mesos/isolators/docker/volume/state.hpp
index bc0c329..8e5f1aa 100644
--- a/src/slave/containerizer/mesos/isolators/docker/volume/state.hpp
+++ b/src/slave/containerizer/mesos/isolators/docker/volume/state.hpp
@@ -17,7 +17,43 @@
#ifndef __ISOLATOR_DOCKER_VOLUME_STATE_HPP__
#define __ISOLATOR_DOCKER_VOLUME_STATE_HPP__
+#include <boost/functional/hash.hpp>
+
// ONLY USEFUL AFTER RUNNING PROTOC.
#include "slave/containerizer/mesos/isolators/docker/volume/state.pb.h"
+namespace mesos {
+namespace internal {
+namespace slave {
+
+inline bool operator==(const DockerVolume& left, const DockerVolume& right)
+{
+ return (left.driver() == right.driver()) && (left.name() == right.name());
+}
+
+} // namespace slave {
+} // namespace internal {
+} // namespace mesos {
+
+
+namespace std {
+
+template <>
+struct hash<mesos::internal::slave::DockerVolume>
+{
+ typedef size_t result_type;
+
+ typedef mesos::internal::slave::DockerVolume argument_type;
+
+ result_type operator()(const argument_type& volume) const
+ {
+ size_t seed = 0;
+ boost::hash_combine(seed, std::hash<std::string>()(volume.driver()));
+ boost::hash_combine(seed, std::hash<std::string>()(volume.name()));
+ return seed;
+ }
+};
+
+} // namespace std {
+
#endif // __ISOLATOR_DOCKER_VOLUME_STATE_HPP__