diff --git a/hadoop-yarn-project/hadoop-yarn/conf/container-executor.cfg b/hadoop-yarn-project/hadoop-yarn/conf/container-executor.cfg
index d68cee8cc98..6228543238b 100644
--- a/hadoop-yarn-project/hadoop-yarn/conf/container-executor.cfg
+++ b/hadoop-yarn-project/hadoop-yarn/conf/container-executor.cfg
@@ -2,3 +2,15 @@ yarn.nodemanager.linux-container-executor.group=#configured value of yarn.nodema
banned.users=#comma separated list of users who can not run applications
min.user.id=1000#Prevent other super-users
allowed.system.users=##comma separated list of system users who CAN run applications
+feature.docker.enabled=0
+feature.tc.enabled=0
+
+# The configs below deal with settings for Docker
+#[docker]
+# docker.binary=/bin/docker
+# allowed.capabilities=CHOWN,DAC_OVERRIDE,FSETID,FOWNER,MKNOD,NET_RAW,SETGID,SETUID,SETFCAP,SETPCAP,NET_BIND_SERVICE,SYS_CHROOT,KILL,AUDIT_WRITE
+# allowed.devices=## comma seperated list of devices that can be mounted into a container
+# allowed.networks=bridge,host,none
+# allowed.ro-mounts=## comma seperated volumes that can be mounted as read-only
+# allowed.rw-mounts=## comma seperate volumes that can be mounted as read-write, add the yarn local and log dirs to this list to run Hadoop jobs
+# privileged-containers.enabled=0
diff --git a/hadoop-yarn-project/hadoop-yarn/dev-support/findbugs-exclude.xml b/hadoop-yarn-project/hadoop-yarn/dev-support/findbugs-exclude.xml
index 6825a36ebdd..c61da3bdade 100644
--- a/hadoop-yarn-project/hadoop-yarn/dev-support/findbugs-exclude.xml
+++ b/hadoop-yarn-project/hadoop-yarn/dev-support/findbugs-exclude.xml
@@ -393,12 +393,17 @@
-
+
+
+
+
+
+
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/CMakeLists.txt b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/CMakeLists.txt
index 100d7ca7e09..f6643355725 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/CMakeLists.txt
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/CMakeLists.txt
@@ -49,6 +49,11 @@ endif ()
string(REPLACE "-D_FILE_OFFSET_BITS=64" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
string(REPLACE "-D_FILE_OFFSET_BITS=64" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+# set c++-11 std for cc files
+if(UNIX)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")
+endif()
+
include(CheckIncludeFiles)
check_include_files("sys/types.h;sys/sysctl.h" HAVE_SYS_SYSCTL_H)
@@ -100,7 +105,8 @@ add_library(container
main/native/container-executor/impl/configuration.c
main/native/container-executor/impl/container-executor.c
main/native/container-executor/impl/get_executable.c
- main/native/container-executor/impl/utils/string-utils.c
+ main/native/container-executor/impl/utils/container-id-utils.c
+ main/native/container-executor/impl/utils/docker-util.c
)
add_executable(container-executor
@@ -123,9 +129,13 @@ output_directory(test-container-executor target/usr/local/bin)
# unit tests for container executor
add_executable(cetest
+ main/native/container-executor/impl/get_executable.c
main/native/container-executor/impl/util.c
+ main/native/container-executor/impl/utils/container-id-utils.c
main/native/container-executor/test/test_configuration.cc
main/native/container-executor/test/test_main.cc
- main/native/container-executor/test/test_util.cc)
+ main/native/container-executor/test/test_util.cc
+ main/native/container-executor/test/test_docker_util.cc
+ main/native/container-executor/test/test_container_id_utils.cc)
target_link_libraries(cetest gtest)
output_directory(cetest test)
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/DockerLinuxContainerRuntime.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/DockerLinuxContainerRuntime.java
index e058d6ef14d..2e93624c2da 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/DockerLinuxContainerRuntime.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/DockerLinuxContainerRuntime.java
@@ -487,8 +487,8 @@ public void launchContainer(ContainerRuntimeContext ctx)
.setNetworkType(network);
setHostname(runCommand, containerIdStr, hostname);
runCommand.setCapabilities(capabilities)
- .addMountLocation(CGROUPS_ROOT_DIRECTORY,
- CGROUPS_ROOT_DIRECTORY + ":ro", false);
+ .addReadOnlyMountLocation(CGROUPS_ROOT_DIRECTORY,
+ CGROUPS_ROOT_DIRECTORY, false);
List allDirs = new ArrayList<>(containerLocalDirs);
allDirs.addAll(filecacheDirs);
@@ -511,7 +511,7 @@ public void launchContainer(ContainerRuntimeContext ctx)
}
String src = validateMount(dir[0], localizedResources);
String dst = dir[1];
- runCommand.addMountLocation(src, dst + ":ro", true);
+ runCommand.addReadOnlyMountLocation(src, dst, true);
}
}
}
@@ -550,7 +550,7 @@ public void launchContainer(ContainerRuntimeContext ctx)
false, false);
} catch (PrivilegedOperationException e) {
LOG.warn("Launch container failed. Exception: ", e);
- LOG.info("Docker command used: " + runCommand.getCommandWithArguments());
+ LOG.info("Docker command used: " + runCommand);
throw new ContainerExecutionException("Launch container failed", e
.getExitCode(), e.getOutput(), e.getErrorOutput());
@@ -683,8 +683,7 @@ private PrivilegedOperation buildLaunchOp(ContainerRuntimeContext ctx,
launchOp.appendArgs(tcCommandFile);
}
if (LOG.isDebugEnabled()) {
- LOG.debug("Launching container with cmd: " + runCommand
- .getCommandWithArguments());
+ LOG.debug("Launching container with cmd: " + runCommand);
}
return launchOp;
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerClient.java
index faf955f8eea..57eeb5a17b6 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerClient.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerClient.java
@@ -25,6 +25,7 @@
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandlerException;
import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException;
@@ -34,6 +35,8 @@
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
+import java.util.List;
+import java.util.Map;
@InterfaceAudience.Private
@InterfaceStability.Unstable
@@ -70,7 +73,12 @@ public String writeCommandToTempFile(DockerCommand cmd, String filePrefix)
Writer writer = new OutputStreamWriter(new FileOutputStream(dockerCommandFile),
"UTF-8");
PrintWriter printWriter = new PrintWriter(writer);
- printWriter.print(cmd.getCommandWithArguments());
+ printWriter.println("[docker-command-execution]");
+ for (Map.Entry> entry : cmd.getCommandArguments()
+ .entrySet()) {
+ printWriter.println(" " + entry.getKey() + "=" + StringUtils
+ .join(",", entry.getValue()));
+ }
printWriter.close();
return dockerCommandFile.getAbsolutePath();
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommand.java
index 3b76a5cca40..099c957ad1b 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommand.java
@@ -25,8 +25,10 @@
import org.apache.hadoop.util.StringUtils;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
@InterfaceAudience.Private
@InterfaceStability.Unstable
@@ -35,32 +37,55 @@
* e.g 'run', 'load', 'inspect' etc.,
*/
-public abstract class DockerCommand {
+public abstract class DockerCommand {
private final String command;
- private final List commandWithArguments;
+ private final Map> commandArguments;
protected DockerCommand(String command) {
+ String dockerCommandKey = "docker-command";
this.command = command;
- this.commandWithArguments = new ArrayList<>();
- commandWithArguments.add(command);
+ this.commandArguments = new TreeMap<>();
+ commandArguments.put(dockerCommandKey, new ArrayList<>());
+ commandArguments.get(dockerCommandKey).add(command);
}
- /** Returns the docker sub-command string being used
- * e.g 'run'
+ /**
+ * Returns the docker sub-command string being used
+ * e.g 'run'.
*/
public final String getCommandOption() {
return this.command;
}
- /** Add command commandWithArguments - this method is only meant for use by
- * sub-classes
- * @param arguments to be added
+ /**
+ * Add command commandWithArguments - this method is only meant for use by
+ * sub-classes.
+ *
+ * @param key name of the key to be added
+ * @param value value of the key
*/
- protected final void addCommandArguments(String... arguments) {
- this.commandWithArguments.addAll(Arrays.asList(arguments));
+ protected final void addCommandArguments(String key, String value) {
+ if (commandArguments.containsKey(key)) {
+ commandArguments.get(key).add(value);
+ return;
+ }
+ List list = new ArrayList<>();
+ list.add(value);
+ this.commandArguments.put(key, list);
}
- public String getCommandWithArguments() {
- return StringUtils.join(" ", commandWithArguments);
+ public Map> getCommandArguments() {
+ return Collections.unmodifiableMap(commandArguments);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer ret = new StringBuffer("");
+ ret.append(this.command);
+ for (Map.Entry> entry : commandArguments.entrySet()) {
+ ret.append(" ").append(entry.getKey());
+ ret.append("=").append(StringUtils.join(",", entry.getValue()));
+ }
+ return ret.toString();
}
}
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommandExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommandExecutor.java
index 9026d22e71b..c6e903fa132 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommandExecutor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommandExecutor.java
@@ -87,8 +87,7 @@ public static String executeDockerCommand(DockerCommand dockerCommand,
dockerOp.disableFailureLogging();
}
if (LOG.isDebugEnabled()) {
- LOG.debug("Running docker command: "
- + dockerCommand.getCommandWithArguments());
+ LOG.debug("Running docker command: " + dockerCommand);
}
try {
String result = privilegedOperationExecutor
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerInspectCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerInspectCommand.java
index 812a35f43ff..489e693d8cd 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerInspectCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerInspectCommand.java
@@ -26,16 +26,14 @@
*/
public class DockerInspectCommand extends DockerCommand {
private static final String INSPECT_COMMAND = "inspect";
- private String containerName;
public DockerInspectCommand(String containerName) {
super(INSPECT_COMMAND);
- this.containerName = containerName;
+ super.addCommandArguments("name", containerName);
}
public DockerInspectCommand getContainerStatus() {
- super.addCommandArguments("--format='{{.State.Status}}'");
- super.addCommandArguments(containerName);
+ super.addCommandArguments("format", "{{.State.Status}}");
return this;
}
@@ -43,9 +41,8 @@ public DockerInspectCommand getIpAndHost() {
// Be sure to not use space in the argument, otherwise the
// extract_values_delim method in container-executor binary
// cannot parse the arguments correctly.
- super.addCommandArguments("--format='{{range(.NetworkSettings.Networks)}}"
- + "{{.IPAddress}},{{end}}{{.Config.Hostname}}'");
- super.addCommandArguments(containerName);
+ super.addCommandArguments("format", "{{range(.NetworkSettings.Networks)}}"
+ + "{{.IPAddress}},{{end}}{{.Config.Hostname}}");
return this;
}
}
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerLoadCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerLoadCommand.java
index e4d92e08bc1..fa2988c6461 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerLoadCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerLoadCommand.java
@@ -25,6 +25,6 @@
public DockerLoadCommand(String localImageFile) {
super(LOAD_COMMAND);
- super.addCommandArguments("--i=" + localImageFile);
+ super.addCommandArguments("image", localImageFile);
}
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerPullCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerPullCommand.java
index 351e09ebc00..5e6108e8c3f 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerPullCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerPullCommand.java
@@ -25,7 +25,7 @@
public DockerPullCommand(String imageName) {
super(PULL_COMMAND);
- super.addCommandArguments(imageName);
+ super.addCommandArguments("image", imageName);
}
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRmCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRmCommand.java
index b1aea61659a..77837b72a8e 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRmCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRmCommand.java
@@ -25,6 +25,6 @@
public DockerRmCommand(String containerName) {
super(RM_COMMAND);
- super.addCommandArguments(containerName);
+ super.addCommandArguments("name", containerName);
}
}
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRunCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRunCommand.java
index b6457540b3a..d1ed19469fc 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRunCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerRunCommand.java
@@ -20,42 +20,39 @@
package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker;
-import org.apache.hadoop.util.StringUtils;
-
import java.io.File;
-import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
public class DockerRunCommand extends DockerCommand {
private static final String RUN_COMMAND = "run";
- private final String image;
- private List overrrideCommandWithArgs;
/** The following are mandatory: */
public DockerRunCommand(String containerId, String user, String image) {
super(RUN_COMMAND);
- super.addCommandArguments("--name=" + containerId, "--user=" + user);
- this.image = image;
+ super.addCommandArguments("name", containerId);
+ super.addCommandArguments("user", user);
+ super.addCommandArguments("image", image);
}
public DockerRunCommand removeContainerOnExit() {
- super.addCommandArguments("--rm");
+ super.addCommandArguments("rm", "true");
return this;
}
public DockerRunCommand detachOnRun() {
- super.addCommandArguments("-d");
+ super.addCommandArguments("detach", "true");
return this;
}
public DockerRunCommand setContainerWorkDir(String workdir) {
- super.addCommandArguments("--workdir=" + workdir);
+ super.addCommandArguments("workdir", workdir);
return this;
}
public DockerRunCommand setNetworkType(String type) {
- super.addCommandArguments("--net=" + type);
+ super.addCommandArguments("net", type);
return this;
}
@@ -65,72 +62,75 @@ public DockerRunCommand addMountLocation(String sourcePath, String
if (!sourceExists && !createSource) {
return this;
}
- super.addCommandArguments("-v", sourcePath + ":" + destinationPath);
+ super.addCommandArguments("rw-mounts", sourcePath + ":" + destinationPath);
+ return this;
+ }
+
+ public DockerRunCommand addReadOnlyMountLocation(String sourcePath, String
+ destinationPath, boolean createSource) {
+ boolean sourceExists = new File(sourcePath).exists();
+ if (!sourceExists && !createSource) {
+ return this;
+ }
+ super.addCommandArguments("ro-mounts", sourcePath + ":" + destinationPath);
return this;
}
public DockerRunCommand setCGroupParent(String parentPath) {
- super.addCommandArguments("--cgroup-parent=" + parentPath);
+ super.addCommandArguments("cgroup-parent", parentPath);
return this;
}
/* Run a privileged container. Use with extreme care */
public DockerRunCommand setPrivileged() {
- super.addCommandArguments("--privileged");
+ super.addCommandArguments("privileged", "true");
return this;
}
public DockerRunCommand setCapabilities(Set capabilties) {
//first, drop all capabilities
- super.addCommandArguments("--cap-drop=ALL");
+ super.addCommandArguments("cap-drop", "ALL");
//now, add the capabilities supplied
for (String capability : capabilties) {
- super.addCommandArguments("--cap-add=" + capability);
+ super.addCommandArguments("cap-add", capability);
}
return this;
}
public DockerRunCommand setHostname(String hostname) {
- super.addCommandArguments("--hostname=" + hostname);
+ super.addCommandArguments("hostname", hostname);
return this;
}
public DockerRunCommand addDevice(String sourceDevice, String
destinationDevice) {
- super.addCommandArguments("--device=" + sourceDevice + ":" +
+ super.addCommandArguments("devices", sourceDevice + ":" +
destinationDevice);
return this;
}
public DockerRunCommand enableDetach() {
- super.addCommandArguments("--detach=true");
+ super.addCommandArguments("detach", "true");
return this;
}
public DockerRunCommand disableDetach() {
- super.addCommandArguments("--detach=false");
+ super.addCommandArguments("detach", "false");
return this;
}
public DockerRunCommand setOverrideCommandWithArgs(
List overrideCommandWithArgs) {
- this.overrrideCommandWithArgs = overrideCommandWithArgs;
+ for(String override: overrideCommandWithArgs) {
+ super.addCommandArguments("launch-command", override);
+ }
return this;
}
@Override
- public String getCommandWithArguments() {
- List argList = new ArrayList<>();
-
- argList.add(super.getCommandWithArguments());
- argList.add(image);
-
- if (overrrideCommandWithArgs != null) {
- argList.addAll(overrrideCommandWithArgs);
- }
-
- return StringUtils.join(" ", argList);
+ public Map> getCommandArguments() {
+ return super.getCommandArguments();
}
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerStopCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerStopCommand.java
index e9d6c43c0f0..adf016c6b07 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerStopCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerStopCommand.java
@@ -29,11 +29,11 @@
public DockerStopCommand(String containerName) {
super(STOP_COMMAND);
- super.addCommandArguments(containerName);
+ super.addCommandArguments("name", containerName);
}
public DockerStopCommand setGracePeriod(int value) {
- super.addCommandArguments("--time=" + Integer.toString(value));
+ super.addCommandArguments("time", Integer.toString(value));
return this;
}
}
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.c
index 12dbc4c5e4a..f23cff0ef2e 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.c
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.c
@@ -21,6 +21,7 @@
#include "configuration.h"
#include "util.h"
+#include "get_executable.h"
#define __STDC_FORMAT_MACROS
#include
@@ -696,3 +697,19 @@ int get_kv_value(const char *input, char *out, size_t out_len) {
return 0;
}
+
+char *get_config_path(const char *argv0) {
+ char *executable_file = get_executable((char *) argv0);
+ if (!executable_file) {
+ fprintf(ERRORFILE, "realpath of executable: %s\n",
+ errno != 0 ? strerror(errno) : "unknown");
+ return NULL;
+ }
+
+ const char *orig_conf_file = HADOOP_CONF_DIR "/" CONF_FILENAME;
+ char *conf_file = resolve_config_path(orig_conf_file, executable_file);
+ if (conf_file == NULL) {
+ fprintf(ERRORFILE, "Configuration file %s not found.\n", orig_conf_file);
+ }
+ return conf_file;
+}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.h
index 1ea5561bc7f..7fa684e09e5 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.h
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/configuration.h
@@ -23,10 +23,21 @@
#define _WITH_GETLINE
#endif
-#include
+#include "config.h"
+
+#define CONF_FILENAME "container-executor.cfg"
+
+// When building as part of a Maven build this value gets defined by using
+// container-executor.conf.dir property. See:
+// hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/pom.xml
+// for details.
+// NOTE: if this ends up being a relative path it gets resolved relative to
+// the location of the container-executor binary itself, not getwd(3)
+#ifndef HADOOP_CONF_DIR
+#error HADOOP_CONF_DIR must be defined
+#endif
-/** Define a platform-independent constant instead of using PATH_MAX */
-#define EXECUTOR_PATH_MAX 4096
+#include
// Configuration data structures.
struct kv_pair {
@@ -207,4 +218,6 @@ int get_kv_key(const char *input, char *out, size_t out_len);
*/
int get_kv_value(const char *input, char *out, size_t out_len);
+char *get_config_path(const char* argv0);
+
#endif
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c
index 9f754c4f63f..0057b052f8a 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c
@@ -18,7 +18,8 @@
#include "configuration.h"
#include "container-executor.h"
-#include "utils/string-utils.h"
+#include "utils/container-id-utils.h"
+#include "utils/docker-util.h"
#include "util.h"
#include "config.h"
@@ -43,7 +44,6 @@
#include
#include
#include
-#include
#ifndef HAVE_FCHMODAT
#include "compat/fchmodat.h"
@@ -81,11 +81,6 @@ static const char* TC_READ_STATS_OPTS [] = { "-s", "-b", NULL};
//struct to store the user details
struct passwd *user_detail = NULL;
-//Docker container related constants.
-static const char* DOCKER_CONTAINER_NAME_PREFIX = "container_";
-static const char* DOCKER_CLIENT_CONFIG_ARG = "--config=";
-static const char* DOCKER_PULL_COMMAND = "pull";
-
FILE* LOGFILE = NULL;
FILE* ERRORFILE = NULL;
@@ -474,13 +469,6 @@ int is_tc_support_enabled() {
DEFAULT_TC_SUPPORT_ENABLED, &executor_cfg);
}
-char* check_docker_binary(char *docker_binary) {
- if (docker_binary == NULL) {
- return "docker";
- }
- return docker_binary;
-}
-
/**
* Utility function to concatenate argB to argA using the concat_pattern.
*/
@@ -1157,269 +1145,27 @@ int initialize_app(const char *user, const char *app_id,
return -1;
}
-static char* escape_single_quote(const char *str) {
- int p = 0;
- int i = 0;
- char replacement[] = "'\"'\"'";
- size_t replacement_length = strlen(replacement);
- size_t ret_size = strlen(str) * replacement_length + 1;
- char *ret = (char *) calloc(ret_size, sizeof(char));
- if(ret == NULL) {
- exit(OUT_OF_MEMORY);
- }
- while(str[p] != '\0') {
- if(str[p] == '\'') {
- strncat(ret, replacement, ret_size - strlen(ret));
- i += replacement_length;
- }
- else {
- ret[i] = str[p];
- ret[i + 1] = '\0';
- i++;
- }
- p++;
- }
- return ret;
-}
-
-static void quote_and_append_arg(char **str, size_t *size, const char* param, const char *arg) {
- char *tmp = escape_single_quote(arg);
- strcat(*str, param);
- strcat(*str, "'");
- if(strlen(*str) + strlen(tmp) > *size) {
- *str = (char *) realloc(*str, strlen(*str) + strlen(tmp) + 1024);
- if(*str == NULL) {
- exit(OUT_OF_MEMORY);
- }
- *size = strlen(*str) + strlen(tmp) + 1024;
- }
- strcat(*str, tmp);
- strcat(*str, "' ");
- free(tmp);
-}
-
-char** tokenize_docker_command(const char *input, int *split_counter) {
- char *line = (char *)calloc(strlen(input) + 1, sizeof(char));
- char **linesplit = (char **) malloc(sizeof(char *));
- char *p = NULL;
- *split_counter = 0;
- strncpy(line, input, strlen(input));
-
- p = strtok(line, " ");
- while(p != NULL) {
- linesplit[*split_counter] = p;
- (*split_counter)++;
- linesplit = realloc(linesplit, (sizeof(char *) * (*split_counter + 1)));
- if(linesplit == NULL) {
- fprintf(ERRORFILE, "Cannot allocate memory to parse docker command %s",
- strerror(errno));
- fflush(ERRORFILE);
- exit(OUT_OF_MEMORY);
- }
- p = strtok(NULL, " ");
- }
- linesplit[*split_counter] = NULL;
- return linesplit;
-}
-
-int execute_regex_match(const char *regex_str, const char *input) {
- regex_t regex;
- int regex_match;
- if (0 != regcomp(®ex, regex_str, REG_EXTENDED|REG_NOSUB)) {
- fprintf(LOGFILE, "Unable to compile regex.");
- fflush(LOGFILE);
- exit(ERROR_COMPILING_REGEX);
- }
- regex_match = regexec(®ex, input, (size_t) 0, NULL, 0);
- regfree(®ex);
- if(0 == regex_match) {
- return 0;
- }
- return 1;
-}
-
-int validate_docker_image_name(const char *image_name) {
- char *regex_str = "^(([a-zA-Z0-9.-]+)(:[0-9]+)?/)?([a-z0-9_./-]+)(:[a-zA-Z0-9_.-]+)?$";
- return execute_regex_match(regex_str, image_name);
-}
-
-char* sanitize_docker_command(const char *line) {
- static struct option long_options[] = {
- {"name", required_argument, 0, 'n' },
- {"user", required_argument, 0, 'u' },
- {"rm", no_argument, 0, 'r' },
- {"workdir", required_argument, 0, 'w' },
- {"net", required_argument, 0, 'e' },
- {"hostname", required_argument, 0, 'h' },
- {"cgroup-parent", required_argument, 0, 'g' },
- {"privileged", no_argument, 0, 'p' },
- {"cap-add", required_argument, 0, 'a' },
- {"cap-drop", required_argument, 0, 'o' },
- {"device", required_argument, 0, 'i' },
- {"detach", required_argument, 0, 't' },
- {"format", required_argument, 0, 'f' },
- {0, 0, 0, 0}
- };
-
- int c = 0;
- int option_index = 0;
- char *output = NULL;
- size_t output_size = 0;
- char **linesplit;
- int split_counter = 0;
- int len = strlen(line);
-
- linesplit = tokenize_docker_command(line, &split_counter);
-
- output_size = len * 2;
- output = (char *) calloc(output_size, sizeof(char));
- if(output == NULL) {
- exit(OUT_OF_MEMORY);
- }
-
- // Handle docker client config option.
- if(0 == strncmp(linesplit[0], DOCKER_CLIENT_CONFIG_ARG, strlen(DOCKER_CLIENT_CONFIG_ARG))) {
- strcat(output, linesplit[0]);
- strcat(output, " ");
- long index = 0;
- while(index < split_counter) {
- linesplit[index] = linesplit[index + 1];
- if (linesplit[index] == NULL) {
- split_counter--;
- break;
- }
- index++;
- }
- }
-
- // Handle docker pull and image name validation.
- if (0 == strncmp(linesplit[0], DOCKER_PULL_COMMAND, strlen(DOCKER_PULL_COMMAND))) {
- if (0 != validate_docker_image_name(linesplit[1])) {
- fprintf(ERRORFILE, "Invalid Docker image name, exiting.");
- fflush(ERRORFILE);
- exit(DOCKER_IMAGE_INVALID);
- }
- strcat(output, linesplit[0]);
- strcat(output, " ");
- strcat(output, linesplit[1]);
- return output;
- }
-
- strcat(output, linesplit[0]);
- strcat(output, " ");
- optind = 1;
- while((c=getopt_long(split_counter, linesplit, "dv:", long_options, &option_index)) != -1) {
- switch(c) {
- case 'n':
- quote_and_append_arg(&output, &output_size, "--name=", optarg);
- break;
- case 'w':
- quote_and_append_arg(&output, &output_size, "--workdir=", optarg);
- break;
- case 'u':
- quote_and_append_arg(&output, &output_size, "--user=", optarg);
- break;
- case 'e':
- quote_and_append_arg(&output, &output_size, "--net=", optarg);
- break;
- case 'h':
- quote_and_append_arg(&output, &output_size, "--hostname=", optarg);
- break;
- case 'v':
- quote_and_append_arg(&output, &output_size, "-v ", optarg);
- break;
- case 'a':
- quote_and_append_arg(&output, &output_size, "--cap-add=", optarg);
- break;
- case 'o':
- quote_and_append_arg(&output, &output_size, "--cap-drop=", optarg);
- break;
- case 'd':
- strcat(output, "-d ");
- break;
- case 'r':
- strcat(output, "--rm ");
- break;
- case 'g':
- quote_and_append_arg(&output, &output_size, "--cgroup-parent=", optarg);
- break;
- case 'p':
- strcat(output, "--privileged ");
- break;
- case 'i':
- quote_and_append_arg(&output, &output_size, "--device=", optarg);
- break;
- case 't':
- quote_and_append_arg(&output, &output_size, "--detach=", optarg);
- break;
- case 'f':
- strcat(output, "--format=");
- strcat(output, optarg);
- strcat(output, " ");
- break;
- default:
- fprintf(LOGFILE, "Unknown option in docker command, character %d %c, optionindex = %d\n", c, c, optind);
- fflush(LOGFILE);
- return NULL;
- break;
- }
- }
-
- if(optind < split_counter) {
- while(optind < split_counter) {
- if (0 == strncmp(linesplit[optind], DOCKER_CONTAINER_NAME_PREFIX, strlen(DOCKER_CONTAINER_NAME_PREFIX))) {
- if (1 != validate_container_id(linesplit[optind])) {
- fprintf(ERRORFILE, "Specified container_id=%s is invalid\n", linesplit[optind]);
- fflush(ERRORFILE);
- exit(DOCKER_CONTAINER_NAME_INVALID);
- }
- strcat(output, linesplit[optind++]);
- } else {
- quote_and_append_arg(&output, &output_size, "", linesplit[optind++]);
- }
- }
- }
-
- return output;
-}
-
-char* parse_docker_command_file(const char* command_file) {
-
- size_t len = 0;
- char *line = NULL;
- ssize_t read;
- FILE *stream;
- stream = fopen(command_file, "r");
- if (stream == NULL) {
- fprintf(ERRORFILE, "Cannot open file %s - %s",
- command_file, strerror(errno));
- fflush(ERRORFILE);
- exit(ERROR_OPENING_DOCKER_FILE);
- }
- if ((read = getline(&line, &len, stream)) == -1) {
- fprintf(ERRORFILE, "Error reading command_file %s\n", command_file);
- fflush(ERRORFILE);
- exit(ERROR_READING_DOCKER_FILE);
- }
- fclose(stream);
-
- char* ret = sanitize_docker_command(line);
- if(ret == NULL) {
- exit(ERROR_SANITIZING_DOCKER_COMMAND);
+char *construct_docker_command(const char *command_file) {
+ int ret = 0;
+ char *buffer = (char *) malloc(EXECUTOR_PATH_MAX * sizeof(char));
+ memset(buffer, 0, EXECUTOR_PATH_MAX);
+ ret = get_docker_command(command_file, &CFG, buffer, EXECUTOR_PATH_MAX);
+ if (ret != 0) {
+ fprintf(ERRORFILE, "Error constructing docker command, docker error code=%d, error message='%s'\n", ret,
+ get_docker_error_message(ret));
+ fflush(ERRORFILE);
+ exit(DOCKER_RUN_FAILED);
}
- fprintf(ERRORFILE, "Using command %s\n", ret);
- fflush(ERRORFILE);
-
- return ret;
+ return buffer;
}
int run_docker(const char *command_file) {
- char* docker_command = parse_docker_command_file(command_file);
- char* docker_binary = get_section_value(DOCKER_BINARY_KEY, &executor_cfg);
- docker_binary = check_docker_binary(docker_binary);
+ char* docker_command = construct_docker_command(command_file);
+ char* docker_binary = get_docker_binary(&CFG);
char* docker_command_with_binary = calloc(sizeof(char), EXECUTOR_PATH_MAX);
snprintf(docker_command_with_binary, EXECUTOR_PATH_MAX, "%s %s", docker_binary, docker_command);
+ fprintf(LOGFILE, "Invoking '%s'\n", docker_command_with_binary);
char **args = split_delimiter(docker_command_with_binary, " ");
int exit_code = -1;
@@ -1580,9 +1326,8 @@ int launch_docker_container_as_user(const char * user, const char *app_id,
gid_t user_gid = getegid();
uid_t prev_uid = geteuid();
- char *docker_command = parse_docker_command_file(command_file);
- char *docker_binary = get_section_value(DOCKER_BINARY_KEY, &executor_cfg);
- docker_binary = check_docker_binary(docker_binary);
+ char *docker_command = NULL;
+ char *docker_binary = NULL;
fprintf(LOGFILE, "Creating script paths...\n");
exit_code = create_script_paths(
@@ -1605,6 +1350,9 @@ int launch_docker_container_as_user(const char * user, const char *app_id,
goto cleanup;
}
+ docker_command = construct_docker_command(command_file);
+ docker_binary = get_docker_binary(&CFG);
+
fprintf(LOGFILE, "Getting exit code file...\n");
exit_code_file = get_exit_code_file(pid_file);
if (NULL == exit_code_file) {
@@ -1621,6 +1369,7 @@ int launch_docker_container_as_user(const char * user, const char *app_id,
goto cleanup;
}
+ memset(docker_command_with_binary, 0, EXECUTOR_PATH_MAX);
snprintf(docker_command_with_binary, EXECUTOR_PATH_MAX, "%s %s", docker_binary, docker_command);
fprintf(LOGFILE, "Launching docker container...\n");
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h
index ea8b5e38a18..d3c6f740a73 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h
@@ -59,7 +59,6 @@ enum operations {
#define MIN_USERID_KEY "min.user.id"
#define BANNED_USERS_KEY "banned.users"
#define ALLOWED_SYSTEM_USERS_KEY "allowed.system.users"
-#define DOCKER_BINARY_KEY "docker.binary"
#define DOCKER_SUPPORT_ENABLED_KEY "feature.docker.enabled"
#define TC_SUPPORT_ENABLED_KEY "feature.tc.enabled"
#define TMP_DIR "tmp"
@@ -258,11 +257,6 @@ int is_docker_support_enabled();
*/
int run_docker(const char *command_file);
-/**
- * Sanitize docker commands. Returns NULL if there was any failure.
-*/
-char* sanitize_docker_command(const char *line);
-
/*
* Compile the regex_str and determine if the input string matches.
* Return 0 on match, 1 of non-match.
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/get_executable.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/get_executable.c
index 55973a2db57..e1ec293cd47 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/get_executable.c
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/get_executable.c
@@ -29,12 +29,9 @@
*/
#include "config.h"
-#include "configuration.h"
-#include "container-executor.h"
#include "util.h"
#include
-#include
#include
#include
#include
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/get_executable.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/get_executable.h
new file mode 100644
index 00000000000..ee6b375d52b
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/get_executable.h
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __YARN_POSIX_CONTAINER_EXECUTOR_GET_EXECUTABLE_H__
+#define __YARN_POSIX_CONTAINER_EXECUTOR_GET_EXECUTABLE_H__
+
+/**
+ * Get the path to executable that is currently running
+ * @param argv0 the name of the executable
+ * @return the path to the currently running executable
+ */
+char* get_executable(char *argv0);
+
+#endif
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c
index b2187c9daf0..a5be2868b8a 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c
@@ -16,32 +16,15 @@
* limitations under the License.
*/
-#include "config.h"
#include "configuration.h"
#include "container-executor.h"
#include "util.h"
#include
#include
-#include
#include
-#include
-#include
#include
#include
-#include
-
-#define CONF_FILENAME "container-executor.cfg"
-
-// When building as part of a Maven build this value gets defined by using
-// container-executor.conf.dir property. See:
-// hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/pom.xml
-// for details.
-// NOTE: if this ends up being a relative path it gets resolved relative to
-// the location of the container-executor binary itself, not getwd(3)
-#ifndef HADOOP_CONF_DIR
- #error HADOOP_CONF_DIR must be defined
-#endif
static void display_usage(FILE *stream) {
fprintf(stream,
@@ -144,24 +127,19 @@ static void assert_valid_setup(char *argv0) {
int ret;
char *executable_file = get_executable(argv0);
if (!executable_file) {
- fprintf(ERRORFILE,"realpath of executable: %s\n",
- errno != 0 ? strerror(errno) : "unknown");
- flush_and_close_log_files();
- exit(-1);
+ fprintf(ERRORFILE, "realpath of executable: %s\n",
+ errno != 0 ? strerror(errno) : "unknown");
+ exit(INVALID_CONFIG_FILE);
}
- char *orig_conf_file = HADOOP_CONF_DIR "/" CONF_FILENAME;
- char *conf_file = resolve_config_path(orig_conf_file, executable_file);
+ char *conf_file = get_config_path(argv0);
if (conf_file == NULL) {
- free(executable_file);
- fprintf(ERRORFILE, "Configuration file %s not found.\n", orig_conf_file);
flush_and_close_log_files();
exit(INVALID_CONFIG_FILE);
}
if (check_configuration_permissions(conf_file) != 0) {
- free(executable_file);
flush_and_close_log_files();
exit(INVALID_CONFIG_FILE);
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.c
index 8e39ca85760..038de25ba19 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.c
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.c
@@ -17,10 +17,10 @@
*/
#include "util.h"
-#include
#include
#include
#include
+#include
char** split_delimiter(char *value, const char *delim) {
char **return_values = NULL;
@@ -132,3 +132,68 @@ char* trim(const char* input) {
ret[val_end - val_begin] = '\0';
return ret;
}
+
+int execute_regex_match(const char *regex_str, const char *input) {
+ regex_t regex;
+ int regex_match;
+ if (0 != regcomp(®ex, regex_str, REG_EXTENDED|REG_NOSUB)) {
+ fprintf(LOGFILE, "Unable to compile regex.");
+ fflush(LOGFILE);
+ exit(ERROR_COMPILING_REGEX);
+ }
+ regex_match = regexec(®ex, input, (size_t) 0, NULL, 0);
+ regfree(®ex);
+ if(0 == regex_match) {
+ return 0;
+ }
+ return 1;
+}
+
+char* escape_single_quote(const char *str) {
+ int p = 0;
+ int i = 0;
+ char replacement[] = "'\"'\"'";
+ size_t replacement_length = strlen(replacement);
+ size_t ret_size = strlen(str) * replacement_length + 1;
+ char *ret = (char *) calloc(ret_size, sizeof(char));
+ if(ret == NULL) {
+ exit(OUT_OF_MEMORY);
+ }
+ while(str[p] != '\0') {
+ if(str[p] == '\'') {
+ strncat(ret, replacement, ret_size - strlen(ret));
+ i += replacement_length;
+ }
+ else {
+ ret[i] = str[p];
+ ret[i + 1] = '\0';
+ i++;
+ }
+ p++;
+ }
+ return ret;
+}
+
+void quote_and_append_arg(char **str, size_t *size, const char* param, const char *arg) {
+ char *tmp = escape_single_quote(arg);
+ strcat(*str, param);
+ strcat(*str, "'");
+ if(strlen(*str) + strlen(tmp) > *size) {
+ *str = (char *) realloc(*str, strlen(*str) + strlen(tmp) + 1024);
+ if(*str == NULL) {
+ exit(OUT_OF_MEMORY);
+ }
+ *size = strlen(*str) + strlen(tmp) + 1024;
+ }
+ strcat(*str, tmp);
+ strcat(*str, "' ");
+ free(tmp);
+}
+
+void* alloc_and_clear_memory(size_t num, size_t size) {
+ void *ret = calloc(num, size);
+ if (ret == NULL) {
+ exit(OUT_OF_MEMORY);
+ }
+ return ret;
+}
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.h
index a8a12a937bb..41043e3b4a6 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.h
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.h
@@ -19,6 +19,9 @@
#ifndef __YARN_POSIX_CONTAINER_EXECUTOR_UTIL_H__
#define __YARN_POSIX_CONTAINER_EXECUTOR_UTIL_H__
+/** Define a platform-independent constant instead of using PATH_MAX, set to 128K */
+#define EXECUTOR_PATH_MAX 131072
+
#include
enum errorcodes {
@@ -62,7 +65,7 @@ enum errorcodes {
ERROR_CREATE_CONTAINER_DIRECTORIES_ARGUMENTS = 38,
ERROR_SANITIZING_DOCKER_COMMAND = 39,
DOCKER_IMAGE_INVALID = 40,
- DOCKER_CONTAINER_NAME_INVALID = 41,
+ // DOCKER_CONTAINER_NAME_INVALID = 41,
ERROR_COMPILING_REGEX = 42
};
@@ -112,4 +115,37 @@ void free_values(char **values);
*/
char* trim(const char *input);
+/**
+ * Run a regex to check if the provided input matches against it
+ * @param regex_str Regex to run
+ * @param input String to run the regex against
+ * @return 0 on match, non-zero on no match
+ */
+int execute_regex_match(const char *regex_str, const char *input);
+
+/**
+ * Helper function to escape single-quotes in a string. The assumption is that the string passed will be enclosed in
+ * single quotes and passed to bash for a command invocation.
+ * @param str The string in which to esacpe single quotes
+ * @return String with single quotes escaped, must be freed by the user.
+ */
+char* escape_single_quote(const char *str);
+
+/**
+ * Helper function to quote the argument to a parameter and then append it to the provided string.
+ * @param str Buffer to which the param='arg' string must be appended
+ * @param size Size of the buffer
+ * @param param Param name
+ * @param arg Argument to be quoted
+ */
+void quote_and_append_arg(char **str, size_t *size, const char* param, const char *arg);
+
+/**
+ * Helper function to allocate and clear a block of memory. It'll call exit if the allocation fails.
+ * @param num Num of elements to be allocated
+ * @param size Size of each element
+ * @return Pointer to the allocated memory, must be freed by the user
+ */
+void* alloc_and_clear_memory(size_t num, size_t size);
+
#endif
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/container-id-utils.c
similarity index 99%
rename from hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.c
rename to hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/container-id-utils.c
index 703d484cb18..0baf017ffab 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.c
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/container-id-utils.c
@@ -18,7 +18,6 @@
#include
#include
-#include
#include
/*
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/container-id-utils.h
similarity index 100%
rename from hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.h
rename to hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/container-id-utils.h
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c
new file mode 100644
index 00000000000..3273af8a032
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c
@@ -0,0 +1,1000 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+#include
+#include "docker-util.h"
+#include "container-id-utils.h"
+#include "util.h"
+
+static int read_and_verify_command_file(const char *command_file, const char *docker_command,
+ struct configuration *command_config) {
+ int ret = 0;
+ ret = read_config(command_file, command_config);
+ if (ret != 0) {
+ return INVALID_COMMAND_FILE;
+ }
+ char *command = get_configuration_value("docker-command", DOCKER_COMMAND_FILE_SECTION, command_config);
+ if (command == NULL || (strcmp(command, docker_command) != 0)) {
+ if (command != NULL) {
+ free(command);
+ }
+ return INCORRECT_COMMAND;
+ }
+ free(command);
+ return 0;
+}
+
+static int add_to_buffer(char *buff, const size_t bufflen, const char *string) {
+ size_t current_len = strlen(buff);
+ size_t string_len = strlen(string);
+ if (current_len + string_len < bufflen) {
+ strncpy(buff + current_len, string, bufflen - current_len);
+ return 0;
+ }
+ return -1;
+}
+
+static int add_docker_config_param(const struct configuration *command_config, char *out, const size_t outlen) {
+ int ret = 0;
+ size_t tmp_buffer_size = 4096;
+ char *tmp_buffer;
+ char *config = get_configuration_value("docker-config", DOCKER_COMMAND_FILE_SECTION, command_config);
+ if (config != NULL) {
+ tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "--config=", config);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ free(tmp_buffer);
+ free(config);
+ }
+ return ret;
+}
+
+const char *get_docker_error_message(const int error_code) {
+
+ switch (error_code) {
+ case INVALID_COMMAND_FILE:
+ return "Invalid command file passed";
+ case INCORRECT_COMMAND:
+ return "Incorrect command";
+ case BUFFER_TOO_SMALL:
+ return "Command buffer too small";
+ case INVALID_DOCKER_CONTAINER_NAME:
+ return "Invalid docker container name";
+ case INVALID_DOCKER_IMAGE_NAME:
+ return "Invalid docker image name";
+ case INVALID_DOCKER_USER_NAME:
+ return "Invalid docker user name";
+ case INVALID_DOCKER_INSPECT_FORMAT:
+ return "Invalid docker inspect format";
+ case UNKNOWN_DOCKER_COMMAND:
+ return "Unknown docker command";
+ case INVALID_DOCKER_NETWORK:
+ return "Invalid docker network";
+ case INVALID_DOCKER_CAPABILITY:
+ return "Invalid docker capability";
+ case PRIVILEGED_CONTAINERS_DISABLED:
+ return "Privileged containers are disabled";
+ case INVALID_DOCKER_MOUNT:
+ return "Invalid docker mount";
+ case INVALID_DOCKER_RO_MOUNT:
+ return "Invalid docker read-only mount";
+ case INVALID_DOCKER_RW_MOUNT:
+ return "Invalid docker read-write mount";
+ case MOUNT_ACCESS_ERROR:
+ return "Mount access error";
+ case INVALID_DOCKER_DEVICE:
+ return "Invalid docker device";
+ default:
+ return "Unknown error";
+ }
+}
+
+char *get_docker_binary(const struct configuration *conf) {
+ char *docker_binary = NULL;
+ docker_binary = get_configuration_value(DOCKER_BINARY_KEY, CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf);
+ if (docker_binary == NULL) {
+ docker_binary = get_configuration_value(DOCKER_BINARY_KEY, "", conf);
+ if (docker_binary == NULL) {
+ docker_binary = strdup("/usr/bin/docker");
+ }
+ }
+ return docker_binary;
+}
+
+int get_docker_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) {
+ int ret = 0;
+ struct configuration command_config = {.size=0, .sections=NULL};
+ ret = read_config(command_file, &command_config);
+ if (ret != 0) {
+ return INVALID_COMMAND_FILE;
+ }
+
+ char *command = get_configuration_value("docker-command", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (strcmp(DOCKER_INSPECT_COMMAND, command) == 0) {
+ return get_docker_inspect_command(command_file, conf, out, outlen);
+ } else if (strcmp(DOCKER_LOAD_COMMAND, command) == 0) {
+ return get_docker_load_command(command_file, conf, out, outlen);
+ } else if (strcmp(DOCKER_PULL_COMMAND, command) == 0) {
+ return get_docker_pull_command(command_file, conf, out, outlen);
+ } else if (strcmp(DOCKER_RM_COMMAND, command) == 0) {
+ return get_docker_rm_command(command_file, conf, out, outlen);
+ } else if (strcmp(DOCKER_RUN_COMMAND, command) == 0) {
+ return get_docker_run_command(command_file, conf, out, outlen);
+ } else if (strcmp(DOCKER_STOP_COMMAND, command) == 0) {
+ return get_docker_stop_command(command_file, conf, out, outlen);
+ } else {
+ return UNKNOWN_DOCKER_COMMAND;
+ }
+}
+
+int get_docker_inspect_command(const char *command_file, const struct configuration *conf, char *out,
+ const size_t outlen) {
+ int ret = 0;
+ char *format = NULL, *container_name = NULL;
+ //container related constants.
+ const char* CONTAINER_NAME_PREFIX = "container_";
+ size_t tmp_buffer_size = 1024;
+ char *tmp_buffer = NULL;
+ struct configuration command_config = {.size=0, .sections=NULL};
+ ret = read_and_verify_command_file(command_file, DOCKER_INSPECT_COMMAND, &command_config);
+ if (ret != 0) {
+ return ret;
+ }
+
+ container_name = get_configuration_value("name", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (container_name == NULL) {
+ return INVALID_DOCKER_CONTAINER_NAME;
+ }
+ if (0 == strncmp(container_name, CONTAINER_NAME_PREFIX, strlen(CONTAINER_NAME_PREFIX))) {
+ if (1 != validate_container_id(container_name)) {
+ fprintf(ERRORFILE, "Specified container_id=%s is invalid\n", container_name);
+ fflush(ERRORFILE);
+ return INVALID_DOCKER_CONTAINER_NAME;
+ }
+ }
+
+ format = get_configuration_value("format", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (format == NULL) {
+ free(container_name);
+ return INVALID_DOCKER_INSPECT_FORMAT;
+ }
+
+ memset(out, 0, outlen);
+
+ ret = add_docker_config_param(&command_config, out, outlen);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+
+ ret = add_to_buffer(out, outlen, DOCKER_INSPECT_COMMAND);
+ if (ret == 0) {
+ tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, " --format=", format);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ if (ret == 0) {
+ memset(tmp_buffer, 0, tmp_buffer_size);
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "", container_name);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ }
+ free(tmp_buffer);
+ free(format);
+ free(container_name);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+ return 0;
+ }
+ free(format);
+ free(container_name);
+ return BUFFER_TOO_SMALL;
+}
+
+int get_docker_load_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) {
+ int ret = 0;
+ char *image_name = NULL;
+ size_t tmp_buffer_size = 1024;
+ char *tmp_buffer = NULL;
+ struct configuration command_config = {.size=0, .sections=NULL};
+ ret = read_and_verify_command_file(command_file, DOCKER_LOAD_COMMAND, &command_config);
+ if (ret != 0) {
+ return ret;
+ }
+
+ image_name = get_configuration_value("image", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (image_name == NULL) {
+ return INVALID_DOCKER_IMAGE_NAME;
+ }
+
+ memset(out, 0, outlen);
+
+ ret = add_docker_config_param(&command_config, out, outlen);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+
+ ret = add_to_buffer(out, outlen, DOCKER_LOAD_COMMAND);
+ if (ret == 0) {
+ tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, " --i=", image_name);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ free(tmp_buffer);
+ free(image_name);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+ return 0;
+ }
+ free(image_name);
+ return BUFFER_TOO_SMALL;
+}
+
+static int validate_docker_image_name(const char *image_name) {
+ const char *regex_str = "^(([a-zA-Z0-9.-]+)(:[0-9]+)?/)?([a-z0-9_./-]+)(:[a-zA-Z0-9_.-]+)?$";
+ return execute_regex_match(regex_str, image_name);
+}
+
+int get_docker_pull_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) {
+ int ret = 0;
+ char *image_name = NULL;
+ size_t tmp_buffer_size = 1024;
+ char *tmp_buffer = NULL;
+ struct configuration command_config = {.size=0, .sections=NULL};
+ ret = read_and_verify_command_file(command_file, DOCKER_PULL_COMMAND, &command_config);
+ if (ret != 0) {
+ return ret;
+ }
+
+ image_name = get_configuration_value("image", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (image_name == NULL || validate_docker_image_name(image_name) != 0) {
+ return INVALID_DOCKER_IMAGE_NAME;
+ }
+
+ memset(out, 0, outlen);
+
+ ret = add_docker_config_param(&command_config, out, outlen);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+
+ ret = add_to_buffer(out, outlen, DOCKER_PULL_COMMAND);
+ if (ret == 0) {
+ tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, " ", image_name);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ free(tmp_buffer);
+ free(image_name);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+ return 0;
+ }
+ free(image_name);
+ return BUFFER_TOO_SMALL;
+}
+
+int get_docker_rm_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) {
+ int ret = 0;
+ char *container_name = NULL;
+ size_t tmp_buffer_size = 1024;
+ char *tmp_buffer = NULL;
+ struct configuration command_config = {.size=0, .sections=NULL};
+ ret = read_and_verify_command_file(command_file, DOCKER_RM_COMMAND, &command_config);
+ if (ret != 0) {
+ return ret;
+ }
+
+ container_name = get_configuration_value("name", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (container_name == NULL) {
+ return INVALID_DOCKER_CONTAINER_NAME;
+ }
+
+ memset(out, 0, outlen);
+
+ ret = add_docker_config_param(&command_config, out, outlen);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+
+ ret = add_to_buffer(out, outlen, DOCKER_RM_COMMAND);
+ if (ret == 0) {
+ tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, " ", container_name);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ free(tmp_buffer);
+ free(container_name);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+ return 0;
+ }
+ free(container_name);
+ return BUFFER_TOO_SMALL;
+}
+
+int get_docker_stop_command(const char *command_file, const struct configuration *conf,
+ char *out, const size_t outlen) {
+ int ret = 0;
+ char *value = NULL;
+ char *container_name = NULL;
+ size_t tmp_buffer_size = 1024;
+ char *tmp_buffer = NULL;
+ struct configuration command_config = {.size=0, .sections=NULL};
+ ret = read_and_verify_command_file(command_file, DOCKER_STOP_COMMAND, &command_config);
+ if (ret != 0) {
+ return ret;
+ }
+
+ container_name = get_configuration_value("name", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (container_name == NULL) {
+ return INVALID_DOCKER_CONTAINER_NAME;
+ }
+
+ memset(out, 0, outlen);
+
+ ret = add_docker_config_param(&command_config, out, outlen);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+
+ ret = add_to_buffer(out, outlen, DOCKER_STOP_COMMAND);
+ if (ret == 0) {
+ tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ value = get_configuration_value("time", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (value != NULL) {
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, " --time=", value);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ if (ret != 0) {
+ free(tmp_buffer);
+ free(container_name);
+ return BUFFER_TOO_SMALL;
+ }
+ memset(tmp_buffer, 0, tmp_buffer_size);
+ }
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, " ", container_name);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ free(tmp_buffer);
+ free(container_name);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+ return 0;
+ }
+ free(container_name);
+ return BUFFER_TOO_SMALL;
+}
+
+static int add_param_to_command(const struct configuration *command_config, const char *key, const char *param,
+ const int with_argument, char *out, const size_t outlen) {
+ size_t tmp_buffer_size = 1024;
+ int ret = 0;
+ char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ char *value = get_configuration_value(key, DOCKER_COMMAND_FILE_SECTION, command_config);
+ if (value != NULL) {
+ if (with_argument) {
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, param, value);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ } else if (strcmp(value, "true") == 0) {
+ ret = add_to_buffer(out, outlen, param);
+ }
+ free(value);
+ if (ret != 0) {
+ ret = BUFFER_TOO_SMALL;
+ }
+ }
+ free(tmp_buffer);
+ return ret;
+}
+
+static int detach_container(const struct configuration *command_config, char *out, const size_t outlen) {
+ return add_param_to_command(command_config, "detach", "-d ", 0, out, outlen);
+}
+
+static int rm_container_on_exit(const struct configuration *command_config, char *out, const size_t outlen) {
+ return add_param_to_command(command_config, "rm", "--rm ", 0, out, outlen);
+}
+
+static int set_container_workdir(const struct configuration *command_config, char *out, const size_t outlen) {
+ return add_param_to_command(command_config, "workdir", "--workdir=", 1, out, outlen);
+}
+
+static int set_cgroup_parent(const struct configuration *command_config, char *out, const size_t outlen) {
+ return add_param_to_command(command_config, "cgroup-parent", "--cgroup-parent=", 1, out, outlen);
+}
+
+static int set_hostname(const struct configuration *command_config, char *out, const size_t outlen) {
+ return add_param_to_command(command_config, "hostname", "--hostname=", 1, out, outlen);
+}
+
+static int set_network(const struct configuration *command_config, const struct configuration *conf, char *out,
+ const size_t outlen) {
+ size_t tmp_buffer_size = 1024;
+ char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ char **permitted_values = get_configuration_values_delimiter("allowed.networks",
+ CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ",");
+ char *value = get_configuration_value("net", DOCKER_COMMAND_FILE_SECTION, command_config);
+ int i = 0, ret = 0;
+ if (value != NULL && permitted_values != NULL) {
+ for (i = 0; permitted_values[i] != NULL; ++i) {
+ if (strcmp(value, permitted_values[i]) == 0) {
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "--net=", value);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ if(ret != 0) {
+ ret = BUFFER_TOO_SMALL;
+ }
+ goto free_and_exit;
+ }
+ }
+ fprintf(ERRORFILE, "Could not find network '%s' in allowed networks\n", value);
+ } else if (value == NULL) {
+ ret = 0;
+ goto free_and_exit;
+ }
+ ret = INVALID_DOCKER_NETWORK;
+
+ free_and_exit:
+ free(tmp_buffer);
+ if (permitted_values != NULL) {
+ free(permitted_values[0]);
+ free(permitted_values);
+ }
+ if (value != NULL) {
+ free(value);
+ }
+ if (ret != 0) {
+ memset(out, 0, outlen);
+ }
+ return ret;
+}
+
+static int check_mount_permitted(const char **permitted_mounts, const char *requested) {
+ int i = 0;
+ size_t permitted_mount_len = 0;
+ if (permitted_mounts == NULL) {
+ return 0;
+ }
+ for (i = 0; permitted_mounts[i] != NULL; ++i) {
+ if (strcmp(requested, permitted_mounts[i]) == 0) {
+ return 1;
+ }
+ // directory check
+ permitted_mount_len = strlen(permitted_mounts[i]);
+ if (permitted_mounts[i][permitted_mount_len - 1] == '/') {
+ if (strncmp(requested, permitted_mounts[i], permitted_mount_len) == 0) {
+ return 1;
+ }
+ }
+
+ }
+ return 0;
+}
+
+static char* normalize_mount(const char* mount) {
+ int ret = 0;
+ struct stat buff;
+ char *ret_ptr = NULL, *real_mount = NULL;
+ if (mount == NULL) {
+ return NULL;
+ }
+ real_mount = realpath(mount, NULL);
+ if (real_mount == NULL) {
+ fprintf(ERRORFILE, "Could not determine real path of mount '%s'\n", mount);
+ return NULL;
+ }
+ ret = stat(real_mount, &buff);
+ if (ret == 0) {
+ if (S_ISDIR(buff.st_mode)) {
+ size_t len = strlen(real_mount);
+ if (real_mount[len - 1] != '/') {
+ ret_ptr = (char *) alloc_and_clear_memory(len + 2, sizeof(char));
+ strncpy(ret_ptr, real_mount, len);
+ ret_ptr[len] = '/';
+ ret_ptr[len + 1] = '\0';
+ } else {
+ ret_ptr = strdup(real_mount);
+ }
+ } else {
+ ret_ptr = strdup(real_mount);
+ }
+ } else {
+ fprintf(ERRORFILE, "Could not stat path '%s'\n", real_mount);
+ ret_ptr = NULL;
+ }
+ free(real_mount);
+ return ret_ptr;
+}
+
+static int normalize_mounts(char **mounts) {
+ int i = 0;
+ char *tmp = NULL;
+ if (mounts == NULL) {
+ return 0;
+ }
+ char *alloc_ptr = mounts[0];
+ for (i = 0; mounts[i] != NULL; ++i) {
+ tmp = normalize_mount(mounts[i]);
+ if (tmp == NULL) {
+ return -1;
+ }
+ mounts[i] = tmp;
+ }
+ free(alloc_ptr);
+ return 0;
+}
+
+static char* get_src_mount(const char *mount) {
+ char *src_mount = NULL;
+ const char *tmp = NULL;
+ tmp = strchr(mount, ':');
+ if (tmp == NULL) {
+ fprintf(ERRORFILE, "Invalid docker mount '%s'\n", mount);
+ return NULL;
+ }
+ src_mount = strndup(mount, tmp - mount);
+ return src_mount;
+}
+
+static char* get_real_src_mount(const char *src_mount) {
+ char *real_src_mount = NULL;
+ char *tmp = strdup(src_mount);
+ if (tmp == NULL) {
+ fprintf(ERRORFILE, "Could not allocate memory\n");
+ exit(OUT_OF_MEMORY);
+ }
+ real_src_mount = realpath(tmp, NULL);
+ if (real_src_mount == NULL) {
+ fprintf(ERRORFILE, "Could not determine realpath of '%s'\n", src_mount);
+ }
+ free(tmp);
+ return real_src_mount;
+}
+
+static int add_mounts(const struct configuration *command_config, const struct configuration *conf, const char *key,
+ const int ro, char *out, const size_t outlen) {
+ size_t tmp_buffer_size = 1024;
+ const char *ro_suffix = "";
+ const char *tmp_path_buffer[2] = {NULL, NULL};
+ char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ char **permitted_ro_mounts = get_configuration_values_delimiter("allowed.ro-mounts",
+ CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ",");
+ char **permitted_rw_mounts = get_configuration_values_delimiter("allowed.rw-mounts",
+ CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ",");
+ char **values = get_configuration_values_delimiter(key, DOCKER_COMMAND_FILE_SECTION, command_config, ",");
+ char *tmp_buffer_2 = NULL, *src_mount = NULL, *real_src_mount = NULL, *normalized_src_mount = NULL;
+ const char *container_executor_cfg_path = normalize_mount(get_config_path(""));
+ int i = 0, permitted_rw = 0, permitted_ro = 0, ret = 0;
+ if (ro != 0) {
+ ro_suffix = ":ro";
+ }
+
+ ret = normalize_mounts(permitted_ro_mounts);
+ ret |= normalize_mounts(permitted_rw_mounts);
+ if (ret != 0) {
+ fprintf(ERRORFILE, "Unable to find permitted docker mounts on disk\n");
+ ret = MOUNT_ACCESS_ERROR;
+ goto free_and_exit;
+ }
+
+ if (values != NULL) {
+ for (i = 0; values[i] != NULL; ++i) {
+ src_mount = get_src_mount(values[i]);
+ if (src_mount == NULL) {
+ ret = INVALID_DOCKER_MOUNT;
+ goto free_and_exit;
+ }
+ real_src_mount = get_real_src_mount(src_mount);
+ if (real_src_mount == NULL) {
+ ret = INVALID_DOCKER_MOUNT;
+ goto free_and_exit;
+ }
+ normalized_src_mount = normalize_mount(real_src_mount);
+ if(normalized_src_mount == NULL) {
+ ret = INVALID_DOCKER_MOUNT;
+ goto free_and_exit;
+ }
+ permitted_rw = check_mount_permitted((const char **) permitted_rw_mounts, normalized_src_mount);
+ permitted_ro = check_mount_permitted((const char **) permitted_ro_mounts, normalized_src_mount);
+ // rw mount
+ if (ro == 0) {
+ if (permitted_rw == 0) {
+ fprintf(ERRORFILE, "Invalid docker rw mount '%s', realpath=%s\n", values[i], real_src_mount);
+ ret = INVALID_DOCKER_RW_MOUNT;
+ goto free_and_exit;
+ } else {
+ // determine if the user can modify the container-executor.cfg file
+ tmp_path_buffer[0] = normalized_src_mount;
+ // just re-use the function, flip the args to check if the container-executor path is in the requested
+ // mount point
+ ret = check_mount_permitted(tmp_path_buffer, container_executor_cfg_path);
+ if (ret == 1) {
+ fprintf(ERRORFILE, "Attempting to mount a parent directory '%s' of container-executor.cfg as read-write\n",
+ values[i]);
+ ret = INVALID_DOCKER_RW_MOUNT;
+ goto free_and_exit;
+ }
+ }
+ }
+ //ro mount
+ if (ro != 0 && permitted_ro == 0 && permitted_rw == 0) {
+ ret = INVALID_DOCKER_RO_MOUNT;
+ goto free_and_exit;
+ }
+ tmp_buffer_2 = (char *) alloc_and_clear_memory(strlen(values[i]) + strlen(ro_suffix) + 1, sizeof(char));
+ strncpy(tmp_buffer_2, values[i], strlen(values[i]));
+ strncpy(tmp_buffer_2 + strlen(values[i]), ro_suffix, strlen(ro_suffix));
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "-v ", tmp_buffer_2);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ free(tmp_buffer_2);
+ free(real_src_mount);
+ free(src_mount);
+ free(normalized_src_mount);
+ src_mount = NULL;
+ real_src_mount = NULL;
+ normalized_src_mount = NULL;
+ memset(tmp_buffer, 0, tmp_buffer_size);
+ if (ret != 0) {
+ ret = BUFFER_TOO_SMALL;
+ goto free_and_exit;
+ }
+ }
+ }
+
+ free_and_exit:
+ if(permitted_ro_mounts != NULL) {
+ free(permitted_ro_mounts[0]);
+ free(permitted_ro_mounts);
+ }
+ if (permitted_rw_mounts != NULL) {
+ for (i = 0; permitted_rw_mounts[i] != NULL; ++i) {
+ free(permitted_rw_mounts[i]);
+ }
+ free(permitted_rw_mounts);
+ }
+ if (values != NULL) {
+ free(values[0]);
+ free(values);
+ }
+ if (real_src_mount != NULL) {
+ free(real_src_mount);
+ }
+ if (src_mount != NULL) {
+ free(src_mount);
+ }
+ if(normalized_src_mount != NULL) {
+ free(normalized_src_mount);
+ }
+ if(container_executor_cfg_path != NULL) {
+ free((char *) container_executor_cfg_path);
+ }
+ free(tmp_buffer);
+ if (ret != 0) {
+ memset(out, 0, outlen);
+ }
+ return ret;
+}
+
+static int add_ro_mounts(const struct configuration *command_config, const struct configuration *conf, char *out,
+ const size_t outlen) {
+ return add_mounts(command_config, conf, "ro-mounts", 1, out, outlen);
+}
+
+static int add_rw_mounts(const struct configuration *command_config, const struct configuration *conf, char *out,
+ const size_t outlen) {
+ return add_mounts(command_config, conf, "rw-mounts", 0, out, outlen);
+}
+
+static int set_privileged(const struct configuration *command_config, const struct configuration *conf, char *out,
+ const size_t outlen) {
+ size_t tmp_buffer_size = 1024;
+ char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ char *value = get_configuration_value("privileged", DOCKER_COMMAND_FILE_SECTION, command_config);
+ char *privileged_container_enabled
+ = get_configuration_value("privileged-containers.enabled", CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf);
+ int ret = 0;
+
+ if (value != NULL && strcmp(value, "true") == 0) {
+ if (privileged_container_enabled != NULL) {
+ if (strcmp(privileged_container_enabled, "1") == 0) {
+ ret = add_to_buffer(out, outlen, "--privileged ");
+ if (ret != 0) {
+ ret = BUFFER_TOO_SMALL;
+ }
+ } else {
+ fprintf(ERRORFILE, "Privileged containers are disabled\n");
+ ret = PRIVILEGED_CONTAINERS_DISABLED;
+ goto free_and_exit;
+ }
+ } else {
+ fprintf(ERRORFILE, "Privileged containers are disabled\n");
+ ret = PRIVILEGED_CONTAINERS_DISABLED;
+ goto free_and_exit;
+ }
+ }
+
+ free_and_exit:
+ free(tmp_buffer);
+ if (value != NULL) {
+ free(value);
+ }
+ if (privileged_container_enabled != NULL) {
+ free(privileged_container_enabled);
+ }
+ if (ret != 0) {
+ memset(out, 0, outlen);
+ }
+ return ret;
+}
+
+static int set_capabilities(const struct configuration *command_config, const struct configuration *conf, char *out,
+ const size_t outlen) {
+ size_t tmp_buffer_size = 1024;
+ char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ char **values = get_configuration_values_delimiter("cap-add", DOCKER_COMMAND_FILE_SECTION, command_config, ",");
+ char **permitted_values = get_configuration_values_delimiter("allowed.capabilities",
+ CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ",");
+ int i = 0, j = 0, permitted = 0, ret = 0;
+
+ ret = add_to_buffer(out, outlen, "--cap-drop='ALL' ");
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+ if (values != NULL) {
+ if(permitted_values != NULL) {
+ for (i = 0; values[i] != NULL; ++i) {
+ memset(tmp_buffer, 0, tmp_buffer_size);
+ permitted = 0;
+ for (j = 0; permitted_values[j] != NULL; ++j) {
+ if (strcmp(values[i], permitted_values[j]) == 0) {
+ permitted = 1;
+ break;
+ }
+ }
+ if (permitted == 1) {
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "--cap-add=", values[i]);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ if (ret != 0) {
+ ret = BUFFER_TOO_SMALL;
+ goto free_and_exit;
+ }
+ } else {
+ fprintf(ERRORFILE, "Invalid docker capability '%s' requested\n", values[i]);
+ ret = INVALID_DOCKER_CAPABILITY;
+ goto free_and_exit;
+ }
+ }
+ } else {
+ fprintf(ERRORFILE, "Invalid docker capability requested\n");
+ ret = INVALID_DOCKER_CAPABILITY;
+ goto free_and_exit;
+ }
+ }
+
+ free_and_exit:
+ if(values != NULL) {
+ free(values[0]);
+ free(values);
+ }
+ if(permitted_values != NULL) {
+ free(permitted_values[0]);
+ free(permitted_values);
+ }
+ free(tmp_buffer);
+ if(ret != 0) {
+ memset(out, 0, outlen);
+ }
+ return ret;
+}
+
+static int add_devices(const struct configuration *command_config, const struct configuration *conf, char *out,
+ const size_t outlen) {
+ size_t tmp_buffer_size = 1024;
+ char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+ char **permitted_devices = get_configuration_values_delimiter("allowed.devices",
+ CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ",");
+ char **values = get_configuration_values_delimiter("devices", DOCKER_COMMAND_FILE_SECTION, command_config, ",");
+ int i = 0, j = 0, ret = 0, permitted = 0;
+ char *tmp_ptr = NULL;
+
+ if (values != NULL) {
+ if (permitted_devices != NULL) {
+ for (i = 0; values[i] != NULL; ++i) {
+ memset(tmp_buffer, 0, tmp_buffer_size);
+ permitted = 0;
+ tmp_ptr = strchr(values[i], ':');
+ if (tmp_ptr == NULL) {
+ ret = INVALID_DOCKER_DEVICE;
+ goto free_and_exit;
+ }
+ for (j = 0; permitted_devices[j] != NULL; ++j) {
+ if (strncmp(values[i], permitted_devices[j], tmp_ptr - values[i]) == 0) {
+ permitted = 1;
+ }
+ }
+ if (permitted == 1) {
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "--device=", values[i]);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ if (ret != 0) {
+ ret = BUFFER_TOO_SMALL;
+ goto free_and_exit;
+ }
+ } else {
+ fprintf(ERRORFILE, "Device '%s' not permitted to be mounted\n", values[i]);
+ ret = INVALID_DOCKER_DEVICE;
+ goto free_and_exit;
+ }
+ }
+ } else {
+ fprintf(ERRORFILE, "Device '%s' not permitted to be mounted\n", values[i]);
+ ret = INVALID_DOCKER_DEVICE;
+ goto free_and_exit;
+ }
+ }
+ free_and_exit:
+ free(tmp_buffer);
+ if (permitted_devices != NULL) {
+ free(permitted_devices[0]);
+ free(permitted_devices);
+ }
+ if (values != NULL) {
+ free(values[0]);
+ free(values);
+ }
+ if (ret != 0) {
+ memset(out, 0, outlen);
+ }
+ return ret;
+}
+
+int get_docker_run_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) {
+ int ret = 0, i = 0;
+ char *container_name = NULL, *user = NULL, *image = NULL;
+ size_t tmp_buffer_size = 1024;
+ char *tmp_buffer = NULL;
+ char **launch_command = NULL;
+ struct configuration command_config = {.size=0, .sections=NULL};
+ ret = read_and_verify_command_file(command_file, DOCKER_RUN_COMMAND, &command_config);
+ if (ret != 0) {
+ return ret;
+ }
+
+ container_name = get_configuration_value("name", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (container_name == NULL) {
+ return INVALID_DOCKER_CONTAINER_NAME;
+ }
+ user = get_configuration_value("user", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (user == NULL) {
+ return INVALID_DOCKER_USER_NAME;
+ }
+ image = get_configuration_value("image", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (image == NULL || validate_docker_image_name(image) != 0) {
+ return INVALID_DOCKER_IMAGE_NAME;
+ }
+
+ memset(out, 0, outlen);
+
+ ret = add_docker_config_param(&command_config, out, outlen);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+
+ ret = add_to_buffer(out, outlen, DOCKER_RUN_COMMAND);
+ if (ret == 0) {
+ tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char));
+
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, " --name=", container_name);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+ memset(tmp_buffer, 0, tmp_buffer_size);
+
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "--user=", user);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+ memset(tmp_buffer, 0, tmp_buffer_size);
+
+ ret = detach_container(&command_config, out, outlen);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = rm_container_on_exit(&command_config, out, outlen);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = set_container_workdir(&command_config, out, outlen);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = set_network(&command_config, conf, out, outlen);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = add_ro_mounts(&command_config, conf, out, outlen);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = add_rw_mounts(&command_config, conf, out, outlen);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = set_cgroup_parent(&command_config, out, outlen);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = set_privileged(&command_config, conf, out, outlen);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = set_capabilities(&command_config, conf, out, outlen);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = set_hostname(&command_config, out, outlen);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = add_devices(&command_config, conf, out, outlen);
+ if (ret != 0) {
+ return ret;
+ }
+
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "", image);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ if (ret != 0) {
+ return BUFFER_TOO_SMALL;
+ }
+ memset(tmp_buffer, 0, tmp_buffer_size);
+
+ launch_command = get_configuration_values_delimiter("launch-command", DOCKER_COMMAND_FILE_SECTION, &command_config,
+ ",");
+ if (launch_command != NULL) {
+ for (i = 0; launch_command[i] != NULL; ++i) {
+ memset(tmp_buffer, 0, tmp_buffer_size);
+ quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "", launch_command[i]);
+ ret = add_to_buffer(out, outlen, tmp_buffer);
+ if (ret != 0) {
+ free(launch_command[0]);
+ free(launch_command);
+ free(tmp_buffer);
+ return BUFFER_TOO_SMALL;
+ }
+ }
+ free(launch_command[0]);
+ free(launch_command);
+ }
+ free(tmp_buffer);
+ return 0;
+ }
+ return BUFFER_TOO_SMALL;
+}
+
+
+
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.h
new file mode 100644
index 00000000000..665d927f84f
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.h
@@ -0,0 +1,139 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __YARN_POSIX_CONTAINER_EXECUTOR_DOCKER_UTIL_H__
+#define __YARN_POSIX_CONTAINER_EXECUTOR_DOCKER_UTIL_H__
+
+#include "configuration.h"
+
+#define CONTAINER_EXECUTOR_CFG_DOCKER_SECTION "docker"
+#define DOCKER_BINARY_KEY "docker.binary"
+#define DOCKER_COMMAND_FILE_SECTION "docker-command-execution"
+#define DOCKER_INSPECT_COMMAND "inspect"
+#define DOCKER_LOAD_COMMAND "load"
+#define DOCKER_PULL_COMMAND "pull"
+#define DOCKER_RM_COMMAND "rm"
+#define DOCKER_RUN_COMMAND "run"
+#define DOCKER_STOP_COMMAND "stop"
+
+
+enum docker_error_codes {
+ INVALID_COMMAND_FILE = 1,
+ INCORRECT_COMMAND,
+ BUFFER_TOO_SMALL,
+ INVALID_DOCKER_CONTAINER_NAME,
+ INVALID_DOCKER_IMAGE_NAME,
+ INVALID_DOCKER_USER_NAME,
+ INVALID_DOCKER_INSPECT_FORMAT,
+ UNKNOWN_DOCKER_COMMAND,
+ INVALID_DOCKER_NETWORK,
+ INVALID_DOCKER_CAPABILITY,
+ PRIVILEGED_CONTAINERS_DISABLED,
+ INVALID_DOCKER_MOUNT,
+ INVALID_DOCKER_RO_MOUNT,
+ INVALID_DOCKER_RW_MOUNT,
+ MOUNT_ACCESS_ERROR,
+ INVALID_DOCKER_DEVICE
+};
+
+/**
+ * Get the full path for the docker binary.
+ * @param conf Configuration for the container-executor
+ * @return String containing the docker binary to be freed by the user.
+ */
+char *get_docker_binary(const struct configuration *conf);
+
+/**
+ * Get the Docker command line string. The function will inspect the params file to determine the command to be run.
+ * @param command_file File containing the params for the Docker command
+ * @param conf Configuration struct containing the container-executor.cfg details
+ * @param out Buffer to fill with the Docker command
+ * @param outlen Size of the output buffer
+ * @return Return code with 0 indicating success and non-zero codes indicating error
+ */
+int get_docker_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+
+/**
+ * Get the Docker inspect command line string. The function will verify that the params file is meant for the
+ * inspect command.
+ * @param command_file File containing the params for the Docker inspect command
+ * @param conf Configuration struct containing the container-executor.cfg details
+ * @param out Buffer to fill with the inspect command
+ * @param outlen Size of the output buffer
+ * @return Return code with 0 indicating success and non-zero codes indicating error
+ */
+int get_docker_inspect_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+
+/**
+ * Get the Docker load command line string. The function will verify that the params file is meant for the load command.
+ * @param command_file File containing the params for the Docker load command
+ * @param conf Configuration struct containing the container-executor.cfg details
+ * @param out Buffer to fill with the load command
+ * @param outlen Size of the output buffer
+ * @return Return code with 0 indicating success and non-zero codes indicating error
+ */
+int get_docker_load_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+
+/**
+ * Get the Docker pull command line string. The function will verify that the params file is meant for the pull command.
+ * @param command_file File containing the params for the Docker pull command
+ * @param conf Configuration struct containing the container-executor.cfg details
+ * @param out Buffer to fill with the pull command
+ * @param outlen Size of the output buffer
+ * @return Return code with 0 indicating success and non-zero codes indicating error
+ */
+int get_docker_pull_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+
+/**
+ * Get the Docker rm command line string. The function will verify that the params file is meant for the rm command.
+ * @param command_file File containing the params for the Docker rm command
+ * @param conf Configuration struct containing the container-executor.cfg details
+ * @param out Buffer to fill with the rm command
+ * @param outlen Size of the output buffer
+ * @return Return code with 0 indicating success and non-zero codes indicating error
+ */
+int get_docker_rm_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+
+/**
+ * Get the Docker run command line string. The function will verify that the params file is meant for the run command.
+ * @param command_file File containing the params for the Docker run command
+ * @param conf Configuration struct containing the container-executor.cfg details
+ * @param out Buffer to fill with the run command
+ * @param outlen Size of the output buffer
+ * @return Return code with 0 indicating success and non-zero codes indicating error
+ */
+int get_docker_run_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+
+/**
+ * Get the Docker stop command line string. The function will verify that the params file is meant for the stop command.
+ * @param command_file File containing the params for the Docker stop command
+ * @param conf Configuration struct containing the container-executor.cfg details
+ * @param out Buffer to fill with the stop command
+ * @param outlen Size of the output buffer
+ * @return Return code with 0 indicating success and non-zero codes indicating error
+ */
+int get_docker_stop_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen);
+
+/**
+ * Give an error message for the supplied error code
+ * @param error_code the error code
+ * @return const string containing the error message
+ */
+const char *get_docker_error_message(const int error_code);
+
+#endif
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/resources/test/test-configurations/docker-container-executor.cfg b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/resources/test/test-configurations/docker-container-executor.cfg
new file mode 100644
index 00000000000..339bec950cc
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/resources/test/test-configurations/docker-container-executor.cfg
@@ -0,0 +1,13 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+[docker]
+privieged-containers.enabled=0
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c
index 3cfefa03e82..2108497bf6c 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c
@@ -17,7 +17,7 @@
*/
#include "configuration.h"
#include "container-executor.h"
-#include "utils/string-utils.h"
+#include "utils/container-id-utils.h"
#include "util.h"
#include
@@ -1173,145 +1173,6 @@ void test_trim_function() {
free(trimmed);
}
-void test_sanitize_docker_command() {
-
- char *input[] = {
- "run --name=cname --user=nobody -d --workdir=/yarn/local/cdir --privileged --rm --device=/sys/fs/cgroup/device:/sys/fs/cgroup/device --detach=true --cgroup-parent=/sys/fs/cgroup/cpu/yarn/cid --net=host --hostname=test.host.name --cap-drop=ALL --cap-add=SYS_CHROOT --cap-add=MKNOD --cap-add=SETFCAP --cap-add=SETPCAP --cap-add=FSETID --cap-add=CHOWN --cap-add=AUDIT_WRITE --cap-add=SETGID --cap-add=NET_RAW --cap-add=FOWNER --cap-add=SETUID --cap-add=DAC_OVERRIDE --cap-add=KILL --cap-add=NET_BIND_SERVICE -v /sys/fs/cgroup:/sys/fs/cgroup:ro -v /yarn/local/cdir:/yarn/local/cdir -v /yarn/local/usercache/test/:/yarn/local/usercache/test/ ubuntu bash /yarn/local/usercache/test/appcache/aid/cid/launch_container.sh",
- "run --name=$CID --user=nobody -d --workdir=/yarn/local/cdir --privileged --rm --device=/sys/fs/cgroup/device:/sys/fs/cgroup/device --detach=true --cgroup-parent=/sys/fs/cgroup/cpu/yarn/cid --net=host --hostname=test.host.name --cap-drop=ALL --cap-add=SYS_CHROOT --cap-add=MKNOD --cap-add=SETFCAP --cap-add=SETPCAP --cap-add=FSETID --cap-add=CHOWN --cap-add=AUDIT_WRITE --cap-add=SETGID --cap-add=NET_RAW --cap-add=FOWNER --cap-add=SETUID --cap-add=DAC_OVERRIDE --cap-add=KILL --cap-add=NET_BIND_SERVICE -v /sys/fs/cgroup:/sys/fs/cgroup:ro -v /yarn/local/cdir:/yarn/local/cdir -v /yarn/local/usercache/test/:/yarn/local/usercache/test/ ubuntu bash /yarn/local/usercache/test/appcache/aid/cid/launch_container.sh",
- "run --name=cname --user=nobody -d --workdir=/yarn/local/cdir --privileged --rm --device=/sys/fs/cgroup/device:/sys/fs/cgroup/device --detach=true --cgroup-parent=/sys/fs/cgroup/cpu/yarn/cid --net=host --hostname=test.host.name --cap-drop=ALL --cap-add=SYS_CHROOT --cap-add=MKNOD --cap-add=SETFCAP --cap-add=SETPCAP --cap-add=FSETID --cap-add=CHOWN --cap-add=AUDIT_WRITE --cap-add=SETGID --cap-add=NET_RAW --cap-add=FOWNER --cap-add=SETUID --cap-add=DAC_OVERRIDE --cap-add=KILL --cap-add=NET_BIND_SERVICE -v /sys/fs/cgroup:/sys/fs/cgroup:ro -v /yarn/local/cdir:/yarn/local/cdir -v /yarn/local/usercache/test/:/yarn/local/usercache/test/ ubuntu || touch /tmp/file # bash /yarn/local/usercache/test/appcache/aid/cid/launch_container.sh",
- "run --name=cname --user=nobody -d --workdir=/yarn/local/cdir --privileged --rm --device=/sys/fs/cgroup/device:/sys/fs/cgroup/device --detach=true --cgroup-parent=/sys/fs/cgroup/cpu/yarn/cid --net=host --hostname=test.host.name --cap-drop=ALL --cap-add=SYS_CHROOT --cap-add=MKNOD --cap-add=SETFCAP --cap-add=SETPCAP --cap-add=FSETID --cap-add=CHOWN --cap-add=AUDIT_WRITE --cap-add=SETGID --cap-add=NET_RAW --cap-add=FOWNER --cap-add=SETUID --cap-add=DAC_OVERRIDE --cap-add=KILL --cap-add=NET_BIND_SERVICE -v /sys/fs/cgroup:/sys/fs/cgroup:ro -v /yarn/local/cdir:/yarn/local/cdir -v /yarn/local/usercache/test/:/yarn/local/usercache/test/ ubuntu' || touch /tmp/file # bash /yarn/local/usercache/test/appcache/aid/cid/launch_container.sh",
- "run ''''''''",
- "inspect --format='{{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}}' container_e111_1111111111111_1111_01_111111",
- "rm container_e111_1111111111111_1111_01_111111",
- "stop container_e111_1111111111111_1111_01_111111",
- "pull ubuntu",
- "pull registry.com/user/ubuntu",
- "--config=/yarn/local/cdir/ pull registry.com/user/ubuntu"
- };
- char *expected_output[] = {
- "run --name='cname' --user='nobody' -d --workdir='/yarn/local/cdir' --privileged --rm --device='/sys/fs/cgroup/device:/sys/fs/cgroup/device' --detach='true' --cgroup-parent='/sys/fs/cgroup/cpu/yarn/cid' --net='host' --hostname='test.host.name' --cap-drop='ALL' --cap-add='SYS_CHROOT' --cap-add='MKNOD' --cap-add='SETFCAP' --cap-add='SETPCAP' --cap-add='FSETID' --cap-add='CHOWN' --cap-add='AUDIT_WRITE' --cap-add='SETGID' --cap-add='NET_RAW' --cap-add='FOWNER' --cap-add='SETUID' --cap-add='DAC_OVERRIDE' --cap-add='KILL' --cap-add='NET_BIND_SERVICE' -v '/sys/fs/cgroup:/sys/fs/cgroup:ro' -v '/yarn/local/cdir:/yarn/local/cdir' -v '/yarn/local/usercache/test/:/yarn/local/usercache/test/' 'ubuntu' 'bash' '/yarn/local/usercache/test/appcache/aid/cid/launch_container.sh' ",
- "run --name='$CID' --user='nobody' -d --workdir='/yarn/local/cdir' --privileged --rm --device='/sys/fs/cgroup/device:/sys/fs/cgroup/device' --detach='true' --cgroup-parent='/sys/fs/cgroup/cpu/yarn/cid' --net='host' --hostname='test.host.name' --cap-drop='ALL' --cap-add='SYS_CHROOT' --cap-add='MKNOD' --cap-add='SETFCAP' --cap-add='SETPCAP' --cap-add='FSETID' --cap-add='CHOWN' --cap-add='AUDIT_WRITE' --cap-add='SETGID' --cap-add='NET_RAW' --cap-add='FOWNER' --cap-add='SETUID' --cap-add='DAC_OVERRIDE' --cap-add='KILL' --cap-add='NET_BIND_SERVICE' -v '/sys/fs/cgroup:/sys/fs/cgroup:ro' -v '/yarn/local/cdir:/yarn/local/cdir' -v '/yarn/local/usercache/test/:/yarn/local/usercache/test/' 'ubuntu' 'bash' '/yarn/local/usercache/test/appcache/aid/cid/launch_container.sh' ",
- "run --name='cname' --user='nobody' -d --workdir='/yarn/local/cdir' --privileged --rm --device='/sys/fs/cgroup/device:/sys/fs/cgroup/device' --detach='true' --cgroup-parent='/sys/fs/cgroup/cpu/yarn/cid' --net='host' --hostname='test.host.name' --cap-drop='ALL' --cap-add='SYS_CHROOT' --cap-add='MKNOD' --cap-add='SETFCAP' --cap-add='SETPCAP' --cap-add='FSETID' --cap-add='CHOWN' --cap-add='AUDIT_WRITE' --cap-add='SETGID' --cap-add='NET_RAW' --cap-add='FOWNER' --cap-add='SETUID' --cap-add='DAC_OVERRIDE' --cap-add='KILL' --cap-add='NET_BIND_SERVICE' -v '/sys/fs/cgroup:/sys/fs/cgroup:ro' -v '/yarn/local/cdir:/yarn/local/cdir' -v '/yarn/local/usercache/test/:/yarn/local/usercache/test/' 'ubuntu' '||' 'touch' '/tmp/file' '#' 'bash' '/yarn/local/usercache/test/appcache/aid/cid/launch_container.sh' ",
- "run --name='cname' --user='nobody' -d --workdir='/yarn/local/cdir' --privileged --rm --device='/sys/fs/cgroup/device:/sys/fs/cgroup/device' --detach='true' --cgroup-parent='/sys/fs/cgroup/cpu/yarn/cid' --net='host' --hostname='test.host.name' --cap-drop='ALL' --cap-add='SYS_CHROOT' --cap-add='MKNOD' --cap-add='SETFCAP' --cap-add='SETPCAP' --cap-add='FSETID' --cap-add='CHOWN' --cap-add='AUDIT_WRITE' --cap-add='SETGID' --cap-add='NET_RAW' --cap-add='FOWNER' --cap-add='SETUID' --cap-add='DAC_OVERRIDE' --cap-add='KILL' --cap-add='NET_BIND_SERVICE' -v '/sys/fs/cgroup:/sys/fs/cgroup:ro' -v '/yarn/local/cdir:/yarn/local/cdir' -v '/yarn/local/usercache/test/:/yarn/local/usercache/test/' 'ubuntu'\"'\"'' '||' 'touch' '/tmp/file' '#' 'bash' '/yarn/local/usercache/test/appcache/aid/cid/launch_container.sh' ",
- "run ''\"'\"''\"'\"''\"'\"''\"'\"''\"'\"''\"'\"''\"'\"''\"'\"'' ",
- "inspect --format='{{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}}' container_e111_1111111111111_1111_01_111111",
- "rm container_e111_1111111111111_1111_01_111111",
- "stop container_e111_1111111111111_1111_01_111111",
- "pull ubuntu",
- "pull registry.com/user/ubuntu",
- "--config=/yarn/local/cdir/ pull registry.com/user/ubuntu"
- };
-
- int input_size = sizeof(input) / sizeof(char *);
- int i = 0;
- for(i = 0; i < input_size; i++) {
- char *command = (char *) calloc(strlen(input[i]) + 1 , sizeof(char));
- strncpy(command, input[i], strlen(input[i]));
- char *op = sanitize_docker_command(command);
- if(strncmp(expected_output[i], op, strlen(expected_output[i])) != 0) {
- printf("FAIL: expected output %s does not match actual output '%s'\n", expected_output[i], op);
- exit(1);
- }
- free(command);
- }
-}
-
-void test_validate_docker_image_name() {
-
- char *good_input[] = {
- "ubuntu",
- "ubuntu:latest",
- "ubuntu:14.04",
- "ubuntu:LATEST",
- "registry.com:5000/user/ubuntu",
- "registry.com:5000/user/ubuntu:latest",
- "registry.com:5000/user/ubuntu:0.1.2.3",
- "registry.com/user/ubuntu",
- "registry.com/user/ubuntu:latest",
- "registry.com/user/ubuntu:0.1.2.3",
- "registry.com/user/ubuntu:test-image",
- "registry.com/user/ubuntu:test_image",
- "registry.com/ubuntu",
- "user/ubuntu",
- "user/ubuntu:0.1.2.3",
- "user/ubuntu:latest",
- "user/ubuntu:test_image",
- "user/ubuntu.test:test_image",
- "user/ubuntu-test:test-image",
- "registry.com/ubuntu/ubuntu/ubuntu"
- };
-
- char *bad_input[] = {
- "UBUNTU",
- "registry.com|5000/user/ubuntu",
- "registry.com | 5000/user/ubuntu",
- "ubuntu' || touch /tmp/file #",
- "ubuntu || touch /tmp/file #",
- "''''''''",
- "bad_host_name:5000/user/ubuntu",
- "registry.com:foo/ubuntu/ubuntu/ubuntu",
- "registry.com/ubuntu:foo/ubuntu/ubuntu"
- };
-
- int good_input_size = sizeof(good_input) / sizeof(char *);
- int i = 0;
- for(i = 0; i < good_input_size; i++) {
- int op = validate_docker_image_name(good_input[i]);
- if(0 != op) {
- printf("\nFAIL: docker image name %s is invalid", good_input[i]);
- exit(1);
- }
- }
-
- int bad_input_size = sizeof(bad_input) / sizeof(char *);
- int j = 0;
- for(j = 0; j < bad_input_size; j++) {
- int op = validate_docker_image_name(bad_input[j]);
- if(1 != op) {
- printf("\nFAIL: docker image name %s is valid, expected invalid", bad_input[j]);
- exit(1);
- }
- }
-}
-
-void test_validate_container_id() {
- char *good_input[] = {
- "container_e134_1499953498516_50875_01_000007",
- "container_1499953498516_50875_01_000007",
- "container_e1_12312_11111_02_000001"
- };
-
- char *bad_input[] = {
- "CONTAINER",
- "container_e1_12312_11111_02_000001 | /tmp/file"
- "container_e1_12312_11111_02_000001 || # /tmp/file",
- "container_e1_12312_11111_02_000001 # /tmp/file",
- "container_e1_12312_11111_02_000001' || touch /tmp/file #",
- "ubuntu || touch /tmp/file #",
- "''''''''"
- };
-
- int good_input_size = sizeof(good_input) / sizeof(char *);
- int i = 0;
- for(i = 0; i < good_input_size; i++) {
- int op = validate_container_id(good_input[i]);
- if(1 != op) {
- printf("FAIL: docker container name %s is invalid\n", good_input[i]);
- exit(1);
- }
- }
-
- int bad_input_size = sizeof(bad_input) / sizeof(char *);
- int j = 0;
- for(j = 0; j < bad_input_size; j++) {
- int op = validate_container_id(bad_input[j]);
- if(0 != op) {
- printf("FAIL: docker container name %s is valid, expected invalid\n", bad_input[j]);
- exit(1);
- }
- }
-}
-
// This test is expected to be executed either by a regular
// user or by root. If executed by a regular user it doesn't
// test all the functions that would depend on changing the
@@ -1406,15 +1267,6 @@ int main(int argc, char **argv) {
printf("\nTesting is_feature_enabled()\n");
test_is_feature_enabled();
- printf("\nTesting sanitize docker commands()\n");
- test_sanitize_docker_command();
-
- printf("\nTesting validate_docker_image_name()\n");
- test_validate_docker_image_name();
-
- printf("\nTesting validate_container_id()\n");
- test_validate_container_id();
-
test_check_user(0);
#ifdef __APPLE__
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test_container_id_utils.cc b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test_container_id_utils.cc
new file mode 100644
index 00000000000..d6278064cd9
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test_container_id_utils.cc
@@ -0,0 +1,71 @@
+/**
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#include
+
+extern "C" {
+#include "utils/container-id-utils.h"
+}
+
+namespace ContainerExecutor {
+
+ class TestContainerIdUtils : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+ };
+
+ TEST_F(TestContainerIdUtils, test_validate_container_id) {
+
+ const char *good_input[] = {
+ "container_e134_1499953498516_50875_01_000007",
+ "container_1499953498516_50875_01_000007",
+ "container_e1_12312_11111_02_000001"
+ };
+
+ const char *bad_input[] = {
+ "CONTAINER",
+ "container_e1_12312_11111_02_000001 | /tmp/file"
+ "container_e1_12312_11111_02_000001 || # /tmp/file",
+ "container_e1_12312_11111_02_000001 # /tmp/file",
+ "container_e1_12312_11111_02_000001' || touch /tmp/file #",
+ "ubuntu || touch /tmp/file #",
+ "''''''''"
+ };
+
+ int good_input_size = sizeof(good_input) / sizeof(char *);
+ int i = 0;
+ for (i = 0; i < good_input_size; i++) {
+ int op = validate_container_id(good_input[i]);
+ ASSERT_EQ(1, op);
+ }
+
+ int bad_input_size = sizeof(bad_input) / sizeof(char *);
+ int j = 0;
+ for (j = 0; j < bad_input_size; j++) {
+ int op = validate_container_id(bad_input[j]);
+ ASSERT_EQ(0, op);
+ }
+ }
+}
+
+
+
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test_docker_util.cc b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test_docker_util.cc
new file mode 100644
index 00000000000..91fd1d7695c
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test_docker_util.cc
@@ -0,0 +1,962 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include
+#include
+#include
+
+extern "C" {
+#include "utils/docker-util.c"
+}
+
+namespace ContainerExecutor {
+
+ class TestDockerUtil : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ docker_command_file = "docker-command.cmd";
+ container_executor_cfg_file = "container-executor.cfg";
+ container_executor_cfg.size = 0;
+ container_executor_cfg.sections = NULL;
+ }
+
+ virtual void TearDown() {
+ remove(docker_command_file.c_str());
+ remove(container_executor_cfg_file.c_str());
+ delete_ce_file();
+ }
+
+ struct configuration container_executor_cfg;
+ std::string docker_command_file;
+ std::string container_executor_cfg_file;
+
+
+ void write_file(const std::string fname, const std::string contents) {
+ std::ofstream command_file;
+ command_file.open(fname);
+ command_file << contents;
+ command_file.close();
+ }
+
+ int create_ce_file() {
+ const char *fname = HADOOP_CONF_DIR "/" CONF_FILENAME;
+ if (strcmp("../etc/hadoop/container-executor.cfg", fname) == 0) {
+ int ret = mkdir("../etc", 0755);
+ if (ret == 0 || errno == EEXIST) {
+ ret = mkdir("../etc/hadoop", 0755);
+ if (ret == 0 || errno == EEXIST) {
+ write_file("../etc/hadoop/container-executor.cfg", "");
+ return 0;
+ } else {
+ std::cerr << "Could not create ../etc/hadoop, " << strerror(errno) << std::endl;
+ }
+ } else {
+ std::cerr << "Could not create ../etc, " << strerror(errno) << std::endl;
+ }
+ }
+ std::cerr << "Could not create " << fname << std::endl;
+ return 1;
+ }
+
+ void delete_ce_file() {
+ const char *fname = HADOOP_CONF_DIR "/" CONF_FILENAME;
+ if (strcmp("../etc/hadoop/container-executor.cfg", fname) == 0) {
+ struct stat buffer;
+ if (stat(fname, &buffer) == 0) {
+ remove("../etc/hadoop/container-executor.cfg");
+ rmdir("../etc/hadoop");
+ rmdir("../etc");
+ }
+ }
+ }
+
+ void write_container_executor_cfg(const std::string contents) {
+ write_file(container_executor_cfg_file, contents);
+ }
+
+ void write_command_file(const std::string contents) {
+ write_file(docker_command_file, contents);
+ }
+
+ void run_docker_command_test(const std::unordered_map &file_cmd_map,
+ const std::unordered_map &bad_file_cmd_map,
+ int (*docker_func)(const char *, const struct configuration *, char *, const size_t)) {
+ char tmp[8192];
+ std::unordered_map::const_iterator itr;
+ for (itr = file_cmd_map.begin(); itr != file_cmd_map.end(); ++itr) {
+ write_command_file(itr->first);
+ int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, tmp, 8192);
+ ASSERT_EQ(0, ret) << "error message: " << get_docker_error_message(ret) << " for input " << itr->first;
+ ASSERT_STREQ(itr->second.c_str(), tmp);
+ }
+
+ memset(tmp, 0, 8192);
+ std::unordered_map::const_iterator itr2;
+ for (itr2 = bad_file_cmd_map.begin(); itr2 != bad_file_cmd_map.end(); ++itr2) {
+ write_command_file(itr2->first);
+ int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, tmp, 8192);
+ ASSERT_EQ(itr2->second, ret);
+ ASSERT_EQ(0, strlen(tmp));
+ }
+ int ret = (*docker_func)("unknown-file", &container_executor_cfg, tmp, 8192);
+ ASSERT_EQ(static_cast(INVALID_COMMAND_FILE), ret);
+ }
+
+ void run_docker_run_helper_function(const std::unordered_map &file_cmd_map,
+ int (*helper_func)(const struct configuration *, char *, const size_t)) {
+ std::unordered_map::const_iterator itr;
+ for(itr = file_cmd_map.begin(); itr != file_cmd_map.end(); ++itr) {
+ struct configuration cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ memset(buff, 0, buff_len);
+ write_command_file(itr->first);
+ int ret = read_config(docker_command_file.c_str(), &cfg);
+ if(ret == 0) {
+ ret = (*helper_func)(&cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+ }
+ }
+ };
+
+ TEST_F(TestDockerUtil, test_docker_inspect) {
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=inspect\n format={{.State.Status}}\n name=ctr-id"]
+ = "inspect --format='{{.State.Status}}' 'ctr-id' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=inspect\n"
+ " format={{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}}\n"
+ " name=ctr-id"]
+ = "inspect --format='{{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}}' 'ctr-id' ";
+
+ std::unordered_map bad_file_cmd_map;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=run\n format='{{.State.Status}}'"]
+ = INCORRECT_COMMAND;
+ bad_file_cmd_map["docker-command=inspect\n format='{{.State.Status}}'"] = INCORRECT_COMMAND;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=inspect\n format={{.State.Status}}\n name="]
+ = INVALID_DOCKER_CONTAINER_NAME;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=inspect\n format={{.State.Status}}"]
+ = INVALID_DOCKER_CONTAINER_NAME;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=inspect\n format=\n name=ctr-id"]
+ = INVALID_DOCKER_INSPECT_FORMAT;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=inspect\n name=ctr-id"]
+ = INVALID_DOCKER_INSPECT_FORMAT;
+
+ run_docker_command_test(file_cmd_map, bad_file_cmd_map, get_docker_inspect_command);
+ }
+
+ TEST_F(TestDockerUtil, test_docker_load) {
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=load\n image=image-id"] = "load --i='image-id' ";
+
+ std::unordered_map bad_file_cmd_map;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=run\n image=image-id"] = INCORRECT_COMMAND;
+ bad_file_cmd_map["docker-command=load\n image=image-id"] = INCORRECT_COMMAND;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=load\n image="] = INVALID_DOCKER_IMAGE_NAME;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=load"] = INVALID_DOCKER_IMAGE_NAME;
+
+ run_docker_command_test(file_cmd_map, bad_file_cmd_map, get_docker_load_command);
+ }
+
+ TEST_F(TestDockerUtil, test_docker_validate_image_name) {
+ const char *good_input[] = {
+ "ubuntu",
+ "ubuntu:latest",
+ "ubuntu:14.04",
+ "ubuntu:LATEST",
+ "registry.com:5000/user/ubuntu",
+ "registry.com:5000/user/ubuntu:latest",
+ "registry.com:5000/user/ubuntu:0.1.2.3",
+ "registry.com/user/ubuntu",
+ "registry.com/user/ubuntu:latest",
+ "registry.com/user/ubuntu:0.1.2.3",
+ "registry.com/user/ubuntu:test-image",
+ "registry.com/user/ubuntu:test_image",
+ "registry.com/ubuntu",
+ "user/ubuntu",
+ "user/ubuntu:0.1.2.3",
+ "user/ubuntu:latest",
+ "user/ubuntu:test_image",
+ "user/ubuntu.test:test_image",
+ "user/ubuntu-test:test-image",
+ "registry.com/ubuntu/ubuntu/ubuntu"
+ };
+
+ const char *bad_input[] = {
+ "UBUNTU",
+ "registry.com|5000/user/ubuntu",
+ "registry.com | 5000/user/ubuntu",
+ "ubuntu' || touch /tmp/file #",
+ "ubuntu || touch /tmp/file #",
+ "''''''''",
+ "bad_host_name:5000/user/ubuntu",
+ "registry.com:foo/ubuntu/ubuntu/ubuntu",
+ "registry.com/ubuntu:foo/ubuntu/ubuntu"
+ };
+
+ int good_input_size = sizeof(good_input) / sizeof(char *);
+ int i = 0;
+ for (i = 0; i < good_input_size; i++) {
+ int op = validate_docker_image_name(good_input[i]);
+ ASSERT_EQ(0, op);
+ }
+
+ int bad_input_size = sizeof(bad_input) / sizeof(char *);
+ int j = 0;
+ for (j = 0; j < bad_input_size; j++) {
+ int op = validate_docker_image_name(bad_input[j]);
+ ASSERT_EQ(1, op);
+ }
+ }
+
+ TEST_F(TestDockerUtil, test_docker_pull) {
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=pull\n image=image-id"] = "pull 'image-id' ";
+
+ std::unordered_map bad_file_cmd_map;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=run\n image=image-id"] = INCORRECT_COMMAND;
+ bad_file_cmd_map["docker-command=pull\n image=image-id"] = INCORRECT_COMMAND;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=pull\n image="] = INVALID_DOCKER_IMAGE_NAME;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=pull"] = INVALID_DOCKER_IMAGE_NAME;
+
+ run_docker_command_test(file_cmd_map, bad_file_cmd_map, get_docker_pull_command);
+ }
+
+ TEST_F(TestDockerUtil, test_docker_rm) {
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=rm\n name=ctr-id"] = "rm 'ctr-id' ";
+
+ std::unordered_map bad_file_cmd_map;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=run\n name=ctr-id"] = INCORRECT_COMMAND;
+ bad_file_cmd_map["docker-command=rm\n name=ctr-id"] = INCORRECT_COMMAND;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=rm\n name="] = INVALID_DOCKER_CONTAINER_NAME;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=rm"] = INVALID_DOCKER_CONTAINER_NAME;
+
+ run_docker_command_test(file_cmd_map, bad_file_cmd_map, get_docker_rm_command);
+ }
+
+ TEST_F(TestDockerUtil, test_docker_stop) {
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=stop\n name=ctr-id"] = "stop 'ctr-id' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=stop\n name=ctr-id\ntime=25"]
+ = "stop --time='25' 'ctr-id' ";
+
+ std::unordered_map bad_file_cmd_map;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=run\n name=ctr-id"] = INCORRECT_COMMAND;
+ bad_file_cmd_map["docker-command=stop\n name=ctr-id"] = INCORRECT_COMMAND;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=stop\n name="] = INVALID_DOCKER_CONTAINER_NAME;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=stop"] = INVALID_DOCKER_CONTAINER_NAME;
+
+ run_docker_command_test(file_cmd_map, bad_file_cmd_map, get_docker_stop_command);
+ }
+
+ TEST_F(TestDockerUtil, test_detach_container) {
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n detach=true"] = "-d ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run"] = "";
+
+ run_docker_run_helper_function(file_cmd_map, detach_container);
+ }
+
+ TEST_F(TestDockerUtil, test_rm_container) {
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n rm=true"] = "--rm ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run"] = "";
+
+ run_docker_run_helper_function(file_cmd_map, rm_container_on_exit);
+ }
+
+ TEST_F(TestDockerUtil, test_set_container_workdir) {
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n workdir=/tmp/test"] = "--workdir='/tmp/test' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run"] = "";
+
+ run_docker_run_helper_function(file_cmd_map, set_container_workdir);
+ }
+
+ TEST_F(TestDockerUtil, test_set_cgroup_parent) {
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n cgroup-parent=/sys/fs/cgroup/yarn"]
+ = "--cgroup-parent='/sys/fs/cgroup/yarn' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run"] = "";
+
+ run_docker_run_helper_function(file_cmd_map, set_cgroup_parent);
+ }
+
+ TEST_F(TestDockerUtil, test_set_hostname) {
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n hostname=ctr-id"] = "--hostname='ctr-id' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run"] = "";
+
+ run_docker_run_helper_function(file_cmd_map, set_hostname);
+ }
+
+ TEST_F(TestDockerUtil, test_set_network) {
+ struct configuration container_cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ int ret = 0;
+ std::string container_executor_cfg_contents = "[docker]\n allowed.networks=sdn1,bridge";
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n net=bridge"] = "--net='bridge' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n net=sdn1"] = "--net='sdn1' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run"] = "";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+
+ std::unordered_map::const_iterator itr;
+ if (ret != 0) {
+ FAIL();
+ }
+ for (itr = file_cmd_map.begin(); itr != file_cmd_map.end(); ++itr) {
+ struct configuration cmd_cfg;
+ memset(buff, 0, buff_len);
+ write_command_file(itr->first);
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ ret = set_network(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+ struct configuration cmd_cfg_1;
+ write_command_file("[docker-command-execution]\n docker-command=run\n net=sdn2");
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg_1);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = set_network(&cmd_cfg_1, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_NETWORK, ret);
+ ASSERT_EQ(0, strlen(buff));
+
+ container_executor_cfg_contents = "[docker]\n";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = set_network(&cmd_cfg_1, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_NETWORK, ret);
+ ASSERT_EQ(0, strlen(buff));
+ }
+
+ TEST_F(TestDockerUtil, test_check_mount_permitted) {
+ const char *permitted_mounts[] = {"/var/hadoop/data/", "/tmp/test-file", NULL};
+ std::unordered_map test_data;
+ test_data["/var/hadoop/data"] = 0;
+ test_data["/var/hadoop/data/"] = 1;
+ test_data["/var/hadoop/data/tmp"] = 1;
+ test_data["/tmp/test-file"] = 1;
+ test_data["/tmp/test-file-dir/"] = 0;
+
+ std::unordered_map::const_iterator itr;
+ for (itr = test_data.begin(); itr != test_data.end(); ++itr) {
+ int ret = check_mount_permitted(permitted_mounts, itr->first.c_str());
+ ASSERT_EQ(itr->second, ret);
+ }
+ }
+
+ TEST_F(TestDockerUtil, test_normalize_mounts) {
+ const int entries = 4;
+ const char *permitted_mounts[] = {"/home", "/usr", "/bin/ls", NULL};
+ const char *expected[] = {"/home/", "/usr/", "/bin/ls", NULL};
+ char **ptr = static_cast(malloc(entries * sizeof(char *)));
+ for (int i = 0; i < entries; ++i) {
+ if (permitted_mounts[i] != NULL) {
+ ptr[i] = strdup(permitted_mounts[i]);
+ } else {
+ ptr[i] = NULL;
+ }
+ }
+ normalize_mounts(ptr);
+ for (int i = 0; i < entries; ++i) {
+ ASSERT_STREQ(expected[i], ptr[i]);
+ }
+ }
+
+ TEST_F(TestDockerUtil, test_set_privileged) {
+ struct configuration container_cfg, cmd_cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ int ret = 0;
+ std::string container_executor_cfg_contents[] = {"[docker]\n privileged-containers.enabled=1",
+ "[docker]\n privileged-containers.enabled=0",
+ "[docker]\n"};
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n privileged=true"] = "--privileged ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n privileged=false"] = "";
+ file_cmd_map["[docker-command-execution]\n docker-command=run"] = "";
+ write_container_executor_cfg(container_executor_cfg_contents[0]);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+
+ std::unordered_map::const_iterator itr;
+ if (ret != 0) {
+ FAIL();
+ }
+ for (itr = file_cmd_map.begin(); itr != file_cmd_map.end(); ++itr) {
+ memset(buff, 0, buff_len);
+ write_command_file(itr->first);
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ ret = set_privileged(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+
+ // check default case and when it's turned off
+ for (int i = 1; i < 3; ++i) {
+ write_container_executor_cfg(container_executor_cfg_contents[i]);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ file_cmd_map.clear();
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n privileged=false"] = "";
+ file_cmd_map["[docker-command-execution]\n docker-command=run"] = "";
+ for (itr = file_cmd_map.begin(); itr != file_cmd_map.end(); ++itr) {
+ memset(buff, 0, buff_len);
+ write_command_file(itr->first);
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ ret = set_privileged(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+ write_command_file("[docker-command-execution]\n docker-command=run\n privileged=true");
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ ret = set_privileged(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(PRIVILEGED_CONTAINERS_DISABLED, ret);
+ ASSERT_EQ(0, strlen(buff));
+ }
+ }
+
+ TEST_F(TestDockerUtil, test_set_capabilities) {
+ struct configuration container_cfg, cmd_cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ int ret = 0;
+ std::string container_executor_cfg_contents = "[docker]\n allowed.capabilities=CHROOT,MKNOD";
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n cap-add=CHROOT,MKNOD"]
+ = "--cap-drop='ALL' --cap-add='CHROOT' --cap-add='MKNOD' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n cap-add=CHROOT"]
+ = "--cap-drop='ALL' --cap-add='CHROOT' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run"] = "--cap-drop='ALL' ";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+
+ std::unordered_map::const_iterator itr;
+ if (ret != 0) {
+ FAIL();
+ }
+ for (itr = file_cmd_map.begin(); itr != file_cmd_map.end(); ++itr) {
+ memset(buff, 0, buff_len);
+ write_command_file(itr->first);
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ ret = set_capabilities(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+ write_command_file("[docker-command-execution]\n docker-command=run\n cap-add=SETGID");
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = set_capabilities(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_CAPABILITY, ret);
+ ASSERT_EQ(0, strlen(buff));
+
+ container_executor_cfg_contents = "[docker]\n";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = set_capabilities(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_CAPABILITY, ret);
+ ASSERT_EQ(0, strlen(buff));
+ }
+
+ TEST_F(TestDockerUtil, test_add_devices) {
+ struct configuration container_cfg, cmd_cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ int ret = 0;
+ std::string container_executor_cfg_contents = "[docker]\n allowed.devices=/dev/test-device,/dev/device2";
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n devices=/dev/test-device:/dev/test-device"]
+ = "--device='/dev/test-device:/dev/test-device' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n devices=/dev/device2:/dev/device2"]
+ = "--device='/dev/device2:/dev/device2' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n "
+ "devices=/dev/test-device:/dev/test-device,/dev/device2:/dev/device2"]
+ = "--device='/dev/test-device:/dev/test-device' --device='/dev/device2:/dev/device2' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n"] = "";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+
+ std::unordered_map::const_iterator itr;
+ if (ret != 0) {
+ FAIL();
+ }
+ for (itr = file_cmd_map.begin(); itr != file_cmd_map.end(); ++itr) {
+ memset(buff, 0, buff_len);
+ write_command_file(itr->first);
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ ret = add_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+ write_command_file("[docker-command-execution]\n docker-command=run\n devices=/dev/device3:/dev/device3");
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = add_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
+ ASSERT_EQ(0, strlen(buff));
+
+ container_executor_cfg_contents = "[docker]\n";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = add_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
+ ASSERT_EQ(0, strlen(buff));
+ }
+
+
+ TEST_F(TestDockerUtil, test_add_rw_mounts) {
+ struct configuration container_cfg, cmd_cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ int ret = 0;
+ std::string container_executor_cfg_contents = "[docker]\n allowed.rw-mounts=/usr,/var,/bin/ls,..\n "
+ "allowed.ro-mounts=/bin/cat";
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n rw-mounts=/var:/var"]
+ = "-v '/var:/var' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n rw-mounts=/var/:/var/"]
+ = "-v '/var/:/var/' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n rw-mounts=/usr:/usr"]
+ = "-v '/usr:/usr' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n rw-mounts=/usr/:/usr"]
+ = "-v '/usr/:/usr' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n rw-mounts=/bin/ls:/bin/ls"]
+ = "-v '/bin/ls:/bin/ls' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n "
+ "rw-mounts=/usr/bin:/mydisk1,/var/log/:/mydisk2"]
+ = "-v '/usr/bin:/mydisk1' -v '/var/log/:/mydisk2' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n"] = "";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+
+ ret = create_ce_file();
+ if (ret != 0) {
+ std::cerr << "Could not create ce file, skipping test" << std::endl;
+ return;
+ }
+
+ std::unordered_map::const_iterator itr;
+
+ for (itr = file_cmd_map.begin(); itr != file_cmd_map.end(); ++itr) {
+ memset(buff, 0, buff_len);
+ write_command_file(itr->first);
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+
+ std::unordered_map bad_file_cmds_map;
+ bad_file_cmds_map["[docker-command-execution]\n docker-command=run\n rw-mounts=/home:/home"]
+ = INVALID_DOCKER_RW_MOUNT;
+ bad_file_cmds_map["[docker-command-execution]\n docker-command=run\n rw-mounts=/bin/cat:/bin/cat"]
+ = INVALID_DOCKER_RW_MOUNT;
+ bad_file_cmds_map["[docker-command-execution]\n docker-command=run\n rw-mounts=/blah:/blah"]
+ = INVALID_DOCKER_MOUNT;
+
+ std::unordered_map::const_iterator itr2;
+
+ for (itr2 = bad_file_cmds_map.begin(); itr2 != bad_file_cmds_map.end(); ++itr2) {
+ memset(buff, 0, buff_len);
+ write_command_file(itr2->first);
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(itr2->second, ret);
+ ASSERT_STREQ("", buff);
+ }
+
+ // verify that you can't mount any directory in the container-executor.cfg path
+ char *ce_path = realpath("../etc/hadoop/container-executor.cfg", NULL);
+ while (strlen(ce_path) != 0) {
+ std::string cmd_file_contents = "[docker-command-execution]\n docker-command=run\n rw-mounts=";
+ cmd_file_contents.append(ce_path).append(":").append("/etc/hadoop");
+ memset(buff, 0, buff_len);
+ write_command_file(cmd_file_contents);
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_RW_MOUNT, ret);
+ ASSERT_STREQ("", buff);
+ char *tmp = strrchr(ce_path, '/');
+ if (tmp != NULL) {
+ *tmp = '\0';
+ }
+ }
+ free(ce_path);
+
+ container_executor_cfg_contents = "[docker]\n";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_RW_MOUNT, ret);
+ ASSERT_EQ(0, strlen(buff));
+ }
+
+ TEST_F(TestDockerUtil, test_add_ro_mounts) {
+ struct configuration container_cfg, cmd_cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ int ret = 0;
+ std::string container_executor_cfg_contents = "[docker]\n allowed.rw-mounts=/usr,/var,/bin/ls\n "
+ "allowed.ro-mounts=/bin/cat,/bin/ln";
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n ro-mounts=/var:/var"]
+ = "-v '/var:/var:ro' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n ro-mounts=/var/:/var/"]
+ = "-v '/var/:/var/:ro' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n ro-mounts=/usr:/usr"]
+ = "-v '/usr:/usr:ro' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n ro-mounts=/usr/:/usr"]
+ = "-v '/usr/:/usr:ro' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n ro-mounts=/bin/ls:/bin/ls"]
+ = "-v '/bin/ls:/bin/ls:ro' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n ro-mounts=/bin/ln:/bin/ln"]
+ = "-v '/bin/ln:/bin/ln:ro' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n ro-mounts=/bin/cat:/bin/cat"]
+ = "-v '/bin/cat:/bin/cat:ro' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n "
+ "ro-mounts=/usr/bin:/mydisk1,/bin/cat:/bin/cat"]
+ = "-v '/usr/bin:/mydisk1:ro' -v '/bin/cat:/bin/cat:ro' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n"] = "";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+
+ ret = create_ce_file();
+ if (ret != 0) {
+ std::cerr << "Could not create ce file, skipping test" << std::endl;
+ return;
+ }
+
+ std::unordered_map::const_iterator itr;
+
+ for (itr = file_cmd_map.begin(); itr != file_cmd_map.end(); ++itr) {
+ memset(buff, 0, buff_len);
+ write_command_file(itr->first);
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ ret = add_ro_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+
+ std::unordered_map bad_file_cmds_map;
+ bad_file_cmds_map["[docker-command-execution]\n docker-command=run\n ro-mounts=/home:/home"]
+ = INVALID_DOCKER_RO_MOUNT;
+ bad_file_cmds_map["[docker-command-execution]\n docker-command=run\n ro-mounts=/blah:/blah"]
+ = INVALID_DOCKER_MOUNT;
+
+ std::unordered_map::const_iterator itr2;
+
+ for (itr2 = bad_file_cmds_map.begin(); itr2 != bad_file_cmds_map.end(); ++itr2) {
+ memset(buff, 0, buff_len);
+ write_command_file(itr2->first);
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = add_ro_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(itr2->second, ret);
+ ASSERT_STREQ("", buff);
+ }
+
+ container_executor_cfg_contents = "[docker]\n";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ write_command_file("[docker-command-execution]\n docker-command=run\n ro-mounts=/home:/home");
+ strcpy(buff, "test string");
+ ret = add_ro_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_RO_MOUNT, ret);
+ ASSERT_EQ(0, strlen(buff));
+ }
+
+ TEST_F(TestDockerUtil, test_docker_run_privileged) {
+
+ std::string container_executor_contents = "[docker]\n allowed.ro-mounts=/var,/etc,/bin/ls\n"
+ " allowed.rw-mounts=/tmp\n allowed.networks=bridge\n "
+ " privileged-containers.enabled=1\n allowed.capabilities=CHOWN,SETUID\n"
+ " allowed.devices=/dev/test";
+ write_file(container_executor_cfg_file, container_executor_contents);
+ int ret = read_config(container_executor_cfg_file.c_str(), &container_executor_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ ret = create_ce_file();
+ if (ret != 0) {
+ std::cerr << "Could not create ce file, skipping test" << std::endl;
+ return;
+ }
+
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n name=ctr-id\n image=docker-image\n user=test"]
+ = "run --name='ctr-id' --user='test' --cap-drop='ALL' 'docker-image' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = "run --name='ctr-id' --user='test' --cap-drop='ALL' 'docker-image' 'bash' 'test_script.sh' 'arg1' 'arg2' ";
+
+ file_cmd_map["[docker-command-execution]\n"
+ " docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = "run --name='ctr-id' --user='test' -d --rm -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
+ " -v '/bin/ls:/bin/ls:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --cap-add='CHOWN'"
+ " --cap-add='SETUID' --hostname='host-id' --device='/dev/test:/dev/test' 'docker-image' 'bash' "
+ "'test_script.sh' 'arg1' 'arg2' ";
+
+ file_cmd_map["[docker-command-execution]\n"
+ " docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n net=bridge\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = "run --name='ctr-id' --user='test' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
+ " -v '/bin/ls:/bin/ls:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --cap-add='CHOWN' "
+ "--cap-add='SETUID' --hostname='host-id' --device='/dev/test:/dev/test' 'docker-image' 'bash'"
+ " 'test_script.sh' 'arg1' 'arg2' ";
+
+ file_cmd_map["[docker-command-execution]\n"
+ " docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n net=bridge\n privileged=true\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = "run --name='ctr-id' --user='test' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
+ " -v '/bin/ls:/bin/ls:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --privileged --cap-drop='ALL' "
+ "--cap-add='CHOWN' --cap-add='SETUID' --hostname='host-id' --device='/dev/test:/dev/test' 'docker-image' "
+ "'bash' 'test_script.sh' 'arg1' 'arg2' ";
+
+
+ std::unordered_map bad_file_cmd_map;
+
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=run\n image=docker-image\n user=test"]
+ = INVALID_DOCKER_CONTAINER_NAME;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=run\n name=ctr-id\n user=test\n"]
+ = INVALID_DOCKER_IMAGE_NAME;
+ bad_file_cmd_map["[docker-command-execution]\n docker-command=run\n name=ctr-id\n image=docker-image\n"]
+ = INVALID_DOCKER_USER_NAME;
+ // invalid rw mount
+ bad_file_cmd_map["[docker-command-execution]\n"
+ " docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/var/log:/var/log\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = INVALID_DOCKER_RW_MOUNT;
+ // invalid ro mount
+ bad_file_cmd_map["[docker-command-execution]\n"
+ " docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/bin:/bin,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = INVALID_DOCKER_RO_MOUNT;
+ // invalid capability
+ bad_file_cmd_map["[docker-command-execution]\n"
+ " docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n"
+ " cap-add=CHOWN,SETUID,SETGID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = INVALID_DOCKER_CAPABILITY;
+ // invalid device
+ bad_file_cmd_map["[docker-command-execution]\n"
+ " docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/dev1:/dev/dev1\n privileged=true\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = INVALID_DOCKER_DEVICE;
+ // invalid network
+ bad_file_cmd_map["[docker-command-execution]\n"
+ " docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n privileged=true\n net=host\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = INVALID_DOCKER_NETWORK;
+
+ run_docker_command_test(file_cmd_map, bad_file_cmd_map, get_docker_run_command);
+ }
+
+ TEST_F(TestDockerUtil, test_docker_run_no_privileged) {
+
+ std::string container_executor_contents[] = { "[docker]\n allowed.ro-mounts=/var,/etc,/bin/ls\n"
+ " allowed.rw-mounts=/tmp\n allowed.networks=bridge\n "
+ " allowed.capabilities=CHOWN,SETUID\n"
+ " allowed.devices=/dev/test",
+ "[docker]\n allowed.ro-mounts=/var,/etc,/bin/ls\n"
+ " allowed.rw-mounts=/tmp\n allowed.networks=bridge\n "
+ " allowed.capabilities=CHOWN,SETUID\n"
+ " privileged=0\n"
+ " allowed.devices=/dev/test" };
+ for (int i = 0; i < 2; ++i) {
+ write_file(container_executor_cfg_file, container_executor_contents[i]);
+ int ret = read_config(container_executor_cfg_file.c_str(), &container_executor_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ ret = create_ce_file();
+ if (ret != 0) {
+ std::cerr << "Could not create ce file, skipping test" << std::endl;
+ return;
+ }
+
+ std::unordered_map file_cmd_map;
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n name=ctr-id\n image=docker-image\n user=test"]
+ = "run --name='ctr-id' --user='test' --cap-drop='ALL' 'docker-image' ";
+ file_cmd_map["[docker-command-execution]\n docker-command=run\n name=ctr-id\n image=docker-image\n"
+ " user=test\n launch-command=bash,test_script.sh,arg1,arg2"]
+ = "run --name='ctr-id' --user='test' --cap-drop='ALL' 'docker-image' 'bash' 'test_script.sh' 'arg1' 'arg2' ";
+
+ file_cmd_map["[docker-command-execution]\n"
+ " docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = "run --name='ctr-id' --user='test' -d --rm -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
+ " -v '/bin/ls:/bin/ls:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --cap-add='CHOWN'"
+ " --cap-add='SETUID' --hostname='host-id' --device='/dev/test:/dev/test' 'docker-image' 'bash' "
+ "'test_script.sh' 'arg1' 'arg2' ";
+
+ file_cmd_map["[docker-command-execution]\n"
+ " docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n net=bridge\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = "run --name='ctr-id' --user='test' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
+ " -v '/bin/ls:/bin/ls:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --cap-add='CHOWN' "
+ "--cap-add='SETUID' --hostname='host-id' --device='/dev/test:/dev/test' 'docker-image' 'bash'"
+ " 'test_script.sh' 'arg1' 'arg2' ";
+
+ std::unordered_map bad_file_cmd_map;
+ bad_file_cmd_map["[docker-command-execution]\n"
+ " docker-command=run\n name=ctr-id\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n net=bridge\n privileged=true\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2"]
+ = PRIVILEGED_CONTAINERS_DISABLED;
+
+ run_docker_command_test(file_cmd_map, bad_file_cmd_map, get_docker_run_command);
+ }
+ }
+
+ TEST_F(TestDockerUtil, test_docker_config_param) {
+ std::unordered_map input_output_map;
+ input_output_map["[docker-command-execution]\n docker-command=inspect\n docker-config=/my-config\n"
+ " format={{.State.Status}}\n name=ctr-id"]
+ = "--config='/my-config' inspect --format='{{.State.Status}}' 'ctr-id' ";
+ input_output_map["[docker-command-execution]\n docker-command=load\n docker-config=/my-config\n image=image-id"]
+ = "--config='/my-config' load --i='image-id' ";
+ input_output_map["[docker-command-execution]\n docker-command=pull\n docker-config=/my-config\n image=image-id"]
+ = "--config='/my-config' pull 'image-id' ";
+ input_output_map["[docker-command-execution]\n docker-command=rm\n docker-config=/my-config\n name=ctr-id"]
+ = "--config='/my-config' rm 'ctr-id' ";
+ input_output_map["[docker-command-execution]\n docker-command=stop\n docker-config=/my-config\n name=ctr-id"]
+ = "--config='/my-config' stop 'ctr-id' ";
+ input_output_map["[docker-command-execution]\n docker-command=run\n docker-config=/my-config\n name=ctr-id\n"
+ " image=docker-image\n user=test"]
+ = "--config='/my-config' run --name='ctr-id' --user='test' --cap-drop='ALL' 'docker-image' ";
+
+ std::unordered_map::const_iterator itr;
+ char buffer[4096];
+ struct configuration cfg = {.size = 0, .sections = NULL};
+ for (itr = input_output_map.begin(); itr != input_output_map.end(); ++itr) {
+ memset(buffer, 0, 4096);
+ write_command_file(itr->first);
+ int ret = get_docker_command(docker_command_file.c_str(), &cfg, buffer, 4096);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buffer);
+ }
+ }
+}
+
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test_util.cc b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test_util.cc
index 2ec7b2a09c7..ebcba0f80ab 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test_util.cc
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test_util.cc
@@ -18,6 +18,7 @@
#include
#include
+#include
extern "C" {
#include "util.h"
@@ -135,4 +136,39 @@ namespace ContainerExecutor {
ASSERT_STREQ("foo", trimmed);
free(trimmed);
}
+
+ TEST_F(TestUtil, test_escape_single_quote) {
+ std::unordered_map input_output_map;
+ input_output_map["'abcd'"] = "'\"'\"'abcd'\"'\"'";
+ input_output_map["'"] = "'\"'\"'";
+
+ std::unordered_map::const_iterator itr;
+ for (itr = input_output_map.begin(); itr != input_output_map.end(); ++itr) {
+ char *ret = escape_single_quote(itr->first.c_str());
+ ASSERT_STREQ(itr->second.c_str(), ret);
+ free(ret);
+ }
+ }
+
+ TEST_F(TestUtil, test_quote_and_append_arg) {
+
+ char *tmp = static_cast(malloc(4096));
+ size_t tmp_size = 4096;
+
+ memset(tmp, 0, tmp_size);
+ quote_and_append_arg(&tmp, &tmp_size, "param=", "argument1");
+ ASSERT_STREQ("param='argument1' ", tmp);
+
+ memset(tmp, 0, tmp_size);
+ quote_and_append_arg(&tmp, &tmp_size, "param=", "ab'cd");
+ ASSERT_STREQ("param='ab'\"'\"'cd' ", tmp);
+ free(tmp);
+
+ tmp = static_cast(malloc(4));
+ tmp_size = 4;
+ memset(tmp, 0, tmp_size);
+ quote_and_append_arg(&tmp, &tmp_size, "param=", "argument1");
+ ASSERT_STREQ("param='argument1' ", tmp);
+ ASSERT_EQ(1040, tmp_size);
+ }
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java
index 9894dcd90fc..fe02c9e78b6 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java
@@ -97,6 +97,7 @@
private final String whitelistedUser = "yoda";
private String[] testCapabilities;
private final String signalPid = "1234";
+ private File cgroup = new File("/sys/fs/cgroup");
@Before
public void setup() {
@@ -285,32 +286,44 @@ public void testDockerContainerLaunch()
List args = op.getArguments();
String dockerCommandFile = args.get(11);
- //This is the expected docker invocation for this case
- StringBuffer expectedCommandTemplate = new StringBuffer("run --name=%1$s ")
- .append("--user=%2$s -d ")
- .append("--workdir=%3$s ")
- .append("--net=host ")
- .append("--hostname=" + defaultHostname + " ")
- .append(getExpectedTestCapabilitiesArgumentString())
- .append(getExpectedCGroupsMountString())
- .append("-v %4$s:%4$s ")
- .append("-v %5$s:%5$s ")
- .append("-v %6$s:%6$s ")
- .append("-v %7$s:%7$s ")
- .append("-v %8$s:%8$s ").append("%9$s ")
- .append("bash %10$s/launch_container.sh");
-
- String expectedCommand = String
- .format(expectedCommandTemplate.toString(), containerId, runAsUser,
- containerWorkDir, containerLocalDirs.get(0), filecacheDirs.get(0),
- containerWorkDir, containerLogDirs.get(0), userLocalDirs.get(0),
- image, containerWorkDir);
-
List dockerCommands = Files.readAllLines(Paths.get
(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals(expectedCommand, dockerCommands.get(0));
+ int expected = 13;
+ if (cgroup.exists()) {
+ expected = 14;
+ }
+ int counter = 0;
+ Assert.assertEquals(expected, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(counter++));
+ Assert.assertEquals(" detach=true", dockerCommands.get(counter++));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(counter++));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" image=busybox:latest", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(counter++));
+ Assert.assertEquals(" net=host", dockerCommands.get(counter++));
+ if (cgroup.exists()) {
+ Assert.assertEquals(" ro-mounts=/sys/fs/cgroup:/sys/fs/cgroup",
+ dockerCommands.get(counter++));
+ }
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(counter++));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(counter++));
}
@Test
@@ -396,29 +409,45 @@ public void testContainerLaunchWithNetworkingDefaults()
String dockerCommandFile = args.get(11);
//This is the expected docker invocation for this case
- StringBuffer expectedCommandTemplate =
- new StringBuffer("run --name=%1$s ").append("--user=%2$s -d ")
- .append("--workdir=%3$s ")
- .append("--net=" + allowedNetwork + " ")
- .append("--hostname=" + expectedHostname + " ")
- .append(getExpectedTestCapabilitiesArgumentString())
- .append(getExpectedCGroupsMountString())
- .append("-v %4$s:%4$s ").append("-v %5$s:%5$s ")
- .append("-v %6$s:%6$s ").append("-v %7$s:%7$s ")
- .append("-v %8$s:%8$s ").append("%9$s ")
- .append("bash %10$s/launch_container.sh");
-
- String expectedCommand = String
- .format(expectedCommandTemplate.toString(), containerId, runAsUser,
- containerWorkDir, containerLocalDirs.get(0), filecacheDirs.get(0),
- containerWorkDir, containerLogDirs.get(0), userLocalDirs.get(0),
- image, containerWorkDir);
-
List dockerCommands = Files
.readAllLines(Paths.get(dockerCommandFile), Charset.forName("UTF-8"));
-
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals(expectedCommand, dockerCommands.get(0));
+ int expected = 13;
+ if (cgroup.exists()) {
+ expected = 14;
+ }
+ int counter = 0;
+ Assert.assertEquals(expected, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(counter++));
+ Assert.assertEquals(" detach=true", dockerCommands.get(counter++));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(counter++));
+ Assert.assertEquals(" hostname=test.hostname",
+ dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" image=busybox:latest", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" net=" + allowedNetwork, dockerCommands.get(counter++));
+ if (cgroup.exists()) {
+ Assert.assertEquals(" ro-mounts=/sys/fs/cgroup:/sys/fs/cgroup",
+ dockerCommands.get(counter++));
+ }
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(counter++));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(counter++));
}
@Test
@@ -452,30 +481,44 @@ public void testContainerLaunchWithCustomNetworks()
//This is the expected docker invocation for this case. customNetwork1
// ("sdn1") is the expected network to be used in this case
- StringBuffer expectedCommandTemplate =
- new StringBuffer("run --name=%1$s ").append("--user=%2$s -d ")
- .append("--workdir=%3$s ")
- .append("--net=" + customNetwork1 + " ")
- .append("--hostname=" + defaultHostname + " ")
- .append(getExpectedTestCapabilitiesArgumentString())
- .append(getExpectedCGroupsMountString())
- .append("-v %4$s:%4$s ").append("-v %5$s:%5$s ")
- .append("-v %6$s:%6$s ").append("-v %7$s:%7$s ")
- .append("-v %8$s:%8$s ").append("%9$s ")
- .append("bash %10$s/launch_container.sh");
-
- String expectedCommand = String
- .format(expectedCommandTemplate.toString(), containerId, runAsUser,
- containerWorkDir, containerLocalDirs.get(0), filecacheDirs.get(0),
- containerWorkDir, containerLogDirs.get(0), userLocalDirs.get(0),
- image, containerWorkDir);
-
List dockerCommands = Files
.readAllLines(Paths.get(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals(expectedCommand, dockerCommands.get(0));
-
+ int expected = 13;
+ if (cgroup.exists()) {
+ expected = 14;
+ }
+ int counter = 0;
+ Assert.assertEquals(expected, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(counter++));
+ Assert.assertEquals(" detach=true", dockerCommands.get(counter++));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(counter++));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" image=busybox:latest", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(counter++));
+ Assert.assertEquals(" net=sdn1", dockerCommands.get(counter++));
+ if (cgroup.exists()) {
+ Assert.assertEquals(" ro-mounts=/sys/fs/cgroup:/sys/fs/cgroup",
+ dockerCommands.get(counter++));
+ }
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(counter++));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(counter++));
//now set an explicit (non-default) allowedNetwork and ensure that it is
// used.
@@ -490,28 +533,41 @@ public void testContainerLaunchWithCustomNetworks()
//This is the expected docker invocation for this case. customNetwork2
// ("sdn2") is the expected network to be used in this case
- expectedCommandTemplate =
- new StringBuffer("run --name=%1$s ").append("--user=%2$s -d ")
- .append("--workdir=%3$s ")
- .append("--net=" + customNetwork2 + " ")
- .append("--hostname=" + defaultHostname + " ")
- .append(getExpectedTestCapabilitiesArgumentString())
- .append(getExpectedCGroupsMountString())
- .append("-v %4$s:%4$s ").append("-v %5$s:%5$s ")
- .append("-v %6$s:%6$s ").append("-v %7$s:%7$s ")
- .append("-v %8$s:%8$s ").append("%9$s ")
- .append("bash %10$s/launch_container.sh");
-
- expectedCommand = String
- .format(expectedCommandTemplate.toString(), containerId, runAsUser,
- containerWorkDir, containerLocalDirs.get(0), filecacheDirs.get(0),
- containerWorkDir, containerLogDirs.get(0), userLocalDirs.get(0),
- image, containerWorkDir);
dockerCommands = Files
.readAllLines(Paths.get(dockerCommandFile), Charset.forName("UTF-8"));
+ counter = 0;
+ Assert.assertEquals(expected, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(counter++));
+ Assert.assertEquals(" detach=true", dockerCommands.get(counter++));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(counter++));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" image=busybox:latest", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(counter++));
+
+ Assert.assertEquals(" name=container_id", dockerCommands.get(counter++));
+ Assert.assertEquals(" net=sdn2", dockerCommands.get(counter++));
+ if (cgroup.exists()) {
+ Assert.assertEquals(" ro-mounts=/sys/fs/cgroup:/sys/fs/cgroup",
+ dockerCommands.get(counter++));
+ }
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(counter++));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(counter++));
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals(expectedCommand, dockerCommands.get(0));
//disallowed network should trigger a launch failure
@@ -545,7 +601,11 @@ public void testLaunchPrivilegedContainersInvalidEnvVar()
List dockerCommands = Files.readAllLines(Paths.get
(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
+ int expected = 13;
+ if (cgroup.exists()) {
+ expected = 14;
+ }
+ Assert.assertEquals(expected, dockerCommands.size());
String command = dockerCommands.get(0);
@@ -653,13 +713,42 @@ public void testLaunchPrivilegedContainersWithEnabledSettingAndDefaultACL()
List dockerCommands = Files.readAllLines(Paths.get
(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
-
- String command = dockerCommands.get(0);
-
- //submitting user is whitelisted. ensure --privileged is in the invocation
- Assert.assertTrue("Did not find expected '--privileged' in docker run args "
- + ": " + command, command.contains("--privileged"));
+ int expected = 14;
+ if (cgroup.exists()) {
+ expected = 15;
+ }
+ int counter = 0;
+ Assert.assertEquals(expected, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(counter++));
+ Assert.assertEquals(" detach=true", dockerCommands.get(counter++));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(counter++));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" image=busybox:latest", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(counter++));
+ Assert.assertEquals(" net=host", dockerCommands.get(counter++));
+ Assert.assertEquals(" privileged=true", dockerCommands.get(counter++));
+ if (cgroup.exists()) {
+ Assert.assertEquals(" ro-mounts=/sys/fs/cgroup:/sys/fs/cgroup",
+ dockerCommands.get(counter++));
+ }
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(counter++));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(counter++));
}
@Test
@@ -748,15 +837,40 @@ public void testMountSourceTarget()
List dockerCommands = Files.readAllLines(Paths.get
(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
-
- String command = dockerCommands.get(0);
+ Assert.assertEquals(14, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(1));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(2));
+ Assert.assertEquals(" detach=true", dockerCommands.get(3));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(4));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(5));
+ Assert.assertEquals(" image=busybox:latest", dockerCommands.get(6));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(7));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(8));
+ Assert.assertEquals(" net=host", dockerCommands.get(9));
+ if (cgroup.exists()) {
+ Assert.assertEquals(" ro-mounts=/sys/fs/cgroup:/sys/fs/cgroup,"
+ + "/test_local_dir/test_resource_file:test_mount",
+ dockerCommands.get(10));
+ } else {
+ Assert.assertEquals(
+ " ro-mounts=/test_local_dir/test_resource_file:test_mount",
+ dockerCommands.get(10));
+ }
- Assert.assertTrue("Did not find expected " +
- "/test_local_dir/test_resource_file:test_mount mount in docker " +
- "run args : " + command,
- command.contains(" -v /test_local_dir/test_resource_file:test_mount" +
- ":ro "));
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(11));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(12));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(13));
}
@Test
@@ -800,20 +914,43 @@ public void testMountMultiple()
List dockerCommands = Files.readAllLines(Paths.get
(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
+ Assert.assertEquals(14, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(1));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(2));
+ Assert.assertEquals(" detach=true", dockerCommands.get(3));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(4));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(5));
+ Assert.assertEquals(" image=busybox:latest", dockerCommands.get(6));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(7));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(8));
+ Assert.assertEquals(" net=host", dockerCommands.get(9));
+ if (cgroup.exists()) {
+ Assert.assertEquals(" ro-mounts=/sys/fs/cgroup:/sys/fs/cgroup,"
+ + "/test_local_dir/test_resource_file:test_mount1,"
+ + "/test_local_dir/test_resource_file:test_mount2",
+ dockerCommands.get(10));
+ } else {
+ Assert.assertEquals(
+ " ro-mounts=/test_local_dir/test_resource_file:test_mount1,"
+ + "/test_local_dir/test_resource_file:test_mount2",
+ dockerCommands.get(10));
+ }
- String command = dockerCommands.get(0);
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(11));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(12));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(13));
- Assert.assertTrue("Did not find expected " +
- "/test_local_dir/test_resource_file:test_mount1 mount in docker " +
- "run args : " + command,
- command.contains(" -v /test_local_dir/test_resource_file:test_mount1" +
- ":ro "));
- Assert.assertTrue("Did not find expected " +
- "/test_local_dir/test_resource_file:test_mount2 mount in docker " +
- "run args : " + command,
- command.contains(" -v /test_local_dir/test_resource_file:test_mount2" +
- ":ro "));
}
@Test
@@ -845,8 +982,10 @@ public void testDockerStopOnTermSignal()
IOException {
List dockerCommands = getDockerCommandsForSignal(
ContainerExecutor.Signal.TERM);
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals("stop container_id", dockerCommands.get(0));
+ Assert.assertEquals(3, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ Assert.assertEquals(" docker-command=stop", dockerCommands.get(1));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(2));
}
@Test
@@ -855,8 +994,10 @@ public void testDockerStopOnKillSignal()
IOException {
List dockerCommands = getDockerCommandsForSignal(
ContainerExecutor.Signal.KILL);
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals("stop container_id", dockerCommands.get(0));
+ Assert.assertEquals(3, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ Assert.assertEquals(" docker-command=stop", dockerCommands.get(1));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(2));
}
@Test
@@ -865,8 +1006,10 @@ public void testDockerStopOnQuitSignal()
IOException {
List dockerCommands = getDockerCommandsForSignal(
ContainerExecutor.Signal.QUIT);
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals("stop container_id", dockerCommands.get(0));
+ Assert.assertEquals(3, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ Assert.assertEquals(" docker-command=stop", dockerCommands.get(1));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(2));
}
private List getDockerCommandsForSignal(
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerCommandExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerCommandExecutor.java
index 60fce406605..05b44b8a93c 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerCommandExecutor.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerCommandExecutor.java
@@ -114,8 +114,10 @@ public void testExecuteDockerRm() throws Exception {
assertEquals(1, ops.size());
assertEquals(PrivilegedOperation.OperationType.RUN_DOCKER_CMD.name(),
ops.get(0).getOperationType().name());
- assertEquals(1, dockerCommands.size());
- assertEquals("rm " + MOCK_CONTAINER_ID, dockerCommands.get(0));
+ assertEquals(3, dockerCommands.size());
+ assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ assertEquals(" docker-command=rm", dockerCommands.get(1));
+ assertEquals(" name=" + MOCK_CONTAINER_ID, dockerCommands.get(2));
}
@Test
@@ -130,8 +132,10 @@ public void testExecuteDockerStop() throws Exception {
assertEquals(1, ops.size());
assertEquals(PrivilegedOperation.OperationType.RUN_DOCKER_CMD.name(),
ops.get(0).getOperationType().name());
- assertEquals(1, dockerCommands.size());
- assertEquals("stop " + MOCK_CONTAINER_ID, dockerCommands.get(0));
+ assertEquals(3, dockerCommands.size());
+ assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ assertEquals(" docker-command=stop", dockerCommands.get(1));
+ assertEquals(" name=" + MOCK_CONTAINER_ID, dockerCommands.get(2));
}
@Test
@@ -147,9 +151,12 @@ public void testExecuteDockerInspectStatus() throws Exception {
assertEquals(1, ops.size());
assertEquals(PrivilegedOperation.OperationType.RUN_DOCKER_CMD.name(),
ops.get(0).getOperationType().name());
- assertEquals(1, dockerCommands.size());
- assertEquals("inspect --format='{{.State.Status}}' " + MOCK_CONTAINER_ID,
- dockerCommands.get(0));
+ assertEquals(4, dockerCommands.size());
+ assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ assertEquals(" docker-command=inspect", dockerCommands.get(1));
+ assertEquals(" format={{.State.Status}}", dockerCommands.get(2));
+ assertEquals(" name=" + MOCK_CONTAINER_ID, dockerCommands.get(3));
+
}
@Test
@@ -165,8 +172,10 @@ public void testExecuteDockerPull() throws Exception {
assertEquals(1, ops.size());
assertEquals(PrivilegedOperation.OperationType.RUN_DOCKER_CMD.name(),
ops.get(0).getOperationType().name());
- assertEquals(1, dockerCommands.size());
- assertEquals("pull " + MOCK_IMAGE_NAME, dockerCommands.get(0));
+ assertEquals(3, dockerCommands.size());
+ assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ assertEquals(" docker-command=pull", dockerCommands.get(1));
+ assertEquals(" image=" + MOCK_IMAGE_NAME, dockerCommands.get(2));
}
@Test
@@ -182,8 +191,12 @@ public void testExecuteDockerLoad() throws Exception {
assertEquals(1, ops.size());
assertEquals(PrivilegedOperation.OperationType.RUN_DOCKER_CMD.name(),
ops.get(0).getOperationType().name());
- assertEquals(1, dockerCommands.size());
- assertEquals("load --i=" + MOCK_LOCAL_IMAGE_NAME, dockerCommands.get(0));
+ assertEquals(3, dockerCommands.size());
+ assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ assertEquals(" docker-command=load", dockerCommands.get(1));
+ assertEquals(" image=" + MOCK_LOCAL_IMAGE_NAME, dockerCommands.get(2));
+
+
}
@Test
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerInspectCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerInspectCommand.java
index 619f202d05b..d4d9b6dc415 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerInspectCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerInspectCommand.java
@@ -18,6 +18,8 @@
package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker;
import static org.junit.Assert.assertEquals;
+
+import org.apache.hadoop.util.StringUtils;
import org.junit.Before;
import org.junit.Test;
@@ -44,16 +46,25 @@ public void testGetCommandOption() {
@Test
public void testGetContainerStatus() throws Exception {
dockerInspectCommand.getContainerStatus();
- assertEquals("inspect --format='{{.State.Status}}' foo",
- dockerInspectCommand.getCommandWithArguments());
+ assertEquals("inspect", StringUtils.join(",",
+ dockerInspectCommand.getCommandArguments().get("docker-command")));
+ assertEquals("{{.State.Status}}", StringUtils
+ .join(",", dockerInspectCommand.getCommandArguments().get("format")));
+ assertEquals("foo", StringUtils
+ .join(",", dockerInspectCommand.getCommandArguments().get("name")));
+ assertEquals(3, dockerInspectCommand.getCommandArguments().size());
}
@Test
public void testGetIpAndHost() throws Exception {
dockerInspectCommand.getIpAndHost();
- assertEquals(
- "inspect --format='{{range(.NetworkSettings.Networks)}}{{.IPAddress}}"
- + ",{{end}}{{.Config.Hostname}}' foo",
- dockerInspectCommand.getCommandWithArguments());
+ assertEquals("inspect", StringUtils.join(",",
+ dockerInspectCommand.getCommandArguments().get("docker-command")));
+ assertEquals("{{range(.NetworkSettings.Networks)}}"
+ + "{{.IPAddress}},{{end}}{{.Config.Hostname}}", StringUtils
+ .join(",", dockerInspectCommand.getCommandArguments().get("format")));
+ assertEquals("foo", StringUtils
+ .join(",", dockerInspectCommand.getCommandArguments().get("name")));
+ assertEquals(3, dockerInspectCommand.getCommandArguments().size());
}
}
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerLoadCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerLoadCommand.java
index 85fa0f8f733..3c3f93d53fd 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerLoadCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerLoadCommand.java
@@ -16,6 +16,7 @@
*/
package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker;
+import org.apache.hadoop.util.StringUtils;
import org.junit.Before;
import org.junit.Test;
@@ -42,7 +43,10 @@ public void testGetCommandOption() {
@Test
public void testGetCommandWithArguments() {
- assertEquals("load --i=foo",
- dockerLoadCommand.getCommandWithArguments());
+ assertEquals("load", StringUtils.join(",",
+ dockerLoadCommand.getCommandArguments().get("docker-command")));
+ assertEquals("foo", StringUtils
+ .join(",", dockerLoadCommand.getCommandArguments().get("image")));
+ assertEquals(2, dockerLoadCommand.getCommandArguments().size());
}
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerPullCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerPullCommand.java
index 89157ff751a..6549d9f3978 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerPullCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerPullCommand.java
@@ -16,6 +16,7 @@
*/
package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker;
+import org.apache.hadoop.util.StringUtils;
import org.junit.Before;
import org.junit.Test;
@@ -42,7 +43,11 @@ public void testGetCommandOption() {
@Test
public void testGetCommandWithArguments() {
- assertEquals("pull foo", dockerPullCommand.getCommandWithArguments());
+ assertEquals("pull", StringUtils.join(",",
+ dockerPullCommand.getCommandArguments().get("docker-command")));
+ assertEquals("foo", StringUtils
+ .join(",", dockerPullCommand.getCommandArguments().get("image")));
+ assertEquals(2, dockerPullCommand.getCommandArguments().size());
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerRmCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerRmCommand.java
index d1b99043aec..ef816107ce6 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerRmCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerRmCommand.java
@@ -17,6 +17,8 @@
package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker;
import static org.junit.Assert.assertEquals;
+
+import org.apache.hadoop.util.StringUtils;
import org.junit.Before;
import org.junit.Test;
@@ -42,7 +44,11 @@ public void testGetCommandOption() {
@Test
public void testGetCommandWithArguments() {
- assertEquals("rm foo", dockerRmCommand.getCommandWithArguments());
+ assertEquals("rm", StringUtils.join(",",
+ dockerRmCommand.getCommandArguments().get("docker-command")));
+ assertEquals("foo", StringUtils
+ .join(",", dockerRmCommand.getCommandArguments().get("name")));
+ assertEquals(2, dockerRmCommand.getCommandArguments().size());
}
}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerRunCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerRunCommand.java
index 85bccd2d51d..272ef3965f2 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerRunCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerRunCommand.java
@@ -16,6 +16,7 @@
*/
package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker;
+import org.apache.hadoop.util.StringUtils;
import org.junit.Before;
import org.junit.Test;
@@ -56,8 +57,22 @@ public void testCommandArguments() {
commands.add("launch_command");
dockerRunCommand.setOverrideCommandWithArgs(commands);
dockerRunCommand.removeContainerOnExit();
- assertEquals("run --name=foo --user=user_id --device=source:dest --rm "
- + "image_name launch_command",
- dockerRunCommand.getCommandWithArguments());
+
+ assertEquals("run", StringUtils.join(",",
+ dockerRunCommand.getCommandArguments().get("docker-command")));
+ assertEquals("foo", StringUtils
+ .join(",", dockerRunCommand.getCommandArguments().get("name")));
+ assertEquals("user_id", StringUtils
+ .join(",", dockerRunCommand.getCommandArguments().get("user")));
+ assertEquals("image_name", StringUtils
+ .join(",", dockerRunCommand.getCommandArguments().get("image")));
+
+ assertEquals("source:dest", StringUtils
+ .join(",", dockerRunCommand.getCommandArguments().get("devices")));
+ assertEquals("true", StringUtils
+ .join(",", dockerRunCommand.getCommandArguments().get("rm")));
+ assertEquals("launch_command", StringUtils.join(",",
+ dockerRunCommand.getCommandArguments().get("launch-command")));
+ assertEquals(7, dockerRunCommand.getCommandArguments().size());
}
}
\ No newline at end of file
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerStopCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerStopCommand.java
index c9743f3d069..d16f5c723b6 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerStopCommand.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/TestDockerStopCommand.java
@@ -21,6 +21,8 @@
package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.docker;
import static org.junit.Assert.assertEquals;
+
+import org.apache.hadoop.util.StringUtils;
import org.junit.Before;
import org.junit.Test;
@@ -48,8 +50,12 @@ public void testGetCommandOption() {
@Test
public void testSetGracePeriod() throws Exception {
dockerStopCommand.setGracePeriod(GRACE_PERIOD);
- assertEquals("stop foo --time=10",
- dockerStopCommand.getCommandWithArguments());
-
+ assertEquals("stop", StringUtils.join(",",
+ dockerStopCommand.getCommandArguments().get("docker-command")));
+ assertEquals("foo", StringUtils
+ .join(",", dockerStopCommand.getCommandArguments().get("name")));
+ assertEquals("10", StringUtils
+ .join(",", dockerStopCommand.getCommandArguments().get("time")));
+ assertEquals(3, dockerStopCommand.getCommandArguments().size());
}
}
\ No newline at end of file