You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by an...@apache.org on 2017/01/20 00:52:48 UTC
[6/6] mesos git commit: Made the Agent API able to handle containers
nested at arbitrary levels.
Made the Agent API able to handle containers nested at arbitrary levels.
Review: https://reviews.apache.org/r/55464/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/dd922d51
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/dd922d51
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/dd922d51
Branch: refs/heads/master
Commit: dd922d51530931fe513df80b7adfd3dd0d23ae27
Parents: 60c59ad
Author: Gast�n Kleiman <ga...@mesosphere.com>
Authored: Thu Jan 19 16:52:01 2017 -0800
Committer: Anand Mazumdar <an...@apache.org>
Committed: Thu Jan 19 16:52:01 2017 -0800
----------------------------------------------------------------------
src/slave/http.cpp | 8 --
src/slave/slave.cpp | 7 +-
src/tests/api_tests.cpp | 201 +++++++++++++++++++++++++++++++++++++------
3 files changed, 178 insertions(+), 38 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/dd922d51/src/slave/http.cpp
----------------------------------------------------------------------
diff --git a/src/slave/http.cpp b/src/slave/http.cpp
index 0cf07e1..4c64fe5 100644
--- a/src/slave/http.cpp
+++ b/src/slave/http.cpp
@@ -2180,14 +2180,6 @@ Future<Response> Slave::Http::_launchNestedContainer(
ContentType acceptType,
const Owned<ObjectApprover>& approver) const
{
- // We do not yet support launching containers that are nested
- // two levels beneath the executor's container.
- if (containerId.parent().has_parent()) {
- return NotImplemented(
- "Only a single level of container nesting is supported currently,"
- " but 'launch_nested_container.container_id.parent.parent' is set");
- }
-
Executor* executor = slave->getExecutor(containerId);
if (executor == nullptr) {
return NotFound("Container " + stringify(containerId) + " cannot be found");
http://git-wip-us.apache.org/repos/asf/mesos/blob/dd922d51/src/slave/slave.cpp
----------------------------------------------------------------------
diff --git a/src/slave/slave.cpp b/src/slave/slave.cpp
index 2bb5b4e..0548b04 100644
--- a/src/slave/slave.cpp
+++ b/src/slave/slave.cpp
@@ -6478,19 +6478,20 @@ Executor* Framework::getExecutor(const TaskID& taskId)
Executor* Slave::getExecutor(const ContainerID& containerId) const
{
+ const ContainerID rootContainerId = protobuf::getRootContainerId(containerId);
+
// Locate the executor (for now we just loop since we don't
// index based on container id and this likely won't have a
// significant performance impact due to the low number of
// executors per-agent).
- // TODO(adam-mesos): Support more levels of nesting.
foreachvalue (Framework* framework, frameworks) {
foreachvalue (Executor* executor, framework->executors) {
- if (executor->containerId == containerId ||
- executor->containerId == containerId.parent()) {
+ if (rootContainerId == executor->containerId) {
return executor;
}
}
}
+
return nullptr;
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/dd922d51/src/tests/api_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/api_tests.cpp b/src/tests/api_tests.cpp
index 47fa3bf..8c0ed23 100644
--- a/src/tests/api_tests.cpp
+++ b/src/tests/api_tests.cpp
@@ -3609,29 +3609,61 @@ TEST_P_TEMP_DISABLED_ON_WINDOWS(AgentAPITest, NestedContainerLaunchFalse)
}
-TEST_P(AgentAPITest, NestedContainerLaunchGrandchildNotSupported)
+TEST_P_TEMP_DISABLED_ON_WINDOWS(AgentAPITest, NestedContainerLaunch)
{
ContentType contentType = GetParam();
Clock::pause();
- Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover);
+ Try<Owned<cluster::Master>> master = StartMaster();
+ ASSERT_SOME(master);
- StandaloneMasterDetector detector;
- Try<Owned<cluster::Slave>> slave = StartSlave(&detector);
+ Owned<MasterDetector> detector = master.get()->createDetector();
+
+ MockExecutor exec(DEFAULT_EXECUTOR_ID);
+ TestContainerizer containerizer(&exec);
+
+ slave::Flags agentFlags = CreateSlaveFlags();
+ Try<Owned<cluster::Slave>> slave =
+ StartSlave(detector.get(), &containerizer, agentFlags);
ASSERT_SOME(slave);
- // Wait for the agent to finish recovery.
- AWAIT_READY(__recover);
- Clock::settle();
+ MockScheduler sched;
+ MesosSchedulerDriver driver(
+ &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- // Try to launch a grandchild container.
+ EXPECT_CALL(sched, registered(&driver, _, _))
+ .Times(1);
+
+ Future<vector<Offer>> offers;
+ EXPECT_CALL(sched, resourceOffers(&driver, _))
+ .WillOnce(LaunchTasks(DEFAULT_EXECUTOR_INFO, 1, 0.1, 32, "*"))
+ .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+ Future<Nothing> executorRegistered;
+ EXPECT_CALL(exec, registered(_, _, _, _))
+ .WillOnce(FutureSatisfy(&executorRegistered));
+
+ EXPECT_CALL(exec, launchTask(_, _))
+ .Times(1);
+
+ driver.start();
+
+ // Trigger authentication and registration for the agent.
+ Clock::advance(agentFlags.authentication_backoff_factor);
+ Clock::advance(agentFlags.registration_backoff_factor);
+
+ AWAIT_READY(executorRegistered);
+
+ Future<hashset<ContainerID>> containerIds = containerizer.containers();
+ AWAIT_READY(containerIds);
+ ASSERT_EQ(1u, containerIds->size());
+
+ // Launch a nested container and wait for it to finish.
v1::ContainerID containerId;
containerId.set_value(UUID::random().toString());
- containerId.mutable_parent()->set_value(UUID::random().toString());
- containerId.mutable_parent()->mutable_parent()
- ->set_value(UUID::random().toString());
+ containerId.mutable_parent()->set_value(containerIds->begin()->value());
{
v1::agent::Call call;
@@ -3647,12 +3679,58 @@ TEST_P(AgentAPITest, NestedContainerLaunchGrandchildNotSupported)
serialize(contentType, call),
stringify(contentType));
- AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::NotImplemented().status, response);
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response);
+ }
+
+ Future<v1::agent::Response> wait;
+
+ {
+ v1::agent::Call call;
+ call.set_type(v1::agent::Call::WAIT_NESTED_CONTAINER);
+
+ call.mutable_wait_nested_container()->mutable_container_id()
+ ->CopyFrom(containerId);
+
+ wait = post(slave.get()->pid, call, contentType);
+
+ Clock::settle();
+
+ EXPECT_TRUE(wait.isPending());
+ }
+
+ // Now kill the nested container.
+ {
+ v1::agent::Call call;
+ call.set_type(v1::agent::Call::KILL_NESTED_CONTAINER);
+
+ call.mutable_kill_nested_container()->mutable_container_id()
+ ->CopyFrom(containerId);
+
+ Future<http::Response> response = http::post(
+ slave.get()->pid,
+ "api/v1",
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL),
+ serialize(contentType, call),
+ stringify(contentType));
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response);
}
+
+ AWAIT_READY(wait);
+ ASSERT_EQ(v1::agent::Response::WAIT_NESTED_CONTAINER, wait->type());
+
+ // The test containerizer sets exit status to 0 when destroyed.
+ EXPECT_EQ(0, wait->wait_nested_container().exit_status());
+
+ EXPECT_CALL(exec, shutdown(_))
+ .Times(AtMost(1));
+
+ driver.stop();
+ driver.join();
}
-TEST_P_TEMP_DISABLED_ON_WINDOWS(AgentAPITest, NestedContainerLaunch)
+TEST_P_TEMP_DISABLED_ON_WINDOWS(AgentAPITest, TwoLevelNestedContainerLaunch)
{
ContentType contentType = GetParam();
@@ -3701,17 +3779,19 @@ TEST_P_TEMP_DISABLED_ON_WINDOWS(AgentAPITest, NestedContainerLaunch)
AWAIT_READY(containerIds);
ASSERT_EQ(1u, containerIds->size());
- // Launch a nested container and wait for it to finish.
- v1::ContainerID containerId;
- containerId.set_value(UUID::random().toString());
- containerId.mutable_parent()->set_value(containerIds->begin()->value());
+ // Launch a two level nested parent/child container and then wait for them to
+ // finish.
+ v1::ContainerID parentContainerId;
+ parentContainerId.set_value(UUID::random().toString());
+ parentContainerId.mutable_parent()->set_value(containerIds->begin()->value());
+ // Launch the parent container.
{
v1::agent::Call call;
call.set_type(v1::agent::Call::LAUNCH_NESTED_CONTAINER);
call.mutable_launch_nested_container()->mutable_container_id()
- ->CopyFrom(containerId);
+ ->CopyFrom(parentContainerId);
Future<http::Response> response = http::post(
slave.get()->pid,
@@ -3723,29 +3803,69 @@ TEST_P_TEMP_DISABLED_ON_WINDOWS(AgentAPITest, NestedContainerLaunch)
AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response);
}
- Future<v1::agent::Response> wait;
+ // Launch the child container.
+ v1::ContainerID childContainerId;
+ childContainerId.set_value(UUID::random().toString());
+ childContainerId.mutable_parent()->CopyFrom(parentContainerId);
+
+ {
+ v1::agent::Call call;
+ call.set_type(v1::agent::Call::LAUNCH_NESTED_CONTAINER);
+
+ call.mutable_launch_nested_container()->mutable_container_id()
+ ->CopyFrom(childContainerId);
+
+ Future<http::Response> response = http::post(
+ slave.get()->pid,
+ "api/v1",
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL),
+ serialize(contentType, call),
+ stringify(contentType));
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response);
+ }
+
+ // Wait for the parent container.
+ Future<v1::agent::Response> waitParent;
{
v1::agent::Call call;
call.set_type(v1::agent::Call::WAIT_NESTED_CONTAINER);
call.mutable_wait_nested_container()->mutable_container_id()
- ->CopyFrom(containerId);
+ ->CopyFrom(parentContainerId);
- wait = post(slave.get()->pid, call, contentType);
+ waitParent = post(slave.get()->pid, call, contentType);
Clock::settle();
- EXPECT_TRUE(wait.isPending());
+ EXPECT_TRUE(waitParent.isPending());
}
- // Now kill the nested container.
+ // Wait for the child container.
+ Future<v1::agent::Response> waitChild;
+
+ {
+ v1::agent::Call call;
+ call.set_type(v1::agent::Call::WAIT_NESTED_CONTAINER);
+
+ call.mutable_wait_nested_container()->mutable_container_id()
+ ->CopyFrom(childContainerId);
+
+ waitChild = post(slave.get()->pid, call, contentType);
+
+ Clock::settle();
+
+ EXPECT_TRUE(waitChild.isPending());
+ }
+
+ // Kill the child container.
{
v1::agent::Call call;
call.set_type(v1::agent::Call::KILL_NESTED_CONTAINER);
call.mutable_kill_nested_container()->mutable_container_id()
- ->CopyFrom(containerId);
+ ->CopyFrom(childContainerId);
Future<http::Response> response = http::post(
slave.get()->pid,
@@ -3757,11 +3877,38 @@ TEST_P_TEMP_DISABLED_ON_WINDOWS(AgentAPITest, NestedContainerLaunch)
AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response);
}
- AWAIT_READY(wait);
- ASSERT_EQ(v1::agent::Response::WAIT_NESTED_CONTAINER, wait->type());
+ AWAIT_READY(waitChild);
+ ASSERT_EQ(v1::agent::Response::WAIT_NESTED_CONTAINER, waitChild->type());
// The test containerizer sets exit status to 0 when destroyed.
- EXPECT_EQ(0, wait->wait_nested_container().exit_status());
+ EXPECT_EQ(0, waitChild->wait_nested_container().exit_status());
+
+ // The parent container should still be running.
+ EXPECT_TRUE(waitParent.isPending());
+
+ // Kill the parent container.
+ {
+ v1::agent::Call call;
+ call.set_type(v1::agent::Call::KILL_NESTED_CONTAINER);
+
+ call.mutable_kill_nested_container()->mutable_container_id()
+ ->CopyFrom(parentContainerId);
+
+ Future<http::Response> response = http::post(
+ slave.get()->pid,
+ "api/v1",
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL),
+ serialize(contentType, call),
+ stringify(contentType));
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response);
+ }
+
+ AWAIT_READY(waitParent);
+ ASSERT_EQ(v1::agent::Response::WAIT_NESTED_CONTAINER, waitParent->type());
+
+ // The test containerizer sets exit status to 0 when destroyed.
+ EXPECT_EQ(0, waitParent->wait_nested_container().exit_status());
EXPECT_CALL(exec, shutdown(_))
.Times(AtMost(1));