You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2017/08/04 23:01:02 UTC

[3/3] mesos git commit: Made the capabilities isolator work with nested containers.

Made the capabilities isolator work with nested containers.

Make the capabilities isolator support nesting. Without this patch
capabilities sets for tasks launched by the DefaultExecutor are silently
ignored.

Review: https://reviews.apache.org/r/61394/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/50a553dd
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/50a553dd
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/50a553dd

Branch: refs/heads/master
Commit: 50a553dd10a2adbf653d5ad751723294a14720a8
Parents: cbb2262
Author: Gastón Kleiman <ga...@mesosphere.io>
Authored: Fri Aug 4 15:51:27 2017 -0700
Committer: Jie Yu <yu...@gmail.com>
Committed: Fri Aug 4 15:51:27 2017 -0700

----------------------------------------------------------------------
 .../mesos/isolators/linux/capabilities.cpp      |   6 +
 .../mesos/isolators/linux/capabilities.hpp      |   2 +
 .../linux_capabilities_isolator_tests.cpp       | 147 +++++++++++++++++++
 3 files changed, 155 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/50a553dd/src/slave/containerizer/mesos/isolators/linux/capabilities.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/linux/capabilities.cpp b/src/slave/containerizer/mesos/isolators/linux/capabilities.cpp
index f85a84d..21d851e 100644
--- a/src/slave/containerizer/mesos/isolators/linux/capabilities.cpp
+++ b/src/slave/containerizer/mesos/isolators/linux/capabilities.cpp
@@ -74,6 +74,12 @@ Try<Isolator*> LinuxCapabilitiesIsolatorProcess::create(const Flags& flags)
 }
 
 
+bool LinuxCapabilitiesIsolatorProcess::supportsNesting()
+{
+  return true;
+}
+
+
 Future<Option<ContainerLaunchInfo>> LinuxCapabilitiesIsolatorProcess::prepare(
     const ContainerID& containerId,
     const ContainerConfig& containerConfig)

http://git-wip-us.apache.org/repos/asf/mesos/blob/50a553dd/src/slave/containerizer/mesos/isolators/linux/capabilities.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/linux/capabilities.hpp b/src/slave/containerizer/mesos/isolators/linux/capabilities.hpp
index c3afe20..b9862a2 100644
--- a/src/slave/containerizer/mesos/isolators/linux/capabilities.hpp
+++ b/src/slave/containerizer/mesos/isolators/linux/capabilities.hpp
@@ -32,6 +32,8 @@ class LinuxCapabilitiesIsolatorProcess : public MesosIsolatorProcess
 public:
   static Try<mesos::slave::Isolator*> create(const Flags& flags);
 
+  virtual bool supportsNesting();
+
   virtual process::Future<Option<mesos::slave::ContainerLaunchInfo>> prepare(
       const ContainerID& containerId,
       const mesos::slave::ContainerConfig& containerConfig);

http://git-wip-us.apache.org/repos/asf/mesos/blob/50a553dd/src/tests/containerizer/linux_capabilities_isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/containerizer/linux_capabilities_isolator_tests.cpp b/src/tests/containerizer/linux_capabilities_isolator_tests.cpp
index 8050876..6d95d60 100644
--- a/src/tests/containerizer/linux_capabilities_isolator_tests.cpp
+++ b/src/tests/containerizer/linux_capabilities_isolator_tests.cpp
@@ -41,6 +41,8 @@
 
 #include <mesos/master/detector.hpp>
 
+#include <mesos/resources.hpp>
+
 #include "linux/capabilities.hpp"
 
 #include "master/detector/standalone.hpp"
@@ -328,6 +330,151 @@ TEST_P(LinuxCapabilitiesIsolatorTest, ROOT_Ping)
 }
 
 
+// Parameterized test confirming the behavior of the capabilities
+// isolator with nested containers. We here use the fact has `ping`
+// has `NET_RAW` and `NET_ADMIN` in its file capabilities. This test
+// should be instantiated with above `TestParam` struct.
+TEST_P(LinuxCapabilitiesIsolatorTest, ROOT_NestedPing)
+{
+  Try<Owned<cluster::Master>> master = StartMaster();
+  ASSERT_SOME(master);
+
+  slave::Flags flags = CreateSlaveFlags();
+  flags.isolation = "linux/capabilities";
+  flags.effective_capabilities = param.operator_effective;
+  flags.bounding_capabilities = param.operator_bounding;
+
+#ifndef USE_SSL_SOCKET
+  // Disable operator API authentication for the default executor. Executor
+  // authentication currently has SSL as a dependency, so we cannot require
+  // executors to authenticate with the agent operator API if Mesos was not
+  // built with SSL support.
+  flags.authenticate_http_readwrite = false;
+#endif // USE_SSL_SOCKET
+
+  if (param.useImage == TestParam::WITH_IMAGE) {
+    const string registry = path::join(sandbox.get(), "registry");
+    AWAIT_READY(DockerArchive::create(registry, "test_image"));
+
+    flags.docker_registry = registry;
+    flags.docker_store_dir = path::join(os::getcwd(), "store");
+    flags.image_providers = "docker";
+    flags.isolation += ",docker/runtime,filesystem/linux";
+  }
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), flags);
+  ASSERT_SOME(slave);
+
+  MockScheduler sched;
+
+  MesosSchedulerDriver driver(
+      &sched,
+      DEFAULT_FRAMEWORK_INFO,
+      master.get()->pid,
+      DEFAULT_CREDENTIAL);
+
+  Future<FrameworkID> frameworkId;
+  EXPECT_CALL(sched, registered(&driver, _, _))
+    .WillOnce(FutureArg<1>(&frameworkId));
+
+  Future<vector<Offer>> offers;
+
+  EXPECT_CALL(sched, resourceOffers(_, _))
+    .WillOnce(FutureArg<1>(&offers))
+    .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+  driver.start();
+
+  AWAIT_READY(frameworkId);
+
+  AWAIT_READY(offers);
+  ASSERT_NE(0u, offers->size());
+
+  Resources resources = Resources::parse("cpus:0.1;mem:32;disk:32").get();
+
+  ExecutorInfo executorInfo;
+  executorInfo.set_type(ExecutorInfo::DEFAULT);
+  executorInfo.mutable_executor_id()->CopyFrom(DEFAULT_EXECUTOR_ID);
+  executorInfo.mutable_framework_id()->CopyFrom(frameworkId.get());
+  executorInfo.mutable_resources()->CopyFrom(resources);
+
+  const Offer& offer = offers->front();
+  const SlaveID& slaveId = offer.slave_id();
+
+  // We use 'ping' as the command since it has file capabilities
+  // (`NET_RAW` and `NET_ADMIN` in permitted set). This allows us to
+  // test if capabilities are properly set.
+  CommandInfo command;
+  command.set_shell(false);
+  command.set_value("/bin/ping");
+  command.add_arguments("ping");
+  command.add_arguments("-c");
+  command.add_arguments("1");
+  command.add_arguments("127.0.0.1");
+
+  TaskInfo task = createTask(slaveId, resources, command);
+
+  if (param.framework_effective.isSome() ||
+      param.framework_bounding.isSome()) {
+    ContainerInfo* container = task.mutable_container();
+    container->set_type(ContainerInfo::MESOS);
+
+    LinuxInfo* linux = container->mutable_linux_info();
+
+    if (param.framework_effective.isSome()) {
+      CapabilityInfo* capabilities = linux->mutable_effective_capabilities();
+      capabilities->CopyFrom(param.framework_effective.get());
+    }
+
+    if (param.framework_bounding.isSome()) {
+      CapabilityInfo* capabilities = linux->mutable_bounding_capabilities();
+      capabilities->CopyFrom(param.framework_bounding.get());
+    }
+  }
+
+  if (param.useImage == TestParam::WITH_IMAGE) {
+    ContainerInfo* container = task.mutable_container();
+    container->set_type(ContainerInfo::MESOS);
+
+    Image* image = container->mutable_mesos()->mutable_image();
+    image->set_type(Image::DOCKER);
+    image->mutable_docker()->set_name("test_image");
+  }
+
+  Queue<TaskStatus> statuses;
+  EXPECT_CALL(sched, statusUpdate(_, _))
+    .WillRepeatedly(PushTaskStatus<1>(&statuses));
+
+  TaskGroupInfo taskGroup = createTaskGroupInfo({task});
+
+  driver.acceptOffers({offer.id()}, {LAUNCH_GROUP(executorInfo, taskGroup)});
+
+  // Wait for the terminal status update.
+  for (;;) {
+    Future<TaskStatus> status = statuses.get();
+    AWAIT_READY(status);
+
+    TaskState state = status->state();
+    if (protobuf::isTerminalState(state)) {
+      switch (param.result) {
+        case TestParam::SUCCESS:
+          EXPECT_EQ(TASK_FINISHED, state) << status->DebugString();
+          break;
+        case TestParam::FAILURE:
+          EXPECT_EQ(TASK_FAILED, state) << status->DebugString();
+          break;
+      }
+      break;
+    }
+  }
+
+  driver.stop();
+  driver.join();
+}
+
+
 // TODO(jieyu): We used DAC_READ_SEARCH capability below so that test
 // results won't be affected even if the executable (e.g., command
 // executor) to launch is not accessible (e.g., under someone's home