You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by qi...@apache.org on 2019/08/06 02:06:39 UTC

[mesos] 02/02: Added a test `ROOT_VETH_VerifyNestedContainerIPAfterReboot`.

This is an automated email from the ASF dual-hosted git repository.

qianzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git

commit e443026c608f842e6dc29ba3cc78c69ce4272779
Author: Qian Zhang <zh...@gmail.com>
AuthorDate: Sat Aug 3 10:44:28 2019 +0800

    Added a test `ROOT_VETH_VerifyNestedContainerIPAfterReboot`.
    
    Review: https://reviews.apache.org/r/71235
---
 src/tests/containerizer/cni_isolator_tests.cpp | 165 +++++++++++++++++++++++++
 1 file changed, 165 insertions(+)

diff --git a/src/tests/containerizer/cni_isolator_tests.cpp b/src/tests/containerizer/cni_isolator_tests.cpp
index 0fc664b..ad8239b 100644
--- a/src/tests/containerizer/cni_isolator_tests.cpp
+++ b/src/tests/containerizer/cni_isolator_tests.cpp
@@ -2763,6 +2763,171 @@ TEST_F(CniIsolatorTest, ROOT_CleanupAfterReboot)
   ASSERT_TRUE(os::exists(cniDeleteSignalFile));
 }
 
+
+// This test verifies that after agent recover the task status update still
+// contains the correct IP address. This is a regression test for MESOS-9868.
+TEST_F(CniIsolatorTest, ROOT_VETH_VerifyNestedContainerIPAfterReboot)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "network/cni";
+  flags.network_cni_plugins_dir = cniPluginDir;
+  flags.network_cni_config_dir = cniConfigDir;
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  // Start the slave with a static process ID. This allows the executor to
+  // reconnect with the slave upon a process restart.
+  const string id("agent");
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), id, flags);
+  ASSERT_SOME(slave);
+
+  auto scheduler = std::make_shared<v1::MockHTTPScheduler>();
+
+  // Start the framework with the task killing capability.
+  v1::FrameworkInfo::Capability capability;
+  capability.set_type(v1::FrameworkInfo::Capability::TASK_KILLING_STATE);
+
+  v1::FrameworkInfo frameworkInfo = v1::DEFAULT_FRAMEWORK_INFO;
+  frameworkInfo.set_checkpoint(true);
+  frameworkInfo.add_capabilities()->CopyFrom(capability);
+
+  EXPECT_CALL(*scheduler, connected(_))
+    .WillOnce(v1::scheduler::SendSubscribe(frameworkInfo));
+
+  Future<v1::scheduler::Event::Subscribed> subscribed;
+  EXPECT_CALL(*scheduler, subscribed(_, _))
+    .WillOnce(FutureArg<1>(&subscribed));
+
+  Future<v1::scheduler::Event::Offers> offers;
+  EXPECT_CALL(*scheduler, offers(_, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return());
+
+  EXPECT_CALL(*scheduler, heartbeat(_))
+    .WillRepeatedly(Return()); // Ignore heartbeats.
+
+  v1::scheduler::TestMesos mesos(
+      master.get()->pid, ContentType::PROTOBUF, scheduler);
+
+  AWAIT_READY(subscribed);
+  v1::FrameworkID frameworkId(subscribed->framework_id());
+
+  v1::ExecutorInfo executorInfo = v1::createExecutorInfo(
+      "test_default_executor",
+      None(),
+      "cpus:0.1;mem:32;disk:32",
+      v1::ExecutorInfo::DEFAULT);
+
+  // Update `executorInfo` with the subscribed `frameworkId`.
+  executorInfo.mutable_framework_id()->CopyFrom(frameworkId);
+
+  mesos::v1::ContainerInfo *container = executorInfo.mutable_container();
+  container->set_type(mesos::v1::ContainerInfo::MESOS);
+
+  // Make sure the container joins the mock CNI network.
+  container->add_network_infos()->set_name("veth");
+
+  AWAIT_READY(offers);
+  ASSERT_FALSE(offers->offers().empty());
+
+  const v1::Offer& offer = offers->offers(0);
+  const v1::AgentID& agentId = offer.agent_id();
+
+  v1::TaskInfo taskInfo = v1::createTask(
+      agentId,
+      v1::Resources::parse("cpus:0.1;mem:32;disk:32").get(),
+      "sleep 1000");
+
+  Future<Event::Update> updateStarting;
+  Future<Event::Update> updateRunning;
+  EXPECT_CALL(*scheduler, update(_, _))
+    .WillOnce(DoAll(FutureArg<1>(&updateStarting),
+                    v1::scheduler::SendAcknowledge(
+                        frameworkId,
+                        offer.agent_id())))
+    .WillOnce(DoAll(FutureArg<1>(&updateRunning),
+                    v1::scheduler::SendAcknowledge(
+                        frameworkId,
+                        offer.agent_id())));
+
+  Future<Nothing> ackStarting =
+    FUTURE_DISPATCH(_, &Slave::_statusUpdateAcknowledgement);
+
+  Future<Nothing> ackRunning =
+    FUTURE_DISPATCH(_, &Slave::_statusUpdateAcknowledgement);
+
+  v1::Offer::Operation launchGroup = v1::LAUNCH_GROUP(
+      executorInfo,
+      v1::createTaskGroupInfo({taskInfo}));
+
+  mesos.send(v1::createCallAccept(frameworkId, offer, {launchGroup}));
+
+  AWAIT_READY(updateStarting);
+  ASSERT_EQ(v1::TASK_STARTING, updateStarting->status().state());
+  EXPECT_EQ(taskInfo.task_id(), updateStarting->status().task_id());
+
+  AWAIT_READY(ackStarting);
+
+  AWAIT_READY(updateRunning);
+  ASSERT_EQ(v1::TASK_RUNNING, updateRunning->status().state());
+  EXPECT_EQ(taskInfo.task_id(), updateRunning->status().task_id());
+
+  AWAIT_READY(ackRunning);
+
+  // Stop the slave after TASK_RUNNING is received.
+  slave.get()->terminate();
+  slave->reset();
+
+  Future<SlaveReregisteredMessage> slaveReregisteredMessage =
+    FUTURE_PROTOBUF(SlaveReregisteredMessage(), _, _);
+
+  // Restart the slave.
+  slave = StartSlave(detector.get(), id, flags);
+  ASSERT_SOME(slave);
+
+  // Wait for the slave to reregister.
+  AWAIT_READY(slaveReregisteredMessage);
+
+  Future<Event::Update> updateKilling;
+  Future<Event::Update> updateKilled;
+  EXPECT_CALL(*scheduler, update(_, _))
+    .WillOnce(DoAll(FutureArg<1>(&updateKilling),
+                    v1::scheduler::SendAcknowledge(
+                        frameworkId,
+                        offer.agent_id())))
+    .WillOnce(DoAll(FutureArg<1>(&updateKilled),
+                    v1::scheduler::SendAcknowledge(
+                        frameworkId,
+                        offer.agent_id())));
+
+  // Kill the task.
+  mesos.send(v1::createCallKill(frameworkId, taskInfo.task_id()));
+
+  AWAIT_READY(updateKilling);
+  ASSERT_EQ(v1::TASK_KILLING, updateKilling->status().state());
+  ASSERT_EQ(taskInfo.task_id(), updateKilling->status().task_id());
+  ASSERT_TRUE(updateKilling->status().has_container_status());
+  ASSERT_EQ(updateKilling->status().container_status().network_infos_size(), 1);
+
+  const mesos::v1::NetworkInfo networkInfo =
+    updateKilling->status().container_status().network_infos(0);
+
+  ASSERT_EQ(networkInfo.ip_addresses_size(), 1);
+
+  // Check the IP address in the task status update is from
+  // the mock CNI network.
+  ASSERT_TRUE(strings::startsWith(
+      networkInfo.ip_addresses(0).ip_address(), "203.0.113"));
+
+  AWAIT_READY(updateKilled);
+  ASSERT_EQ(v1::TASK_KILLED, updateKilled->status().state());
+  ASSERT_EQ(taskInfo.task_id(), updateKilled->status().task_id());
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {