You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2016/10/06 02:00:59 UTC
[2/4] mesos git commit: Added support for nested containers to the
test containerizer.
Added support for nested containers to the test containerizer.
In the process, the maps that were stored were simplified.
Review: https://reviews.apache.org/r/52568
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/0ce6361b
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/0ce6361b
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/0ce6361b
Branch: refs/heads/master
Commit: 0ce6361bfa17d0d75f1cae60800bbc35a69eb449
Parents: 9b7a2a5
Author: Benjamin Mahler <bm...@apache.org>
Authored: Wed Oct 5 12:15:23 2016 -0700
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Wed Oct 5 18:36:57 2016 -0700
----------------------------------------------------------------------
src/tests/containerizer.cpp | 178 ++++++++++++++++++++++++++-------------
src/tests/containerizer.hpp | 50 +++++++++--
2 files changed, 162 insertions(+), 66 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/0ce6361b/src/tests/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer.cpp b/src/tests/containerizer.cpp
index 89c5400..3affa0f 100644
--- a/src/tests/containerizer.cpp
+++ b/src/tests/containerizer.cpp
@@ -44,15 +44,21 @@ TestContainerizer::TestContainerizer(
const ExecutorID& executorId,
const shared_ptr<MockV1HTTPExecutor>& executor)
{
- v1Executors[executorId] = executor;
+ executors[executorId] = Owned<ExecutorData>(new ExecutorData());
+ executors.at(executorId)->v1ExecutorMock = executor;
+
setup();
}
TestContainerizer::TestContainerizer(
const hashmap<ExecutorID, Executor*>& _executors)
- : executors(_executors)
{
+ foreachpair (const ExecutorID& executorId, Executor* executor, _executors) {
+ executors[executorId] = Owned<ExecutorData>(new ExecutorData());
+ executors.at(executorId)->executor = executor;
+ }
+
setup();
}
@@ -61,14 +67,18 @@ TestContainerizer::TestContainerizer(
const ExecutorID& executorId,
Executor* executor)
{
- executors[executorId] = executor;
+ executors[executorId] = Owned<ExecutorData>(new ExecutorData());
+ executors.at(executorId)->executor = executor;
+
setup();
}
TestContainerizer::TestContainerizer(MockExecutor* executor)
{
- executors[executor->id] = executor;
+ executors[executor->id] = Owned<ExecutorData>(new ExecutorData());
+ executors.at(executor->id)->executor = executor;
+
setup();
}
@@ -81,11 +91,12 @@ TestContainerizer::TestContainerizer()
TestContainerizer::~TestContainerizer()
{
- foreachvalue (const Owned<MesosExecutorDriver>& driver, drivers) {
- driver->stop();
- driver->join();
+ foreachvalue (const Owned<ExecutorData>& data, executors) {
+ if (data->driver.get() != nullptr) {
+ data->driver->stop();
+ data->driver->join();
+ }
}
- drivers.clear();
}
@@ -99,22 +110,20 @@ Future<bool> TestContainerizer::_launch(
const map<string, string>& environment,
bool checkpoint)
{
- CHECK(!drivers.contains(containerId))
- << "Failed to launch executor '" << executorInfo.executor_id()
- << "' of framework " << executorInfo.framework_id()
+ CHECK(!containers_.contains(containerId))
+ << "Failed to launch container " << containerId
+ << " for executor '" << executorInfo.executor_id() << "'"
+ << " of framework " << executorInfo.framework_id()
<< " because it is already launched";
- CHECK(executors.contains(executorInfo.executor_id()) ||
- v1Executors.contains(executorInfo.executor_id()))
- << "Failed to launch executor '" << executorInfo.executor_id()
- << "' of framework " << executorInfo.framework_id()
+ CHECK(executors.contains(executorInfo.executor_id()))
+ << "Failed to launch executor '" << executorInfo.executor_id() << "'"
+ << " of framework " << executorInfo.framework_id()
<< " because it is unknown to the containerizer";
- // Store mapping from (frameworkId, executorId) -> containerId to facilitate
- // easy destroy from tests.
- std::pair<FrameworkID, ExecutorID> key(executorInfo.framework_id(),
- executorInfo.executor_id());
- containers_[key] = containerId;
+ containers_[containerId] = Owned<ContainerData>(new ContainerData());
+ containers_.at(containerId)->executorId = executorInfo.executor_id();
+ containers_.at(containerId)->frameworkId = executorInfo.framework_id();
// We need to synchronize all reads and writes to the environment as this is
// global state.
@@ -153,21 +162,17 @@ Future<bool> TestContainerizer::_launch(
os::setenv("MESOS_LOCAL", "1");
- if (executors.contains(executorInfo.executor_id())) {
- Executor* executor = executors[executorInfo.executor_id()];
+ const Owned<ExecutorData>& executorData =
+ executors.at(executorInfo.executor_id());
- Owned<MesosExecutorDriver> driver(new MesosExecutorDriver(executor));
- drivers[containerId] = driver;
-
- driver->start();
+ if (executorData->executor != nullptr) {
+ executorData->driver = Owned<MesosExecutorDriver>(
+ new MesosExecutorDriver(executorData->executor));
+ executorData->driver->start();
} else {
- shared_ptr<MockV1HTTPExecutor> executor =
- v1Executors[executorInfo.executor_id()];
-
- Owned<executor::TestV1Mesos> mesos(
- new executor::TestV1Mesos(ContentType::PROTOBUF, executor));
-
- v1Libraries[containerId] = mesos;
+ shared_ptr<MockV1HTTPExecutor> executor = executorData->v1ExecutorMock;
+ executorData->v1Library = Owned<executor::TestV1Mesos>(
+ new executor::TestV1Mesos(ContentType::PROTOBUF, executor));
}
os::unsetenv("MESOS_LOCAL");
@@ -186,10 +191,24 @@ Future<bool> TestContainerizer::_launch(
}
}
- promises[containerId] =
- Owned<Promise<ContainerTermination>>(
- new Promise<ContainerTermination>());
+ return true;
+}
+
+Future<bool> TestContainerizer::_launch(
+ const ContainerID& containerId,
+ const CommandInfo& commandInfo,
+ const Option<ContainerInfo>& containerInfo,
+ const Option<string>& user,
+ const SlaveID& slaveId)
+{
+ CHECK(!containers_.contains(containerId))
+ << "Failed to launch nested container " << containerId
+ << " because it is already launched";
+
+ containers_[containerId] = Owned<ContainerData>(new ContainerData());
+
+ // No-op for now.
return true;
}
@@ -199,11 +218,11 @@ Future<Option<ContainerTermination>> TestContainerizer::_wait(
{
// An unknown container is possible for tests where we "drop" the
// 'launch' in order to verify recovery still works correctly.
- if (!promises.contains(containerId)) {
+ if (!containers_.contains(containerId)) {
return None();
}
- return promises.at(containerId)->future()
+ return containers_.at(containerId)->termination.future()
.then(Option<ContainerTermination>::some);
}
@@ -212,46 +231,65 @@ Future<bool> TestContainerizer::destroy(
const FrameworkID& frameworkId,
const ExecutorID& executorId)
{
- std::pair<FrameworkID, ExecutorID> key(frameworkId, executorId);
- if (!containers_.contains(key)) {
- LOG(WARNING) << "Ignoring destroy of unknown container for executor '"
- << executorId << "' of framework " << frameworkId;
+ Option<ContainerID> containerId = None();
+
+ foreachpair (const ContainerID& containerId_,
+ const Owned<ContainerData>& container,
+ containers_) {
+ if (container->frameworkId == frameworkId &&
+ container->executorId == executorId) {
+ containerId = containerId_;
+ }
+ }
+
+ if (containerId.isNone()) {
+ LOG(WARNING) << "Ignoring destroy of unknown container"
+ << " for executor '" << executorId << "'"
+ << " of framework " << frameworkId;
return false;
}
- return _destroy(containers_.at(key));
+ return _destroy(containerId.get());
}
Future<bool> TestContainerizer::_destroy(const ContainerID& containerId)
{
- if (drivers.contains(containerId)) {
- Owned<MesosExecutorDriver> driver = drivers.at(containerId);
- driver->stop();
- driver->join();
- drivers.erase(containerId);
+ if (!containers_.contains(containerId)) {
+ return false;
}
- if (v1Libraries.contains(containerId)) {
- v1Libraries.erase(containerId);
- }
+ const Owned<ContainerData>& containerData = containers_.at(containerId);
- if (promises.contains(containerId)) {
- ContainerTermination termination;
- termination.set_message("Killed executor");
- termination.set_status(0);
+ if (containerData->executorId.isSome()) {
+ CHECK(executors.contains(containerData->executorId.get()));
- promises.at(containerId)->set(termination);
- promises.erase(containerId);
+ const Owned<ExecutorData>& executorData =
+ executors.at(containerData->executorId.get());
+
+ if (executorData->driver.get() != nullptr) {
+ executorData->driver->stop();
+ executorData->driver->join();
+ }
+
+ executors.erase(containerData->executorId.get());
}
+ ContainerTermination termination;
+ termination.set_message("Killed executor");
+ termination.set_status(0);
+
+ containerData->termination.set(termination);
+
+ containers_.erase(containerId);
+
return true;
}
Future<hashset<ContainerID>> TestContainerizer::containers()
{
- return promises.keys();
+ return containers_.keys();
}
@@ -280,8 +318,30 @@ void TestContainerizer::setup()
EXPECT_CALL(*this, update(_, _))
.WillRepeatedly(Return(Nothing()));
+ Future<bool> (TestContainerizer::*_launch)(
+ const ContainerID& containerId,
+ const Option<TaskInfo>& taskInfo,
+ const ExecutorInfo& executorInfo,
+ const string& directory,
+ const Option<string>& user,
+ const SlaveID& slaveId,
+ const map<string, string>& environment,
+ bool checkpoint) =
+ &TestContainerizer::_launch;
+
EXPECT_CALL(*this, launch(_, _, _, _, _, _, _, _))
- .WillRepeatedly(Invoke(this, &TestContainerizer::_launch));
+ .WillRepeatedly(Invoke(this, _launch));
+
+ Future<bool> (TestContainerizer::*_launchNested)(
+ const ContainerID& containerId,
+ const CommandInfo& commandInfo,
+ const Option<ContainerInfo>& containerInfo,
+ const Option<string>& user,
+ const SlaveID& slaveId) =
+ &TestContainerizer::_launch;
+
+ EXPECT_CALL(*this, launch(_, _, _, _, _))
+ .WillRepeatedly(Invoke(this, _launchNested));
EXPECT_CALL(*this, wait(_))
.WillRepeatedly(Invoke(this, &TestContainerizer::_wait));
http://git-wip-us.apache.org/repos/asf/mesos/blob/0ce6361b/src/tests/containerizer.hpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer.hpp b/src/tests/containerizer.hpp
index 3cf418a..0ffba73 100644
--- a/src/tests/containerizer.hpp
+++ b/src/tests/containerizer.hpp
@@ -57,6 +57,8 @@ class MockExecutor;
class TestContainerizer : public slave::Containerizer
{
public:
+ // TODO(bmahler): These constructors assume that ExecutorIDs are
+ // unique across FrameworkIDs, which is not the case.
TestContainerizer(
const ExecutorID& executorId,
const std::shared_ptr<MockV1HTTPExecutor>& executor);
@@ -89,6 +91,15 @@ public:
const std::map<std::string, std::string>&,
bool checkpoint));
+ MOCK_METHOD5(
+ launch,
+ process::Future<bool>(
+ const ContainerID& containerId,
+ const CommandInfo& commandInfo,
+ const Option<ContainerInfo>& containerInfo,
+ const Option<std::string>& user,
+ const SlaveID& slaveId));
+
MOCK_METHOD2(
update,
process::Future<Nothing>(const ContainerID&, const Resources&));
@@ -120,6 +131,7 @@ private:
void setup();
// Default implementations of mock methods.
+
process::Future<bool> _launch(
const ContainerID& containerId,
const Option<TaskInfo>& taskInfo,
@@ -130,19 +142,43 @@ private:
const std::map<std::string, std::string>& environment,
bool checkpoint);
+ process::Future<bool> _launch(
+ const ContainerID& containerId,
+ const CommandInfo& commandInfo,
+ const Option<ContainerInfo>& containerInfo,
+ const Option<std::string>& user,
+ const SlaveID& slaveId);
+
process::Future<Option<mesos::slave::ContainerTermination>> _wait(
const ContainerID& containerId) const;
process::Future<bool> _destroy(const ContainerID& containerID);
- hashmap<ExecutorID, Executor*> executors;
- hashmap<ExecutorID, std::shared_ptr<MockV1HTTPExecutor>> v1Executors;
+ struct ContainerData
+ {
+ Option<ExecutorID> executorId;
+ Option<FrameworkID> frameworkId;
+
+ process::Promise<mesos::slave::ContainerTermination> termination;
+ };
+
+ hashmap<ContainerID, process::Owned<ContainerData>> containers_;
+
+ struct ExecutorData
+ {
+ // Pre-HTTP executors.
+ Executor* executor;
+ process::Owned<MesosExecutorDriver> driver;
+
+ // HTTP executors. Note that `mesos::v1::executor::Mesos`
+ // requires that we provide it a shared pointer to the executor.
+ std::shared_ptr<MockV1HTTPExecutor> v1ExecutorMock;
+ process::Owned<executor::TestV1Mesos> v1Library;
+ };
- hashmap<std::pair<FrameworkID, ExecutorID>, ContainerID> containers_;
- hashmap<ContainerID, process::Owned<MesosExecutorDriver>> drivers;
- hashmap<ContainerID, process::Owned<executor::TestV1Mesos>> v1Libraries;
- hashmap<ContainerID, process::Owned<
- process::Promise<mesos::slave::ContainerTermination>>> promises;
+ // TODO(bmahler): The test containerizer currently assumes that
+ // executor IDs are unique across frameworks (see the constructors).
+ hashmap<ExecutorID, process::Owned<ExecutorData>> executors;
};
} // namespace tests {