commit 139d99f86b06af14f0f38a120c31934d9968894a Author: Eric Yang Date: Mon Mar 5 20:02:40 2018 -0500 YARN-7654. Added support for docker ENTRY_PONT. Contributed by Eric Yang diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/provider/AbstractProviderService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/provider/AbstractProviderService.java index 7015591..d4a0aef 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/provider/AbstractProviderService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-applications/hadoop-yarn-services/hadoop-yarn-services-core/src/main/java/org/apache/hadoop/yarn/service/provider/AbstractProviderService.java @@ -18,6 +18,7 @@ package org.apache.hadoop.yarn.service.provider; import org.apache.commons.lang.StringUtils; +import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.yarn.api.ApplicationConstants; import org.apache.hadoop.yarn.api.records.Container; @@ -49,6 +50,10 @@ protected static final Logger log = LoggerFactory.getLogger(AbstractProviderService.class); + @InterfaceAudience.Private + public static final String ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE = + "YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE"; + public abstract void processArtifact(AbstractLauncher launcher, ComponentInstance compInstance, SliderFileSystem fileSystem, Service service) @@ -100,7 +105,12 @@ public void buildContainerLaunchContext(AbstractLauncher launcher, .substituteStrWithTokens(launchCommand, tokensForSubstitution); CommandLineBuilder operation = new CommandLineBuilder(); operation.add(launchCommand); - operation.addOutAndErrFiles(OUT_FILE, ERR_FILE); + if (component.getConfiguration() + .getEnv(ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE) == null || + component.getConfiguration() + .getEnv(ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE).equals("false")) { + operation.addOutAndErrFiles(OUT_FILE, ERR_FILE); + } launcher.addCommand(operation.build()); } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java index 01cd992..b76984e 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java @@ -18,7 +18,9 @@ package org.apache.hadoop.yarn.server.nodemanager; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; @@ -51,6 +53,7 @@ import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerDiagnosticsUpdateEvent; import org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeConstants; import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerPrepareContext; import org.apache.hadoop.yarn.server.nodemanager.util.NodeManagerHardwareUtils; import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerLivenessContext; @@ -64,8 +67,12 @@ import org.apache.hadoop.util.Shell; import org.apache.hadoop.util.StringUtils; +import static org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeConstants.ENV_CONTAINER_TYPE; import static org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.CONTAINER_PRE_LAUNCH_STDERR; import static org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.CONTAINER_PRE_LAUNCH_STDOUT; +import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE; +import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_RUN_USER_ENV; +import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_RUN_CMD; /** * This class is abstraction of the mechanism used to launch a container on the 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/launcher/ContainerLaunch.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/launcher/ContainerLaunch.java index b4f03fc..863f1a9 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/launcher/ContainerLaunch.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/launcher/ContainerLaunch.java @@ -94,6 +94,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.runtime.DockerLinuxContainerRuntime.ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE; + public class ContainerLaunch implements Callable { private static final Logger LOG = @@ -266,10 +268,16 @@ public Integer call() { try (DataOutputStream containerScriptOutStream = lfs.create(nmPrivateContainerScriptPath, EnumSet.of(CREATE, OVERWRITE))) { - // Sanitize the container's environment - sanitizeEnv(environment, containerWorkDir, appDirs, userLocalDirs, - containerLogDirs, localResources, nmPrivateClasspathJarDir, - nmEnvVars); + if (environment.get(ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE) == null + || environment.get(ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE) + .equalsIgnoreCase("false")) { + // Sanitize the container's environment + sanitizeEnv(environment, containerWorkDir, appDirs, userLocalDirs, + containerLogDirs, localResources, nmPrivateClasspathJarDir, + nmEnvVars); + } else { + environment.remove("WORK_DIR"); + } prepareContainer(localResources, containerLocalDirs); @@ -1317,6 +1325,7 @@ public void listDebugInformation(Path output) throws IOException { public void setExitOnFailure() { line("set -o pipefail -e"); } + } private static final class WindowsShellScriptBuilder @@ -1403,6 +1412,7 @@ public void listDebugInformation(Path output) throws IOException { String.format("@echo \"dir:\" > \"%s\"", output.toString())); lineWithLenCheck(String.format("dir >> \"%s\"", output.toString())); } + } private static void putEnvIfNotNull( 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 48c802f..b46d662 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 @@ -202,6 +202,12 @@ public static final String ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE = "YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE"; @InterfaceAudience.Private + public static final String ENV_DOCKER_CONTAINER_RUN_USER_ENV = + "YARN_CONTAINER_RUNTIME_DOCKER_RUN_USER_ENV"; + @InterfaceAudience.Private + public static final String ENV_DOCKER_CONTAINER_RUN_CMD = + "YARN_CONTAINER_RUNTIME_DOCKER_RUN_CMD"; + @InterfaceAudience.Private public static final String ENV_DOCKER_CONTAINER_NETWORK = "YARN_CONTAINER_RUNTIME_DOCKER_CONTAINER_NETWORK"; @InterfaceAudience.Private @@ -720,6 +726,8 @@ public void launchContainer(ContainerRuntimeContext ctx) String imageName = environment.get(ENV_DOCKER_CONTAINER_IMAGE); String network = environment.get(ENV_DOCKER_CONTAINER_NETWORK); String hostname = environment.get(ENV_DOCKER_CONTAINER_HOSTNAME); + String disableOverride = environment.get( + ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE); if(network == null || network.isEmpty()) { network = defaultNetwork; @@ -778,9 +786,11 @@ public void launchContainer(ContainerRuntimeContext ctx) @SuppressWarnings("unchecked") DockerRunCommand runCommand = new DockerRunCommand(containerIdStr, dockerRunAsUser, imageName) - .detachOnRun() - .setContainerWorkDir(containerWorkDir.toString()) .setNetworkType(network); + + if (disableOverride == null || disableOverride.equals("false")) { + runCommand.setContainerWorkDir(containerWorkDir.toString()); + } setHostname(runCommand, containerIdStr, hostname); runCommand.setCapabilities(capabilities); @@ -848,11 +858,21 @@ public void launchContainer(ContainerRuntimeContext ctx) addCGroupParentIfRequired(resourcesOpts, containerIdStr, runCommand); - String disableOverride = environment.get( - ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE); - if (disableOverride != null && disableOverride.equals("true")) { LOG.info("command override disabled"); + runCommand.setOverrideDisabled(true); + StringBuilder userEnv = new StringBuilder(); + for (Map.Entry kv: environment.entrySet()) { + userEnv.append("-e "); + userEnv.append(kv.getKey()); + userEnv.append("|"); + userEnv.append(kv.getValue()); + userEnv.append(" "); + } + runCommand.setEnv(userEnv.toString()); + runCommand.setOverrideCommandWithArgs(container.getLaunchContext().getCommands()); + runCommand.disableDetach(); + runCommand.setLogDir(container.getLogDir()); } else { List overrideCommands = new ArrayList<>(); Path launchDst = @@ -861,6 +881,7 @@ public void launchContainer(ContainerRuntimeContext ctx) overrideCommands.add("bash"); overrideCommands.add(launchDst.toUri().getPath()); runCommand.setOverrideCommandWithArgs(overrideCommands); + runCommand.detachOnRun(); } if(enableUserReMapping) { 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 b7e84d7..5de7b5d 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 @@ -160,4 +160,23 @@ public DockerRunCommand setOverrideCommandWithArgs( public Map> getDockerCommandWithArguments() { return super.getDockerCommandWithArguments(); } + + public DockerRunCommand setOverrideDisabled(boolean toggle) { + String value = "false"; + if (toggle) { + value = "true"; + } + super.addCommandArguments("use-entry-point", value); + return this; + } + + public DockerRunCommand setEnv(String env) { + super.addCommandArguments("environ", env); + return this; + } + + public DockerRunCommand setLogDir(String logDir) { + super.addCommandArguments("log-dir", logDir); + return this; + } } 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 5ce6a00..1f9bb73 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 @@ -67,6 +67,7 @@ #endif static const int DEFAULT_MIN_USERID = 1000; +static const int MAX_RETRIES = 10; static const char* DEFAULT_BANNED_USERS[] = {"yarn", "mapred", "hdfs", "bin", 0}; @@ -93,6 +94,8 @@ static gid_t nm_gid = -1; struct configuration CFG = {.size=0, .sections=NULL}; struct section executor_cfg = {.size=0, .kv_pairs=NULL}; +char *chosen_container_log_dir = NULL; + char *concatenate(char *concat_pattern, char *return_path_name, int numArgs, ...); @@ -744,6 +747,8 @@ static int create_container_directories(const char* user, const char *app_id, free(container_log_dir); } else { result = 0; + chosen_container_log_dir = (char *) alloc_and_clear_memory(strlen(container_log_dir), sizeof(char)); + strncpy(chosen_container_log_dir, container_log_dir, strlen(container_log_dir)); free(container_log_dir); } } @@ -1082,7 +1087,6 @@ int initialize_user(const char *user, char* const* local_dirs) { } int create_log_dirs(const char *app_id, char * const * log_dirs) { - char* const* log_root; char *any_one_app_log_dir = NULL; for(log_root=log_dirs; *log_root != NULL; ++log_root) { @@ -1118,6 +1122,34 @@ char* get_container_log_directory(const char *log_root, const char* app_id, container_id); } +char *init_log_path(const char *container_log_dir, const char *logfile) { + int tmp_buffer_size = 0; + char *tmp_buffer = NULL; + tmp_buffer_size = strlen(container_log_dir) + strlen(logfile) + 2; + tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); + snprintf(tmp_buffer, tmp_buffer_size, "%s/%s", container_log_dir, logfile); + + mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP; + int fd = open(tmp_buffer, O_CREAT | O_WRONLY, permissions); + if (fd >= 0) { + close(fd); + if (change_owner(tmp_buffer, user_detail->pw_uid, user_detail->pw_gid) != 0) { + fprintf(ERRORFILE, "Failed to chown %s to %d:%d: %s\n", tmp_buffer, user_detail->pw_uid, user_detail->pw_gid, + strerror(errno)); + tmp_buffer = NULL; + } else if (chmod(tmp_buffer, permissions) != 0) { + fprintf(ERRORFILE, "Can't chmod %s to add the sticky bit - %s\n", + tmp_buffer, strerror(errno)); + tmp_buffer = NULL; + } + } else { + fprintf(ERRORFILE, "Failed to create file %s - %s\n", tmp_buffer, + strerror(errno)); + tmp_buffer = NULL; + } + return tmp_buffer; +} + int create_container_log_dirs(const char *container_id, const char *app_id, char * const * log_dirs) { char* const* log_root; @@ -1263,11 +1295,12 @@ int initialize_app(const char *user, const char *app_id, return -1; } -char *construct_docker_command(const char *command_file) { +char **construct_docker_command(const char *command_file) { int ret = 0; - size_t command_size = MIN(sysconf(_SC_ARG_MAX), 128*1024); - char *buffer = alloc_and_clear_memory(command_size, sizeof(char)); - ret = get_docker_command(command_file, &CFG, buffer, command_size); + int index = 0; + size_t command_size = sysconf(_SC_ARG_MAX); + char **buffer = alloc_and_clear_memory(command_size, sizeof(char *)); + ret = get_docker_command(command_file, &CFG, buffer, index); if (ret != 0) { fprintf(ERRORFILE, "Error constructing docker command, docker error code=%d, error message='%s'\n", ret, get_docker_error_message(ret)); @@ -1278,15 +1311,8 @@ char *construct_docker_command(const char *command_file) { } int run_docker(const char *command_file) { - char* docker_command = construct_docker_command(command_file); + char **args = construct_docker_command(command_file); char* docker_binary = get_docker_binary(&CFG); - size_t command_size = MIN(sysconf(_SC_ARG_MAX), 128*1024); - - char* docker_command_with_binary = alloc_and_clear_memory(command_size, sizeof(char)); - snprintf(docker_command_with_binary, command_size, "%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; if (execvp(docker_binary, args) != 0) { fprintf(ERRORFILE, "Couldn't execute the container launch with args %s - %s", @@ -1295,8 +1321,6 @@ int run_docker(const char *command_file) { fflush(ERRORFILE); free(docker_binary); free(args); - free(docker_command_with_binary); - free(docker_command); exit_code = DOCKER_RUN_FAILED; } else { exit_code = 0; @@ -1394,9 +1418,9 @@ int create_local_dirs(const char * user, const char *app_id, goto cleanup; } - // Copy script file with permissions 700 + // Copy script file with permissions 751 if (copy_file(container_file_source, script_name, script_file_dest,S_IRWXU) != 0) { - fprintf(ERRORFILE, "Could not create copy file %d %s\n", container_file_source, script_file_dest); + fprintf(ERRORFILE, "Could not create copy file %s %s (%d)\n", script_name, script_file_dest, container_file_source); fflush(ERRORFILE); exit_code = COULD_NOT_CREATE_SCRIPT_COPY; goto cleanup; @@ -1443,6 +1467,7 @@ int launch_docker_container_as_user(const char * user, const char *app_id, int cred_file_source = -1; int BUFFER_SIZE = 4096; char buffer[BUFFER_SIZE]; + int docker_override = -1; size_t command_size = MIN(sysconf(_SC_ARG_MAX), 128*1024); @@ -1456,7 +1481,7 @@ 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 = NULL; + char **docker_command = NULL; char *docker_binary = NULL; fprintf(LOGFILE, "Creating script paths...\n"); @@ -1499,37 +1524,90 @@ int launch_docker_container_as_user(const char * user, const char *app_id, goto cleanup; } - snprintf(docker_command_with_binary, command_size, "%s %s", docker_binary, docker_command); + docker_override = use_entry_point(command_file); + char *so = init_log_path(chosen_container_log_dir, "stdout.txt"); + if (so == NULL) { + exit_code = UNABLE_TO_EXECUTE_CONTAINER_SCRIPT; + goto cleanup; + } + char *se = init_log_path(chosen_container_log_dir, "stderr.txt"); + if (se == NULL) { + exit_code = UNABLE_TO_EXECUTE_CONTAINER_SCRIPT; + goto cleanup; + } + + docker_command_with_binary = flatten(docker_command); - fprintf(LOGFILE, "Launching docker container...\n"); - fprintf(LOGFILE, "Docker run command: %s\n", docker_command_with_binary); - FILE* start_docker = popen(docker_command_with_binary, "r"); - if (pclose (start_docker) != 0) - { + // Launch container + pid_t child_pid = fork(); + if (child_pid == -1) { fprintf (ERRORFILE, - "Could not invoke docker %s.\n", docker_command_with_binary); + "Could not invoke docker %s.\n", docker_command_with_binary); fflush(ERRORFILE); exit_code = UNABLE_TO_EXECUTE_CONTAINER_SCRIPT; goto cleanup; + } + + if (child_pid == 0) { + FILE* so_fd = fopen(so, "a+"); + if (so_fd == NULL) { + fprintf(ERRORFILE, "Could not append to %s\n", so); + exit_code = UNABLE_TO_EXECUTE_CONTAINER_SCRIPT; + goto cleanup; + } + FILE* se_fd = fopen(se, "a+"); + if (se_fd == NULL) { + fprintf(ERRORFILE, "Could not append to %s\n", se); + exit_code = UNABLE_TO_EXECUTE_CONTAINER_SCRIPT; + goto cleanup; + } + fprintf(so_fd, "Launching docker container...\n"); + fprintf(so_fd, "Docker run command: %s\n", docker_command_with_binary); + // if entry point is enabled, clone docker command output + // to stdout.txt and stderr.txt for yarn. + if (docker_override == 0) { + dup2(fileno(so_fd), fileno(stdout)); + dup2(fileno(se_fd), fileno(stderr)); + } + fclose(so_fd); + fclose(se_fd); + //char **args = split_delimiter(docker_command_with_binary, " "); + execv(docker_binary, docker_command); + fprintf(LOGFILE, "failed to execute tc command! error: %s\n", strerror(errno)); + return UNABLE_TO_EXECUTE_CONTAINER_SCRIPT; + } else { + sleep(3); } + free(so); + free(se); + int pid = 0; + int res = 0; + int count = 0; snprintf(docker_inspect_command, command_size, "%s inspect --format {{.State.Pid}} %s", docker_binary, container_id); - fprintf(LOGFILE, "Inspecting docker container...\n"); - fprintf(LOGFILE, "Docker inspect command: %s\n", docker_inspect_command); - FILE* inspect_docker = popen(docker_inspect_command, "r"); - int pid = 0; - int res = fscanf (inspect_docker, "%d", &pid); - fprintf(LOGFILE, "pid from docker inspect: %d\n", pid); - if (pclose (inspect_docker) != 0 || res <= 0) - { - fprintf (ERRORFILE, - "Could not inspect docker to get pid %s.\n", docker_inspect_command); - fflush(ERRORFILE); - exit_code = UNABLE_TO_EXECUTE_CONTAINER_SCRIPT; - goto cleanup; + // check for docker container pid + while (count < MAX_RETRIES) { + fprintf(LOGFILE, "Inspecting docker container...\n"); + fprintf(LOGFILE, "Docker inspect command: %s\n", docker_inspect_command); + fflush(LOGFILE); + FILE* inspect_docker = popen(docker_inspect_command, "r"); + res = fscanf (inspect_docker, "%d", &pid); + fprintf(LOGFILE, "pid from docker inspect: %d\n", pid); + if (pclose (inspect_docker) != 0 || res <= 0) { + fprintf (ERRORFILE, + "Could not inspect docker to get pid %s.\n", docker_inspect_command); + fflush(ERRORFILE); + exit_code = UNABLE_TO_EXECUTE_CONTAINER_SCRIPT; + } else { + if (pid != 0) { + break; + } + } + sleep(3); + count++; } if (pid != 0) { @@ -1561,6 +1639,8 @@ int launch_docker_container_as_user(const char * user, const char *app_id, } fprintf(LOGFILE, "Waiting for docker container to finish.\n"); + + // wait for pid to finish #ifdef __linux size_t command_size = MIN(sysconf(_SC_ARG_MAX), 128*1024); char* proc_pid_path = alloc_and_clear_memory(command_size, sizeof(char)); @@ -1577,60 +1657,62 @@ int launch_docker_container_as_user(const char * user, const char *app_id, sleep(1); } #endif + } - sprintf(docker_inspect_exitcode_command, - "%s inspect --format {{.State.ExitCode}} %s", - docker_binary, container_id); - fprintf(LOGFILE, "Obtaining the exit code...\n"); - fprintf(LOGFILE, "Docker inspect command: %s\n", docker_inspect_exitcode_command); - FILE* inspect_exitcode_docker = popen(docker_inspect_exitcode_command, "r"); - if(inspect_exitcode_docker == NULL) { - fprintf(ERRORFILE, "Done with inspect_exitcode, inspect_exitcode_docker is null\n"); - fflush(ERRORFILE); - exit_code = -1; - goto cleanup; - } - res = fscanf (inspect_exitcode_docker, "%d", &exit_code); - if (pclose (inspect_exitcode_docker) != 0 || res <= 0) { - fprintf (ERRORFILE, - "Could not inspect docker to get exitcode: %s.\n", docker_inspect_exitcode_command); - fflush(ERRORFILE); - exit_code = -1; - goto cleanup; - } - fprintf(LOGFILE, "Exit code from docker inspect: %d\n", exit_code); - if(exit_code != 0) { - fprintf(ERRORFILE, "Docker container exit code was not zero: %d\n", - exit_code); - snprintf(docker_logs_command, command_size, "%s logs --tail=250 %s", - docker_binary, container_id); - FILE* logs = popen(docker_logs_command, "r"); - if(logs != NULL) { - clearerr(logs); - res = fread(buffer, BUFFER_SIZE, 1, logs); - if(res < 1) { - fprintf(ERRORFILE, "%s %d %d\n", - "Unable to read from docker logs(ferror, feof):", ferror(logs), feof(logs)); - fflush(ERRORFILE); - } - else { - fprintf(ERRORFILE, "%s\n", buffer); - fflush(ERRORFILE); - } - } - else { - fprintf(ERRORFILE, "%s\n", "Failed to get output of docker logs"); - fprintf(ERRORFILE, "Command was '%s'\n", docker_logs_command); - fprintf(ERRORFILE, "%s\n", strerror(errno)); + // discover container exit code + sprintf(docker_inspect_exitcode_command, + "%s inspect --format {{.State.ExitCode}} %s", + docker_binary, container_id); + fprintf(LOGFILE, "Obtaining the exit code...\n"); + fprintf(LOGFILE, "Docker inspect command: %s\n", docker_inspect_exitcode_command); + FILE* inspect_exitcode_docker = popen(docker_inspect_exitcode_command, "r"); + if(inspect_exitcode_docker == NULL) { + fprintf(ERRORFILE, "Done with inspect_exitcode, inspect_exitcode_docker is null\n"); + fflush(ERRORFILE); + exit_code = -1; + goto cleanup; + } + res = fscanf (inspect_exitcode_docker, "%d", &exit_code); + if (pclose (inspect_exitcode_docker) != 0 || res <= 0) { + fprintf (ERRORFILE, + "Could not inspect docker to get exitcode: %s.\n", docker_inspect_exitcode_command); + fflush(ERRORFILE); + exit_code = -1; + goto cleanup; + } + fprintf(LOGFILE, "Exit code from docker inspect: %d\n", exit_code); + if(exit_code != 0) { + fprintf(ERRORFILE, "Docker container exit code was not zero: %d\n", + exit_code); + snprintf(docker_logs_command, command_size, "%s logs --tail=250 %s", + docker_binary, container_id); + FILE* logs = popen(docker_logs_command, "r"); + if(logs != NULL) { + clearerr(logs); + res = fread(buffer, BUFFER_SIZE, 1, logs); + if(res < 1) { + fprintf(ERRORFILE, "%s %d %d\n", + "Unable to read from docker logs(ferror, feof):", ferror(logs), feof(logs)); fflush(ERRORFILE); } - if(pclose(logs) != 0) { - fprintf(ERRORFILE, "%s\n", "Failed to fetch docker logs"); + else { + fprintf(ERRORFILE, "%s\n", buffer); fflush(ERRORFILE); } } + else { + fprintf(ERRORFILE, "%s\n", "Failed to get output of docker logs"); + fprintf(ERRORFILE, "Command was '%s'\n", docker_logs_command); + fprintf(ERRORFILE, "%s\n", strerror(errno)); + fflush(ERRORFILE); + } + if(pclose(logs) != 0) { + fprintf(ERRORFILE, "%s\n", "Failed to fetch docker logs"); + fflush(ERRORFILE); + } } + cleanup: if (exit_code_file != NULL && write_exit_code_file_as_nm(exit_code_file, exit_code) < 0) { @@ -1665,6 +1747,7 @@ cleanup: free(docker_logs_command); free(docker_inspect_command); free(docker_rm_command); + free(chosen_container_log_dir); return exit_code; } @@ -2353,3 +2436,27 @@ int traffic_control_read_stats(char *command_file) { struct configuration* get_cfg() { return &CFG; } + +/** + * Flatten docker launch command + */ +char* flatten(char **args) { + size_t string_len = 0; + size_t current_len = 0; + char *buffer = (char *) malloc(8192 * sizeof(char)); + for (int i = 0; args[i] != NULL; i++) { + string_len = strlen(args[i]); + if (string_len != 0) { + strncpy(buffer + current_len, args[i], string_len); + current_len = current_len + string_len; + if (args[i +1] != NULL) { + strncpy(buffer + current_len, " ", 1); + current_len++; + } + } + } + buffer[current_len] = '\0'; + return buffer; +} + + 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 5835214..bb171be 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 @@ -275,3 +275,8 @@ int execute_regex_match(const char *regex_str, const char *input); int validate_docker_image_name(const char *image_name); struct configuration* get_cfg(); + +/** + * Flatten docker launch command + */ +char* flatten(char **args); 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 index 6b003a2..c7c60a4 100644 --- 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 @@ -44,29 +44,35 @@ static int read_and_verify_command_file(const char *command_file, const char *do return ret; } -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 - 1) { - strncpy(buff + current_len, string, string_len); - buff[current_len + string_len] = '\0'; +static int add_to_buffer(char **buff, int *index, const char *string) { + if (strlen(string)==0) { return 0; } - return -1; + if (*index > sysconf(_SC_ARG_MAX)) { + return -1; + } + char *clone = (char *) alloc_and_clear_memory(strlen(string), sizeof(char)); + if (clone == NULL) { + return -1; + } + strcpy(clone, string); + buff[*index] = clone; + (*index)++; + return 0; } 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) { + const int with_argument, char **out, int *index) { size_t tmp_buffer_size = 4096; 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); + snprintf(tmp_buffer, tmp_buffer_size, "%s%s", param, value); + ret = add_to_buffer(out, index, tmp_buffer); } else if (strcmp(value, "true") == 0) { - ret = add_to_buffer(out, outlen, param); + ret = add_to_buffer(out, index, param); } free(value); if (ret != 0) { @@ -123,7 +129,8 @@ static int add_param_to_command_if_allowed(const struct configuration *command_c const struct configuration *executor_cfg, const char *key, const char *allowed_key, const char *param, const int multiple_values, const char prefix, - char *out, const size_t outlen) { + char **out, int *index) { + int previous = (*index); size_t tmp_buffer_size = 4096; char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); char *tmp_ptr = NULL; @@ -178,8 +185,8 @@ static int add_param_to_command_if_allowed(const struct configuration *command_c } } if (permitted == 1) { - quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, param, values[i]); - ret = add_to_buffer(out, outlen, tmp_buffer); + snprintf(tmp_buffer, tmp_buffer_size, "%s%s", param, values[i]); + ret = add_to_buffer(out, index, tmp_buffer); if (ret != 0) { fprintf(ERRORFILE, "Output buffer too small\n"); ret = BUFFER_TOO_SMALL; @@ -204,13 +211,13 @@ static int add_param_to_command_if_allowed(const struct configuration *command_c free_values(permitted_values); free(tmp_buffer); if (ret != 0) { - memset(out, 0, outlen); + (*index)=previous; } return ret; } -static int add_docker_config_param(const struct configuration *command_config, char *out, const size_t outlen) { - return add_param_to_command(command_config, "docker-config", "--config=", 1, out, outlen); +static int add_docker_config_param(const struct configuration *command_config, char **out, int *index) { + return add_param_to_command(command_config, "docker-config", "--config=", 1, out, index); } static int validate_volume_name(const char *volume_name) { @@ -294,6 +301,22 @@ char *get_docker_binary(const struct configuration *conf) { return docker_binary; } +int use_entry_point(const char *command_file) { + int use_entry_point = -1; + int ret = 0; + struct configuration command_config = {0, NULL}; + ret = read_config(command_file, &command_config); + if (ret != 0) { + return use_entry_point; + } + char *value = get_configuration_value("use-entry-point", DOCKER_COMMAND_FILE_SECTION, &command_config); + if (strcasecmp(value, "true") == 0) { + use_entry_point = 0; + } + free(value); + return use_entry_point; +} + int docker_module_enabled(const struct configuration *conf) { struct section *section = get_configuration_section(CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf); if (section != NULL) { @@ -302,7 +325,7 @@ int docker_module_enabled(const struct configuration *conf) { return 0; } -int get_docker_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) { +int get_docker_command(const char *command_file, const struct configuration *conf, char **out, const size_t buff_len) { int ret = 0; struct configuration command_config = {0, NULL}; ret = read_config(command_file, &command_config); @@ -312,21 +335,21 @@ int get_docker_command(const char *command_file, const struct configuration *con 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); + return get_docker_inspect_command(command_file, conf, out, buff_len); } else if (strcmp(DOCKER_KILL_COMMAND, command) == 0) { - return get_docker_kill_command(command_file, conf, out, outlen); + return get_docker_kill_command(command_file, conf, out, buff_len); } else if (strcmp(DOCKER_LOAD_COMMAND, command) == 0) { - return get_docker_load_command(command_file, conf, out, outlen); + return get_docker_load_command(command_file, conf, out, buff_len); } else if (strcmp(DOCKER_PULL_COMMAND, command) == 0) { - return get_docker_pull_command(command_file, conf, out, outlen); + return get_docker_pull_command(command_file, conf, out, buff_len); } else if (strcmp(DOCKER_RM_COMMAND, command) == 0) { - return get_docker_rm_command(command_file, conf, out, outlen); + return get_docker_rm_command(command_file, conf, out, buff_len); } else if (strcmp(DOCKER_RUN_COMMAND, command) == 0) { - return get_docker_run_command(command_file, conf, out, outlen); + return get_docker_run_command(command_file, conf, out, buff_len); } else if (strcmp(DOCKER_STOP_COMMAND, command) == 0) { - return get_docker_stop_command(command_file, conf, out, outlen); + return get_docker_stop_command(command_file, conf, out, buff_len); } else if (strcmp(DOCKER_VOLUME_COMMAND, command) == 0) { - return get_docker_volume_command(command_file, conf, out, outlen); + return get_docker_volume_command(command_file, conf, out, buff_len); } else { return UNKNOWN_DOCKER_COMMAND; } @@ -358,9 +381,11 @@ static int value_permitted(const struct configuration* executor_cfg, return found; } -int get_docker_volume_command(const char *command_file, const struct configuration *conf, char *out, - const size_t outlen) { +int get_docker_volume_command(const char *command_file, const struct configuration *conf, char **out, + const size_t buff_len) { + int index = 0; int ret = 0; + int tmp_buffer_size = 1024; char *driver = NULL, *volume_name = NULL, *sub_command = NULL, *format = NULL; struct configuration command_config = {0, NULL}; ret = read_and_verify_command_file(command_file, DOCKER_VOLUME_COMMAND, &command_config); @@ -377,15 +402,21 @@ int get_docker_volume_command(const char *command_file, const struct configurati goto cleanup; } - memset(out, 0, outlen); + memset(out, 0, buff_len); + + ret = add_to_buffer(out, &index, "docker"); + if (ret != 0) { + ret = BUFFER_TOO_SMALL; + goto cleanup; + } - ret = add_docker_config_param(&command_config, out, outlen); + ret = add_docker_config_param(&command_config, out, &index); if (ret != 0) { ret = BUFFER_TOO_SMALL; goto cleanup; } - ret = add_to_buffer(out, outlen, DOCKER_VOLUME_COMMAND); + ret = add_to_buffer(out, &index, DOCKER_VOLUME_COMMAND); if (ret != 0) { goto cleanup; } @@ -404,17 +435,15 @@ int get_docker_volume_command(const char *command_file, const struct configurati goto cleanup; } - ret = add_to_buffer(out, outlen, " create"); - if (ret != 0) { - goto cleanup; - } - - ret = add_to_buffer(out, outlen, " --name="); + ret = add_to_buffer(out, &index, "create"); if (ret != 0) { goto cleanup; } - ret = add_to_buffer(out, outlen, volume_name); + char *name_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); + sprintf(name_buffer, "--name=%s", volume_name); + ret = add_to_buffer(out, &index, name_buffer); + free(name_buffer); if (ret != 0) { goto cleanup; } @@ -426,29 +455,25 @@ int get_docker_volume_command(const char *command_file, const struct configurati goto cleanup; } - ret = add_to_buffer(out, outlen, " --driver="); - if (ret != 0) { - goto cleanup; - } - - ret = add_to_buffer(out, outlen, driver); + char *driver_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); + sprintf(driver_buffer, "--driver=%s", driver); + ret = add_to_buffer(out, &index, driver_buffer); + free(driver_buffer); if (ret != 0) { goto cleanup; } } else if (0 == strcmp(sub_command, "ls")) { format = get_configuration_value("format", DOCKER_COMMAND_FILE_SECTION, &command_config); - ret = add_to_buffer(out, outlen, " ls"); + ret = add_to_buffer(out, &index, "ls"); if (ret != 0) { goto cleanup; } - if (format) { - ret = add_to_buffer(out, outlen, " --format="); - if (ret != 0) { - goto cleanup; - } - ret = add_to_buffer(out, outlen, format); + char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); + sprintf(tmp_buffer, "--format=%s", format); + ret = add_to_buffer(out, &index, tmp_buffer); + free(tmp_buffer); if (ret != 0) { goto cleanup; } @@ -468,12 +493,14 @@ cleanup: return ret; } -int get_docker_inspect_command(const char *command_file, const struct configuration *conf, char *out, - const size_t outlen) { +int get_docker_inspect_command(const char *command_file, const struct configuration *conf, char **out, + const size_t buff_len) { const char *valid_format_strings[] = { "{{.State.Status}}", "{{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}}" }; - int ret = 0, i = 0, valid_format = 0; + int ret = 0, i = 0, valid_format = 0, index = 0; char *format = NULL, *container_name = NULL; + int tmp_buffer_size=256; + char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); struct configuration command_config = {0, NULL}; ret = read_and_verify_command_file(command_file, DOCKER_INSPECT_COMMAND, &command_config); if (ret != 0) { @@ -503,32 +530,32 @@ int get_docker_inspect_command(const char *command_file, const struct configurat return INVALID_DOCKER_INSPECT_FORMAT; } - memset(out, 0, outlen); + memset(out, 0, buff_len); - ret = add_docker_config_param(&command_config, out, outlen); + char *docker = get_docker_binary(conf); + ret = add_to_buffer(out, &index, docker); + if (ret != 0) { + goto free_and_exit; + } + + ret = add_docker_config_param(&command_config, out, &index); if (ret != 0) { free(container_name); free(format); return BUFFER_TOO_SMALL; } - ret = add_to_buffer(out, outlen, DOCKER_INSPECT_COMMAND); - if (ret != 0) { - goto free_and_exit; - } - ret = add_to_buffer(out, outlen, " --format="); - if (ret != 0) { - goto free_and_exit; - } - ret = add_to_buffer(out, outlen, format); + ret = add_to_buffer(out, &index, DOCKER_INSPECT_COMMAND); if (ret != 0) { goto free_and_exit; } - ret = add_to_buffer(out, outlen, " "); + sprintf(tmp_buffer, "--format=%s", format); + ret = add_to_buffer(out, &index, tmp_buffer); if (ret != 0) { goto free_and_exit; } - ret = add_to_buffer(out, outlen, container_name); + free(tmp_buffer); + ret = add_to_buffer(out, &index, container_name); if (ret != 0) { goto free_and_exit; } @@ -539,11 +566,13 @@ int get_docker_inspect_command(const char *command_file, const struct configurat free_and_exit: free(format); free(container_name); + free(docker); return BUFFER_TOO_SMALL; } -int get_docker_load_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) { +int get_docker_load_command(const char *command_file, const struct configuration *conf, char **out, const size_t buff_len) { int ret = 0; + int index = 0; char *image_name = NULL; size_t tmp_buffer_size = 1024; char *tmp_buffer = NULL; @@ -558,19 +587,27 @@ int get_docker_load_command(const char *command_file, const struct configuration return INVALID_DOCKER_IMAGE_NAME; } - memset(out, 0, outlen); + memset(out, 0, buff_len); + + char *docker = get_docker_binary(conf); + ret = add_to_buffer(out, &index, docker); + if (ret != 0) { + free(docker); + return BUFFER_TOO_SMALL; + } + free(docker); - ret = add_docker_config_param(&command_config, out, outlen); + ret = add_docker_config_param(&command_config, out, &index); if (ret != 0) { free(image_name); return BUFFER_TOO_SMALL; } - ret = add_to_buffer(out, outlen, DOCKER_LOAD_COMMAND); + ret = add_to_buffer(out, &index, 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); + quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "--i=", image_name); + ret = add_to_buffer(out, &index, tmp_buffer); free(tmp_buffer); free(image_name); if (ret != 0) { @@ -587,11 +624,10 @@ static int validate_docker_image_name(const char *image_name) { 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 get_docker_pull_command(const char *command_file, const struct configuration *conf, char **out, const size_t buff_len) { int ret = 0; + int index = 0; char *image_name = NULL; - size_t tmp_buffer_size = 1024; - char *tmp_buffer = NULL; struct configuration command_config = {0, NULL}; ret = read_and_verify_command_file(command_file, DOCKER_PULL_COMMAND, &command_config); if (ret != 0) { @@ -603,31 +639,37 @@ int get_docker_pull_command(const char *command_file, const struct configuration return INVALID_DOCKER_IMAGE_NAME; } - memset(out, 0, outlen); + memset(out, 0, buff_len); - ret = add_docker_config_param(&command_config, out, outlen); + char *docker = get_docker_binary(conf); + ret = add_to_buffer(out, &index, docker); if (ret != 0) { - return BUFFER_TOO_SMALL; + goto free_pull; + } + + ret = add_docker_config_param(&command_config, out, &index); + if (ret != 0) { + goto free_pull; } - ret = add_to_buffer(out, outlen, DOCKER_PULL_COMMAND); + ret = add_to_buffer(out, &index, 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); + ret = add_to_buffer(out, &index, image_name); free(image_name); if (ret != 0) { - return BUFFER_TOO_SMALL; + goto free_pull; } return 0; } + free_pull: free(image_name); + free(docker); return BUFFER_TOO_SMALL; } -int get_docker_rm_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) { +int get_docker_rm_command(const char *command_file, const struct configuration *conf, char **out, const size_t buff_len) { int ret = 0; + int index = 0; char *container_name = NULL; struct configuration command_config = {0, NULL}; ret = read_and_verify_command_file(command_file, DOCKER_RM_COMMAND, &command_config); @@ -640,19 +682,24 @@ int get_docker_rm_command(const char *command_file, const struct configuration * return INVALID_DOCKER_CONTAINER_NAME; } - memset(out, 0, outlen); + memset(out, 0, buff_len); - ret = add_docker_config_param(&command_config, out, outlen); + char *docker = get_docker_binary(conf); + ret = add_to_buffer(out, &index, docker); if (ret != 0) { + free(docker); return BUFFER_TOO_SMALL; } + free(docker); - ret = add_to_buffer(out, outlen, DOCKER_RM_COMMAND); + ret = add_docker_config_param(&command_config, out, &index); + if (ret != 0) { + return BUFFER_TOO_SMALL; + } + + ret = add_to_buffer(out, &index, DOCKER_RM_COMMAND); if (ret == 0) { - ret = add_to_buffer(out, outlen, " "); - if (ret == 0) { - ret = add_to_buffer(out, outlen, container_name); - } + ret = add_to_buffer(out, &index, container_name); free(container_name); if (ret != 0) { return BUFFER_TOO_SMALL; @@ -664,9 +711,11 @@ int get_docker_rm_command(const char *command_file, const struct configuration * } int get_docker_stop_command(const char *command_file, const struct configuration *conf, - char *out, const size_t outlen) { + char **out, const size_t buff_len) { int ret = 0; + int index = 0; size_t len = 0, i = 0; + int tmp_buffer_size=256; char *value = NULL; char *container_name = NULL; struct configuration command_config = {0, NULL}; @@ -680,14 +729,22 @@ int get_docker_stop_command(const char *command_file, const struct configuration return INVALID_DOCKER_CONTAINER_NAME; } - memset(out, 0, outlen); + memset(out, 0, buff_len); - ret = add_docker_config_param(&command_config, out, outlen); + char *docker = get_docker_binary(conf); + ret = add_to_buffer(out, &index, docker); if (ret != 0) { + free(docker); return BUFFER_TOO_SMALL; } + free(docker); - ret = add_to_buffer(out, outlen, DOCKER_STOP_COMMAND); + ret = add_docker_config_param(&command_config, out, &index); + if (ret != 0) { + return BUFFER_TOO_SMALL; + } + + ret = add_to_buffer(out, &index, DOCKER_STOP_COMMAND); if (ret == 0) { value = get_configuration_value("time", DOCKER_COMMAND_FILE_SECTION, &command_config); if (value != NULL) { @@ -696,23 +753,20 @@ int get_docker_stop_command(const char *command_file, const struct configuration if (isdigit(value[i]) == 0) { fprintf(ERRORFILE, "Value for time is not a number '%s'\n", value); free(container_name); - memset(out, 0, outlen); + memset(out, 0, buff_len); return INVALID_DOCKER_STOP_COMMAND; } } - ret = add_to_buffer(out, outlen, " --time="); - if (ret == 0) { - ret = add_to_buffer(out, outlen, value); - } + char *time_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); + sprintf(time_buffer, "--time=%s", value); + ret = add_to_buffer(out, &index, time_buffer); if (ret != 0) { + free(time_buffer); free(container_name); return BUFFER_TOO_SMALL; } } - ret = add_to_buffer(out, outlen, " "); - if (ret == 0) { - ret = add_to_buffer(out, outlen, container_name); - } + ret = add_to_buffer(out, &index, container_name); free(container_name); if (ret != 0) { return BUFFER_TOO_SMALL; @@ -724,8 +778,10 @@ int get_docker_stop_command(const char *command_file, const struct configuration } int get_docker_kill_command(const char *command_file, const struct configuration *conf, - char *out, const size_t outlen) { + char **out, const size_t buff_len) { int ret = 0; + int index = 0; + int tmp_buffer_size = 40; size_t len = 0, i = 0; char *value = NULL; char *container_name = NULL; @@ -740,14 +796,22 @@ int get_docker_kill_command(const char *command_file, const struct configuration return INVALID_DOCKER_CONTAINER_NAME; } - memset(out, 0, outlen); + memset(out, 0, buff_len); + + char *docker = get_docker_binary(conf); + ret = add_to_buffer(out, &index, docker); + if (ret != 0) { + free(docker); + return BUFFER_TOO_SMALL; + } + free(docker); - ret = add_docker_config_param(&command_config, out, outlen); + ret = add_docker_config_param(&command_config, out, &index); if (ret != 0) { return BUFFER_TOO_SMALL; } - ret = add_to_buffer(out, outlen, DOCKER_KILL_COMMAND); + ret = add_to_buffer(out, &index, DOCKER_KILL_COMMAND); if (ret == 0) { value = get_configuration_value("signal", DOCKER_COMMAND_FILE_SECTION, &command_config); if (value != NULL) { @@ -756,23 +820,21 @@ int get_docker_kill_command(const char *command_file, const struct configuration if (isupper(value[i]) == 0) { fprintf(ERRORFILE, "Value for signal contains non-uppercase characters '%s'\n", value); free(container_name); - memset(out, 0, outlen); + memset(out, 0, buff_len); return INVALID_DOCKER_KILL_COMMAND; } } - ret = add_to_buffer(out, outlen, " --signal="); - if (ret == 0) { - ret = add_to_buffer(out, outlen, value); - } + + char *signal_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); + snprintf(signal_buffer, tmp_buffer_size, "--signal=%s", value); + ret = add_to_buffer(out, &index, signal_buffer); + free(signal_buffer); if (ret != 0) { free(container_name); return BUFFER_TOO_SMALL; } } - ret = add_to_buffer(out, outlen, " "); - if (ret == 0) { - ret = add_to_buffer(out, outlen, container_name); - } + ret = add_to_buffer(out, &index, container_name); free(container_name); if (ret != 0) { return BUFFER_TOO_SMALL; @@ -783,31 +845,29 @@ int get_docker_kill_command(const char *command_file, const struct configuration return BUFFER_TOO_SMALL; } -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 detach_container(const struct configuration *command_config, char **out, int *index) { + return add_param_to_command(command_config, "detach", "-d", 0, out, index); } -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 rm_container_on_exit(const struct configuration *command_config, char **out, int *index) { + return add_param_to_command(command_config, "rm", "--rm", 0, out, index); } -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_container_workdir(const struct configuration *command_config, char **out, int *index) { + return add_param_to_command(command_config, "workdir", "--workdir=", 1, out, index); } -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_cgroup_parent(const struct configuration *command_config, char **out, int *index) { + return add_param_to_command(command_config, "cgroup-parent", "--cgroup-parent=", 1, out, index); } -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_hostname(const struct configuration *command_config, char **out, int *index) { + return add_param_to_command(command_config, "hostname", "--hostname=", 1, out, index); } -static int set_group_add(const struct configuration *command_config, char *out, const size_t outlen) { +static int set_group_add(const struct configuration *command_config, char **out, int *index) { int i = 0, ret = 0; char **group_add = get_configuration_values_delimiter("group-add", DOCKER_COMMAND_FILE_SECTION, command_config, ","); - size_t tmp_buffer_size = 4096; - char *tmp_buffer = NULL; char *privileged = NULL; privileged = get_configuration_value("privileged", DOCKER_COMMAND_FILE_SECTION, command_config); @@ -819,9 +879,11 @@ static int set_group_add(const struct configuration *command_config, char *out, if (group_add != NULL) { for (i = 0; group_add[i] != NULL; ++i) { - tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); - quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "--group-add ", group_add[i]); - ret = add_to_buffer(out, outlen, tmp_buffer); + ret = add_to_buffer(out, index, "--group-add"); + if (ret != 0) { + return BUFFER_TOO_SMALL; + } + ret = add_to_buffer(out, index, group_add[i]); if (ret != 0) { return BUFFER_TOO_SMALL; } @@ -831,25 +893,25 @@ static int set_group_add(const struct configuration *command_config, char *out, } static int set_network(const struct configuration *command_config, - const struct configuration *conf, char *out, - const size_t outlen) { + const struct configuration *conf, char **out, + int *index) { int ret = 0; ret = add_param_to_command_if_allowed(command_config, conf, "net", "docker.allowed.networks", "--net=", - 0, 0, out, outlen); + 0, 0, out, index); if (ret != 0) { fprintf(ERRORFILE, "Could not find requested network in allowed networks\n"); ret = INVALID_DOCKER_NETWORK; - memset(out, 0, outlen); + //memset(out, 0, index); } return ret; } static int set_pid_namespace(const struct configuration *command_config, - const struct configuration *conf, char *out, - const size_t outlen) { + const struct configuration *conf, char **out, + int *index) { size_t tmp_buffer_size = 1024; char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); char *value = get_configuration_value("pid", DOCKER_COMMAND_FILE_SECTION, @@ -863,7 +925,7 @@ static int set_pid_namespace(const struct configuration *command_config, if (pid_host_enabled != NULL) { if (strcmp(pid_host_enabled, "1") == 0 || strcasecmp(pid_host_enabled, "True") == 0) { - ret = add_to_buffer(out, outlen, "--pid='host' "); + ret = add_to_buffer(out, index, "--pid='host'"); if (ret != 0) { ret = BUFFER_TOO_SMALL; } @@ -887,19 +949,15 @@ static int set_pid_namespace(const struct configuration *command_config, free(tmp_buffer); free(value); free(pid_host_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) { - + const struct configuration *conf, char **out, + int *index) { int ret = 0; - ret = add_to_buffer(out, outlen, "--cap-drop='ALL' "); + ret = add_to_buffer(out, index, "--cap-drop=ALL"); if (ret != 0) { return BUFFER_TOO_SMALL; } @@ -907,7 +965,7 @@ static int set_capabilities(const struct configuration *command_config, ret = add_param_to_command_if_allowed(command_config, conf, "cap-add", "docker.allowed.capabilities", "--cap-add=", 1, 0, - out, outlen); + out, index); switch (ret) { case 0: break; @@ -918,26 +976,46 @@ static int set_capabilities(const struct configuration *command_config, default: fprintf(ERRORFILE, "Invalid docker capability requested\n"); ret = INVALID_DOCKER_CAPABILITY; - memset(out, 0, outlen); } return ret; } -static int set_devices(const struct configuration *command_config, const struct configuration *conf, char *out, - const size_t outlen) { +static int set_devices(const struct configuration *command_config, const struct configuration *conf, char **out, + int *index) { int ret = 0; ret = add_param_to_command_if_allowed(command_config, conf, "devices", "docker.allowed.devices", "--device=", 1, ':', - out, outlen); + out, index); if (ret != 0) { fprintf(ERRORFILE, "Invalid docker device requested\n"); ret = INVALID_DOCKER_DEVICE; - memset(out, 0, outlen); + (*index) = 0; } return ret; } +static int set_env(const struct configuration *command_config, char **out, int *index) { + int ret = 0; + char *value = get_configuration_value("environ", DOCKER_COMMAND_FILE_SECTION, command_config); + if (value != NULL) { + for (int i = 0; i < (int) strlen(value); i++) { + if (value[i]=='|') { + value[i]='='; + } + } + ret = add_to_buffer(out, index, value); + if (ret != 0) { + return BUFFER_TOO_SMALL; + } +/* ret = add_to_buffer(out, index, " "); + if (ret != 0) { + return BUFFER_TOO_SMALL; + }*/ + } + return ret; +} + /** * Helper function to help normalize mounts for checking if mounts are * permitted. The function does the following - @@ -962,7 +1040,6 @@ static char* normalize_mount(const char* mount) { } fprintf(ERRORFILE, "Could not determine real path of mount '%s'\n", mount); - free(real_mount); return NULL; } ret = stat(real_mount, &buff); @@ -970,6 +1047,7 @@ static char* normalize_mount(const char* mount) { if (S_ISDIR(buff.st_mode)) { size_t len = strlen(real_mount); if (len <= 0) { + free(real_mount); return NULL; } if (real_mount[len - 1] != '/') { @@ -1013,6 +1091,7 @@ static int check_mount_permitted(const char **permitted_mounts, const char *requ size_t permitted_mount_len = 0; char *normalized_path = normalize_mount(requested); if (permitted_mounts == NULL) { + free(normalized_path); return 0; } if (normalized_path == NULL) { @@ -1033,40 +1112,37 @@ static int check_mount_permitted(const char **permitted_mounts, const char *requ break; } } - } free(normalized_path); return ret; } static char* get_mount_source(const char *mount) { - char *src_mount = NULL; - const char *tmp = NULL; - tmp = strchr(mount, ':'); + const char *tmp = strchr(mount, ':'); if (tmp == NULL) { fprintf(ERRORFILE, "Invalid docker mount '%s'\n", mount); return NULL; } - src_mount = strndup(mount, tmp - mount); + size_t len = tmp - mount; + char *src_mount; + src_mount = strndup(mount, len); return 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) { + const int ro, char **out, int *index) { size_t tmp_buffer_size = 1024; - const char *ro_suffix = ""; + char *ro_suffix = (char*) ""; 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("docker.allowed.ro-mounts", CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf, ","); char **permitted_rw_mounts = get_configuration_values_delimiter("docker.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, *mount_src = 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"; + ro_suffix = (char*) ":ro"; } if (values != NULL) { @@ -1090,8 +1166,8 @@ static int add_mounts(const struct configuration *command_config, const struct c ret = MOUNT_ACCESS_ERROR; goto free_and_exit; } - for (i = 0; values[i] != NULL; ++i) { - mount_src = get_mount_source(values[i]); + for (i = 0; values[i] != NULL; i++) { + char *mount_src = get_mount_source(values[i]); if (mount_src == NULL) { fprintf(ERRORFILE, "Invalid docker mount '%s', realpath=%s\n", values[i], mount_src); ret = INVALID_DOCKER_MOUNT; @@ -1102,12 +1178,14 @@ static int add_mounts(const struct configuration *command_config, const struct c if (permitted_ro == -1 || permitted_rw == -1) { fprintf(ERRORFILE, "Invalid docker mount '%s', realpath=%s\n", values[i], mount_src); ret = INVALID_DOCKER_MOUNT; + free(mount_src); goto free_and_exit; } // rw mount if (ro == 0) { if (permitted_rw == 0) { fprintf(ERRORFILE, "Invalid docker rw mount '%s', realpath=%s\n", values[i], mount_src); + free(mount_src); ret = INVALID_DOCKER_RW_MOUNT; goto free_and_exit; } else { @@ -1121,6 +1199,7 @@ static int add_mounts(const struct configuration *command_config, const struct c fprintf(ERRORFILE, "Attempting to mount a parent directory '%s' of container-executor.cfg as read-write\n", values[i]); ret = INVALID_DOCKER_RW_MOUNT; + free(mount_src); goto free_and_exit; } } @@ -1129,18 +1208,20 @@ static int add_mounts(const struct configuration *command_config, const struct c if (ro != 0 && permitted_ro == 0 && permitted_rw == 0) { fprintf(ERRORFILE, "Invalid docker ro mount '%s', realpath=%s\n", values[i], mount_src); ret = INVALID_DOCKER_RO_MOUNT; + free(mount_src); + goto free_and_exit; + } + + ret = add_to_buffer(out, index, "-v"); + if (ret != 0) { + ret = BUFFER_TOO_SMALL; 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(mount_src); - tmp_buffer_2 = NULL; - mount_src = NULL; - memset(tmp_buffer, 0, tmp_buffer_size); + + char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); + sprintf(tmp_buffer, "%s%s", values[i], ro_suffix); + ret = add_to_buffer(out, index, tmp_buffer); + free(tmp_buffer); if (ret != 0) { ret = BUFFER_TOO_SMALL; goto free_and_exit; @@ -1152,23 +1233,18 @@ static int add_mounts(const struct configuration *command_config, const struct c free_values(permitted_ro_mounts); free_values(permitted_rw_mounts); free_values(values); - free(mount_src); free((void *) 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_ro_mounts(const struct configuration *command_config, const struct configuration *conf, char **out, + int *index) { + return add_mounts(command_config, conf, "ro-mounts", 1, out, index); } -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 add_rw_mounts(const struct configuration *command_config, const struct configuration *conf, char **out, + int *index) { + return add_mounts(command_config, conf, "rw-mounts", 0, out, index); } static int check_privileges(const char *user) { @@ -1177,8 +1253,9 @@ static int check_privileges(const char *user) { char tmpl[] = "id -G -n %s"; char buffer[4096]; if (fork()==0) { - char *cmd = (char *) alloc_and_clear_memory(strlen(tmpl) + strlen(user), sizeof(char)); - sprintf(cmd, tmpl, user); + int cmd_size = strlen(tmpl) + strlen(user); + char *cmd = (char *) alloc_and_clear_memory(cmd_size, sizeof(char)); + snprintf(cmd, cmd_size, tmpl, user); fp = popen(cmd, "r"); if (fp == NULL) { exit(127); @@ -1194,7 +1271,7 @@ static int check_privileges(const char *user) { if (strcmp(token, "root")==0 || strcmp(token, "docker")==0) { pclose(fp); free(cmd); - exit(0); + return 0; } } free(token); @@ -1208,15 +1285,15 @@ static int check_privileges(const char *user) { wait(&statval); if (WIFEXITED(statval)) { if (WEXITSTATUS(statval)==0) { - return 1; + return 0; } } } - return 0; + return 1; } -static int set_privileged(const struct configuration *command_config, const struct configuration *conf, char *out, - const size_t outlen) { +static int set_privileged(const struct configuration *command_config, const struct configuration *conf, char **out, + int *index) { size_t tmp_buffer_size = 1024; char *user = NULL; char *tmp_buffer = (char *) alloc_and_clear_memory(tmp_buffer_size, sizeof(char)); @@ -1224,7 +1301,7 @@ static int set_privileged(const struct configuration *command_config, const stru char *privileged_container_enabled = get_configuration_value("docker.privileged-containers.enabled", CONTAINER_EXECUTOR_CFG_DOCKER_SECTION, conf); int ret = 0; - int allowed = 0; + int allowed = 1; user = get_configuration_value("user", DOCKER_COMMAND_FILE_SECTION, command_config); if (user == NULL) { @@ -1242,8 +1319,8 @@ static int set_privileged(const struct configuration *command_config, const stru goto free_and_exit; } allowed = check_privileges(user); - if (allowed) { - ret = add_to_buffer(out, outlen, "--privileged "); + if (allowed == 0) { + ret = add_to_buffer(out, index, "--privileged"); if (ret != 0) { ret = BUFFER_TOO_SMALL; } @@ -1264,14 +1341,12 @@ static int set_privileged(const struct configuration *command_config, const stru free(tmp_buffer); free(value); free(privileged_container_enabled); - 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 get_docker_run_command(const char *command_file, const struct configuration *conf, char **out, const size_t buff_len) { int ret = 0, i = 0; + int index = 0; char *container_name = NULL, *user = NULL, *image = NULL; size_t tmp_buffer_size = 1024; char *tmp_buffer = NULL; @@ -1296,21 +1371,28 @@ int get_docker_run_command(const char *command_file, const struct configuration return INVALID_DOCKER_IMAGE_NAME; } - ret = add_docker_config_param(&command_config, out, outlen); + char *docker = get_docker_binary(conf); + ret = add_to_buffer(out, &index, docker); if (ret != 0) { + free(docker); return BUFFER_TOO_SMALL; } + free(docker); - ret = add_to_buffer(out, outlen, DOCKER_RUN_COMMAND); - if(ret != 0) { + ret = add_docker_config_param(&command_config, out, &index); + if (ret != 0) { return BUFFER_TOO_SMALL; } + ret = add_to_buffer(out, &index, DOCKER_RUN_COMMAND); + if(ret != 0) { + return BUFFER_TOO_SMALL; + } 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); + snprintf(tmp_buffer, tmp_buffer_size, "--name=%s", container_name); + ret = add_to_buffer(out, &index, tmp_buffer); if (ret != 0) { return BUFFER_TOO_SMALL; } @@ -1319,107 +1401,107 @@ int get_docker_run_command(const char *command_file, const struct configuration privileged = get_configuration_value("privileged", DOCKER_COMMAND_FILE_SECTION, &command_config); if (privileged == NULL || strcmp(privileged, "false") == 0) { - 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); + snprintf(tmp_buffer, tmp_buffer_size, "--user=%s", user); + ret = add_to_buffer(out, &index, tmp_buffer); + if (ret != 0) { + return BUFFER_TOO_SMALL; + } + memset(tmp_buffer, 0, tmp_buffer_size); } free(privileged); - ret = detach_container(&command_config, out, outlen); + ret = detach_container(&command_config, out, &index); if (ret != 0) { return ret; } - ret = rm_container_on_exit(&command_config, out, outlen); + ret = rm_container_on_exit(&command_config, out, &index); if (ret != 0) { return ret; } - ret = set_container_workdir(&command_config, out, outlen); + ret = set_container_workdir(&command_config, out, &index); if (ret != 0) { return ret; } - ret = set_network(&command_config, conf, out, outlen); + ret = set_network(&command_config, conf, out, &index); if (ret != 0) { return ret; } - ret = set_pid_namespace(&command_config, conf, out, outlen); + ret = set_pid_namespace(&command_config, conf, out, &index); if (ret != 0) { return ret; } - ret = add_ro_mounts(&command_config, conf, out, outlen); + ret = add_ro_mounts(&command_config, conf, out, &index); if (ret != 0) { return ret; } - ret = add_rw_mounts(&command_config, conf, out, outlen); + ret = add_rw_mounts(&command_config, conf, out, &index); if (ret != 0) { return ret; } - ret = set_cgroup_parent(&command_config, out, outlen); + ret = set_cgroup_parent(&command_config, out, &index); if (ret != 0) { return ret; } - ret = set_privileged(&command_config, conf, out, outlen); + ret = set_privileged(&command_config, conf, out, &index); if (ret != 0) { return ret; } - ret = set_capabilities(&command_config, conf, out, outlen); + ret = set_capabilities(&command_config, conf, out, &index); if (ret != 0) { return ret; } - ret = set_hostname(&command_config, out, outlen); + ret = set_hostname(&command_config, out, &index); if (ret != 0) { return ret; } - ret = set_group_add(&command_config, out, outlen); + ret = set_group_add(&command_config, out, &index); if (ret != 0) { return ret; } - ret = set_devices(&command_config, conf, out, outlen); + ret = set_devices(&command_config, conf, out, &index); if (ret != 0) { return ret; } - quote_and_append_arg(&tmp_buffer, &tmp_buffer_size, "", image); - ret = add_to_buffer(out, outlen, tmp_buffer); + ret = set_env(&command_config, out, &index); + if (ret != 0) { + return BUFFER_TOO_SMALL; + } + + ret = add_to_buffer(out, &index, image); if (ret != 0) { return BUFFER_TOO_SMALL; } launch_command = get_configuration_values_delimiter("launch-command", DOCKER_COMMAND_FILE_SECTION, &command_config, ","); - if (check_trusted_image(&command_config, conf) != 0) { launch_command = NULL; } 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); + ret = add_to_buffer(out, &index, launch_command[i]); if (ret != 0) { free_values(launch_command); - free(tmp_buffer); return BUFFER_TOO_SMALL; } } free_values(launch_command); } - free(tmp_buffer); + free(tmp_buffer); return 0; } 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 index 8299acd..826c738 100644 --- 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 @@ -69,6 +69,13 @@ enum docker_error_codes { char *get_docker_binary(const struct configuration *conf); /** + * Check if use-entry-point flag is set. + * @param command_file File containing the params for the Docker command + * @return 1 when use-entry-point flag is set. + */ +int use_entry_point(const char *command_file); + +/** * 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 @@ -76,7 +83,7 @@ char *get_docker_binary(const struct configuration *conf); * @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); +int get_docker_command(const char* command_file, const struct configuration* conf, char **out, const size_t buff_len); /** * Get the Docker inspect command line string. The function will verify that the params file is meant for the @@ -87,7 +94,7 @@ int get_docker_command(const char* command_file, const struct configuration* con * @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); +int get_docker_inspect_command(const char* command_file, const struct configuration* conf, char **out, const size_t buff_len); /** * Get the Docker load command line string. The function will verify that the params file is meant for the load command. @@ -97,7 +104,7 @@ int get_docker_inspect_command(const char* command_file, const struct configurat * @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); +int get_docker_load_command(const char* command_file, const struct configuration* conf, char **out, const size_t buff_len); /** * Get the Docker pull command line string. The function will verify that the params file is meant for the pull command. @@ -107,7 +114,7 @@ int get_docker_load_command(const char* command_file, const struct configuration * @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); +int get_docker_pull_command(const char* command_file, const struct configuration* conf, char **out, const size_t buff_len); /** * Get the Docker rm command line string. The function will verify that the params file is meant for the rm command. @@ -117,7 +124,7 @@ int get_docker_pull_command(const char* command_file, const struct configuration * @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); +int get_docker_rm_command(const char* command_file, const struct configuration* conf, char **out, const size_t buff_len); /** * Get the Docker run command line string. The function will verify that the params file is meant for the run command. @@ -127,7 +134,7 @@ int get_docker_rm_command(const char* command_file, const struct configuration* * @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); +int get_docker_run_command(const char* command_file, const struct configuration* conf, char **out, const size_t buff_len); /** * Get the Docker stop command line string. The function will verify that the params file is meant for the stop command. @@ -137,7 +144,7 @@ int get_docker_run_command(const char* command_file, const struct configuration* * @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); +int get_docker_stop_command(const char* command_file, const struct configuration* conf, char **out, const size_t buff_len); /** * Get the Docker kill command line string. The function will verify that the params file is meant for the kill command. @@ -147,7 +154,7 @@ int get_docker_stop_command(const char* command_file, const struct configuration * @param outlen Size of the output buffer * @return Return code with 0 indicating success and non-zero codes indicating error */ -int get_docker_kill_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen); +int get_docker_kill_command(const char* command_file, const struct configuration* conf, char **out, const size_t buff_len); /** * Get the Docker volume command line string. The function will verify that the @@ -158,8 +165,8 @@ int get_docker_kill_command(const char* command_file, const struct configuration * @param outlen Size of the output buffer * @return Return code with 0 indicating success and non-zero codes indicating error */ -int get_docker_volume_command(const char *command_file, const struct configuration *conf, char *out, - const size_t outlen); +int get_docker_volume_command(const char *command_file, const struct configuration *conf, char **out, + const size_t buff_len); /** * Give an error message for the supplied error code diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc index 15b6c69..cb12523 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc @@ -94,45 +94,75 @@ namespace ContainerExecutor { write_file(docker_command_file, contents); } + char* flatten(char **args) { + size_t string_len = 0; + size_t current_len = 0; + char *buffer = (char *) malloc(8192 * sizeof(char)); + for (int i = 0; args[i] != NULL; i++) { + string_len = strlen(args[i]); + if (string_len != 0) { + strncpy(buffer + current_len, args[i], string_len); + current_len = current_len + string_len; + if (args[i +1] != NULL) { + strncpy(buffer + current_len, " ", 1); + current_len++; + } + } + } + buffer[current_len] = '\0'; + return buffer; + } + + void reset(char **buffer, const int buff_len, char *first, int *index) { + memset(buffer, 0, buff_len); + (*index) = 0; + buffer[*index] = first; + (*index)++; + } + void run_docker_command_test(const std::vector > &file_cmd_vec, const std::vector > &bad_file_cmd_vec, - int (*docker_func)(const char *, const struct configuration *, char *, const size_t)) { - char tmp[8192]; + int (*docker_func)(const char *, const struct configuration *, char **, const size_t)) { + size_t buff_len = 8192; + char **tmp = (char **) malloc(buff_len * sizeof(char *)); std::vector >::const_iterator itr; for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) { - memset(tmp, 0, 8192); + memset(tmp, 0, buff_len); write_command_file(itr->first); - int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, tmp, 8192); + int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, tmp, buff_len); ASSERT_EQ(0, ret) << "error message: " << get_docker_error_message(ret) << " for input " << itr->first; - ASSERT_STREQ(itr->second.c_str(), tmp); + char *actual = flatten(tmp); + ASSERT_STREQ(itr->second.c_str(), actual); } std::vector >::const_iterator itr2; for (itr2 = bad_file_cmd_vec.begin(); itr2 != bad_file_cmd_vec.end(); ++itr2) { - memset(tmp, 0, 8192); + memset(tmp, 0, buff_len); write_command_file(itr2->first); - int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, tmp, 8192); + int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, tmp, buff_len); ASSERT_EQ(itr2->second, ret) << " for " << itr2->first << std::endl; - ASSERT_EQ(0, strlen(tmp)); + //char *actual = flatten(tmp); + //ASSERT_EQ(0, strlen(actual)); } - int ret = (*docker_func)("unknown-file", &container_executor_cfg, tmp, 8192); + int ret = (*docker_func)("unknown-file", &container_executor_cfg, tmp, buff_len); ASSERT_EQ(static_cast(INVALID_COMMAND_FILE), ret); } void run_docker_run_helper_function(const std::vector > &file_cmd_vec, - int (*helper_func)(const struct configuration *, char *, const size_t)) { + int (*helper_func)(const struct configuration *, char **, int *)) { std::vector >::const_iterator itr; for(itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) { struct configuration cfg; const int buff_len = 1024; - char buff[buff_len]; + int index = 0; + char **buff = (char **) malloc(buff_len * sizeof(char *)); 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); + ret = (*helper_func)(&cfg, buff, &index); ASSERT_EQ(0, ret); - ASSERT_STREQ(itr->second.c_str(), buff); + ASSERT_STREQ(itr->second.c_str(), flatten(buff)); } } } @@ -249,7 +279,7 @@ namespace ContainerExecutor { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=pull\n image=image-id", - "pull 'image-id' ")); + "pull image-id")); std::vector > bad_file_cmd_vec; bad_file_cmd_vec.push_back(std::make_pair( @@ -341,7 +371,7 @@ namespace ContainerExecutor { TEST_F(TestDockerUtil, test_detach_container) { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n detach=true", "-d ")); + "[docker-command-execution]\n docker-command=run\n detach=true", "-d")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run", "")); @@ -351,7 +381,7 @@ namespace ContainerExecutor { TEST_F(TestDockerUtil, test_rm_container) { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n rm=true", "--rm ")); + "[docker-command-execution]\n docker-command=run\n rm=true", "--rm")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run", "")); @@ -361,7 +391,7 @@ namespace ContainerExecutor { TEST_F(TestDockerUtil, test_set_container_workdir) { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n workdir=/tmp/test", "--workdir='/tmp/test' ")); + "[docker-command-execution]\n docker-command=run\n workdir=/tmp/test", "--workdir=/tmp/test")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run", "")); @@ -372,7 +402,7 @@ namespace ContainerExecutor { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n cgroup-parent=/sys/fs/cgroup/yarn", - "--cgroup-parent='/sys/fs/cgroup/yarn' ")); + "--cgroup-parent=/sys/fs/cgroup/yarn")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run", "")); @@ -382,7 +412,7 @@ namespace ContainerExecutor { TEST_F(TestDockerUtil, test_set_hostname) { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n hostname=ctr-id", "--hostname='ctr-id' ")); + "[docker-command-execution]\n docker-command=run\n hostname=ctr-id", "--hostname=ctr-id")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run", "")); @@ -392,7 +422,7 @@ namespace ContainerExecutor { TEST_F(TestDockerUtil, test_set_group_add) { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n group-add=1000,1001", "--group-add '1000' --group-add '1001' ")); + "[docker-command-execution]\n docker-command=run\n group-add=1000,1001", "--group-add 1000 --group-add 1001")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run", "")); @@ -402,14 +432,15 @@ namespace ContainerExecutor { TEST_F(TestDockerUtil, test_set_network) { struct configuration container_cfg; const int buff_len = 1024; - char buff[buff_len]; + int index = 0; + char **buff = (char **) calloc(buff_len, sizeof(char *)); int ret = 0; std::string container_executor_cfg_contents = "[docker]\n docker.allowed.networks=sdn1,bridge"; std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n net=bridge", "--net='bridge' ")); + "[docker-command-execution]\n docker-command=run\n net=bridge", "--net=bridge")); file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n net=sdn1", "--net='sdn1' ")); + "[docker-command-execution]\n docker-command=run\n net=sdn1", "--net=sdn1")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run", "")); write_container_executor_cfg(container_executor_cfg_contents); @@ -422,14 +453,15 @@ namespace ContainerExecutor { for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) { struct configuration cmd_cfg; memset(buff, 0, buff_len); + index = 0; 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); + ret = set_network(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(0, ret); - ASSERT_STREQ(itr->second.c_str(), buff); + ASSERT_STREQ(itr->second.c_str(), flatten(buff)); } struct configuration cmd_cfg_1; write_command_file("[docker-command-execution]\n docker-command=run\n net=sdn2"); @@ -437,10 +469,10 @@ namespace ContainerExecutor { if (ret != 0) { FAIL(); } - strcpy(buff, "test string"); - ret = set_network(&cmd_cfg_1, &container_cfg, buff, buff_len); + reset(buff, buff_len, (char *) "test string", &index); + ret = set_network(&cmd_cfg_1, &container_cfg, buff, &index); ASSERT_EQ(INVALID_DOCKER_NETWORK, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(1, index); container_executor_cfg_contents = "[docker]\n"; write_container_executor_cfg(container_executor_cfg_contents); @@ -448,16 +480,17 @@ namespace ContainerExecutor { if (ret != 0) { FAIL(); } - strcpy(buff, "test string"); - ret = set_network(&cmd_cfg_1, &container_cfg, buff, buff_len); + reset(buff, buff_len, (char *) "test string", &index); + ret = set_network(&cmd_cfg_1, &container_cfg, buff, &index); ASSERT_EQ(INVALID_DOCKER_NETWORK, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(1, index); } TEST_F(TestDockerUtil, test_set_pid_namespace) { struct configuration container_cfg, cmd_cfg; const int buff_len = 1024; - char buff[buff_len]; + int index = 0; + char **buff = (char **) malloc(buff_len * sizeof (char *)); int ret = 0; std::string container_executor_cfg_contents[] = {"[docker]\n docker.host-pid-namespace.enabled=1", "[docker]\n docker.host-pid-namespace.enabled=true", @@ -470,7 +503,7 @@ namespace ContainerExecutor { std::vector >::const_iterator itr; std::vector >::const_iterator itr2; file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n pid=host", "--pid='host' ")); + "[docker-command-execution]\n docker-command=run\n pid=host", "--pid='host'")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run", "")); bad_file_cmd_vec.push_back(std::make_pair( @@ -486,25 +519,27 @@ namespace ContainerExecutor { } for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) { memset(buff, 0, buff_len); + index = 0; write_command_file(itr->first); ret = read_config(docker_command_file.c_str(), &cmd_cfg); if (ret != 0) { FAIL(); } - ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, buff_len); + ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(0, ret); - ASSERT_STREQ(itr->second.c_str(), buff); + ASSERT_STREQ(itr->second.c_str(), flatten(buff)); } for (itr2 = bad_file_cmd_vec.begin(); itr2 != bad_file_cmd_vec.end(); ++itr2) { memset(buff, 0, buff_len); + index = 0; write_command_file(itr2->first); ret = read_config(docker_command_file.c_str(), &cmd_cfg); if (ret != 0) { FAIL(); } - ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, buff_len); + ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(itr2->second, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(0, index); } } @@ -520,14 +555,15 @@ namespace ContainerExecutor { "[docker-command-execution]\n docker-command=run", "")); for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) { memset(buff, 0, buff_len); + index = 0; write_command_file(itr->first); ret = read_config(docker_command_file.c_str(), &cmd_cfg); if (ret != 0) { FAIL(); } - ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, buff_len); + ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(0, ret); - ASSERT_STREQ(itr->second.c_str(), buff); + ASSERT_STREQ(itr->second.c_str(), flatten(buff)); } bad_file_cmd_vec.clear(); bad_file_cmd_vec.push_back(std::make_pair( @@ -538,14 +574,15 @@ namespace ContainerExecutor { static_cast(PID_HOST_DISABLED))); for (itr2 = bad_file_cmd_vec.begin(); itr2 != bad_file_cmd_vec.end(); ++itr2) { memset(buff, 0, buff_len); + index = 0; write_command_file(itr2->first); ret = read_config(docker_command_file.c_str(), &cmd_cfg); if (ret != 0) { FAIL(); } - ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, buff_len); + ret = set_pid_namespace(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(itr2->second, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(0, index); } } } @@ -588,7 +625,8 @@ namespace ContainerExecutor { TEST_F(TestDockerUtil, test_set_privileged) { struct configuration container_cfg, cmd_cfg; const int buff_len = 1024; - char buff[buff_len]; + char **buff = (char **) malloc(buff_len * sizeof(char *)); + int index = 0; int ret = 0; std::string container_executor_cfg_contents[] = {"[docker]\n docker.privileged-containers.enabled=1\n docker.privileged-containers.registries=hadoop", "[docker]\n docker.privileged-containers.enabled=true\n docker.privileged-containers.registries=hadoop", @@ -616,24 +654,26 @@ namespace ContainerExecutor { FAIL(); } for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) { + index = 0; 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); + ret = set_privileged(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(6, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(0, index); } write_command_file("[docker-command-execution]\n docker-command=run\n user=test\n privileged=true\n image=nothadoop/image"); ret = read_config(docker_command_file.c_str(), &cmd_cfg); if (ret != 0) { FAIL(); } - ret = set_privileged(&cmd_cfg, &container_cfg, buff, buff_len); + index = 0; + ret = set_privileged(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(PRIVILEGED_CONTAINERS_DISABLED, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(0, index); } @@ -654,25 +694,26 @@ namespace ContainerExecutor { if (ret != 0) { FAIL(); } - ret = set_privileged(&cmd_cfg, &container_cfg, buff, buff_len); + ret = set_privileged(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(0, ret); - ASSERT_STREQ(itr->second.c_str(), buff); + ASSERT_STREQ(itr->second.c_str(), flatten(buff)); } write_command_file("[docker-command-execution]\n docker-command=run\n user=root\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); + ret = set_privileged(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(PRIVILEGED_CONTAINERS_DISABLED, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(0, index); } } TEST_F(TestDockerUtil, test_set_capabilities) { struct configuration container_cfg, cmd_cfg; const int buff_len = 1024; - char buff[buff_len]; + char **buff = (char **) calloc(buff_len, sizeof(char*)); + int index = 0; int ret = 0; std::string container_executor_cfg_contents = "[docker]\n" " docker.allowed.capabilities=CHROOT,MKNOD\n" @@ -680,19 +721,19 @@ namespace ContainerExecutor { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/docker-image\n cap-add=CHROOT,MKNOD", - "--cap-drop='ALL' --cap-add='CHROOT' --cap-add='MKNOD' ")); + "--cap-drop=ALL --cap-add=CHROOT --cap-add=MKNOD")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=nothadoop/docker-image\n cap-add=CHROOT,MKNOD", - "--cap-drop='ALL' ")); + "--cap-drop=ALL")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/docker-image\n cap-add=CHROOT", - "--cap-drop='ALL' --cap-add='CHROOT' ")); + "--cap-drop=ALL --cap-add=CHROOT")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/docker-image\n", - "--cap-drop='ALL' ")); + "--cap-drop=ALL")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=nothadoop/docker-image\n", - "--cap-drop='ALL' ")); + "--cap-drop=ALL")); write_container_executor_cfg(container_executor_cfg_contents); ret = read_config(container_executor_cfg_file.c_str(), &container_cfg); @@ -701,25 +742,25 @@ namespace ContainerExecutor { FAIL(); } for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) { + index = 0; 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); + ret = set_capabilities(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(0, ret); - ASSERT_STREQ(itr->second.c_str(), buff); + ASSERT_STREQ(itr->second.c_str(), flatten(buff)); } write_command_file("[docker-command-execution]\n docker-command=run\n image=hadoop/docker-image\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); + reset(buff, buff_len, (char *) "test string", &index); + ret = set_capabilities(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(INVALID_DOCKER_CAPABILITY, ret); - ASSERT_EQ(0, strlen(buff)); container_executor_cfg_contents = "[docker]\n docker.privileged-containers.registries=hadoop\n"; write_container_executor_cfg(container_executor_cfg_contents); @@ -727,16 +768,16 @@ namespace ContainerExecutor { if (ret != 0) { FAIL(); } - strcpy(buff, "test string"); - ret = set_capabilities(&cmd_cfg, &container_cfg, buff, buff_len); + reset(buff, buff_len, (char *) "test string", &index); + ret = set_capabilities(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(INVALID_DOCKER_CAPABILITY, ret); - ASSERT_EQ(0, strlen(buff)); } TEST_F(TestDockerUtil, test_set_devices) { struct configuration container_cfg, cmd_cfg; const int buff_len = 1024; - char buff[buff_len]; + char **buff = (char **) calloc(buff_len, sizeof(char*)); + int index = 0; int ret = 0; std::string container_executor_cfg_contents = "[docker]\n" " docker.privileged-containers.registries=hadoop\n" @@ -744,14 +785,14 @@ namespace ContainerExecutor { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n devices=/dev/test-device:/dev/test-device", - "--device='/dev/test-device:/dev/test-device' ")); + "--device=/dev/test-device:/dev/test-device")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n devices=/dev/device2:/dev/device2", - "--device='/dev/device2:/dev/device2' ")); + "--device=/dev/device2:/dev/device2")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n" " devices=/dev/test-device:/dev/test-device,/dev/device2:/dev/device2", - "--device='/dev/test-device:/dev/test-device' --device='/dev/device2:/dev/device2' ")); + "--device=/dev/test-device:/dev/test-device --device=/dev/device2:/dev/device2")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image", "")); write_container_executor_cfg(container_executor_cfg_contents); @@ -763,44 +804,45 @@ namespace ContainerExecutor { } for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) { memset(buff, 0, buff_len); + index = 0; write_command_file(itr->first); ret = read_config(docker_command_file.c_str(), &cmd_cfg); if (ret != 0) { FAIL(); } - ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len); + ret = set_devices(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(0, ret); - ASSERT_STREQ(itr->second.c_str(), buff); + ASSERT_STREQ(itr->second.c_str(), flatten(buff)); } write_command_file("[docker-command-execution]\n docker-command=run\n image=nothadoop/image\n devices=/dev/test-device:/dev/test-device"); ret = read_config(docker_command_file.c_str(), &cmd_cfg); if (ret != 0) { FAIL(); } - strcpy(buff, "test string"); - ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len); + reset(buff, buff_len, (char *) "test string", &index); + ret = set_devices(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(INVALID_DOCKER_DEVICE, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(0, index); write_command_file("[docker-command-execution]\n docker-command=run\n image=hadoop/image\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 = set_devices(&cmd_cfg, &container_cfg, buff, buff_len); + reset(buff, buff_len, (char *) "test string", &index); + ret = set_devices(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(INVALID_DOCKER_DEVICE, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(0, index); write_command_file("[docker-command-execution]\n docker-command=run\n image=hadoop/image\n devices=/dev/device1"); ret = read_config(docker_command_file.c_str(), &cmd_cfg); if (ret != 0) { FAIL(); } - strcpy(buff, "test string"); - ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len); + reset(buff, buff_len, (char *) "test string", &index); + ret = set_devices(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(INVALID_DOCKER_DEVICE, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(0, index); container_executor_cfg_contents = "[docker]\n"; write_container_executor_cfg(container_executor_cfg_contents); @@ -808,37 +850,38 @@ namespace ContainerExecutor { if (ret != 0) { FAIL(); } - strcpy(buff, "test string"); - ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len); + reset(buff, buff_len, (char *) "test string", &index); + ret = set_devices(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(INVALID_DOCKER_DEVICE, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(0, index); } TEST_F(TestDockerUtil, test_add_rw_mounts) { struct configuration container_cfg, cmd_cfg; const int buff_len = 1024; - char buff[buff_len]; + char **buff = (char **) calloc(buff_len, sizeof(char *)); + int index = 0; int ret = 0; std::string container_executor_cfg_contents = "[docker]\n docker.privileged-containers.registries=hadoop\n " - "docker.allowed.rw-mounts=/opt,/var,/usr/bin/cut,..\n " + "docker.allowed.rw-mounts=/opt,/var,/usr/bin/cut\n " "docker.allowed.ro-mounts=/etc/passwd"; std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n rw-mounts=/var:/var", "-v '/var:/var' ")); + "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n rw-mounts=/var:/var", "-v /var:/var")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=nothadoop/image\n rw-mounts=/var:/var", "")); file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n rw-mounts=/var/:/var/", "-v '/var/:/var/' ")); + "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n rw-mounts=/var/:/var/", "-v /var/:/var/")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n rw-mounts=/usr/bin/cut:/usr/bin/cut", - "-v '/usr/bin/cut:/usr/bin/cut' ")); + "-v /usr/bin/cut:/usr/bin/cut")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=nothadoop/image\n rw-mounts=/lib:/lib", "")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n rw-mounts=/opt:/mydisk1,/var/log/:/mydisk2", - "-v '/opt:/mydisk1' -v '/var/log/:/mydisk2' ")); + "-v /opt:/mydisk1 -v /var/log/:/mydisk2")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=nothadoop/image\n rw-mounts=/opt:/mydisk1,/var/log/:/mydisk2", "")); @@ -862,14 +905,15 @@ namespace ContainerExecutor { for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) { memset(buff, 0, buff_len); + index = 0; 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); + ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(0, ret); - ASSERT_STREQ(itr->second.c_str(), buff); + ASSERT_STREQ(itr->second.c_str(), flatten(buff)); } std::vector > bad_file_cmds_vec; @@ -887,15 +931,16 @@ namespace ContainerExecutor { for (itr2 = bad_file_cmds_vec.begin(); itr2 != bad_file_cmds_vec.end(); ++itr2) { memset(buff, 0, buff_len); + index = 0; 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); + reset(buff, buff_len, (char *) "test string", &index); + ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(itr2->second, ret); - ASSERT_STREQ("", buff); + ASSERT_STREQ("test string", flatten(buff)); } // verify that you can't mount any directory in the container-executor.cfg path @@ -904,15 +949,16 @@ namespace ContainerExecutor { std::string cmd_file_contents = "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n rw-mounts="; cmd_file_contents.append(ce_path).append(":").append("/etc/hadoop"); memset(buff, 0, buff_len); + index = 0; 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); + reset(buff, buff_len, (char *) "test string", &index); + ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(INVALID_DOCKER_RW_MOUNT, ret) << " for input " << cmd_file_contents; - ASSERT_STREQ("", buff); + ASSERT_STREQ("test string", flatten(buff)); char *tmp = strrchr(ce_path, '/'); if (tmp != NULL) { *tmp = '\0'; @@ -928,46 +974,45 @@ namespace ContainerExecutor { if (ret != 0) { FAIL(); } - strcpy(buff, "test string"); - ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, buff_len); + reset(buff, buff_len, (char *) "test string", &index); + ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(0, ret); - ASSERT_EQ(11, strlen(buff)); + ASSERT_STREQ("test string", flatten(buff)); } TEST_F(TestDockerUtil, test_add_ro_mounts) { struct configuration container_cfg, cmd_cfg; const int buff_len = 1024; - char buff[buff_len]; + char **buff = (char **) calloc(buff_len, sizeof(char*)); + int index = 0; int ret = 0; std::string container_executor_cfg_contents = "[docker]\n docker.privileged-containers.registries=hadoop\n " - "docker.allowed.rw-mounts=/home/,/var,/usr/bin/cut,..\n " + "docker.allowed.rw-mounts=/home/,/var,/usr/bin/cut\n " "docker.allowed.ro-mounts=/etc/passwd,/etc/group"; std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/var:/var", "-v '/var:/var:ro' ")); - file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=nothadoop/image\n ro-mounts=/var:/var", "")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=nothadoop/image\n ro-mounts=/etc:/etc", "")); file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/var/:/var/", "-v '/var/:/var/:ro' ")); + "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/var/:/var/", "-v /var/:/var/:ro")); file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/home:/home", "-v '/home:/home:ro' ")); + "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/home:/home", "-v /home:/home:ro")); file_cmd_vec.push_back(std::make_pair( - "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/home/:/home", "-v '/home/:/home:ro' ")); + "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/home/:/home", "-v /home/:/home:ro")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/usr/bin/cut:/usr/bin/cut", - "-v '/usr/bin/cut:/usr/bin/cut:ro' ")); + "-v /usr/bin/cut:/usr/bin/cut:ro")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/etc/group:/etc/group", - "-v '/etc/group:/etc/group:ro' ")); + "-v /etc/group:/etc/group:ro")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/etc/passwd:/etc/passwd", - "-v '/etc/passwd:/etc/passwd:ro' ")); + "-v /etc/passwd:/etc/passwd:ro")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/var/log:/mydisk1,/etc/passwd:/etc/passwd", - "-v '/var/log:/mydisk1:ro' -v '/etc/passwd:/etc/passwd:ro' ")); + "-v /var/log:/mydisk1:ro -v /etc/passwd:/etc/passwd:ro")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n", "")); write_container_executor_cfg(container_executor_cfg_contents); @@ -986,14 +1031,15 @@ namespace ContainerExecutor { for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) { memset(buff, 0, buff_len); + index = 0; 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); + ret = add_ro_mounts(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(0, ret); - ASSERT_STREQ(itr->second.c_str(), buff); + ASSERT_STREQ(itr->second.c_str(), flatten(buff)); } std::vector > bad_file_cmds_vec; @@ -1008,15 +1054,16 @@ namespace ContainerExecutor { for (itr2 = bad_file_cmds_vec.begin(); itr2 != bad_file_cmds_vec.end(); ++itr2) { memset(buff, 0, buff_len); + index = 0; 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); + reset(buff, buff_len, (char *) "test string", &index); + ret = add_ro_mounts(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(itr2->second, ret); - ASSERT_STREQ("", buff); + ASSERT_STREQ("test string", flatten(buff)); } container_executor_cfg_contents = "[docker]\n docker.privileged-containers.registries=hadoop\n"; @@ -1026,10 +1073,10 @@ namespace ContainerExecutor { FAIL(); } write_command_file("[docker-command-execution]\n docker-command=run\n image=hadoop/image\n ro-mounts=/home:/home"); - strcpy(buff, "test string"); - ret = add_ro_mounts(&cmd_cfg, &container_cfg, buff, buff_len); + reset(buff, buff_len, (char *) "test string", &index); + ret = add_ro_mounts(&cmd_cfg, &container_cfg, buff, &index); ASSERT_EQ(INVALID_DOCKER_RO_MOUNT, ret); - ASSERT_EQ(0, strlen(buff)); + ASSERT_EQ(1, index); } TEST_F(TestDockerUtil, test_docker_run_privileged) { @@ -1052,14 +1099,14 @@ namespace ContainerExecutor { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n name=container_e1_12312_11111_02_000001\n image=hadoop/docker-image\n user=test", - "run --name='container_e1_12312_11111_02_000001' --user='test' --cap-drop='ALL' 'hadoop/docker-image' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test --cap-drop=ALL hadoop/docker-image")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n name=container_e1_12312_11111_02_000001\n image=nothadoop/docker-image\n user=test", - "run --name='container_e1_12312_11111_02_000001' --user='test' --cap-drop='ALL' 'nothadoop/docker-image' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test --cap-drop=ALL nothadoop/docker-image")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n name=container_e1_12312_11111_02_000001\n image=hadoop/docker-image\n user=test\n" " launch-command=bash,test_script.sh,arg1,arg2", - "run --name='container_e1_12312_11111_02_000001' --user='test' --cap-drop='ALL' 'hadoop/docker-image' 'bash' 'test_script.sh' 'arg1' 'arg2' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test --cap-drop=ALL hadoop/docker-image bash test_script.sh arg1 arg2")); // Test non-privileged conatiner with launch command file_cmd_vec.push_back(std::make_pair( @@ -1069,10 +1116,10 @@ namespace ContainerExecutor { " 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='container_e1_12312_11111_02_000001' --user='test' -d --rm -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'" - " -v '/usr/bin/cut:/usr/bin/cut: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' 'hadoop/docker-image' 'bash' " - "'test_script.sh' 'arg1' 'arg2' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test -d --rm -v /var/log:/var/log:ro -v /var/lib:/lib:ro" + " -v /usr/bin/cut:/usr/bin/cut: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 hadoop/docker-image bash " + "test_script.sh arg1 arg2")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n" " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=nothadoop/docker-image\n user=test\n hostname=host-id\n" @@ -1080,8 +1127,8 @@ namespace ContainerExecutor { " network=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='container_e1_12312_11111_02_000001' --user='test' -d --rm" - " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test -d --rm" + " --cgroup-parent=ctr-cgroup --cap-drop=ALL --hostname=host-id nothadoop/docker-image")); // Test non-privileged container and drop all privileges file_cmd_vec.push_back(std::make_pair( @@ -1091,10 +1138,10 @@ namespace ContainerExecutor { " 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='container_e1_12312_11111_02_000001' --user='test' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'" - " -v '/usr/bin/cut:/usr/bin/cut: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' 'hadoop/docker-image' 'bash'" - " 'test_script.sh' 'arg1' 'arg2' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test -d --rm --net=bridge -v /var/log:/var/log:ro -v /var/lib:/lib:ro" + " -v /usr/bin/cut:/usr/bin/cut: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 hadoop/docker-image bash" + " test_script.sh arg1 arg2")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n" " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=nothadoop/docker-image\n user=test\n hostname=host-id\n" @@ -1102,8 +1149,8 @@ namespace ContainerExecutor { " network=bridge\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='container_e1_12312_11111_02_000001' --user='test' -d --rm --net='bridge'" - " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test -d --rm --net=bridge" + " --cgroup-parent=ctr-cgroup --cap-drop=ALL --hostname=host-id nothadoop/docker-image")); // Test privileged container file_cmd_vec.push_back(std::make_pair( @@ -1113,10 +1160,10 @@ namespace ContainerExecutor { " 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='container_e1_12312_11111_02_000001' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'" - " -v '/usr/bin/cut:/usr/bin/cut: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' 'hadoop/docker-image' " - "'bash' 'test_script.sh' 'arg1' 'arg2' ")); + "run --name=container_e1_12312_11111_02_000001 -d --rm --net=bridge -v /var/log:/var/log:ro -v /var/lib:/lib:ro" + " -v /usr/bin/cut:/usr/bin/cut: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 hadoop/docker-image " + "bash test_script.sh arg1 arg2")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n" @@ -1125,10 +1172,10 @@ namespace ContainerExecutor { " 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 group-add=1000,1001\n" " launch-command=bash,test_script.sh,arg1,arg2", - "run --name='container_e1_12312_11111_02_000001' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'" - " -v '/usr/bin/cut:/usr/bin/cut: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' 'hadoop/docker-image' 'bash' 'test_script.sh' 'arg1' 'arg2' ")); + "run --name=container_e1_12312_11111_02_000001 -d --rm --net=bridge -v /var/log:/var/log:ro -v /var/lib:/lib:ro" + " -v /usr/bin/cut:/usr/bin/cut: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 hadoop/docker-image bash test_script.sh arg1 arg2")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n" @@ -1136,9 +1183,9 @@ namespace ContainerExecutor { " network=bridge\n net=bridge\n" " detach=true\n rm=true\n group-add=1000,1001\n" " launch-command=bash,test_script.sh,arg1,arg2", - "run --name='container_e1_12312_11111_02_000001' --user='test' -d --rm --net='bridge' --cap-drop='ALL' " - "--hostname='host-id' --group-add '1000' --group-add '1001' " - "'docker-image' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test -d --rm --net=bridge --cap-drop=ALL " + "--hostname=host-id --group-add 1000 --group-add 1001 " + "docker-image")); std::vector > bad_file_cmd_vec; @@ -1213,6 +1260,7 @@ namespace ContainerExecutor { run_docker_command_test(file_cmd_vec, bad_file_cmd_vec, get_docker_run_command); } + TEST_F(TestDockerUtil, test_docker_run_no_privileged) { std::string container_executor_contents[] = {"[docker]\n docker.allowed.ro-mounts=/var,/etc,/usr/bin/cut\n" @@ -1241,11 +1289,11 @@ namespace ContainerExecutor { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test", - "run --name='container_e1_12312_11111_02_000001' --user='test' --cap-drop='ALL' 'docker-image' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test --cap-drop=ALL docker-image")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n" " user=test\n launch-command=bash,test_script.sh,arg1,arg2", - "run --name='container_e1_12312_11111_02_000001' --user='test' --cap-drop='ALL' 'docker-image' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test --cap-drop=ALL docker-image")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n" @@ -1254,10 +1302,10 @@ namespace ContainerExecutor { " 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='container_e1_12312_11111_02_000001' --user='test' -d --rm -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'" - " -v '/usr/bin/cut:/usr/bin/cut: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' 'hadoop/docker-image' 'bash' " - "'test_script.sh' 'arg1' 'arg2' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test -d --rm -v /var/log:/var/log:ro -v /var/lib:/lib:ro" + " -v /usr/bin/cut:/usr/bin/cut: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 hadoop/docker-image bash " + "test_script.sh arg1 arg2")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n" " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=nothadoop/docker-image\n user=test\n hostname=host-id\n" @@ -1265,8 +1313,8 @@ namespace ContainerExecutor { " network=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='container_e1_12312_11111_02_000001' --user='test' -d --rm" - " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test -d --rm" + " --cgroup-parent=ctr-cgroup --cap-drop=ALL --hostname=host-id nothadoop/docker-image")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n" @@ -1275,10 +1323,10 @@ namespace ContainerExecutor { " 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='container_e1_12312_11111_02_000001' --user='test' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'" - " -v '/usr/bin/cut:/usr/bin/cut: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' 'hadoop/docker-image' 'bash'" - " 'test_script.sh' 'arg1' 'arg2' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test -d --rm --net=bridge -v /var/log:/var/log:ro -v /var/lib:/lib:ro" + " -v /usr/bin/cut:/usr/bin/cut: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 hadoop/docker-image bash" + " test_script.sh arg1 arg2")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n" " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=nothadoop/docker-image\n user=test\n hostname=host-id\n" @@ -1286,8 +1334,8 @@ namespace ContainerExecutor { " network=bridge\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='container_e1_12312_11111_02_000001' --user='test' -d --rm --net='bridge'" - " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' ")); + "run --name=container_e1_12312_11111_02_000001 --user=test -d --rm --net=bridge" + " --cgroup-parent=ctr-cgroup --cap-drop=ALL --hostname=host-id nothadoop/docker-image")); std::vector > bad_file_cmd_vec; bad_file_cmd_vec.push_back(std::make_pair( @@ -1308,33 +1356,33 @@ namespace ContainerExecutor { input_output_map.push_back(std::make_pair( "[docker-command-execution]\n docker-command=inspect\n docker-config=/my-config\n" " format={{.State.Status}}\n name=container_e1_12312_11111_02_000001", - "--config='/my-config' inspect --format={{.State.Status}} container_e1_12312_11111_02_000001")); + "--config=/my-config inspect --format={{.State.Status}} container_e1_12312_11111_02_000001")); input_output_map.push_back(std::make_pair( "[docker-command-execution]\n docker-command=load\n docker-config=/my-config\n image=image-id", - "--config='/my-config' load --i='image-id' ")); + "--config=/my-config load --i='image-id' ")); input_output_map.push_back(std::make_pair( "[docker-command-execution]\n docker-command=pull\n docker-config=/my-config\n image=image-id", - "--config='/my-config' pull 'image-id' ")); + "--config=/my-config pull image-id")); input_output_map.push_back(std::make_pair( "[docker-command-execution]\n docker-command=rm\n docker-config=/my-config\n name=container_e1_12312_11111_02_000001", - "--config='/my-config' rm container_e1_12312_11111_02_000001")); + "--config=/my-config rm container_e1_12312_11111_02_000001")); input_output_map.push_back(std::make_pair( "[docker-command-execution]\n docker-command=stop\n docker-config=/my-config\n name=container_e1_12312_11111_02_000001", - "--config='/my-config' stop container_e1_12312_11111_02_000001")); + "--config=/my-config stop container_e1_12312_11111_02_000001")); input_output_map.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n docker-config=/my-config\n name=container_e1_12312_11111_02_000001\n" " image=docker-image\n user=test", - "--config='/my-config' run --name='container_e1_12312_11111_02_000001' --user='test' --cap-drop='ALL' 'docker-image' ")); + "--config=/my-config run --name=container_e1_12312_11111_02_000001 --user=test --cap-drop=ALL docker-image")); std::vector >::const_iterator itr; - char buffer[4096]; + char **buffer = (char **) calloc(4096, sizeof(char*)); struct configuration cfg = {0, 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) << "for input " << itr->first; - ASSERT_STREQ(itr->second.c_str(), buffer); + ASSERT_STREQ(itr->second.c_str(), flatten(buffer)); } }