Repository: mesos Updated Branches: refs/heads/master a7de6513c -> 65e1712bc
Add support for container image provisioners. Review: https://reviews.apache.org/r/34137/ Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/65e1712b Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/65e1712b Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/65e1712b Branch: refs/heads/master Commit: 65e1712bc84f10d1c6b693998013ec248b12dd4e Parents: a7de651 Author: Ian Downes <[email protected]> Authored: Thu Jul 16 16:54:02 2015 -0700 Committer: Jie Yu <[email protected]> Committed: Tue Jul 21 11:17:35 2015 -0700 ---------------------------------------------------------------------- include/mesos/slave/isolator.hpp | 17 +- src/Makefile.am | 2 + src/slave/containerizer/mesos/containerizer.cpp | 196 +++++++++++++++++-- src/slave/containerizer/mesos/containerizer.hpp | 42 +++- src/slave/containerizer/provisioner.cpp | 36 ++++ src/slave/containerizer/provisioner.hpp | 76 +++++++ src/slave/flags.cpp | 5 + src/slave/flags.hpp | 1 + src/slave/paths.cpp | 19 ++ src/slave/paths.hpp | 8 + src/slave/state.cpp | 24 +++ src/slave/state.hpp | 1 + src/tests/containerizer_tests.cpp | 28 ++- 13 files changed, 430 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/include/mesos/slave/isolator.hpp ---------------------------------------------------------------------- diff --git a/include/mesos/slave/isolator.hpp b/include/mesos/slave/isolator.hpp index ef2205d..85e38f5 100644 --- a/include/mesos/slave/isolator.hpp +++ b/include/mesos/slave/isolator.hpp @@ -67,12 +67,23 @@ struct Limitation // any dependency on RunState and in turn on internal protobufs. struct ExecutorRunState { - ExecutorRunState(ContainerID id_, pid_t pid_, std::string directory_) - : id(id_), pid(pid_), directory(directory_) {} - + ExecutorRunState( + const ExecutorInfo& executorInfo_, + const ContainerID& id_, + pid_t pid_, + const std::string& directory_, + const Option<std::string>& rootfs_) + : executorInfo(executorInfo_), + id(id_), + pid(pid_), + directory(directory_), + rootfs(rootfs_) {} + + ExecutorInfo executorInfo; ContainerID id; // Container id of the last executor run. pid_t pid; // Executor pid. std::string directory; // Executor work directory. + Option<std::string> rootfs; // Optional container rootfs. }; http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/Makefile.am ---------------------------------------------------------------------- diff --git a/src/Makefile.am b/src/Makefile.am index e2cbd15..d99f940 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -407,6 +407,7 @@ libmesos_no_3rdparty_la_SOURCES = \ slave/containerizer/launcher.cpp \ slave/containerizer/mesos/containerizer.cpp \ slave/containerizer/mesos/launch.cpp \ + slave/containerizer/provisioner.cpp \ slave/resource_estimators/noop.cpp \ usage/usage.cpp \ watcher/whitelist_watcher.cpp \ @@ -640,6 +641,7 @@ libmesos_no_3rdparty_la_SOURCES += \ slave/containerizer/isolators/cgroups/perf_event.hpp \ slave/containerizer/isolators/namespaces/pid.hpp \ slave/containerizer/isolators/filesystem/shared.hpp \ + slave/containerizer/provisioner.hpp \ slave/resource_estimators/noop.hpp \ tests/cluster.hpp \ tests/containerizer.hpp \ http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/slave/containerizer/mesos/containerizer.cpp ---------------------------------------------------------------------- diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp index 47d1461..d3a596d 100644 --- a/src/slave/containerizer/mesos/containerizer.cpp +++ b/src/slave/containerizer/mesos/containerizer.cpp @@ -178,8 +178,20 @@ Try<MesosContainerizer*> MesosContainerizer::create( return Error("Failed to create launcher: " + launcher.error()); } + Try<hashmap<ContainerInfo::Image::Type, Owned<Provisioner>>> provisioners = + Provisioner::create(flags, fetcher); + + if (provisioners.isError()) { + return Error("Failed to create provisioner(s): " + provisioners.error()); + } + return new MesosContainerizer( - flags_, local, fetcher, Owned<Launcher>(launcher.get()), isolators); + flags_, + local, + fetcher, + Owned<Launcher>(launcher.get()), + isolators, + provisioners.get()); } @@ -188,13 +200,15 @@ MesosContainerizer::MesosContainerizer( bool local, Fetcher* fetcher, const Owned<Launcher>& launcher, - const vector<Owned<Isolator>>& isolators) + const vector<Owned<Isolator>>& isolators, + const hashmap<ContainerInfo::Image::Type, Owned<Provisioner>>& provisioners) : process(new MesosContainerizerProcess( flags, local, fetcher, launcher, - isolators)) + isolators, + provisioners)) { spawn(process.get()); } @@ -385,9 +399,11 @@ Future<Nothing> MesosContainerizerProcess::recover( CHECK(os::exists(directory)); ExecutorRunState executorRunState( + executorInfo, run.get().id.get(), run.get().forkedPid.get(), - directory); + directory, + run.get().rootfs); recoverable.push_back(executorRunState); } @@ -404,13 +420,19 @@ Future<Nothing> MesosContainerizerProcess::_recover( const list<ExecutorRunState>& recoverable, const hashset<ContainerID>& orphans) { - // Then recover the isolators. list<Future<Nothing>> futures; + + // Then recover the provisioners. + foreachvalue (const Owned<Provisioner>& provisioner, provisioners) { + futures.push_back(provisioner->recover(recoverable, orphans)); + } + + // Then recover the isolators. foreach (const Owned<Isolator>& isolator, isolators) { futures.push_back(isolator->recover(recoverable, orphans)); } - // If all isolators recover then continue. + // If all provisioners and isolators recover then continue. return collect(futures) .then(defer(self(), &Self::__recover, recoverable, orphans)); } @@ -431,11 +453,15 @@ Future<Nothing> MesosContainerizerProcess::__recover( container->directory = run.directory; + container->rootfs = run.rootfs; + // We only checkpoint the containerizer pid after the container // successfully launched, therefore we can assume checkpointed // containers should be running after recover. container->state = RUNNING; + container->executorInfo = run.executorInfo; + containers_[containerId] = Owned<Container>(container); foreach (const Owned<Isolator>& isolator, isolators) { @@ -536,6 +562,7 @@ Future<bool> MesosContainerizerProcess::launch( << "' of framework '" << executorInfo.framework_id() << "'"; Container* container = new Container(); + container->executorInfo = executorInfo; container->directory = directory; container->state = PREPARING; containers_[containerId] = Owned<Container>(container); @@ -556,7 +583,13 @@ Future<bool> MesosContainerizerProcess::launch( // container resources. container->resources = executorInfo.resources(); - return prepare(containerId, executorInfo, directory, user) + return provision(containerId, executorInfo, slaveId, directory, checkpoint) + .then(defer(self(), + &Self::prepare, + containerId, + executorInfo, + directory, + user)) .then(defer(self(), &Self::_launch, containerId, @@ -570,6 +603,83 @@ Future<bool> MesosContainerizerProcess::launch( } +Future<Nothing> MesosContainerizerProcess::provision( + const ContainerID& containerId, + const ExecutorInfo& executorInfo, + const SlaveID& slaveId, + const string& directory, + bool checkpoint) +{ + if (!executorInfo.has_container()) { + // TODO(idownes): Consider refusing to run a container if the + // containerizer is configured with an image provisioner but the + // executor doesn't specify an image. + return Nothing(); + } + + if (executorInfo.container().type() != ContainerInfo::MESOS) { + return Failure("Mesos containerizer can only provision Mesos containers"); + } + + if (!executorInfo.container().mesos().has_image()) { + // No image to provision. + return Nothing(); + } + + ContainerInfo::Image image = executorInfo.container().mesos().image(); + + if (!provisioners.contains(image.type())) { + return Failure("ExecutorInfo specifies container image type '" + + stringify(image.type()) + + "' but no suitable provisioner available"); + } + + return provisioners[image.type()]->provision(containerId, image) + .then(defer(self(), + &Self::_provision, + containerId, + executorInfo, + slaveId, + checkpoint, + lambda::_1)); +} + + +Future<Nothing> MesosContainerizerProcess::_provision( + const ContainerID& containerId, + const ExecutorInfo& executorInfo, + const SlaveID& slaveId, + bool checkpoint, + const string& rootfs) +{ + if (!containers_.contains(containerId)) { + return Failure("Container is already destroyed"); + } + + containers_[containerId]->rootfs = rootfs; + + if (checkpoint) { + const string path = slave::paths::getContainerRootfsPath( + slave::paths::getMetaRootDir(flags.work_dir), + slaveId, + executorInfo.framework_id(), + executorInfo.executor_id(), + containerId); + + LOG(INFO) << "Checkpointing container " << containerId << " rootfs path '" + << rootfs << "' to '" << path << "'"; + + Try<Nothing> checkpointed = slave::state::checkpoint(path, rootfs); + if (checkpointed.isError()) { + return Failure("Failed to checkpoint container rootfs path to '" + + path + "': " + checkpointed.error()); + } + } + + return Nothing(); +} + + Future<bool> MesosContainerizerProcess::launch( const ContainerID& containerId, const TaskInfo& taskInfo, @@ -694,7 +804,9 @@ Future<bool> MesosContainerizerProcess::_launch( // Prepare environment variables for the executor. map<string, string> environment = executorEnvironment( executorInfo, - directory, + containers_[containerId]->rootfs.isSome() + ? flags.sandbox_directory + : directory, slaveId, slavePid, checkpoint, @@ -717,7 +829,12 @@ Future<bool> MesosContainerizerProcess::_launch( MesosContainerizerLaunch::Flags launchFlags; launchFlags.command = JSON::Protobuf(executorInfo.command()); - launchFlags.directory = directory; + + launchFlags.directory = containers_[containerId]->rootfs.isSome() + ? flags.sandbox_directory + : directory; + + launchFlags.rootfs = containers_[containerId]->rootfs; launchFlags.user = user; launchFlags.pipe_read = pipes[0]; launchFlags.pipe_write = pipes[1]; @@ -1131,9 +1248,9 @@ void MesosContainerizerProcess::____destroy( foreach (const Future<Nothing>& cleanup, cleanups.get()) { if (!cleanup.isReady()) { container->promise.fail( - "Failed to clean up an isolator when destroying container '" + - stringify(containerId) + "' :" + - (cleanup.isFailed() ? cleanup.failure() : "discarded future")); + "Failed to clean up an isolator when destroying container '" + + stringify(containerId) + "' :" + + (cleanup.isFailed() ? cleanup.failure() : "discarded future")); containers_.erase(containerId); @@ -1143,6 +1260,61 @@ void MesosContainerizerProcess::____destroy( } } + if (container->rootfs.isNone()) { + // No rootfs to clean up so continue. + _____destroy(containerId, status, message, killed, Nothing()); + return; + } + + ContainerInfo::Image::Type type = + container->executorInfo.container().mesos().image().type(); + + if (!provisioners.contains(type)) { + // We should have a provisioner to handle cleaning up the rootfs + // but continue clean up even if we don't. + LOG(WARNING) << "No provisioner to clean up rootfs for container " + << containerId << " (type '" << type << "'), continuing"; + + _____destroy(containerId, status, message, killed, Nothing()); + return; + } + + provisioners[type]->destroy(containerId) + .onAny(defer(self(), + &Self::_____destroy, + containerId, + status, + message, + killed, + lambda::_1)); + + return; +} + + +void MesosContainerizerProcess::_____destroy( + const ContainerID& containerId, + const Future<Option<int>>& status, + Option<string> message, + bool killed, + const Future<Nothing>& future) +{ + CHECK(containers_.contains(containerId)); + + Container* container = containers_[containerId].get(); + + if (!future.isReady()) { + container->promise.fail( + "Failed to clean up the root filesystem when destroying container: " + + (future.isFailed() ? future.failure() : "discarded future")); + + containers_.erase(containerId); + + ++metrics.container_destroy_errors; + + return; + } + // If any isolator limited the container then we mark it to killed. // Note: We may not see a limitation in time for it to be // registered. This could occur if the limitation (e.g., an OOM) http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/slave/containerizer/mesos/containerizer.hpp ---------------------------------------------------------------------- diff --git a/src/slave/containerizer/mesos/containerizer.hpp b/src/slave/containerizer/mesos/containerizer.hpp index 3ac2387..a8c71d6 100644 --- a/src/slave/containerizer/mesos/containerizer.hpp +++ b/src/slave/containerizer/mesos/containerizer.hpp @@ -33,6 +33,7 @@ #include "slave/containerizer/containerizer.hpp" #include "slave/containerizer/launcher.hpp" +#include "slave/containerizer/provisioner.hpp" namespace mesos { namespace internal { @@ -56,7 +57,10 @@ public: bool local, Fetcher* fetcher, const process::Owned<Launcher>& launcher, - const std::vector<process::Owned<mesos::slave::Isolator>>& isolators); + const std::vector<process::Owned<mesos::slave::Isolator>>& isolators, + const hashmap<ContainerInfo::Image::Type, + process::Owned<Provisioner>>& provisioners); + // Used for testing. MesosContainerizer(const process::Owned<MesosContainerizerProcess>& _process); @@ -113,12 +117,15 @@ public: bool _local, Fetcher* _fetcher, const process::Owned<Launcher>& _launcher, - const std::vector<process::Owned<mesos::slave::Isolator>>& _isolators) + const std::vector<process::Owned<mesos::slave::Isolator>>& _isolators, + const hashmap<ContainerInfo::Image::Type, + process::Owned<Provisioner>>& _provisioners) : flags(_flags), local(_local), fetcher(_fetcher), launcher(_launcher), - isolators(_isolators) {} + isolators(_isolators), + provisioners(_provisioners) {} virtual ~MesosContainerizerProcess() {} @@ -176,6 +183,20 @@ private: const std::list<mesos::slave::ExecutorRunState>& recovered, const hashset<ContainerID>& orphans); + process::Future<Nothing> provision( + const ContainerID& containerId, + const ExecutorInfo& executorInfo, + const SlaveID& slaveId, + const std::string& directory, + bool checkpoint); + + process::Future<Nothing> _provision( + const ContainerID& containerId, + const ExecutorInfo& executorInfo, + const SlaveID& slaveId, + bool checkpoint, + const std::string& rootfs); + process::Future<std::list<Option<CommandInfo>>> prepare( const ContainerID& containerId, const ExecutorInfo& executorInfo, @@ -219,7 +240,7 @@ private: const Option<std::string>& message, bool killed); - // Continues (and completes) '__destroy()' once all isolators have completed + // Continues '__destroy()' once all isolators have completed // cleanup. void ____destroy( const ContainerID& containerId, @@ -228,6 +249,15 @@ private: Option<std::string> message, bool killed); + // Continues (and completes) '__destroy()' once any root filessystem + // has been cleaned up. + void _____destroy( + const ContainerID& containerId, + const process::Future<Option<int>>& status, + Option<std::string> message, + bool killed, + const process::Future<Nothing>& cleanup); + // Call back for when an isolator limits a container and impacts the // processes. This will trigger container destruction. void limited( @@ -254,6 +284,7 @@ private: Fetcher* fetcher; const process::Owned<Launcher> launcher; const std::vector<process::Owned<mesos::slave::Isolator>> isolators; + hashmap<ContainerInfo::Image::Type, process::Owned<Provisioner>> provisioners; enum State { @@ -292,6 +323,9 @@ private: // ResourceStatistics limits in usage(). Resources resources; + // We keep track of the ExecutorInfo so we have the optional ContainerInfo. + ExecutorInfo executorInfo; + // The executor's working directory on the host. std::string directory; http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/slave/containerizer/provisioner.cpp ---------------------------------------------------------------------- diff --git a/src/slave/containerizer/provisioner.cpp b/src/slave/containerizer/provisioner.cpp new file mode 100644 index 0000000..df52e36 --- /dev/null +++ b/src/slave/containerizer/provisioner.cpp @@ -0,0 +1,36 @@ +/** + * 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 "slave/containerizer/provisioner.hpp" + +using namespace process; + +namespace mesos { +namespace internal { +namespace slave { + +Try<hashmap<ContainerInfo::Image::Type, Owned<Provisioner>>> + Provisioner::create(const Flags& flags, Fetcher* fetcher) +{ + // TODO(tnachen): Load provisioners when one of them is available. + return hashmap<ContainerInfo::Image::Type, Owned<Provisioner>>(); +} + +} // namespace slave { +} // namespace internal { +} // namespace mesos { http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/slave/containerizer/provisioner.hpp ---------------------------------------------------------------------- diff --git a/src/slave/containerizer/provisioner.hpp b/src/slave/containerizer/provisioner.hpp new file mode 100644 index 0000000..f7fb068 --- /dev/null +++ b/src/slave/containerizer/provisioner.hpp @@ -0,0 +1,76 @@ +/** + * 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_HPP__ +#define __MESOS_PROVISIONER_HPP__ + +#include <list> + +#include <mesos/resources.hpp> + +#include <mesos/slave/isolator.hpp> // For ExecutorRunState. + +#include <stout/hashmap.hpp> +#include <stout/nothing.hpp> +#include <stout/try.hpp> + +#include <process/future.hpp> +#include <process/owned.hpp> + +#include "slave/flags.hpp" + +#include "slave/containerizer/fetcher.hpp" + +namespace mesos { +namespace internal { +namespace slave { + +class Provisioner +{ +public: + virtual ~Provisioner() {} + + static Try<hashmap<ContainerInfo::Image::Type, process::Owned<Provisioner>>> + create(const Flags& flags, Fetcher* fetcher); + + // Recover root filesystems for containers from the run states and + // the orphan containers (known to the launcher but not known to the + // slave) detected by the launcher. This function is also + // responsible for cleaning up any intermediate artifacts (e.g. + // directories) to not leak anything. + virtual process::Future<Nothing> recover( + const std::list<mesos::slave::ExecutorRunState>& states, + const hashset<ContainerID>& orphans) = 0; + + // Provision a root filesystem for the container using the specified + // image and return the absolute path to the root filesystem. + virtual process::Future<std::string> provision( + const ContainerID& containerId, + const ContainerInfo::Image& image) = 0; + + // Destroy a previously provisioned root filesystem. Assumes that + // all references (e.g., mounts, open files) to the provisioned + // filesystem have been removed. + virtual process::Future<Nothing> destroy(const ContainerID& containerId) = 0; +}; + +} // namespace slave { +} // namespace internal { +} // namespace mesos { + +#endif // __MESOS_PROVISIONER_HPP__ http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/slave/flags.cpp ---------------------------------------------------------------------- diff --git a/src/slave/flags.cpp b/src/slave/flags.cpp index f569363..82b6cf4 100644 --- a/src/slave/flags.cpp +++ b/src/slave/flags.cpp @@ -59,6 +59,11 @@ mesos::internal::slave::Flags::Flags() "for the Mesos Containerizer.", "posix/cpu,posix/mem"); + add(&Flags::provisioners, + "provisioners", + "Comma separated list of image rootfs provisioners,\n" + "e.g., appc,docker"); + add(&Flags::default_role, "default_role", "Any resources in the --resources flag that\n" http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/slave/flags.hpp ---------------------------------------------------------------------- diff --git a/src/slave/flags.hpp b/src/slave/flags.hpp index bbc1b9e..881d494 100644 --- a/src/slave/flags.hpp +++ b/src/slave/flags.hpp @@ -46,6 +46,7 @@ public: Option<std::string> hostname; Option<std::string> resources; std::string isolation; + Option<std::string> provisioners; std::string default_role; Option<std::string> attributes; Bytes fetcher_cache_size; http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/slave/paths.cpp ---------------------------------------------------------------------- diff --git a/src/slave/paths.cpp b/src/slave/paths.cpp index 0741616..404c214 100644 --- a/src/slave/paths.cpp +++ b/src/slave/paths.cpp @@ -51,6 +51,7 @@ const char LIBPROCESS_PID_FILE[] = "libprocess.pid"; const char EXECUTOR_INFO_FILE[] = "executor.info"; const char EXECUTOR_SENTINEL_FILE[] = "executor.sentinel"; const char FORKED_PID_FILE[] = "forked.pid"; +const char CONTAINER_ROOTFS_FILE[] = "rootfs"; const char TASK_INFO_FILE[] = "task.info"; const char TASK_UPDATES_FILE[] = "task.updates"; const char RESOURCES_INFO_FILE[] = "resources.info"; @@ -268,6 +269,24 @@ string getForkedPidPath( } +string getContainerRootfsPath( + const string& rootDir, + const SlaveID& slaveId, + const FrameworkID& frameworkId, + const ExecutorID& executorId, + const ContainerID& containerId) +{ + return path::join( + getExecutorRunPath( + rootDir, + slaveId, + frameworkId, + executorId, + containerId), + CONTAINER_ROOTFS_FILE); +} + + Try<list<string>> getTaskPaths( const string& rootDir, const SlaveID& slaveId, http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/slave/paths.hpp ---------------------------------------------------------------------- diff --git a/src/slave/paths.hpp b/src/slave/paths.hpp index 00476f1..c7f85f1 100644 --- a/src/slave/paths.hpp +++ b/src/slave/paths.hpp @@ -204,6 +204,14 @@ std::string getForkedPidPath( const ContainerID& containerId); +std::string getContainerRootfsPath( + const std::string& rootDir, + const SlaveID& slaveId, + const FrameworkID& frameworkId, + const ExecutorID& executorId, + const ContainerID& containerId); + + Try<std::list<std::string>> getTaskPaths( const std::string& rootDir, const SlaveID& slaveId, http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/slave/state.cpp ---------------------------------------------------------------------- diff --git a/src/slave/state.cpp b/src/slave/state.cpp index f8a9514..b9f2d8a 100644 --- a/src/slave/state.cpp +++ b/src/slave/state.cpp @@ -534,6 +534,30 @@ Try<RunState> RunState::recover( state.libprocessPid = process::UPID(pid.get()); + // Read the location of the container's root filesystem, if used. + path = paths::getContainerRootfsPath( + rootDir, slaveId, frameworkId, executorId, containerId); + + // Because a container root filesystem is optional we'll recover the + // path if present but continue to recover normally if it's not. + if (os::exists(path)) { + Try<string> rootfs = os::read(path); + if (rootfs.isError()) { + message = "Failed to recover container rootfs from '" + path + + "': " + rootfs.error(); + + if (strict) { + return Error(message); + } else { + LOG(WARNING) << message; + state.errors++; + return state; + } + } + + state.rootfs = rootfs.get(); + } + return state; } http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/slave/state.hpp ---------------------------------------------------------------------- diff --git a/src/slave/state.hpp b/src/slave/state.hpp index bb0eee7..4e00468 100644 --- a/src/slave/state.hpp +++ b/src/slave/state.hpp @@ -208,6 +208,7 @@ struct RunState hashmap<TaskID, TaskState> tasks; Option<pid_t> forkedPid; Option<process::UPID> libprocessPid; + Option<std::string> rootfs; // Executor terminated and all its updates acknowledged. bool completed; http://git-wip-us.apache.org/repos/asf/mesos/blob/65e1712b/src/tests/containerizer_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/containerizer_tests.cpp b/src/tests/containerizer_tests.cpp index 0cdb2d2..29114e7 100644 --- a/src/tests/containerizer_tests.cpp +++ b/src/tests/containerizer_tests.cpp @@ -99,7 +99,8 @@ public: false, fetcher, Owned<Launcher>(launcher.get()), - isolators); + isolators, + hashmap<ContainerInfo::Image::Type, Owned<Provisioner>>()); } @@ -335,8 +336,16 @@ public: bool local, Fetcher* fetcher, const process::Owned<Launcher>& launcher, - const vector<process::Owned<Isolator>>& isolators) - : MesosContainerizerProcess(flags, local, fetcher, launcher, isolators) + const vector<process::Owned<Isolator>>& isolators, + const hashmap<ContainerInfo::Image::Type, + Owned<Provisioner>>& provisioners) + : MesosContainerizerProcess( + flags, + local, + fetcher, + launcher, + isolators, + provisioners) { // NOTE: See TestContainerizer::setup for why we use // 'EXPECT_CALL' and 'WillRepeatedly' here instead of @@ -445,7 +454,8 @@ TEST_F(MesosContainerizerDestroyTest, DestroyWhileFetching) true, &fetcher, Owned<Launcher>(launcher.get()), - isolators); + isolators, + hashmap<ContainerInfo::Image::Type, Owned<Provisioner>>()); Future<Nothing> exec; Promise<bool> promise; @@ -509,12 +519,15 @@ TEST_F(MesosContainerizerDestroyTest, DestroyWhilePreparing) Fetcher fetcher; + hashmap<ContainerInfo::Image::Type, Owned<Provisioner>> provisioners; + MockMesosContainerizerProcess* process = new MockMesosContainerizerProcess( flags, true, &fetcher, Owned<Launcher>(launcher.get()), - isolators); + isolators, + provisioners); MesosContainerizer containerizer((Owned<MesosContainerizerProcess>(process))); @@ -584,12 +597,15 @@ TEST_F(MesosContainerizerDestroyTest, LauncherDestroyFailure) vector<process::Owned<Isolator>> isolators; Fetcher fetcher; + hashmap<ContainerInfo::Image::Type, Owned<Provisioner>> provisioners; + MesosContainerizerProcess* process = new MesosContainerizerProcess( flags, true, &fetcher, Owned<Launcher>(launcher), - isolators); + isolators, + provisioners); MesosContainerizer containerizer((Owned<MesosContainerizerProcess>(process)));
