Simplify docker container launch using docker 1.5+.

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

Branch: refs/heads/master
Commit: 0b5f67eee081df3fe86e1cda140c436752944e64
Parents: 58963ab
Author: Timothy Chen <[email protected]>
Authored: Fri Apr 10 16:03:30 2015 -0700
Committer: Timothy Chen <[email protected]>
Committed: Sun May 24 22:27:40 2015 -0700

----------------------------------------------------------------------
 src/docker/executor.cpp                  |   2 +-
 src/slave/containerizer/docker.cpp       | 450 +++++++++-----------------
 src/slave/containerizer/docker.hpp       |  70 ++--
 src/tests/docker_containerizer_tests.cpp |   4 -
 4 files changed, 183 insertions(+), 343 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/0b5f67ee/src/docker/executor.cpp
----------------------------------------------------------------------
diff --git a/src/docker/executor.cpp b/src/docker/executor.cpp
index fda7b2a..847997b 100644
--- a/src/docker/executor.cpp
+++ b/src/docker/executor.cpp
@@ -126,7 +126,7 @@ public:
         container,
         sandboxDirectory,
         mappedDirectory,
-        task.resources(),
+        task.resources() + task.executor().resources(),
         None(),
         false);
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/0b5f67ee/src/slave/containerizer/docker.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/docker.cpp 
b/src/slave/containerizer/docker.cpp
index 5bce2ce..952d3eb 100644
--- a/src/slave/containerizer/docker.cpp
+++ b/src/slave/containerizer/docker.cpp
@@ -120,28 +120,6 @@ Option<ContainerID> parse(const Docker::Container& 
container)
 }
 
 
-// Launches a docker wait process on given container name.
-// Returns the wait process pid.
-Try<pid_t> launchWaitProcess(const string& docker, const string& name)
-{
-  string command = "exit `" + docker + " wait " + name + "`";
-
-  VLOG(1) << "Launching wait process: " << command;
-
-  Try<Subprocess> wait = subprocess(
-      command,
-      Subprocess::PATH("/dev/null"),
-      Subprocess::PATH("/dev/null"),
-      Subprocess::PATH("/dev/null"));
-
-  if (wait.isError()) {
-    return Error("Unable to launch docker wait on executor: " + wait.error());
-  }
-
-  return wait.get().pid();
-}
-
-
 Try<DockerContainerizer*> DockerContainerizer::create(
     const Flags& flags,
     Fetcher* fetcher)
@@ -151,10 +129,26 @@ Try<DockerContainerizer*> DockerContainerizer::create(
     return Error(docker.error());
   }
 
-  return new DockerContainerizer(
-      flags,
-      fetcher,
-      Shared<Docker>(docker.get()));
+  Shared<Docker> docker_(docker.get());
+
+  if (flags.docker_mesos_image.isSome()) {
+    Future<Version> version = docker_->version();
+    if (!version.await(Seconds(5))) {
+      return Error("Timed out waiting for docker version");
+    }
+
+    if (version.isFailed()) {
+      return Error(version.failure());
+    }
+
+    if (version.get() < Version(1, 5, 0)) {
+      string message = "Docker with mesos images requires docker 1.5+, found ";
+      message += stringify(version.get());
+      return Error(message);
+    }
+  }
+
+  return new DockerContainerizer(flags, fetcher, docker_);
 }
 
 
@@ -183,6 +177,20 @@ DockerContainerizer::~DockerContainerizer()
 }
 
 
+string dockerExecutorCommand(
+    const Flags& flags,
+    const string directory,
+    const string container)
+{
+  string command = "mesos-docker-executor --docker=" + flags.docker +
+                   " --container=" + container +
+                   " --sandbox_directory=" + directory +
+                   " --mapped_directory=" + flags.docker_sandbox_directory;
+
+  return path::join(flags.launcher_dir, command);
+}
+
+
 Try<DockerContainerizerProcess::Container*>
 DockerContainerizerProcess::Container::create(
     const ContainerID& id,
@@ -246,7 +254,7 @@ DockerContainerizerProcess::Container::create(
     symlinked = true;
   }
 
-  return new Container(
+  Container* container = new Container(
       id,
       taskInfo,
       executorInfo,
@@ -257,6 +265,51 @@ DockerContainerizerProcess::Container::create(
       checkpoint,
       symlinked,
       flags);
+
+  if (taskInfo.isSome() && flags.docker_mesos_image.isSome()) {
+    // Override the container and command to launch an executor
+    // in a docker container.
+    ContainerInfo containerInfo;
+
+    // Mounting in the docker socket so the executor can communicate to
+    // the host docker daemon. We are assuming the current instance is
+    // launching docker containers to the host daemon as well.
+    Volume* dockerSockVolume = containerInfo.add_volumes();
+    dockerSockVolume->set_host_path(flags.docker_socket);
+    dockerSockVolume->set_container_path(flags.docker_socket);
+    dockerSockVolume->set_mode(Volume::RO);
+
+    // Mounting in sandbox so the logs from the executor can be
+    // persisted over container failures.
+    Volume* sandboxVolume = containerInfo.add_volumes();
+    sandboxVolume->set_host_path(containerWorkdir);
+    sandboxVolume->set_container_path(containerWorkdir);
+    sandboxVolume->set_mode(Volume::RW);
+
+    ContainerInfo::DockerInfo dockerInfo;
+    dockerInfo.set_image(flags.docker_mesos_image.get());
+
+    containerInfo.mutable_docker()->CopyFrom(dockerInfo);
+
+    const string& command = dockerExecutorCommand(
+        flags, containerWorkdir, container->name());
+
+    CommandInfo commandInfo;
+    commandInfo.set_value(command);
+    commandInfo.set_shell(true);
+
+    container->overrideContainer = containerInfo;
+    container->overrideCommand = commandInfo;
+    container->overrideEnvironment = executorEnvironment(
+        executorInfo,
+        containerWorkdir,
+        slaveId,
+        slavePid,
+        checkpoint,
+        flags.recovery_timeout);
+  }
+
+  return container;
 }
 
 
@@ -345,6 +398,7 @@ Future<bool> DockerContainerizer::launch(
       process.get(),
       &DockerContainerizerProcess::launch,
       containerId,
+      None(),
       executorInfo,
       directory,
       user,
@@ -473,7 +527,7 @@ Future<Nothing> DockerContainerizerProcess::recover(
       .then(defer(self(), &Self::_recover, state.get(), lambda::_1));
   }
 
-return Nothing();
+  return Nothing();
 }
 
 
@@ -502,7 +556,7 @@ Future<Nothing> DockerContainerizerProcess::_recover(
   // detect very unlikely duplicate scenario (see below).
   hashmap<ContainerID, pid_t> pids;
 
-  foreachvalue (const FrameworkState& framework, state.get().frameworks) {
+  foreachvalue (const FrameworkState& framework, state.frameworks) {
     foreachvalue (const ExecutorState& executor, framework.executors) {
       if (executor.info.isNone()) {
         LOG(WARNING) << "Skipping recovery of executor '" << executor.id
@@ -567,7 +621,7 @@ Future<Nothing> DockerContainerizerProcess::_recover(
       // Create and store a container.
       Container* container = new Container(containerId);
       containers_[containerId] = container;
-      container->slaveId = state.get().id;
+      container->slaveId = state.id;
       container->state = Container::RUNNING;
 
       pid_t pid = run.get().forkedPid.get();
@@ -632,7 +686,7 @@ Future<Nothing> DockerContainerizerProcess::__recover(
 
 Future<bool> DockerContainerizerProcess::launch(
     const ContainerID& containerId,
-    const TaskInfo& taskInfo,
+    const Option<TaskInfo>& taskInfo,
     const ExecutorInfo& executorInfo,
     const string& directory,
     const Option<string>& user,
@@ -644,14 +698,20 @@ Future<bool> DockerContainerizerProcess::launch(
     return Failure("Container already started");
   }
 
-  if (!taskInfo.has_container()) {
+  Option<ContainerInfo> containerInfo;
+
+  if (taskInfo.isSome() && taskInfo.get().has_container()) {
+    containerInfo = taskInfo.get().container();
+  } else if (executorInfo.has_container()) {
+    containerInfo = executorInfo.container();
+  }
+
+  if (containerInfo.isNone()) {
     LOG(INFO) << "No container info found, skipping launch";
     return false;
   }
 
-  ContainerInfo containerInfo = taskInfo.container();
-
-  if (containerInfo.type() != ContainerInfo::DOCKER) {
+  if (containerInfo.get().type() != ContainerInfo::DOCKER) {
     LOG(INFO) << "Skipping non-docker container";
     return false;
   }
@@ -673,34 +733,46 @@ Future<bool> DockerContainerizerProcess::launch(
 
   containers_[containerId] = container.get();
 
-  LOG(INFO) << "Starting container '" << containerId
-            << "' for task '" << taskInfo.task_id()
-            << "' (and executor '" << executorInfo.executor_id()
-            << "') of framework '" << executorInfo.framework_id() << "'";
-
-  Future<Nothing> future = fetch(containerId)
-    .then(defer(self(), &Self::_launch, containerId))
-    .then(defer(self(), &Self::__launch, containerId));
-
-  if (flags.docker_mesos_image.isNone()) {
-    // Launch executor and logs with subprocess.
-    return container.get()->launch = future
+  if (taskInfo.isSome()) {
+    LOG(INFO) << "Starting container '" << containerId
+              << "' for task '" << taskInfo.get().task_id()
+              << "' (and executor '" << executorInfo.executor_id()
+              << "') of framework '" << executorInfo.framework_id() << "'";
+  } else {
+    LOG(INFO) << "Starting container '" << containerId
+              << "' for executor '" << executorInfo.executor_id()
+              << "' and framework '" << executorInfo.framework_id() << "'";
+  }
+
+  if (taskInfo.isSome() && flags.docker_mesos_image.isNone()) {
+    // Launching task by forking a subprocess to run docker executor.
+    return container.get()->launch = fetch(containerId)
+      .then(defer(self(), &Self::_launch, containerId))
       .then(defer(self(), &Self::___launch, containerId))
       .then(defer(self(), &Self::______launch, containerId, lambda::_1))
-      .then(defer(self(), &Self::_______launch, containerId, lambda::_1))
       .onFailed(defer(self(), &Self::destroy, containerId, true));
   }
 
-  // Launch executor and logs with docker containers.
-  return container.get()->launch = future
-    .then(defer(self(), &Self::___launchInContainer, containerId))
-    .then(defer(
-        self(),
-        &Self::____launchInContainer,
-        containerId))
-    .then(defer(self(), &Self::______launch, containerId, lambda::_1))
-    .then(defer(self(), &Self::_______launch, containerId, lambda::_1))
-    .onFailed(defer(self(), &Self::destroy, containerId, true));
+  string containerName = container.get()->name();
+
+  if (flags.docker_mesos_image.isSome()) {
+    // Launch the container with the executor name as we expect the
+    // executor will launch the docker container.
+    containerName = container.get()->executorName();
+  }
+
+  // Launching task or executor by launching a seperate docker
+  // container to run the executor.
+  // We need to do so for launching a task because as the slave
+  // is running in a container (via docker_mesos_image flag)
+  // we want the executor to keep running when the slave container
+  // dies.
+  return container.get()->launch = fetch(containerId)
+    .then(defer(self(), &Self::_launch, containerId))
+    .then(defer(self(), &Self::__launch, containerId, containerName))
+    .then(defer(self(), &Self::____launch, containerId, containerName))
+    .then(defer(self(), &Self::_____launch, containerId, lambda::_1))
+    .then(defer(self(), &Self::______launch, containerId, lambda::_1));
 }
 
 
@@ -726,25 +798,26 @@ Future<Nothing> DockerContainerizerProcess::_launch(
 
 
 Future<Nothing> DockerContainerizerProcess::__launch(
-    const ContainerID& containerId)
+    const ContainerID& containerId,
+    const string& container)
 {
   if (!containers_.contains(containerId)) {
     return Failure("Container was destroyed while pulling image");
   }
 
-  Container* container = containers_[containerId];
+  Container* container_ = containers_[containerId];
 
-  container->state = Container::RUNNING;
+  container_->state = Container::RUNNING;
 
   // Try and start the Docker container.
   return docker->run(
-      container->container(),
-      container->command(),
-      container->name(),
-      container->directory,
+      container_->container(),
+      container_->command(),
+      container,
+      container_->directory,
       flags.docker_sandbox_directory,
-      container->resources,
-      container->environment());
+      container_->resources,
+      container_->environment());
 }
 
 
@@ -777,10 +850,8 @@ Future<pid_t> DockerContainerizerProcess::___launch(
     environment["GLOG_v"] = os::getenv("GLOG_v");
   }
 
-  string command = "mesos-docker-executor --docker=" + flags.docker +
-                   " --container=" + container->name();
-
-  command = path::join(flags.launcher_dir, command);
+  const string& command = dockerExecutorCommand(
+      flags, container->directory, container->name());
 
   VLOG(1) << "Launching docker executor with command: " << command;
 
@@ -832,168 +903,13 @@ Future<pid_t> DockerContainerizerProcess::___launch(
 }
 
 
-Future<Nothing> DockerContainerizerProcess::___launchInContainer(
-    const ContainerID& containerId)
-{
-  // After we do Docker::run we shouldn't remove a container until
-  // after we set Container::status.
-  CHECK(containers_.contains(containerId));
-  CHECK(flags.docker_mesos_image.isSome());
-
-  Container* container = containers_[containerId];
-
-  // Prepare environment variables for the executor.
-  map<string, string> environment = executorEnvironment(
-      container->executor,
-      container->directory,
-      container->slaveId,
-      container->slavePid,
-      container->checkpoint,
-      flags.recovery_timeout);
-
-  // Include any enviroment variables from ExecutorInfo.
-  foreach (const Environment::Variable& variable,
-           container->executor.command().environment().variables()) {
-    environment[variable.name()] = variable.value();
-  }
-
-  // Pass GLOG flag to the executor.
-  if (os::hasenv("GLOG_v")) {
-    environment["GLOG_v"] = os::getenv("GLOG_v");
-  }
-
-  // We are launching a mesos-docker-executor in a docker container so
-  // that the containerizer can recover the executor container, as we
-  // are assuming this instance is launched in a docker container and
-  // forked processes are killed on exit.
-  ContainerInfo containerInfo;
-
-  // Mounting in the docker socket so the executor can communicate to
-  // the host docker daemon. We are assuming the current instance is
-  // launching docker containers to the host daemon as well.
-  Volume* dockerSockVolume = containerInfo.add_volumes();
-  dockerSockVolume->set_host_path(flags.docker_socket);
-  dockerSockVolume->set_container_path(flags.docker_socket);
-  dockerSockVolume->set_mode(Volume::RO);
-
-  // Mounting in sandbox so the logs from the executor can be
-  // persisted over container failures.
-  Volume* sandboxVolume = containerInfo.add_volumes();
-  sandboxVolume->set_host_path(container->directory);
-  sandboxVolume->set_container_path(container->directory);
-  sandboxVolume->set_mode(Volume::RW);
-
-  ContainerInfo::DockerInfo dockerInfo;
-
-  dockerInfo.set_image(flags.docker_mesos_image.get());
-  containerInfo.mutable_docker()->CopyFrom(dockerInfo);
-
-  string command = "mesos-docker-executor --docker=" + flags.docker +
-                   " --container=" + container->name() +
-                   " --sandbox_directory=" + container->directory +
-                   " --mapped_directory=" + flags.docker_sandbox_directory;
-
-  command = path::join(flags.launcher_dir, command);
-
-  CommandInfo commandInfo;
-  commandInfo.set_value(command);
-  commandInfo.set_shell(true);
-
-  VLOG(1) << "Launching docker executor in container with command: " << 
command;
-
-  return docker->run(
-      containerInfo,
-      commandInfo,
-      container->executorName(),
-      container->directory,
-      flags.docker_sandbox_directory,
-      None(),
-      environment);
-}
-
-
-// Launches a docker wait process on given container name.
-// Returns the wait process pid.
-Try<pid_t> launchWaitProcess(const string& docker, const string& name)
-{
-  string command = "exit `" + docker + " wait " + name + "`";
-
-  Try<Subprocess> wait = subprocess(
-      command,
-      Subprocess::PATH("/dev/null"),
-      Subprocess::PATH("/dev/null"),
-      Subprocess::PATH("/dev/null"));
-
-  if (wait.isError()) {
-    return Error("Unable to launch docker wait on executor: " + wait.error());
-  }
-
-  return wait.get().pid();
-}
-
-
-Future<bool> DockerContainerizerProcess::launch(
-    const ContainerID& containerId,
-    const ExecutorInfo& executorInfo,
-    const string& directory,
-    const Option<string>& user,
-    const SlaveID& slaveId,
-    const PID<Slave>& slavePid,
-    bool checkpoint)
-{
-  if (containers_.contains(containerId)) {
-    return Failure("Container already started");
-  }
-
-  if (!executorInfo.has_container()) {
-    LOG(INFO) << "No container info found, skipping launch";
-    return false;
-  }
-
-  ContainerInfo containerInfo = executorInfo.container();
-
-  if (containerInfo.type() != ContainerInfo::DOCKER) {
-    LOG(INFO) << "Skipping non-docker container";
-    return false;
-  }
-
-  Try<Container*> container = Container::create(
-      containerId,
-      None(),
-      executorInfo,
-      directory,
-      user,
-      slaveId,
-      slavePid,
-      checkpoint,
-      flags);
-
-  if (container.isError()) {
-    return Failure("Failed to create container: " + container.error());
-  }
-
-  containers_[containerId] = container.get();
-
-  LOG(INFO) << "Starting container '" << containerId
-            << "' for executor '" << executorInfo.executor_id()
-            << "' and framework '" << executorInfo.framework_id() << "'";
-
-  return container.get()->launch = fetch(containerId)
-    .then(defer(self(), &Self::_launch, containerId))
-    .then(defer(self(), &Self::__launch, containerId))
-    .then(defer(self(), &Self::____launch, containerId))
-    .then(defer(self(), &Self::_____launch, containerId, lambda::_1))
-    .then(defer(self(), &Self::______launch, containerId, lambda::_1))
-    .then(defer(self(), &Self::_______launch, containerId, lambda::_1))
-}
-
-
 Future<Docker::Container> DockerContainerizerProcess::____launch(
-    const ContainerID& containerId)
+    const ContainerID& containerId,
+    const std::string& container)
 {
   CHECK(containers_.contains(containerId));
 
-  return docker->inspect(containers_[containerId]->name());
+  return docker->inspect(container);
 }
 
 
@@ -1005,6 +921,8 @@ Future<pid_t> DockerContainerizerProcess::_____launch(
   // after we set Container::status.
   CHECK(containers_.contains(containerId));
 
+  Container* container_ = containers_[containerId];
+
   Option<int> pid = container.pid;
 
   if (!pid.isSome()) {
@@ -1018,48 +936,16 @@ Future<pid_t> DockerContainerizerProcess::_____launch(
         "Failed to checkpoint executor's pid: " + checkpointed.error());
   }
 
-  return pid.get();
-}
-
-
-Future<pid_t> DockerContainerizerProcess::______launch(
-    const ContainerID& containerId,
-    pid_t pid)
-{
-  CHECK(containers_.contains(containerId));
-
-  Container* container = containers_[containerId];
-
-  docker->logs(container->name(), container->directory);
-
-  return pid;
-}
-
-
-Future<pid_t> DockerContainerizerProcess::____launchInContainer(
-    const ContainerID& containerId)
-{
-  CHECK(containers_.contains(containerId));
-
-  Try<pid_t> waitPid =
-    launchWaitProcess(flags.docker, containers_[containerId]->executorName());
-
-  if (waitPid.isError()) {
-    return Failure(waitPid.error());
-  }
-
-  Try<Nothing> checkpointed = checkpoint(containerId, waitPid.get());
-
-  if (checkpointed.isError()) {
-    return Failure(
-        "Failed to checkpoint executor's pid: " + checkpointed.error());
-  }
+  // TODO(tnachen): We need to handle the slave in container scenario.
+  // Instead of forking a log process, launch a log container for
+  // executor.
+  docker->logs(container_->name(), container_->directory);
 
-  return waitPid.get();
+  return pid.get();
 }
 
 
-Future<bool> DockerContainerizerProcess::_______launch(
+Future<bool> DockerContainerizerProcess::______launch(
     const ContainerID& containerId,
     pid_t pid)
 {
@@ -1108,11 +994,6 @@ Future<Nothing> DockerContainerizerProcess::update(
   // Store the resources for usage().
   container->resources = _resources;
 
-  if (flags.docker_mesos_image.isSome()) {
-    LOG(INFO) << "Ignoring update as slave is running under container.";
-    return Nothing();
-  }
-
 #ifdef __linux__
   if (!_resources.cpus().isSome() && !_resources.mem().isSome()) {
     LOG(WARNING) << "Ignoring update as no supported resources are present";
@@ -1472,33 +1353,8 @@ void DockerContainerizerProcess::destroy(
 
   CHECK(container->state == Container::RUNNING);
 
-  // Remove the executor docker containers. They might not
-  // been configured to launch but we might have recovered containers
-  // on previous slave run that has configured to launch executor in
-  // docker.
-  docker->stop(container->executorName(), Seconds(0));
-
   container->state = Container::DESTROYING;
 
-  if (container->executorPid.isSome()) {
-    LOG(INFO) << "Sending SIGTERM to executor with pid: "
-              << container->executorPid.get();
-    // We need to clean up the executor as the executor might not have
-    // received run task due to a failed containerizer update.
-    // We also kill the executor first since container->status below
-    // is waiting for the executor to finish.
-    Try<std::list<os::ProcessTree>> kill =
-      os::killtree(container->executorPid.get(), SIGTERM);
-
-    if (kill.isError()) {
-      // Ignoring the error from killing executor as it can already
-      // have exited.
-      VLOG(1) << "Ignoring error when killing executor pid "
-                << container->executorPid.get() << " in destroy, error: "
-                << kill.error();
-    }
-  }
-
   // Otherwise, wait for Docker::run to succeed, in which case we'll
   // continue in _destroy (calling Docker::kill) or for Docker::run to
   // fail, in which case we'll re-execute this function and cleanup

http://git-wip-us.apache.org/repos/asf/mesos/blob/0b5f67ee/src/slave/containerizer/docker.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/docker.hpp 
b/src/slave/containerizer/docker.hpp
index 0bfb0e9..2961048 100644
--- a/src/slave/containerizer/docker.hpp
+++ b/src/slave/containerizer/docker.hpp
@@ -128,16 +128,7 @@ public:
 
   virtual process::Future<bool> launch(
       const ContainerID& containerId,
-      const ExecutorInfo& executorInfo,
-      const std::string& directory,
-      const Option<std::string>& user,
-      const SlaveID& slaveId,
-      const process::PID<Slave>& slavePid,
-      bool checkpoint);
-
-  virtual process::Future<bool> launch(
-      const ContainerID& containerId,
-      const TaskInfo& taskInfo,
+      const Option<TaskInfo>& taskInfo,
       const ExecutorInfo& executorInfo,
       const std::string& directory,
       const Option<std::string>& user,
@@ -192,27 +183,20 @@ private:
       const ContainerID& containerId);
 
   process::Future<Nothing> __launch(
-      const ContainerID& containerId);
+      const ContainerID& containerId,
+      const std::string& container);
 
   // NOTE: This continuation is only applicable when launching a
   // container for a task.
   process::Future<pid_t> ___launch(
       const ContainerID& containerId);
 
-  // NOTE: This continuation is only applicable when launching a
-  // container for a task.
-  process::Future<Nothing> ___launchInContainer(
-      const ContainerID& containerId);
-
-  // NOTE: This continuation is only applicable when launching a
-  // container for a task.
-  process::Future<pid_t> ____launchInContainer(
-      const ContainerID& containerId);
 
   // NOTE: This continuation is only applicable when launching a
   // container for an executor.
   process::Future<Docker::Container> ____launch(
-      const ContainerID& containerId);
+      const ContainerID& containerId,
+      const std::string& container);
 
   // NOTE: This continuation is only applicable when launching a
   // container for an executor.
@@ -220,20 +204,10 @@ private:
       const ContainerID& containerId,
       const Docker::Container& container);
 
-  process::Future<pid_t> ______launch(
-      const ContainerID& containerId,
-      pid_t pid);
-
-  // NOTE: This continuation is only applicable when launching a
-  // container for a task.
-  process::Future<pid_t> ______launchInContainer(
+  process::Future<bool> ______launch(
       const ContainerID& containerId,
       pid_t pid);
 
-  process::Future<bool> _______launch(
-    const ContainerID& containerId,
-    pid_t pid);
-
   void _destroy(
       const ContainerID& containerId,
       bool killed);
@@ -332,6 +306,14 @@ private:
       if (task.isSome()) {
         CHECK(resources.contains(task.get().resources()));
       }
+
+      overrideEnvironment = executorEnvironment(
+          executor,
+          directory,
+          slaveId,
+          slavePid,
+          checkpoint,
+          flags.recovery_timeout);
     }
 
     ~Container()
@@ -374,6 +356,10 @@ private:
 
     ContainerInfo container() const
     {
+      if (overrideContainer.isSome()) {
+        return overrideContainer.get();
+      }
+
       if (task.isSome()) {
         return task.get().container();
       }
@@ -383,6 +369,10 @@ private:
 
     CommandInfo command() const
     {
+      if (overrideCommand.isSome()) {
+        return overrideCommand.get();
+      }
+
       if (task.isSome()) {
         return task.get().command();
       }
@@ -394,14 +384,8 @@ private:
     // the Docker container (beyond the those found in CommandInfo).
     std::map<std::string, std::string> environment() const
     {
-      if (task.isNone()) {
-        return executorEnvironment(
-            executor,
-            directory,
-            slaveId,
-            slavePid,
-            checkpoint,
-            flags.recovery_timeout);
+      if (overrideEnvironment.isSome()) {
+        return overrideEnvironment.get();
       }
 
       return std::map<std::string, std::string>();
@@ -436,7 +420,7 @@ private:
       DESTROYING = 4
     } state;
 
-    ContainerID id;
+    const ContainerID id;
     Option<TaskInfo> task;
     ExecutorInfo executor;
 
@@ -451,6 +435,10 @@ private:
     bool symlinked;
     Flags flags;
 
+    Option<ContainerInfo> overrideContainer;
+    Option<CommandInfo> overrideCommand;
+    Option<std::map<std::string, std::string>> overrideEnvironment;
+
     // Promise for future returned from wait().
     Promise<containerizer::Termination> termination;
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/0b5f67ee/src/tests/docker_containerizer_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/docker_containerizer_tests.cpp 
b/src/tests/docker_containerizer_tests.cpp
index 7efaea4..e5f24e6 100644
--- a/src/tests/docker_containerizer_tests.cpp
+++ b/src/tests/docker_containerizer_tests.cpp
@@ -2593,10 +2593,6 @@ TEST_F(DockerContainerizerTest, 
ROOT_DOCKER_ExecutorCleanupWhenLaunchFailed)
   MockDocker* mockDocker = new MockDocker(tests::flags.docker);
   Shared<Docker> docker(mockDocker);
 
-  // Skip logging so we can avoid waiting for it to terminate.
-  EXPECT_CALL(*mockDocker, logs(_, _))
-    .WillOnce(Return(Nothing()));
-
   Fetcher fetcher;
 
   // The docker containerizer will free the process, so we must

Reply via email to