Repository: mesos
Updated Branches:
  refs/heads/master 51da8c4bf -> 74c61ceba


Combined Mesos containerizer's launch methods.

This simplifies the container launch path by removing combining
the nested and non-nested container code paths into one.

The Mesos containerizer was originally translating the two
`containerizer->launch` entrypoints into a common method (also
called `launch`).  The previous commits moved this translation
logic into the caller (i.e. the Agent).

The end result has some slight changes:
  * It is now possible for the Agent to specify some more combinations
    of `ContainerConfig`.  For example, specifying a TaskInfo with
    a DEBUG-class container.  Or a nested container with Resources.
    We may need to add extra validation around this.
  * The `bool checkpoint` argument was replaced with a `Option<string>`
    which optionally contains an absolute path.  This allows us to
    remove the `SlaveID` field.

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


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

Branch: refs/heads/master
Commit: 17ffb97ae7eda78edf85b204eba35bc59649a479
Parents: af21bb7
Author: Joseph Wu <josep...@apache.org>
Authored: Mon Apr 10 17:20:46 2017 -0700
Committer: Joseph Wu <josep...@apache.org>
Committed: Thu May 25 18:37:06 2017 -0700

----------------------------------------------------------------------
 src/slave/containerizer/mesos/containerizer.cpp | 354 ++++++-------------
 src/slave/containerizer/mesos/containerizer.hpp |  45 +--
 2 files changed, 111 insertions(+), 288 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/17ffb97a/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp 
b/src/slave/containerizer/mesos/containerizer.cpp
index 199202a..f3e6210 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -493,63 +493,16 @@ Future<Nothing> MesosContainerizer::recover(
 
 Future<bool> MesosContainerizer::launch(
     const ContainerID& containerId,
-    const Option<TaskInfo>& taskInfo,
-    const ExecutorInfo& executorInfo,
-    const string& directory,
-    const Option<string>& user,
-    const SlaveID& slaveId,
+    const ContainerConfig& containerConfig,
     const map<string, string>& environment,
-    bool checkpoint)
+    const Option<std::string>& pidCheckpointPath)
 {
-  // Need to disambiguate for the compiler.
-  Future<bool> (MesosContainerizerProcess::*launch)(
-      const ContainerID&,
-      const Option<TaskInfo>&,
-      const ExecutorInfo&,
-      const string&,
-      const Option<string>&,
-      const SlaveID&,
-      const map<string, string>&,
-      bool) = &MesosContainerizerProcess::launch;
-
   return dispatch(process.get(),
-                  launch,
+                  &MesosContainerizerProcess::launch,
                   containerId,
-                  taskInfo,
-                  executorInfo,
-                  directory,
-                  user,
-                  slaveId,
+                  containerConfig,
                   environment,
-                  checkpoint);
-}
-
-
-Future<bool> MesosContainerizer::launch(
-    const ContainerID& containerId,
-    const CommandInfo& commandInfo,
-    const Option<ContainerInfo>& containerInfo,
-    const Option<string>& user,
-    const SlaveID& slaveId,
-    const Option<ContainerClass>& containerClass)
-{
-  // Need to disambiguate for the compiler.
-  Future<bool> (MesosContainerizerProcess::*launch)(
-      const ContainerID&,
-      const CommandInfo&,
-      const Option<ContainerInfo>&,
-      const Option<string>&,
-      const SlaveID&,
-      const Option<ContainerClass>&) = &MesosContainerizerProcess::launch;
-
-  return dispatch(process.get(),
-                  launch,
-                  containerId,
-                  commandInfo,
-                  containerInfo,
-                  user,
-                  slaveId,
-                  containerClass);
+                  pidCheckpointPath);
 }
 
 
@@ -991,99 +944,117 @@ Future<Nothing> MesosContainerizerProcess::__recover(
 }
 
 
-// Launching an executor involves the following steps:
+// Launching an container involves the following steps:
 // 1. Call prepare on each isolator.
-// 2. Fork the executor. The forked child is blocked from exec'ing until it has
-//    been isolated.
-// 3. Isolate the executor. Call isolate with the pid for each isolator.
-// 4. Fetch the executor.
-// 5. Exec the executor. The forked child is signalled to continue. It will
-//    first execute any preparation commands from isolators and then exec the
-//    executor.
+// 2. Fork a helper process. The forked helper is blocked from exec'ing
+//    until it has been isolated.
+// 3. Isolate the helper's pid; e.g. call `isolate` for each isolator.
+// 4. Fetch any URIs.
+// 5. Signal the helper process to continue. It will first execute any
+//    preparation commands from isolators and then exec the starting command.
 Future<bool> MesosContainerizerProcess::launch(
     const ContainerID& containerId,
-    const Option<TaskInfo>& taskInfo,
-    const ExecutorInfo& _executorInfo,
-    const string& directory,
-    const Option<string>& user,
-    const SlaveID& slaveId,
+    const ContainerConfig& _containerConfig,
     const map<string, string>& environment,
-    bool checkpoint)
+    const Option<std::string>& pidCheckpointPath)
 {
-  CHECK(!containerId.has_parent());
-
   if (containers_.contains(containerId)) {
-    return Failure("Container already started");
+    return Failure(
+        (containerId.has_parent() ? "Nested container" : "Container") +
+        stringify(containerId) + " already started");
   }
 
-  if (taskInfo.isSome() &&
-      taskInfo.get().has_container() &&
-      taskInfo.get().container().type() != ContainerInfo::MESOS) {
+  if (_containerConfig.has_container_info() &&
+      _containerConfig.container_info().type() != ContainerInfo::MESOS) {
     return false;
   }
 
-  // NOTE: We make a copy of the executor info because we may mutate
-  // it with default container info.
-  ExecutorInfo executorInfo = _executorInfo;
+  // NOTE: We make a copy of the ContainerConfig because we may need
+  // to modify it based on the parent container (for nested containers).
+  ContainerConfig containerConfig = _containerConfig;
 
-  if (executorInfo.has_container() &&
-      executorInfo.container().type() != ContainerInfo::MESOS) {
-    return false;
-  }
+  // For nested containers, we must perform some extra validation
+  // (i.e. does the parent exist?) and create the sandbox directory
+  // based on the parent's sandbox.
+  if (containerId.has_parent()) {
+    if (containerConfig.has_task_info() ||
+        containerConfig.has_executor_info()) {
+      return Failure(
+          "Nested containers may not supply a TaskInfo/ExecutorInfo");
+    }
 
-  // Add the default container info to the executor info.
-  // TODO(jieyu): Rename the flag to be default_mesos_container_info.
-  if (!executorInfo.has_container() &&
-      flags.default_container_info.isSome()) {
-    executorInfo.mutable_container()->CopyFrom(
-        flags.default_container_info.get());
-  }
+    if (pidCheckpointPath.isSome()) {
+      return Failure("Nested containers may not be checkpointed");
+    }
 
-  LOG(INFO) << "Starting container " << containerId
-            << " for executor '" << executorInfo.executor_id()
-            << "' of framework " << executorInfo.framework_id();
+    const ContainerID& parentContainerId = containerId.parent();
 
-  ContainerConfig containerConfig;
-  containerConfig.mutable_executor_info()->CopyFrom(executorInfo);
-  containerConfig.mutable_command_info()->CopyFrom(executorInfo.command());
-  containerConfig.mutable_resources()->CopyFrom(executorInfo.resources());
-  containerConfig.set_directory(directory);
+    if (!containers_.contains(parentContainerId)) {
+      return Failure(
+          "Parent container " + stringify(parentContainerId) +
+          " does not exist");
+    }
 
-  if (user.isSome()) {
-    containerConfig.set_user(user.get());
-  }
+    if (containers_[parentContainerId]->state == DESTROYING) {
+      return Failure(
+          "Parent container " + stringify(parentContainerId) +
+          " is in 'DESTROYING' state");
+    }
 
-  if (taskInfo.isSome()) {
-    // Command task case.
-    containerConfig.mutable_task_info()->CopyFrom(taskInfo.get());
+    const ContainerID rootContainerId =
+      protobuf::getRootContainerId(containerId);
 
-    if (taskInfo->has_container()) {
-      ContainerInfo* containerInfo = containerConfig.mutable_container_info();
-      containerInfo->CopyFrom(taskInfo->container());
+    CHECK(containers_.contains(rootContainerId));
+    if (containers_[rootContainerId]->directory.isNone()) {
+      return Failure(
+          "Unexpected empty sandbox directory for root container " +
+          stringify(rootContainerId));
     }
-  } else {
-    // Other cases.
-    if (executorInfo.has_container()) {
-      ContainerInfo* containerInfo = containerConfig.mutable_container_info();
-      containerInfo->CopyFrom(executorInfo.container());
+
+    const string directory = containerizer::paths::getSandboxPath(
+        containers_[rootContainerId]->directory.get(),
+        containerId);
+
+    Try<Nothing> mkdir = os::mkdir(directory);
+    if (mkdir.isError()) {
+      return Failure(
+          "Failed to create nested sandbox directory '" +
+          directory + "': " + mkdir.error());
     }
-  }
 
-  return launch(containerId,
-                containerConfig,
-                environment,
-                slaveId,
-                checkpoint);
-}
+#ifndef __WINDOWS__
+    if (containerConfig.has_user()) {
+      LOG(INFO) << "Trying to chown '" << directory << "' to user '"
+                << containerConfig.user() << "'";
+
+      Try<Nothing> chown = os::chown(containerConfig.user(), directory);
+      if (chown.isError()) {
+        LOG(WARNING)
+          << "Failed to chown sandbox directory '" << directory
+          << "'. This may be due to attempting to run the container "
+          << "as a nonexistent user on the agent; see the description"
+          << " for the `--switch_user` flag for more information: "
+          << chown.error();
+      }
+    }
+#endif // __WINDOWS__
 
+    // Modify the sandbox directory in the ContainerConfig.
+    // TODO(josephw): Should we validate that this value
+    // is not set for nested containers?
+    containerConfig.set_directory(directory);
+
+    // TODO(jieyu): This is currently best effort. After the agent fails
+    // over, 'executor_info' won't be set in root parent container's
+    // 'config'. Consider populating 'executor_info' in recover path.
+    if (containers_[rootContainerId]->config.has_executor_info()) {
+      containerConfig.mutable_executor_info()->CopyFrom(
+          containers_[rootContainerId]->config.executor_info());
+    }
+  }
+
+  LOG(INFO) << "Starting container " << containerId;
 
-Future<bool> MesosContainerizerProcess::launch(
-    const ContainerID& containerId,
-    const ContainerConfig& containerConfig,
-    const map<string, string>& environment,
-    const SlaveID& slaveId,
-    bool checkpoint)
-{
   // Before we launch the container, we first create the container
   // runtime directory to hold internal checkpoint information about
   // the container.
@@ -1146,8 +1117,7 @@ Future<bool> MesosContainerizerProcess::launch(
                   containerId,
                   lambda::_1,
                   environment,
-                  slaveId,
-                  checkpoint));
+                  pidCheckpointPath));
   }
 
   container->provisioning = provisioner->provision(
@@ -1166,8 +1136,7 @@ Future<bool> MesosContainerizerProcess::launch(
                     containerId,
                     lambda::_1,
                     environment,
-                    slaveId,
-                    checkpoint));
+                    pidCheckpointPath));
     }));
 }
 
@@ -1251,8 +1220,7 @@ Future<Nothing> MesosContainerizerProcess::prepare(
 
 
 Future<Nothing> MesosContainerizerProcess::fetch(
-    const ContainerID& containerId,
-    const SlaveID& slaveId)
+    const ContainerID& containerId)
 {
   if (!containers_.contains(containerId)) {
     return Failure("Container destroyed during isolating");
@@ -1270,18 +1238,13 @@ Future<Nothing> MesosContainerizerProcess::fetch(
 
   const string directory = container->config.directory();
 
-  Option<string> user;
-  if (container->config.has_user()) {
-    user = container->config.user();
-  }
-
   return fetcher->fetch(
       containerId,
       container->config.command_info(),
       directory,
-      user,
-      slaveId,
-      flags)
+      container->config.has_user()
+        ? container->config.user()
+        : Option<string>::none())
     .then([=]() -> Future<Nothing> {
       if (HookManager::hooksAvailable()) {
         HookManager::slavePostFetchHook(containerId, directory);
@@ -1295,8 +1258,7 @@ Future<bool> MesosContainerizerProcess::_launch(
     const ContainerID& containerId,
     const Option<ContainerIO>& containerIO,
     const map<string, string>& environment,
-    const SlaveID& slaveId,
-    bool checkpoint)
+    const Option<std::string>& pidCheckpointPath)
 {
   if (!containers_.contains(containerId)) {
     return Failure("Container destroyed during preparing");
@@ -1756,23 +1718,16 @@ Future<bool> MesosContainerizerProcess::_launch(
   container->pid = pid;
 
   // Checkpoint the forked pid if requested by the agent.
-  if (checkpoint) {
-    const string& path = slave::paths::getForkedPidPath(
-        slave::paths::getMetaRootDir(flags.work_dir),
-        slaveId,
-        container->config.executor_info().framework_id(),
-        container->config.executor_info().executor_id(),
-        containerId);
-
+  if (pidCheckpointPath.isSome()) {
     LOG(INFO) << "Checkpointing container's forked pid " << pid
-              << " to '" << path << "'";
+              << " to '" << pidCheckpointPath.get() << "'";
 
     Try<Nothing> checkpointed =
-      slave::state::checkpoint(path, stringify(pid));
+      slave::state::checkpoint(pidCheckpointPath.get(), stringify(pid));
 
     if (checkpointed.isError()) {
       LOG(ERROR) << "Failed to checkpoint container's forked pid to '"
-                 << path << "': " << checkpointed.error();
+                 << pidCheckpointPath.get() << "': " << checkpointed.error();
 
       return Failure("Could not checkpoint container's pid");
     }
@@ -1809,8 +1764,7 @@ Future<bool> MesosContainerizerProcess::_launch(
   return isolate(containerId, pid)
     .then(defer(self(),
                 &Self::fetch,
-                containerId,
-                slaveId))
+                containerId))
     .then(defer(self(), &Self::exec, containerId, pipes[1]))
     .onAny([pipes]() { os::close(pipes[0]); })
     .onAny([pipes]() { os::close(pipes[1]); });
@@ -1903,104 +1857,6 @@ Future<bool> MesosContainerizerProcess::exec(
 }
 
 
-Future<bool> MesosContainerizerProcess::launch(
-    const ContainerID& containerId,
-    const CommandInfo& commandInfo,
-    const Option<ContainerInfo>& containerInfo,
-    const Option<string>& user,
-    const SlaveID& slaveId,
-    const Option<ContainerClass>& containerClass)
-{
-  CHECK(containerId.has_parent());
-
-  if (containers_.contains(containerId)) {
-    return Failure(
-        "Nested container " + stringify(containerId) + " already started");
-  }
-
-  const ContainerID& parentContainerId = containerId.parent();
-  if (!containers_.contains(parentContainerId)) {
-    return Failure(
-        "Parent container " + stringify(parentContainerId) +
-        " does not exist");
-  }
-
-  if (containers_[parentContainerId]->state == DESTROYING) {
-    return Failure(
-        "Parent container " + stringify(parentContainerId) +
-        " is in 'DESTROYING' state");
-  }
-
-  LOG(INFO) << "Starting nested container " << containerId;
-
-  const ContainerID rootContainerId = 
protobuf::getRootContainerId(containerId);
-
-  CHECK(containers_.contains(rootContainerId));
-  if (containers_[rootContainerId]->directory.isNone()) {
-    return Failure(
-        "Unexpected empty sandbox directory for root container " +
-        stringify(rootContainerId));
-  }
-
-  const string directory = containerizer::paths::getSandboxPath(
-      containers_[rootContainerId]->directory.get(),
-      containerId);
-
-  Try<Nothing> mkdir = os::mkdir(directory);
-  if (mkdir.isError()) {
-    return Failure(
-        "Failed to create nested sandbox directory '" +
-        directory + "': " + mkdir.error());
-  }
-
-#ifndef __WINDOWS__
-  if (user.isSome()) {
-    LOG(INFO) << "Trying to chown '" << directory << "' to user '"
-              << user.get() << "'";
-
-    Try<Nothing> chown = os::chown(user.get(), directory);
-    if (chown.isError()) {
-      LOG(WARNING) << "Failed to chown sandbox directory '" << directory
-                   << "'. This may be due to attempting to run the container "
-                   << "as a nonexistent user on the agent; see the description"
-                   << " for the `--switch_user` flag for more information: "
-                   << chown.error();
-    }
-  }
-#endif // __WINDOWS__
-
-  ContainerConfig containerConfig;
-  containerConfig.mutable_command_info()->CopyFrom(commandInfo);
-  containerConfig.set_directory(directory);
-
-  if (user.isSome()) {
-    containerConfig.set_user(user.get());
-  }
-
-  if (containerInfo.isSome()) {
-    containerConfig.mutable_container_info()->CopyFrom(containerInfo.get());
-  }
-
-  if (containerClass.isSome()) {
-    containerConfig.set_container_class(containerClass.get());
-  }
-
-  // TODO(jieyu): This is currently best effort. After the agent fails
-  // over, 'executor_info' won't be set in root parent container's
-  // 'config'. Consider populating 'executor_info' in recover path.
-  if (containers_[rootContainerId]->config.has_executor_info()) {
-    containerConfig.mutable_executor_info()->CopyFrom(
-        containers_[rootContainerId]->config.executor_info());
-  }
-
-  return launch(containerId,
-                containerConfig,
-                map<string, string>(),
-                slaveId,
-                false);
-}
-
-
 Future<Connection> MesosContainerizerProcess::attach(
     const ContainerID& containerId)
 {

http://git-wip-us.apache.org/repos/asf/mesos/blob/17ffb97a/src/slave/containerizer/mesos/containerizer.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.hpp 
b/src/slave/containerizer/mesos/containerizer.hpp
index d767031..ea06919 100644
--- a/src/slave/containerizer/mesos/containerizer.hpp
+++ b/src/slave/containerizer/mesos/containerizer.hpp
@@ -80,21 +80,9 @@ public:
 
   virtual process::Future<bool> launch(
       const ContainerID& containerId,
-      const Option<TaskInfo>& taskInfo,
-      const ExecutorInfo& executorInfo,
-      const std::string& directory,
-      const Option<std::string>& user,
-      const SlaveID& slaveId,
+      const mesos::slave::ContainerConfig& containerConfig,
       const std::map<std::string, std::string>& environment,
-      bool checkpoint);
-
-  virtual process::Future<bool> launch(
-      const ContainerID& containerId,
-      const CommandInfo& commandInfo,
-      const Option<ContainerInfo>& containerInfo,
-      const Option<std::string>& user,
-      const SlaveID& slaveId,
-      const Option<mesos::slave::ContainerClass>& containerClass = None());
+      const Option<std::string>& pidCheckpointPath);
 
   virtual process::Future<process::http::Connection> attach(
       const ContainerID& containerId);
@@ -153,21 +141,9 @@ public:
 
   virtual process::Future<bool> launch(
       const ContainerID& containerId,
-      const Option<TaskInfo>& taskInfo,
-      const ExecutorInfo& executorInfo,
-      const std::string& directory,
-      const Option<std::string>& user,
-      const SlaveID& slaveId,
+      const mesos::slave::ContainerConfig& containerConfig,
       const std::map<std::string, std::string>& environment,
-      bool checkpoint);
-
-  virtual process::Future<bool> launch(
-      const ContainerID& containerId,
-      const CommandInfo& commandInfo,
-      const Option<ContainerInfo>& containerInfo,
-      const Option<std::string>& user,
-      const SlaveID& slaveId,
-      const Option<mesos::slave::ContainerClass>& containerClass);
+      const Option<std::string>& pidCheckpointPath);
 
   virtual process::Future<process::http::Connection> attach(
       const ContainerID& containerId);
@@ -230,22 +206,13 @@ private:
       const Option<ProvisionInfo>& provisionInfo);
 
   process::Future<Nothing> fetch(
-      const ContainerID& containerId,
-      const SlaveID& slaveId);
-
-  process::Future<bool> launch(
-      const ContainerID& containerId,
-      const mesos::slave::ContainerConfig& containerConfig,
-      const std::map<std::string, std::string>& environment,
-      const SlaveID& slaveId,
-      bool checkpoint);
+      const ContainerID& containerId);
 
   process::Future<bool> _launch(
       const ContainerID& containerId,
       const Option<mesos::slave::ContainerIO>& containerIO,
       const std::map<std::string, std::string>& environment,
-      const SlaveID& slaveId,
-      bool checkpoint);
+      const Option<std::string>& pidCheckpointPath);
 
   process::Future<bool> isolate(
       const ContainerID& containerId,

Reply via email to