You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by tn...@apache.org on 2015/08/20 18:58:33 UTC
mesos git commit: Create pre-launch hook before a docker container
launches in slave.
Repository: mesos
Updated Branches:
refs/heads/master bd144fcc7 -> 21c547f50
Create pre-launch hook before a docker container launches in slave.
Review: https://reviews.apache.org/r/36185
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/21c547f5
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/21c547f5
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/21c547f5
Branch: refs/heads/master
Commit: 21c547f502ad397cc8c967e78353b14c6d6cb0d7
Parents: bd144fc
Author: haosdent huang <ha...@gmail.com>
Authored: Thu Aug 20 09:02:03 2015 -0700
Committer: Timothy Chen <tn...@gmail.com>
Committed: Thu Aug 20 09:02:03 2015 -0700
----------------------------------------------------------------------
include/mesos/hook.hpp | 21 ++
src/examples/test_hook_module.cpp | 20 ++
src/hook/manager.cpp | 32 +++
src/hook/manager.hpp | 11 +
src/slave/containerizer/docker.cpp | 33 ++-
src/slave/containerizer/docker.hpp | 14 +-
.../docker_containerizer_tests.cpp | 262 +-----------------
src/tests/hook_tests.cpp | 115 ++++++++
src/tests/mesos.hpp | 263 +++++++++++++++++++
9 files changed, 497 insertions(+), 274 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/21c547f5/include/mesos/hook.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/hook.hpp b/include/mesos/hook.hpp
index 6c3861b..d90bacc 100644
--- a/include/mesos/hook.hpp
+++ b/include/mesos/hook.hpp
@@ -19,7 +19,11 @@
#ifndef __MESOS_HOOK_HPP__
#define __MESOS_HOOK_HPP__
+#include <map>
+#include <string>
+
#include <mesos/mesos.hpp>
+#include <mesos/resources.hpp>
#include <stout/none.hpp>
#include <stout/nothing.hpp>
@@ -71,6 +75,23 @@ public:
return None();
}
+ // This hook is called from within slave before docker is launched.
+ // A typical module implementing the hook will perform some settings
+ // as required.
+ virtual Try<Nothing> slavePreLaunchDockerHook(
+ const ContainerInfo& containerInfo,
+ const CommandInfo& commandInfo,
+ const Option<TaskInfo>& taskInfo,
+ const ExecutorInfo& executorInfo,
+ const std::string& name,
+ const std::string& sandboxDirectory,
+ const std::string& mappedDirectory,
+ const Option<Resources>& resources,
+ const Option<std::map<std::string, std::string>>& env)
+ {
+ return Nothing();
+ }
+
// This hook is called from within slave when an executor is being
// removed. A typical module implementing the hook will perform some
// cleanup as required.
http://git-wip-us.apache.org/repos/asf/mesos/blob/21c547f5/src/examples/test_hook_module.cpp
----------------------------------------------------------------------
diff --git a/src/examples/test_hook_module.cpp b/src/examples/test_hook_module.cpp
index 2f0a1a0..bc13a8a 100644
--- a/src/examples/test_hook_module.cpp
+++ b/src/examples/test_hook_module.cpp
@@ -34,6 +34,9 @@
using namespace mesos;
+using std::map;
+using std::string;
+
using process::Future;
// Must be kept in sync with variables of the same name in
@@ -129,6 +132,23 @@ public:
return environment;
}
+
+ virtual Try<Nothing> slavePreLaunchDockerHook(
+ const ContainerInfo& containerInfo,
+ const CommandInfo& commandInfo,
+ const Option<TaskInfo>& taskInfo,
+ const ExecutorInfo& executorInfo,
+ const string& name,
+ const string& sandboxDirectory,
+ const string& mappedDirectory,
+ const Option<Resources>& resources,
+ const Option<map<string, string>>& env)
+ {
+ LOG(INFO) << "Executing 'slavePreLaunchDockerHook'";
+ return os::touch(sandboxDirectory + "/foo");
+ }
+
+
// This hook locates the file created by environment decorator hook
// and deletes it.
virtual Try<Nothing> slaveRemoveExecutorHook(
http://git-wip-us.apache.org/repos/asf/mesos/blob/21c547f5/src/hook/manager.cpp
----------------------------------------------------------------------
diff --git a/src/hook/manager.cpp b/src/hook/manager.cpp
index 0b693d2..754c238 100644
--- a/src/hook/manager.cpp
+++ b/src/hook/manager.cpp
@@ -33,6 +33,7 @@
#include "hook/manager.hpp"
#include "module/manager.hpp"
+using std::map;
using std::string;
using std::vector;
@@ -184,6 +185,37 @@ Environment HookManager::slaveExecutorEnvironmentDecorator(
}
+void HookManager::slavePreLaunchDockerHook(
+ const ContainerInfo& containerInfo,
+ const CommandInfo& commandInfo,
+ const Option<TaskInfo>& taskInfo,
+ const ExecutorInfo& executorInfo,
+ const string& name,
+ const string& sandboxDirectory,
+ const string& mappedDirectory,
+ const Option<Resources>& resources,
+ const Option<map<string, string>>& env)
+{
+ foreachpair (const string& name, Hook* hook, availableHooks) {
+ Try<Nothing> result =
+ hook->slavePreLaunchDockerHook(
+ containerInfo,
+ commandInfo,
+ taskInfo,
+ executorInfo,
+ name,
+ sandboxDirectory,
+ mappedDirectory,
+ resources,
+ env);
+ if (result.isError()) {
+ LOG(WARNING) << "Slave pre launch docker hook failed for module '"
+ << name << "': " << result.error();
+ }
+ }
+}
+
+
void HookManager::slaveRemoveExecutorHook(
const FrameworkInfo& frameworkInfo,
const ExecutorInfo& executorInfo)
http://git-wip-us.apache.org/repos/asf/mesos/blob/21c547f5/src/hook/manager.hpp
----------------------------------------------------------------------
diff --git a/src/hook/manager.hpp b/src/hook/manager.hpp
index df32484..30d8321 100644
--- a/src/hook/manager.hpp
+++ b/src/hook/manager.hpp
@@ -54,6 +54,17 @@ public:
static Environment slaveExecutorEnvironmentDecorator(
ExecutorInfo executorInfo);
+ static void slavePreLaunchDockerHook(
+ const ContainerInfo& containerInfo,
+ const CommandInfo& commandInfo,
+ const Option<TaskInfo>& taskInfo,
+ const ExecutorInfo& executorInfo,
+ const std::string& name,
+ const std::string& sandboxDirectory,
+ const std::string& mappedDirectory,
+ const Option<Resources>& resources,
+ const Option<std::map<std::string, std::string>>& env);
+
static void slaveRemoveExecutorHook(
const FrameworkInfo& frameworkInfo,
const ExecutorInfo& executorInfo);
http://git-wip-us.apache.org/repos/asf/mesos/blob/21c547f5/src/slave/containerizer/docker.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/docker.cpp b/src/slave/containerizer/docker.cpp
index 8f5d302..a17e4f2 100644
--- a/src/slave/containerizer/docker.cpp
+++ b/src/slave/containerizer/docker.cpp
@@ -35,6 +35,8 @@
#include "common/status_utils.hpp"
+#include "hook/manager.hpp"
+
#ifdef __linux__
#include "linux/cgroups.hpp"
#endif // __linux__
@@ -773,6 +775,19 @@ Future<bool> DockerContainerizerProcess::launch(
<< "' and framework '" << executorInfo.framework_id() << "'";
}
+ if (HookManager::hooksAvailable()) {
+ HookManager::slavePreLaunchDockerHook(
+ container.get()->container,
+ container.get()->command,
+ taskInfo,
+ executorInfo,
+ container.get()->name(),
+ container.get()->directory,
+ flags.sandbox_directory,
+ container.get()->resources,
+ container.get()->environment);
+ }
+
if (taskInfo.isSome() && flags.docker_mesos_image.isNone()) {
// Launching task by forking a subprocess to run docker executor.
return container.get()->launch = fetch(containerId, slaveId)
@@ -826,15 +841,15 @@ Future<Docker::Container> DockerContainerizerProcess::launchExecutorContainer(
// This executor could either be a custom executor specified by an
// ExecutorInfo, or the docker executor.
Future<Nothing> run = docker->run(
- container->container,
- container->command,
- containerName,
- container->directory,
- flags.sandbox_directory,
- container->resources,
- container->environment,
- path::join(container->directory, "stdout"),
- path::join(container->directory, "stderr"));
+ container->container,
+ container->command,
+ containerName,
+ container->directory,
+ flags.sandbox_directory,
+ container->resources,
+ container->environment,
+ path::join(container->directory, "stdout"),
+ path::join(container->directory, "stderr"));
Owned<Promise<Docker::Container>> promise(new Promise<Docker::Container>());
// We like to propogate the run failure when run fails so slave can
http://git-wip-us.apache.org/repos/asf/mesos/blob/21c547f5/src/slave/containerizer/docker.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/docker.hpp b/src/slave/containerizer/docker.hpp
index e7436d0..d03bb1b 100644
--- a/src/slave/containerizer/docker.hpp
+++ b/src/slave/containerizer/docker.hpp
@@ -145,7 +145,7 @@ public:
virtual process::Future<ResourceStatistics> usage(
const ContainerID& containerId);
- virtual Future<containerizer::Termination> wait(
+ virtual process::Future<containerizer::Termination> wait(
const ContainerID& containerId);
virtual void destroy(
@@ -202,12 +202,12 @@ private:
void __destroy(
const ContainerID& containerId,
bool killed,
- const Future<Nothing>& future);
+ const process::Future<Nothing>& future);
void ___destroy(
const ContainerID& containerId,
bool killed,
- const Future<Option<int>>& status);
+ const process::Future<Option<int>>& status);
process::Future<Nothing> _update(
const ContainerID& containerId,
@@ -421,16 +421,16 @@ private:
const Flags flags;
// Promise for future returned from wait().
- Promise<containerizer::Termination> termination;
+ process::Promise<containerizer::Termination> termination;
// Exit status of executor or container (depending on whether or
// not we used the command executor). Represented as a promise so
// that destroying can chain with it being set.
- Promise<Future<Option<int>>> status;
+ process::Promise<process::Future<Option<int>>> status;
// Future that tells us the return value of last launch stage (fetch, pull,
// run, etc).
- Future<bool> launch;
+ process::Future<bool> launch;
// We keep track of the resources for each container so we can set
// the ResourceStatistics limits in usage(). Note that this is
@@ -440,7 +440,7 @@ private:
// The docker pull future is stored so we can discard when
// destroy is called while docker is pulling the image.
- Future<Docker::Image> pull;
+ process::Future<Docker::Image> pull;
// Once the container is running, this saves the pid of the
// running container.
http://git-wip-us.apache.org/repos/asf/mesos/blob/21c547f5/src/tests/containerizer/docker_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/docker_containerizer_tests.cpp b/src/tests/containerizer/docker_containerizer_tests.cpp
index c8c27a6..936f8c7 100644
--- a/src/tests/containerizer/docker_containerizer_tests.cpp
+++ b/src/tests/containerizer/docker_containerizer_tests.cpp
@@ -30,9 +30,6 @@
#include "messages/messages.hpp"
-#include "tests/flags.hpp"
-#include "tests/mesos.hpp"
-
#include "slave/containerizer/docker.hpp"
#include "slave/containerizer/fetcher.hpp"
@@ -40,6 +37,9 @@
#include "slave/slave.hpp"
#include "slave/state.hpp"
+#include "tests/flags.hpp"
+#include "tests/mesos.hpp"
+
using namespace mesos::internal::slave::paths;
using namespace mesos::internal::slave::state;
@@ -57,9 +57,9 @@ using process::Message;
using process::PID;
using process::UPID;
-using std::vector;
using std::list;
using std::string;
+using std::vector;
using testing::_;
using testing::DoAll;
@@ -73,105 +73,6 @@ namespace internal {
namespace tests {
-class MockDocker : public Docker
-{
-public:
- MockDocker(const string& path) : Docker(path)
- {
- EXPECT_CALL(*this, pull(_, _, _))
- .WillRepeatedly(Invoke(this, &MockDocker::_pull));
-
- EXPECT_CALL(*this, stop(_, _, _))
- .WillRepeatedly(Invoke(this, &MockDocker::_stop));
-
- EXPECT_CALL(*this, run(_, _, _, _, _, _, _, _, _))
- .WillRepeatedly(Invoke(this, &MockDocker::_run));
-
- EXPECT_CALL(*this, inspect(_, _))
- .WillRepeatedly(Invoke(this, &MockDocker::_inspect));
- }
-
- MOCK_CONST_METHOD9(
- run,
- process::Future<Nothing>(
- const mesos::ContainerInfo&,
- const mesos::CommandInfo&,
- const std::string&,
- const std::string&,
- const std::string&,
- const Option<mesos::Resources>&,
- const Option<std::map<std::string, std::string>>&,
- const Option<std::string>&,
- const Option<std::string>&));
-
- MOCK_CONST_METHOD3(
- pull,
- process::Future<Docker::Image>(
- const string&,
- const string&,
- bool));
-
- MOCK_CONST_METHOD3(
- stop,
- process::Future<Nothing>(
- const string&,
- const Duration&,
- bool));
-
- MOCK_CONST_METHOD2(
- inspect,
- process::Future<Docker::Container>(
- const string&,
- const Option<Duration>&));
-
- process::Future<Nothing> _run(
- const mesos::ContainerInfo& containerInfo,
- const mesos::CommandInfo& commandInfo,
- const std::string& name,
- const std::string& sandboxDirectory,
- const std::string& mappedDirectory,
- const Option<mesos::Resources>& resources,
- const Option<std::map<std::string, std::string>>& env,
- const Option<std::string>& stdoutPath,
- const Option<std::string>& stderrPath) const
- {
- return Docker::run(
- containerInfo,
- commandInfo,
- name,
- sandboxDirectory,
- mappedDirectory,
- resources,
- env,
- stdoutPath,
- stderrPath);
- }
-
- process::Future<Docker::Image> _pull(
- const string& directory,
- const string& image,
- bool force) const
- {
- return Docker::pull(directory, image, force);
- }
-
- process::Future<Nothing> _stop(
- const string& containerName,
- const Duration& timeout,
- bool remove) const
- {
- return Docker::stop(containerName, timeout, remove);
- }
-
- process::Future<Docker::Container> _inspect(
- const string& containerName,
- const Option<Duration>& retryInterval)
- {
- return Docker::inspect(containerName, retryInterval);
- }
-};
-
-
class DockerContainerizerTest : public MesosTest
{
public:
@@ -257,160 +158,6 @@ public:
};
-class MockDockerContainerizer : public DockerContainerizer {
-public:
- MockDockerContainerizer(
- const slave::Flags& flags,
- Fetcher* fetcher,
- Shared<Docker> docker)
- : DockerContainerizer(flags, fetcher, docker)
- {
- initialize();
- }
-
- MockDockerContainerizer(const Owned<DockerContainerizerProcess>& process)
- : DockerContainerizer(process)
- {
- initialize();
- }
-
- void initialize()
- {
- // NOTE: See TestContainerizer::setup for why we use
- // 'EXPECT_CALL' and 'WillRepeatedly' here instead of
- // 'ON_CALL' and 'WillByDefault'.
- EXPECT_CALL(*this, launch(_, _, _, _, _, _, _))
- .WillRepeatedly(Invoke(this, &MockDockerContainerizer::_launchExecutor));
-
- EXPECT_CALL(*this, launch(_, _, _, _, _, _, _, _))
- .WillRepeatedly(Invoke(this, &MockDockerContainerizer::_launch));
-
- EXPECT_CALL(*this, update(_, _))
- .WillRepeatedly(Invoke(this, &MockDockerContainerizer::_update));
- }
-
- MOCK_METHOD7(
- launch,
- process::Future<bool>(
- const ContainerID&,
- const ExecutorInfo&,
- const std::string&,
- const Option<std::string>&,
- const SlaveID&,
- const process::PID<slave::Slave>&,
- bool checkpoint));
-
- MOCK_METHOD8(
- launch,
- process::Future<bool>(
- const ContainerID&,
- const TaskInfo&,
- const ExecutorInfo&,
- const std::string&,
- const Option<std::string>&,
- const SlaveID&,
- const process::PID<slave::Slave>&,
- bool checkpoint));
-
- MOCK_METHOD2(
- update,
- process::Future<Nothing>(
- const ContainerID&,
- const Resources&));
-
- // Default 'launch' implementation (necessary because we can't just
- // use &DockerContainerizer::launch with 'Invoke').
- process::Future<bool> _launch(
- const ContainerID& containerId,
- const TaskInfo& taskInfo,
- const ExecutorInfo& executorInfo,
- const string& directory,
- const Option<string>& user,
- const SlaveID& slaveId,
- const PID<Slave>& slavePid,
- bool checkpoint)
- {
- return DockerContainerizer::launch(
- containerId,
- taskInfo,
- executorInfo,
- directory,
- user,
- slaveId,
- slavePid,
- checkpoint);
- }
-
- process::Future<bool> _launchExecutor(
- const ContainerID& containerId,
- const ExecutorInfo& executorInfo,
- const string& directory,
- const Option<string>& user,
- const SlaveID& slaveId,
- const PID<Slave>& slavePid,
- bool checkpoint)
- {
- return DockerContainerizer::launch(
- containerId,
- executorInfo,
- directory,
- user,
- slaveId,
- slavePid,
- checkpoint);
- }
-
- process::Future<Nothing> _update(
- const ContainerID& containerId,
- const Resources& resources)
- {
- return DockerContainerizer::update(
- containerId,
- resources);
- }
-};
-
-
-class MockDockerContainerizerProcess : public DockerContainerizerProcess
-{
-public:
- MockDockerContainerizerProcess(
- const slave::Flags& flags,
- Fetcher* fetcher,
- const Shared<Docker>& docker)
- : DockerContainerizerProcess(flags, fetcher, docker)
- {
- EXPECT_CALL(*this, fetch(_, _))
- .WillRepeatedly(Invoke(this, &MockDockerContainerizerProcess::_fetch));
-
- EXPECT_CALL(*this, pull(_))
- .WillRepeatedly(Invoke(this, &MockDockerContainerizerProcess::_pull));
- }
-
- MOCK_METHOD2(
- fetch,
- process::Future<Nothing>(
- const ContainerID& containerId,
- const SlaveID& slaveId));
-
- MOCK_METHOD1(
- pull,
- process::Future<Nothing>(const ContainerID& containerId));
-
- process::Future<Nothing> _fetch(
- const ContainerID& containerId,
- const SlaveID& slaveId)
- {
- return DockerContainerizerProcess::fetch(containerId, slaveId);
- }
-
- process::Future<Nothing> _pull(const ContainerID& containerId)
- {
- return DockerContainerizerProcess::pull(containerId);
- }
-};
-
-
// Only enable executor launch on linux as other platforms
// requires running linux VM and need special port forwarding
// to get host networking to work.
@@ -2950,7 +2697,6 @@ TEST_F(DockerContainerizerTest, ROOT_DOCKER_DockerInspectDiscard)
Shutdown();
}
-
} // namespace tests {
} // namespace internal {
} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/21c547f5/src/tests/hook_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/hook_tests.cpp b/src/tests/hook_tests.cpp
index e9f1c77..cfde49e 100644
--- a/src/tests/hook_tests.cpp
+++ b/src/tests/hook_tests.cpp
@@ -40,6 +40,7 @@
#include "slave/flags.hpp"
#include "slave/slave.hpp"
+#include "slave/containerizer/docker.hpp"
#include "slave/containerizer/fetcher.hpp"
#include "slave/containerizer/mesos/containerizer.hpp"
@@ -62,7 +63,9 @@ using mesos::internal::slave::Slave;
using process::Future;
using process::PID;
+using process::Shared;
+using std::list;
using std::string;
using std::vector;
@@ -513,6 +516,118 @@ TEST_F(HookTest, VerifySlaveTaskStatusLabelDecorator)
Shutdown(); // Must shutdown before 'containerizer' gets deallocated.
}
+
+// Test that the prepare launch docker hook execute before launch
+// a docker container. Test hook create a file "foo" in the sandbox
+// directory. When the docker container launched, the sandbox directory
+// is mounted to the docker container. We validate the hook by verifying
+// the "foo" file exists in the docker container or not.
+TEST_F(HookTest, ROOT_DOCKER_VerifySlavePreLaunchDockerHook)
+{
+ Try<PID<Master>> master = StartMaster();
+ ASSERT_SOME(master);
+
+ MockDocker* mockDocker = new MockDocker(tests::flags.docker);
+ Shared<Docker> docker(mockDocker);
+
+ slave::Flags flags = CreateSlaveFlags();
+
+ Fetcher fetcher;
+
+ MockDockerContainerizer dockerContainerizer(flags, &fetcher, docker);
+
+ Try<PID<Slave>> slave = StartSlave(&dockerContainerizer, flags);
+ ASSERT_SOME(slave);
+
+ MockScheduler sched;
+ MesosSchedulerDriver driver(
+ &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);
+
+ Future<FrameworkID> frameworkId;
+ EXPECT_CALL(sched, registered(&driver, _, _))
+ .WillOnce(FutureArg<1>(&frameworkId));
+
+ Future<vector<Offer>> offers;
+ EXPECT_CALL(sched, resourceOffers(&driver, _))
+ .WillOnce(FutureArg<1>(&offers))
+ .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+ driver.start();
+
+ AWAIT_READY(frameworkId);
+
+ AWAIT_READY(offers);
+ ASSERT_NE(0u, offers.get().size());
+
+ const Offer& offer = offers.get()[0];
+
+ SlaveID slaveId = offer.slave_id();
+
+ TaskInfo task;
+ task.set_name("");
+ task.mutable_task_id()->set_value("1");
+ task.mutable_slave_id()->CopyFrom(offer.slave_id());
+ task.mutable_resources()->CopyFrom(offer.resources());
+
+ CommandInfo command;
+ command.set_value("test -f " + path::join(flags.sandbox_directory, "foo"));
+
+ ContainerInfo containerInfo;
+ containerInfo.set_type(ContainerInfo::DOCKER);
+
+ // TODO(tnachen): Use local image to test if possible.
+ ContainerInfo::DockerInfo dockerInfo;
+ dockerInfo.set_image("busybox");
+ containerInfo.mutable_docker()->CopyFrom(dockerInfo);
+
+ task.mutable_command()->CopyFrom(command);
+ task.mutable_container()->CopyFrom(containerInfo);
+
+ vector<TaskInfo> tasks;
+ tasks.push_back(task);
+
+ Future<ContainerID> containerId;
+ EXPECT_CALL(dockerContainerizer, launch(_, _, _, _, _, _, _, _))
+ .WillOnce(DoAll(FutureArg<0>(&containerId),
+ Invoke(&dockerContainerizer,
+ &MockDockerContainerizer::_launch)));
+
+ Future<TaskStatus> statusRunning;
+ Future<TaskStatus> statusFinished;
+ EXPECT_CALL(sched, statusUpdate(&driver, _))
+ .WillOnce(FutureArg<1>(&statusRunning))
+ .WillOnce(FutureArg<1>(&statusFinished))
+ .WillRepeatedly(DoDefault());
+
+ driver.launchTasks(offers.get()[0].id(), tasks);
+
+ AWAIT_READY_FOR(containerId, Seconds(60));
+ AWAIT_READY_FOR(statusRunning, Seconds(60));
+ EXPECT_EQ(TASK_RUNNING, statusRunning.get().state());
+ AWAIT_READY_FOR(statusFinished, Seconds(60));
+ EXPECT_EQ(TASK_FINISHED, statusFinished.get().state());
+
+ Future<containerizer::Termination> termination =
+ dockerContainerizer.wait(containerId.get());
+
+ driver.stop();
+ driver.join();
+
+ AWAIT_READY(termination);
+
+ Future<list<Docker::Container>> containers =
+ docker.get()->ps(true, slave::DOCKER_NAME_PREFIX);
+
+ AWAIT_READY(containers);
+
+ // Cleanup all mesos launched containers.
+ foreach (const Docker::Container& container, containers.get()) {
+ AWAIT_READY_FOR(docker.get()->rm(container.id, true), Seconds(30));
+ }
+
+ Shutdown();
+}
+
} // namespace tests {
} // namespace internal {
} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/21c547f5/src/tests/mesos.hpp
----------------------------------------------------------------------
diff --git a/src/tests/mesos.hpp b/src/tests/mesos.hpp
index 64987f0..637636a 100644
--- a/src/tests/mesos.hpp
+++ b/src/tests/mesos.hpp
@@ -25,6 +25,8 @@
#include <string>
#include <vector>
+#include <gmock/gmock.h>
+
#include <mesos/executor.hpp>
#include <mesos/scheduler.hpp>
@@ -67,6 +69,8 @@
#include "slave/slave.hpp"
#include "slave/containerizer/containerizer.hpp"
+#include "slave/containerizer/docker.hpp"
+#include "slave/containerizer/fetcher.hpp"
#include "slave/containerizer/mesos/containerizer.hpp"
@@ -81,6 +85,7 @@
using ::testing::_;
using ::testing::An;
using ::testing::DoDefault;
+using ::testing::Invoke;
using ::testing::Return;
namespace mesos {
@@ -956,6 +961,264 @@ public:
};
+// Definition of a mock Docker to be used in tests with gmock.
+class MockDocker : public Docker
+{
+public:
+ MockDocker(const std::string& path) : Docker(path)
+ {
+ EXPECT_CALL(*this, pull(_, _, _))
+ .WillRepeatedly(Invoke(this, &MockDocker::_pull));
+
+ EXPECT_CALL(*this, stop(_, _, _))
+ .WillRepeatedly(Invoke(this, &MockDocker::_stop));
+
+ EXPECT_CALL(*this, run(_, _, _, _, _, _, _, _, _))
+ .WillRepeatedly(Invoke(this, &MockDocker::_run));
+
+ EXPECT_CALL(*this, inspect(_, _))
+ .WillRepeatedly(Invoke(this, &MockDocker::_inspect));
+ }
+
+ MOCK_CONST_METHOD9(
+ run,
+ process::Future<Nothing>(
+ const mesos::ContainerInfo&,
+ const mesos::CommandInfo&,
+ const std::string&,
+ const std::string&,
+ const std::string&,
+ const Option<mesos::Resources>&,
+ const Option<std::map<std::string, std::string>>&,
+ const Option<std::string>&,
+ const Option<std::string>&));
+
+ MOCK_CONST_METHOD3(
+ pull,
+ process::Future<Docker::Image>(
+ const std::string&,
+ const std::string&,
+ bool));
+
+ MOCK_CONST_METHOD3(
+ stop,
+ process::Future<Nothing>(
+ const std::string&,
+ const Duration&,
+ bool));
+
+ MOCK_CONST_METHOD2(
+ inspect,
+ process::Future<Docker::Container>(
+ const std::string&,
+ const Option<Duration>&));
+
+ process::Future<Nothing> _run(
+ const mesos::ContainerInfo& containerInfo,
+ const mesos::CommandInfo& commandInfo,
+ const std::string& name,
+ const std::string& sandboxDirectory,
+ const std::string& mappedDirectory,
+ const Option<mesos::Resources>& resources,
+ const Option<std::map<std::string, std::string>>& env,
+ const Option<std::string>& stdoutPath,
+ const Option<std::string>& stderrPath) const
+ {
+ return Docker::run(
+ containerInfo,
+ commandInfo,
+ name,
+ sandboxDirectory,
+ mappedDirectory,
+ resources,
+ env,
+ stdoutPath,
+ stderrPath);
+ }
+
+ process::Future<Docker::Image> _pull(
+ const std::string& directory,
+ const std::string& image,
+ bool force) const
+ {
+ return Docker::pull(directory, image, force);
+ }
+
+ process::Future<Nothing> _stop(
+ const std::string& containerName,
+ const Duration& timeout,
+ bool remove) const
+ {
+ return Docker::stop(containerName, timeout, remove);
+ }
+
+ process::Future<Docker::Container> _inspect(
+ const std::string& containerName,
+ const Option<Duration>& retryInterval)
+ {
+ return Docker::inspect(containerName, retryInterval);
+ }
+};
+
+
+// Definition of a mock DockerContainerizer to be used in tests with gmock.
+class MockDockerContainerizer : public slave::DockerContainerizer {
+public:
+ MockDockerContainerizer(
+ const slave::Flags& flags,
+ slave::Fetcher* fetcher,
+ process::Shared<Docker> docker)
+ : slave::DockerContainerizer(flags, fetcher, docker)
+ {
+ initialize();
+ }
+
+ MockDockerContainerizer(
+ const process::Owned<slave::DockerContainerizerProcess>& process)
+ : slave::DockerContainerizer(process)
+ {
+ initialize();
+ }
+
+ void initialize()
+ {
+ // NOTE: See TestContainerizer::setup for why we use
+ // 'EXPECT_CALL' and 'WillRepeatedly' here instead of
+ // 'ON_CALL' and 'WillByDefault'.
+ EXPECT_CALL(*this, launch(_, _, _, _, _, _, _))
+ .WillRepeatedly(Invoke(this, &MockDockerContainerizer::_launchExecutor));
+
+ EXPECT_CALL(*this, launch(_, _, _, _, _, _, _, _))
+ .WillRepeatedly(Invoke(this, &MockDockerContainerizer::_launch));
+
+ EXPECT_CALL(*this, update(_, _))
+ .WillRepeatedly(Invoke(this, &MockDockerContainerizer::_update));
+ }
+
+ MOCK_METHOD7(
+ launch,
+ process::Future<bool>(
+ const ContainerID&,
+ const ExecutorInfo&,
+ const std::string&,
+ const Option<std::string>&,
+ const SlaveID&,
+ const process::PID<slave::Slave>&,
+ bool checkpoint));
+
+ MOCK_METHOD8(
+ launch,
+ process::Future<bool>(
+ const ContainerID&,
+ const TaskInfo&,
+ const ExecutorInfo&,
+ const std::string&,
+ const Option<std::string>&,
+ const SlaveID&,
+ const process::PID<slave::Slave>&,
+ bool checkpoint));
+
+ MOCK_METHOD2(
+ update,
+ process::Future<Nothing>(
+ const ContainerID&,
+ const Resources&));
+
+ // Default 'launch' implementation (necessary because we can't just
+ // use &slave::DockerContainerizer::launch with 'Invoke').
+ process::Future<bool> _launch(
+ const ContainerID& containerId,
+ const TaskInfo& taskInfo,
+ const ExecutorInfo& executorInfo,
+ const std::string& directory,
+ const Option<std::string>& user,
+ const SlaveID& slaveId,
+ const slave::PID<slave::Slave>& slavePid,
+ bool checkpoint)
+ {
+ return slave::DockerContainerizer::launch(
+ containerId,
+ taskInfo,
+ executorInfo,
+ directory,
+ user,
+ slaveId,
+ slavePid,
+ checkpoint);
+ }
+
+ process::Future<bool> _launchExecutor(
+ const ContainerID& containerId,
+ const ExecutorInfo& executorInfo,
+ const std::string& directory,
+ const Option<std::string>& user,
+ const SlaveID& slaveId,
+ const slave::PID<slave::Slave>& slavePid,
+ bool checkpoint)
+ {
+ return slave::DockerContainerizer::launch(
+ containerId,
+ executorInfo,
+ directory,
+ user,
+ slaveId,
+ slavePid,
+ checkpoint);
+ }
+
+ process::Future<Nothing> _update(
+ const ContainerID& containerId,
+ const Resources& resources)
+ {
+ return slave::DockerContainerizer::update(
+ containerId,
+ resources);
+ }
+};
+
+
+// Definition of a mock DockerContainerizerProcess to be used in tests
+// with gmock.
+class MockDockerContainerizerProcess : public slave::DockerContainerizerProcess
+{
+public:
+ MockDockerContainerizerProcess(
+ const slave::Flags& flags,
+ slave::Fetcher* fetcher,
+ const process::Shared<Docker>& docker)
+ : slave::DockerContainerizerProcess(flags, fetcher, docker)
+ {
+ EXPECT_CALL(*this, fetch(_, _))
+ .WillRepeatedly(Invoke(this, &MockDockerContainerizerProcess::_fetch));
+
+ EXPECT_CALL(*this, pull(_))
+ .WillRepeatedly(Invoke(this, &MockDockerContainerizerProcess::_pull));
+ }
+
+ MOCK_METHOD2(
+ fetch,
+ process::Future<Nothing>(
+ const ContainerID& containerId,
+ const SlaveID& slaveId));
+
+ MOCK_METHOD1(
+ pull,
+ process::Future<Nothing>(const ContainerID& containerId));
+
+ process::Future<Nothing> _fetch(
+ const ContainerID& containerId,
+ const SlaveID& slaveId)
+ {
+ return slave::DockerContainerizerProcess::fetch(containerId, slaveId);
+ }
+
+ process::Future<Nothing> _pull(const ContainerID& containerId)
+ {
+ return slave::DockerContainerizerProcess::pull(containerId);
+ }
+};
+
+
// Definition of a MockAuthozier that can be used in tests with gmock.
class MockAuthorizer : public Authorizer
{