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 2016/02/04 23:56:22 UTC
[3/3] mesos git commit: Supported entrypoint and cmd in docker
runtime isolator.
Supported entrypoint and cmd in docker runtime isolator.
Review: https://reviews.apache.org/r/43081/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/21224a75
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/21224a75
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/21224a75
Branch: refs/heads/master
Commit: 21224a75349871624db3753adb45de7e8ea2e863
Parents: 020d9ec
Author: Gilbert Song <so...@gmail.com>
Authored: Thu Feb 4 13:27:24 2016 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Thu Feb 4 14:56:14 2016 -0800
----------------------------------------------------------------------
src/slave/containerizer/mesos/containerizer.cpp | 18 +-
.../mesos/isolators/docker/runtime.cpp | 176 +++++++++++++++++++
.../mesos/isolators/docker/runtime.hpp | 4 +
3 files changed, 197 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/21224a75/src/slave/containerizer/mesos/containerizer.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/containerizer.cpp b/src/slave/containerizer/mesos/containerizer.cpp
index ed8a545..8039a10 100644
--- a/src/slave/containerizer/mesos/containerizer.cpp
+++ b/src/slave/containerizer/mesos/containerizer.cpp
@@ -924,6 +924,12 @@ Future<bool> MesosContainerizerProcess::__launch(
// Determine the root filesystem for the container. Only one
// isolator should return the container root filesystem.
Option<string> rootfs;
+
+ // Determine the executor launch command for the container.
+ // At most one command can be returned from docker runtime
+ // isolator if a docker image is specifed.
+ Option<CommandInfo> executorLaunchCommand;
+
foreach (const Option<ContainerLaunchInfo>& launchInfo, launchInfos) {
if (launchInfo.isSome() && launchInfo->has_rootfs()) {
if (rootfs.isSome()) {
@@ -950,6 +956,14 @@ Future<bool> MesosContainerizerProcess::__launch(
environment[name] = value;
}
}
+
+ if (launchInfo.isSome() && launchInfo->has_command()) {
+ if (executorLaunchCommand.isSome()) {
+ return Failure("At most one command can be returned from isolators");
+ } else {
+ executorLaunchCommand = launchInfo->command();
+ }
+ }
}
// TODO(jieyu): Consider moving this to 'executorEnvironment' and
@@ -1008,7 +1022,9 @@ Future<bool> MesosContainerizerProcess::__launch(
// Prepare the flags to pass to the launch process.
MesosContainerizerLaunch::Flags launchFlags;
- launchFlags.command = JSON::protobuf(executorInfo.command());
+ launchFlags.command = executorLaunchCommand.isSome()
+ ? JSON::protobuf(executorLaunchCommand.get())
+ : JSON::protobuf(executorInfo.command());
launchFlags.directory = rootfs.isSome()
? flags.sandbox_directory
http://git-wip-us.apache.org/repos/asf/mesos/blob/21224a75/src/slave/containerizer/mesos/isolators/docker/runtime.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/docker/runtime.cpp b/src/slave/containerizer/mesos/isolators/docker/runtime.cpp
index e60defd..c8a9372 100644
--- a/src/slave/containerizer/mesos/isolators/docker/runtime.cpp
+++ b/src/slave/containerizer/mesos/isolators/docker/runtime.cpp
@@ -19,8 +19,12 @@
#include <glog/logging.h>
+#include <mesos/docker/v1.hpp>
+
+#include <stout/error.hpp>
#include <stout/foreach.hpp>
#include <stout/stringify.hpp>
+#include <stout/strings.hpp>
#include "slave/flags.hpp"
@@ -100,6 +104,17 @@ Future<Option<ContainerLaunchInfo>> DockerRuntimeIsolatorProcess::prepare(
launchInfo.mutable_environment()->CopyFrom(environment.get());
}
+ Try<CommandInfo> command = getExecutorLaunchCommand(
+ containerId,
+ containerConfig);
+
+ if (command.isError()) {
+ return Failure("Failed to determine the executor launch command: " +
+ command.error());
+ }
+
+ launchInfo.mutable_command()->CopyFrom(command.get());
+
return launchInfo;
}
@@ -144,6 +159,167 @@ Option<Environment> DockerRuntimeIsolatorProcess::getLaunchEnvironment(
}
+// This method reads the CommandInfo form ExecutorInfo and optional
+// TaskInfo, and merge them with docker image default Entrypoint and
+// Cmd. It returns a merged CommandInfo which will be used to launch
+// the executor.
+Try<CommandInfo> DockerRuntimeIsolatorProcess::getExecutorLaunchCommand(
+ const ContainerID& containerId,
+ const ContainerConfig& containerConfig)
+{
+ CHECK(containerConfig.docker().manifest().has_config());
+
+ // We may or may not mutate the CommandInfo for executor depending
+ // on the logic table below. For custom executor case, we make
+ // changes to the command directly. For command task case, if no
+ // need to change the launch command for the user task, we do not do
+ // anything and return the CommandInfo from ExecutorInfo. We only
+ // add a flag `--task_command` to carry command as a JSON object if
+ // it is neccessary to mutate.
+ CommandInfo command;
+
+ if (!containerConfig.has_task_info()) {
+ // Custom executor case.
+ CHECK(containerConfig.executor_info().has_command());
+ command = containerConfig.executor_info().command();
+ } else {
+ // Command task case.
+ CHECK(containerConfig.task_info().has_command());
+ command = containerConfig.task_info().command();
+ }
+
+ // We merge the CommandInfo following the logic:
+ // 1. If 'shell' is true, we will ignore Entrypoint and Cmd from
+ // the docker image (row 5-8).
+ // 2. If 'shell' is false and 'value' is set, we will ignore the
+ // Entrypoint and Cmd from the docker image as well (row 3-4).
+ // 3. If 'shell' is false and 'value' is not set, use the docker
+ // image specified runtime configuration.
+ // i. If 'Entrypoint' is set, it is treated as executable,
+ // then 'Cmd' get appended as arguments.
+ // ii.If 'Entrypoint' is not set, use the first 'Cmd' as
+ // executable and the others as arguments.
+ // +---------+--------------+--------------+--------------+--------------+
+ // | | Entrypoint=0 | Entrypoint=0 | Entrypoint=1 | Entrypoint=1 |
+ // | | Cmd=0 | Cmd=1 | Cmd=0 | Cmd=1 |
+ // +---------+--------------+--------------+--------------+--------------+
+ // | sh=0 | Error | ./Cmd[0] | ./Entrypt[0] | ./Entrypt[0] |
+ // | value=0 | | Cmd[1].. | Entrypt[1].. | Entrypt[1].. |
+ // | argv=0 | | | | Cmd.. |
+ // +---------+--------------+--------------+--------------+--------------+
+ // | sh=0 | Error | ./Cmd[0] | ./Entrypt[0] | ./Entrypt[0] |
+ // | value=0 | | argv | Entrypt[1].. | Entrypt[1].. |
+ // | argv=1 | | | argv | argv |
+ // +---------+--------------+--------------+--------------+--------------+
+ // | sh=0 | ./value | ./value | ./value | ./value |
+ // | value=1 | | | | |
+ // | argv=0 | | | | |
+ // +---------+--------------+--------------+--------------+--------------+
+ // | sh=0 | ./value | ./value | ./value | ./value |
+ // | value=1 | argv | argv | argv | argv |
+ // | argv=1 | | | | |
+ // +---------+--------------+--------------+--------------+--------------+
+ // | sh=1 | Error | Error | Error | Error |
+ // | value=0 | | | | |
+ // | argv=0 | | | | |
+ // +---------+--------------+--------------+--------------+--------------+
+ // | sh=1 | Error | Error | Error | Error |
+ // | value=0 | | | | |
+ // | argv=1 | | | | |
+ // +---------+--------------+--------------+--------------+--------------+
+ // | sh=1 | /bin/sh -c | /bin/sh -c | /bin/sh -c | /bin/sh -c |
+ // | value=1 | value | value | value | value |
+ // | argv=0 | | | | |
+ // +---------+--------------+--------------+--------------+--------------+
+ // | sh=1 | /bin/sh -c | /bin/sh -c | /bin/sh -c | /bin/sh -c |
+ // | value=1 | value | value | value | value |
+ // | argv=1 | | | | |
+ // +---------+--------------+--------------+--------------+--------------+
+ if (command.shell()) {
+ if (!command.has_value()) {
+ return Error("Shell specified but no command value provided");
+ }
+ } else {
+ if (!command.has_value()) {
+ // TODO(gilbert): Deprecate 'override' flag option in command
+ // task. We do not exclude override case here.
+
+ // We keep the arguments of commandInfo while it does not have a
+ // value, so that arguments can be specified by user, which is
+ // running with default image Entrypoint.
+ const docker::spec::v1::ImageManifest::Config& config =
+ containerConfig.docker().manifest().config();
+
+ // Filter out executable for commandInfo value.
+ if (config.entrypoint_size() > 0) {
+ command.set_value(config.entrypoint(0));
+
+ // Put user defined argv after default entrypoint argv
+ // in sequence.
+ command.clear_arguments();
+
+ for (int i = 1; i < config.entrypoint_size(); i++) {
+ command.add_arguments(config.entrypoint(i));
+ }
+
+ // Append all possible user argv after entrypoint arguments.
+ if (!containerConfig.has_task_info()) {
+ // Custom executor case.
+ command.mutable_arguments()->MergeFrom(
+ containerConfig.executor_info().command().arguments());
+ } else {
+ // Command task case.
+ command.mutable_arguments()->MergeFrom(
+ containerConfig.task_info().command().arguments());
+ }
+
+ // Overwrite default cmd arguments if CommandInfo arguments
+ // are set by user. The logic below is the case that no
+ // argument is set by user.
+ if (command.arguments_size() == config.entrypoint_size() - 1) {
+ foreach (const string& cmd, config.cmd()) {
+ command.add_arguments(cmd);
+ }
+ }
+ } else if (config.cmd_size() > 0) {
+ command.set_value(config.cmd(0));
+
+ // Overwrite default cmd arguments if CommandInfo arguments
+ // are set by user.
+ if (command.arguments_size() == 0) {
+ for (int i = 1; i < config.cmd_size(); i++) {
+ command.add_arguments(config.cmd(i));
+ }
+ }
+ } else {
+ return Error("No executable is found for container: '" +
+ containerId.value() + "'");
+ }
+ }
+ }
+
+ if (containerConfig.has_task_info()) {
+ // For command executor, with command value as 'mesos-executor'.
+ CommandInfo executorCommand = containerConfig.executor_info().command();
+
+ // Only pass the mutated command to command executor as a flag if
+ // image default config is included (see table above: row 1-2).
+ if (!containerConfig.task_info().command().shell() &&
+ !containerConfig.task_info().command().has_value()) {
+ JSON::Object object = JSON::protobuf(command);
+
+ // Pass task command as a flag, which will be loaded by
+ // command executor.
+ executorCommand.add_arguments("--task_command=" + stringify(object));
+ }
+
+ return executorCommand;
+ }
+
+ return command;
+}
+
+
Future<Nothing> DockerRuntimeIsolatorProcess::isolate(
const ContainerID& containerId,
pid_t pid)
http://git-wip-us.apache.org/repos/asf/mesos/blob/21224a75/src/slave/containerizer/mesos/isolators/docker/runtime.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/mesos/isolators/docker/runtime.hpp b/src/slave/containerizer/mesos/isolators/docker/runtime.hpp
index e419b6b..6e6ec86 100644
--- a/src/slave/containerizer/mesos/isolators/docker/runtime.hpp
+++ b/src/slave/containerizer/mesos/isolators/docker/runtime.hpp
@@ -65,6 +65,10 @@ private:
const ContainerID& containerId,
const mesos::slave::ContainerConfig& containerConfig);
+ Try<CommandInfo> getExecutorLaunchCommand(
+ const ContainerID& containerId,
+ const mesos::slave::ContainerConfig& containerConfig);
+
const Flags flags;
};