commit c688a706c5f9638615f1f4263c8ceb9f2c159264 Author: Eric Yang Date: Mon Mar 5 20:02:40 2018 -0500 YARN-7654. Added support for docker ENTRY_PONT. Contributed by Eric Yang Conflicts: hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc Conflicts: hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.h diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationConstants.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationConstants.java index 38ad596..ddf2785 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationConstants.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-api/src/main/java/org/apache/hadoop/yarn/api/ApplicationConstants.java @@ -244,7 +244,13 @@ * Comma separate list of directories that the container should use for * logging. */ - LOG_DIRS("LOG_DIRS"); + LOG_DIRS("LOG_DIRS"), + + /** + * $YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE + * Final, Docker run support ENTRY_POINT. + */ + YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE("YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE"); private final String variable; private Environment(String variable) { 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/containerlaunch/AbstractLauncher.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/containerlaunch/AbstractLauncher.java index dc51b25..30bfe8f 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/containerlaunch/AbstractLauncher.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/containerlaunch/AbstractLauncher.java @@ -101,6 +101,11 @@ public void addCommand(String cmd) { commands.add(cmd); } + public void setCommand(String cmd) { + commands.clear(); + commands.add(cmd); + } + /** * Complete the launch context (copy in env vars, etc). * @return the container to launch 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 2f840b1..6634d68 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 @@ -87,7 +87,7 @@ public void buildContainerLaunchContext(AbstractLauncher launcher, tokensForSubstitution.put($(entry.getKey()), entry.getValue()); } //TODO add component host tokens? -// ProviderUtils.addComponentHostTokens(tokensForSubstitution, amState); + // ProviderUtils.addComponentHostTokens(tokensForSubstitution, amState); // create config file on hdfs and add local resource ProviderUtils.createConfigFileAndAddLocalResource(launcher, fileSystem, @@ -105,6 +105,7 @@ public void buildContainerLaunchContext(AbstractLauncher launcher, launcher.addCommand(operation.build()); } + // By default retry forever every 30 seconds launcher.setRetryContext(YarnServiceConf .getInt(CONTAINER_RETRY_MAX, -1, service.getConfiguration(), 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/docker/DockerProviderService.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/docker/DockerProviderService.java index 6ac8de1..ed836d2 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/docker/DockerProviderService.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/docker/DockerProviderService.java @@ -17,16 +17,25 @@ */ package org.apache.hadoop.yarn.service.provider.docker; +import org.apache.commons.lang.StringUtils; +import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.registry.client.api.RegistryConstants; import org.apache.hadoop.registry.client.binding.RegistryUtils; import org.apache.hadoop.yarn.service.component.instance.ComponentInstance; import org.apache.hadoop.yarn.service.provider.AbstractProviderService; +import org.apache.hadoop.yarn.service.provider.ProviderUtils; +import org.apache.hadoop.yarn.api.records.Container; +import org.apache.hadoop.yarn.service.api.records.Component; import org.apache.hadoop.yarn.service.api.records.Service; import org.apache.hadoop.yarn.service.utils.SliderFileSystem; import org.apache.hadoop.yarn.service.containerlaunch.AbstractLauncher; +import org.apache.hadoop.yarn.service.containerlaunch.CommandLineBuilder; +import org.apache.hadoop.yarn.service.exceptions.SliderException; +import org.apache.hadoop.yarn.api.ApplicationConstants.Environment; import java.io.IOException; import java.text.MessageFormat; +import java.util.Map; public class DockerProviderService extends AbstractProviderService implements DockerKeys { @@ -54,4 +63,36 @@ public void processArtifact(AbstractLauncher launcher, launcher.setRunPrivilegedContainer( compInstance.getCompSpec().getRunPrivilegedContainer()); } + + @Override + public void buildContainerLaunchContext(AbstractLauncher launcher, + Service service, ComponentInstance instance, + SliderFileSystem fileSystem, Configuration yarnConf, Container container) + throws IOException, SliderException { + Component component = instance.getComponent().getComponentSpec();; + processArtifact(launcher, instance, fileSystem, service); + super.buildContainerLaunchContext(launcher, service, instance, fileSystem, yarnConf, container); + Map globalTokens = + instance.getComponent().getScheduler().globalTokens; + Map tokensForSubstitution = ProviderUtils + .initCompTokensForSubstitute(instance, container); + tokensForSubstitution.putAll(globalTokens); + + // substitute launch command + String launchCommand = component.getLaunchCommand(); + // docker container may have empty commands + if (!StringUtils.isEmpty(launchCommand)) { + launchCommand = ProviderUtils + .substituteStrWithTokens(launchCommand, tokensForSubstitution); + CommandLineBuilder operation = new CommandLineBuilder(); + operation.add(launchCommand); + boolean overrideDisable = Boolean.parseBoolean(component.getConfiguration().getEnv(Environment.YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE.name())); + if (!overrideDisable) { + operation.addOutAndErrFiles(OUT_FILE, ERR_FILE); + } + launcher.setCommand(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/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 9efe686..126c582 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 @@ -98,6 +98,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 = @@ -1674,6 +1676,18 @@ public void sanitizeEnv(Map environment, Path pwd, containerLogDirs, Map> resources, Path nmPrivateClasspathJarDir, Set nmVars) throws IOException { + // Base on discussion in YARN-7654, for ENTRY_POINT enabled + // docker container, we forward user defined environment variables + // without node manager environment variables. This is the reason + // that we skip sanitizeEnv method. + boolean overrideDisable = Boolean.parseBoolean( + environment.get( + Environment.YARN_CONTAINER_RUNTIME_DOCKER_RUN_OVERRIDE_DISABLE.name())); + if (overrideDisable) { + environment.remove("WORK_DIR"); + return; + } + /** * Non-modifiable environment variables */ 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 7106aad..a455982 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 @@ -80,6 +80,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +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.LinuxContainerRuntimeConstants.*; /** @@ -733,6 +734,10 @@ 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); + boolean dockerOverride = ((environment + .get(ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE) == null) ? false : + Boolean.parseBoolean(environment + .get(ENV_DOCKER_CONTAINER_RUN_OVERRIDE_DISABLE))); if(network == null || network.isEmpty()) { network = defaultNetwork; @@ -794,9 +799,10 @@ public void launchContainer(ContainerRuntimeContext ctx) @SuppressWarnings("unchecked") DockerRunCommand runCommand = new DockerRunCommand(containerIdStr, dockerRunAsUser, imageName) - .detachOnRun() - .setContainerWorkDir(containerWorkDir.toString()) .setNetworkType(network); + if (!dockerOverride) { + runCommand.setContainerWorkDir(containerWorkDir.toString()); + } // Only add hostname if network is not host or if Registry DNS is enabled. if (!network.equalsIgnoreCase("host") || conf.getBoolean(RegistryConstants.KEY_DNS_ENABLED, @@ -867,11 +873,15 @@ 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")) { + if (dockerOverride) { LOG.info("command override disabled"); + runCommand.setOverrideDisabled(true); + for (Map.Entry kv: environment.entrySet()) { + runCommand.addEnv(kv.getKey(), kv.getValue()); + } + runCommand.setOverrideCommandWithArgs(container.getLaunchContext().getCommands()); + runCommand.disableDetach(); + runCommand.setLogDir(container.getLogDir()); } else { List overrideCommands = new ArrayList<>(); Path launchDst = @@ -880,6 +890,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/DockerClient.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerClient.java index 77c53a8..8e17ddd 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerClient.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerClient.java @@ -89,6 +89,15 @@ public String writeCommandToTempFile(DockerCommand cmd, String filePrefix) printWriter.println(" " + entry.getKey() + "=" + StringUtils .join(",", entry.getValue())); } + if (cmd instanceof DockerRunCommand) { + if (((DockerRunCommand) cmd).containsEnv()) { + printWriter.println("[docker-command-environment]"); + for (Map.Entry entry : + ((DockerRunCommand) cmd).getEnv().entrySet() ) { + printWriter.println(" " + entry.getKey() + "=" + entry.getValue()); + } + } + } printWriter.close(); return dockerCommandFile.getAbsolutePath(); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommand.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommand.java index 0124c83..0bb8022 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommand.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/docker/DockerCommand.java @@ -104,4 +104,5 @@ public void setClientConfigDir(String clientConfigDir) { addCommandArguments("docker-config", clientConfigDir); } } + } 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 bfeeaf5..e60028b 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 @@ -24,9 +24,11 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; public class DockerRunCommand extends DockerCommand { private static final String RUN_COMMAND = "run"; + private final Map userEnv; /** The following are mandatory: */ public DockerRunCommand(String containerId, String user, String image) { @@ -34,6 +36,7 @@ public DockerRunCommand(String containerId, String user, String image) { super.addCommandArguments("name", containerId); super.addCommandArguments("user", user); super.addCommandArguments("image", image); + this.userEnv = new TreeMap(); } public DockerRunCommand removeContainerOnExit() { @@ -174,4 +177,54 @@ 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; + } + + /** + * Check if user defined environment variables are empty. + * + * @return true if user defined environment variables are not empty. + */ + public boolean containsEnv() { + if (userEnv.size() > 0) { + return true; + } + return false; + } + + /** + * User defined environment variables + * + * @return a map of user defined environment variables + */ + public Map getEnv() { + return userEnv; + } + + /** + * Add user defined environment variables. + * + * @param key + * @param value + */ + public final void addEnv(String key, String value) { + userEnv.put(key, value); + } } 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 af7f8ee..f2dbe1b 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, ...); @@ -737,7 +740,6 @@ static int create_container_directories(const char* user, const char *app_id, result = OUT_OF_MEMORY; } else { sprintf(combined_name, "%s/%s", app_id, container_id); - char* const* log_dir_ptr; for(log_dir_ptr = log_dir; *log_dir_ptr != NULL; ++log_dir_ptr) { char *container_log_dir = get_app_log_directory(*log_dir_ptr, combined_name); @@ -756,7 +758,7 @@ static int create_container_directories(const char* user, const char *app_id, free(container_log_dir); } else { result = 0; - free(container_log_dir); + chosen_container_log_dir = container_log_dir; } } free(combined_name); @@ -1094,7 +1096,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) { @@ -1130,6 +1131,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 - %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; @@ -1275,11 +1304,11 @@ 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); + size_t command_size = DOCKER_ARG_MAX; + char **buffer = alloc_and_clear_memory(command_size, sizeof(char *)); + ret = get_docker_command(command_file, &CFG, buffer); if (ret != 0) { fprintf(ERRORFILE, "Error constructing docker command, docker error code=%d, error message='%s'\n", ret, get_docker_error_message(ret)); @@ -1290,15 +1319,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", @@ -1307,8 +1329,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; @@ -1406,9 +1426,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; @@ -1475,8 +1495,9 @@ int launch_docker_container_as_user(const char * user, const char *app_id, char *docker_inspect_exitcode_command = NULL; int container_file_source =-1; int cred_file_source = -1; + int docker_override = -1; - size_t command_size = MIN(sysconf(_SC_ARG_MAX), 128*1024); + size_t command_size = DOCKER_ARG_MAX; docker_command_with_binary = (char *) alloc_and_clear_memory(command_size, sizeof(char)); docker_wait_command = (char *) alloc_and_clear_memory(command_size, sizeof(char)); @@ -1487,7 +1508,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"); @@ -1537,37 +1558,96 @@ 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(); + 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 (WEXITSTATUS(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; + fclose(so_fd); + 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) { + if (dup2(fileno(so_fd), fileno(stdout)) == -1) { + fprintf(ERRORFILE, "Could not append to stdout.txt\n"); + fclose(so_fd); + return UNABLE_TO_EXECUTE_CONTAINER_SCRIPT; + } + if (dup2(fileno(se_fd), fileno(stderr)) == -1) { + fprintf(ERRORFILE, "Could not append to stderr.txt\n"); + fclose(se_fd); + return UNABLE_TO_EXECUTE_CONTAINER_SCRIPT; + } + } + fclose(so_fd); + fclose(se_fd); + execvp(docker_binary, docker_command); + fprintf(LOGFILE, "failed to execute docker command! error: %s\n", strerror(errno)); + return UNABLE_TO_EXECUTE_CONTAINER_SCRIPT; } + 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) { @@ -1599,8 +1679,10 @@ 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); + size_t command_size = DOCKER_ARG_MAX; char* proc_pid_path = alloc_and_clear_memory(command_size, sizeof(char)); snprintf(proc_pid_path, command_size, "%s/%d", PROC_PATH, pid); while (dir_exists(proc_pid_path) == 0) { @@ -1617,6 +1699,7 @@ int launch_docker_container_as_user(const char * user, const char *app_id, #endif } + // discover container exit code sprintf(docker_inspect_exitcode_command, "%s inspect --format {{.State.ExitCode}} %s", docker_binary, container_id); @@ -1672,6 +1755,7 @@ cleanup: free(docker_wait_command); free(docker_inspect_command); free(docker_rm_command); + free(chosen_container_log_dir); return exit_code; } @@ -2360,3 +2444,31 @@ 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; + size_t total = 1; + for (int i = 0; args[i] != NULL; i++) { + total = total + strlen(args[i]) + 1; + } + char *buffer = (char *) malloc(total * 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 7c3ed77..970aff6 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 @@ -276,3 +276,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 fdeaeea..e2b0501 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 @@ -31,6 +31,9 @@ #include #include #include +#include + +int entry_point = -1; static int read_and_verify_command_file(const char *command_file, const char *docker_command, struct configuration *command_config) { @@ -47,29 +50,42 @@ 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 (!string[0]) { return 0; } - return -1; + if (*index > DOCKER_ARG_MAX) { + return -1; + } + char *clone = strdup(string); + if (clone == NULL) { + return -1; + } + buff[*index] = clone; + (*index)++; + return 0; +} + +void free_buffer(char **buff) { + if (buff != NULL) { + for (int i = 0; buff[i] != NULL; i++) { + free(buff[i]); + } + } } 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) { @@ -141,7 +157,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; @@ -214,8 +231,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; @@ -240,13 +257,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) { @@ -330,6 +347,10 @@ char *get_docker_binary(const struct configuration *conf) { return docker_binary; } +int use_entry_point() { + return 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) { @@ -338,7 +359,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) { int ret = 0; struct configuration command_config = {0, NULL}; ret = read_config(command_file, &command_config); @@ -346,25 +367,31 @@ int get_docker_command(const char *command_file, const struct configuration *con return INVALID_COMMAND_FILE; } + char *value = get_configuration_value("use-entry-point", DOCKER_COMMAND_FILE_SECTION, &command_config); + if (value != NULL && strcasecmp(value, "true") == 0) { + entry_point = 0; + } + free(value); + 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); } 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); } 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); } 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); } 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); } 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); } 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); } 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); } else if (strcmp(DOCKER_START_COMMAND, command) == 0) { - return get_docker_start_command(command_file, conf, out, outlen); + return get_docker_start_command(command_file, conf, out); } else { return UNKNOWN_DOCKER_COMMAND; } @@ -396,10 +423,10 @@ 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) { + int index = 0; int ret = 0; - char *driver = NULL, *volume_name = NULL, *sub_command = NULL, *format = NULL; + char *driver = NULL, *volume_name = NULL, *sub_command = NULL, *format = NULL, *docker = NULL; struct configuration command_config = {0, NULL}; ret = read_and_verify_command_file(command_file, DOCKER_VOLUME_COMMAND, &command_config); if (ret != 0) { @@ -415,15 +442,22 @@ int get_docker_volume_command(const char *command_file, const struct configurati goto cleanup; } - memset(out, 0, outlen); + free_buffer(out); + + docker = get_docker_binary(conf); + 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; } @@ -442,17 +476,14 @@ int get_docker_volume_command(const char *command_file, const struct configurati goto cleanup; } - ret = add_to_buffer(out, outlen, " create"); + ret = add_to_buffer(out, &index, "create"); if (ret != 0) { goto cleanup; } - ret = add_to_buffer(out, outlen, " --name="); - if (ret != 0) { - goto cleanup; - } - - ret = add_to_buffer(out, outlen, volume_name); + char *name_buffer = make_string("--name=%s", volume_name); + ret = add_to_buffer(out, &index, name_buffer); + free(name_buffer); if (ret != 0) { goto cleanup; } @@ -464,29 +495,23 @@ 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 = make_string("--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 = make_string("--format=%s", format); + ret = add_to_buffer(out, &index, tmp_buffer); + free(tmp_buffer); if (ret != 0) { goto cleanup; } @@ -506,12 +531,11 @@ 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 char *valid_format_strings[] = { "{{.State.Status}}", "{{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}}" }; - int ret = 0, i = 0, valid_format = 0; - char *format = NULL, *container_name = NULL; + int ret = 0, i = 0, valid_format = 0, index = 0; + char *format = NULL, *container_name = NULL, *tmp_buffer = NULL; struct configuration command_config = {0, NULL}; ret = read_and_verify_command_file(command_file, DOCKER_INSPECT_COMMAND, &command_config); if (ret != 0) { @@ -541,32 +565,32 @@ int get_docker_inspect_command(const char *command_file, const struct configurat return INVALID_DOCKER_INSPECT_FORMAT; } - memset(out, 0, outlen); + free_buffer(out); - 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); + ret = add_to_buffer(out, &index, DOCKER_INSPECT_COMMAND); if (ret != 0) { goto free_and_exit; } - ret = add_to_buffer(out, outlen, " --format="); + tmp_buffer = make_string("--format=%s", format); + ret = add_to_buffer(out, &index, tmp_buffer); 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, " "); - 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; } @@ -577,14 +601,14 @@ 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) { 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_LOAD_COMMAND, &command_config); if (ret != 0) { @@ -596,19 +620,26 @@ int get_docker_load_command(const char *command_file, const struct configuration return INVALID_DOCKER_IMAGE_NAME; } - memset(out, 0, outlen); + free_buffer(out); + + 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); + char *tmp_buffer = make_string("--i=%s", image_name); + ret = add_to_buffer(out, &index, tmp_buffer); free(tmp_buffer); free(image_name); if (ret != 0) { @@ -625,11 +656,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) { 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) { @@ -641,31 +671,37 @@ int get_docker_pull_command(const char *command_file, const struct configuration return INVALID_DOCKER_IMAGE_NAME; } - memset(out, 0, outlen); + free_buffer(out); - 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_to_buffer(out, outlen, DOCKER_PULL_COMMAND); + ret = add_docker_config_param(&command_config, out, &index); + if (ret != 0) { + goto free_pull; + } + + 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) { 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); @@ -678,19 +714,24 @@ int get_docker_rm_command(const char *command_file, const struct configuration * return INVALID_DOCKER_CONTAINER_NAME; } - memset(out, 0, outlen); + free_buffer(out); + + 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_RM_COMMAND); + 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; @@ -702,8 +743,9 @@ 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) { int ret = 0; + int index = 0; size_t len = 0, i = 0; char *value = NULL; char *container_name = NULL; @@ -718,14 +760,22 @@ int get_docker_stop_command(const char *command_file, const struct configuration return INVALID_DOCKER_CONTAINER_NAME; } - memset(out, 0, outlen); + free_buffer(out); + + 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_STOP_COMMAND); + 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) { @@ -734,23 +784,19 @@ 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); + free_buffer(out); 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 = make_string("--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; @@ -762,8 +808,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) { int ret = 0; + int index = 0; + int tmp_buffer_size = 40; size_t len = 0, i = 0; char *value = NULL; char *container_name = NULL; @@ -778,14 +826,22 @@ int get_docker_kill_command(const char *command_file, const struct configuration return INVALID_DOCKER_CONTAINER_NAME; } - memset(out, 0, outlen); + free_buffer(out); - 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_KILL_COMMAND); + ret = add_docker_config_param(&command_config, out, &index); + if (ret != 0) { + return BUFFER_TOO_SMALL; + } + + 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) { @@ -794,23 +850,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); + free_buffer(out); 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; @@ -821,8 +875,9 @@ int get_docker_kill_command(const char *command_file, const struct configuration return BUFFER_TOO_SMALL; } -int get_docker_start_command(const char *command_file, const struct configuration *conf, char *out, const size_t outlen) { +int get_docker_start_command(const char *command_file, const struct configuration *conf, char **out) { 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_START_COMMAND, &command_config); @@ -835,22 +890,16 @@ int get_docker_start_command(const char *command_file, const struct configuratio return INVALID_DOCKER_CONTAINER_NAME; } - memset(out, 0, outlen); - - 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_START_COMMAND); + ret = add_to_buffer(out, &index, DOCKER_START_COMMAND); if (ret != 0) { goto free_and_exit; } - ret = add_to_buffer(out, outlen, " "); - if (ret != 0) { - goto free_and_exit; - } - ret = add_to_buffer(out, outlen, container_name); + ret = add_to_buffer(out, &index, container_name); if (ret != 0) { goto free_and_exit; } @@ -859,31 +908,29 @@ free_and_exit: return ret; } -static int detach_container(const struct configuration *command_config, char *out, const size_t outlen) { - return add_param_to_command(command_config, "detach", "-d ", 0, out, outlen); +static int 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); @@ -895,9 +942,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; } @@ -907,25 +956,24 @@ 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); } 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, @@ -939,7 +987,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; } @@ -963,19 +1011,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; } @@ -983,7 +1027,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; @@ -994,26 +1038,49 @@ 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; + int count = 0; + const struct section *section = get_configuration_section(DOCKER_COMMAND_ENV_SECTION, command_config); + if (section == NULL) { + return ret; + } + for (count = 0; count < section->size; count++) { + ret = add_to_buffer(out, index, "-e"); + if (ret != 0) { + ret = BUFFER_TOO_SMALL; + break; + } + char *tmp_buffer = make_string("%s=%s", section->kv_pairs[count]->key, section->kv_pairs[count]->value); + ret = add_to_buffer(out, index, tmp_buffer); + free(tmp_buffer); + if (ret != 0) { + ret = BUFFER_TOO_SMALL; + break; + } + } + return ret; +} + /** * Helper function to help normalize mounts for checking if mounts are * permitted. The function does the following - @@ -1045,7 +1112,6 @@ static char* normalize_mount(const char* mount, int isRegexAllowed) { } } fprintf(ERRORFILE, "Could not determine real path of mount '%s'\n", mount); - free(real_mount); return NULL; } ret = stat(real_mount, &buff); @@ -1053,6 +1119,7 @@ static char* normalize_mount(const char* mount, int isRegexAllowed) { 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] != '/') { @@ -1096,6 +1163,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, 0); if (permitted_mounts == NULL) { + free(normalized_path); return 0; } if (normalized_path == NULL) { @@ -1123,40 +1191,36 @@ 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) { - size_t tmp_buffer_size = 1024; - const char *ro_suffix = ""; + const int ro, char **out, int *index) { + 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(""), 0); int i = 0, permitted_rw = 0, permitted_ro = 0, ret = 0; if (ro != 0) { - ro_suffix = ":ro"; + ro_suffix = (char*) ":ro"; } if (values != NULL) { @@ -1179,8 +1243,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; @@ -1191,12 +1255,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 { @@ -1210,6 +1276,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; } } @@ -1218,18 +1285,19 @@ 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; } - 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); + + ret = add_to_buffer(out, index, "-v"); + if (ret != 0) { + ret = BUFFER_TOO_SMALL; + goto free_and_exit; + } + + char *tmp_buffer = make_string("%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; @@ -1241,23 +1309,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) { @@ -1333,8 +1396,8 @@ static int check_privileges(const char *user) { return ret; } -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)); @@ -1342,7 +1405,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) { @@ -1361,7 +1424,7 @@ static int set_privileged(const struct configuration *command_config, const stru } allowed = check_privileges(user); if (allowed) { - ret = add_to_buffer(out, outlen, "--privileged "); + ret = add_to_buffer(out, index, "--privileged"); if (ret != 0) { ret = BUFFER_TOO_SMALL; } @@ -1387,14 +1450,12 @@ static int set_privileged(const struct configuration *command_config, const stru free(value); free(privileged_container_enabled); free(user); - 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) { 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; @@ -1419,21 +1480,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; } @@ -1441,108 +1509,108 @@ 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 || strcasecmp(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); + if (privileged == NULL || strcmp(privileged, "false") == 0) { + 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 c797ecd..e04eee4 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 @@ -24,6 +24,7 @@ #define CONTAINER_EXECUTOR_CFG_DOCKER_SECTION "docker" #define DOCKER_BINARY_KEY "docker.binary" #define DOCKER_COMMAND_FILE_SECTION "docker-command-execution" +#define DOCKER_COMMAND_ENV_SECTION "docker-command-environment" #define DOCKER_INSPECT_COMMAND "inspect" #define DOCKER_LOAD_COMMAND "load" #define DOCKER_PULL_COMMAND "pull" @@ -33,6 +34,7 @@ #define DOCKER_KILL_COMMAND "kill" #define DOCKER_VOLUME_COMMAND "volume" #define DOCKER_START_COMMAND "start" +#define DOCKER_ARG_MAX 1024 enum docker_error_codes { @@ -70,6 +72,12 @@ enum docker_error_codes { char *get_docker_binary(const struct configuration *conf); /** + * Check if use-entry-point flag is set. + * @return 0 when use-entry-point flag is set. + */ +int use_entry_point(); + +/** * 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 @@ -77,7 +85,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); /** * Get the Docker inspect command line string. The function will verify that the params file is meant for the @@ -88,7 +96,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); /** * Get the Docker load command line string. The function will verify that the params file is meant for the load command. @@ -98,7 +106,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); /** * Get the Docker pull command line string. The function will verify that the params file is meant for the pull command. @@ -108,7 +116,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); /** * Get the Docker rm command line string. The function will verify that the params file is meant for the rm command. @@ -118,7 +126,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); /** * Get the Docker run command line string. The function will verify that the params file is meant for the run command. @@ -128,7 +136,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); /** * Get the Docker stop command line string. The function will verify that the params file is meant for the stop command. @@ -138,7 +146,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); /** * Get the Docker kill command line string. The function will verify that the params file is meant for the kill command. @@ -148,7 +156,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); /** * Get the Docker volume command line string. The function will verify that the @@ -159,8 +167,7 @@ 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); /** * Get the Docker start command line string. The function will verify that the params file is meant for the start command. @@ -170,7 +177,7 @@ int get_docker_volume_command(const char *command_file, const struct configurati * @param outlen Size of the output buffer * @return Return code with 0 indicating success and non-zero codes indicating error */ -int get_docker_start_command(const char* command_file, const struct configuration* conf, char *out, const size_t outlen); +int get_docker_start_command(const char* command_file, const struct configuration* conf, char **out); /** * 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/impl/utils/string-utils.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.c index 40b2c25..cb98013 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.c +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.c @@ -22,6 +22,7 @@ #include #include #include +#include /* * if all chars in the input str are numbers @@ -156,3 +157,36 @@ cleanup: } return is_container_id; } + +/* + * Format string utility. + */ +char *make_string(const char *fmt, ...) { + va_list ap; + int n; + int size = 100; + char *p, *np; + p = (char *) malloc(sizeof(char) * size); + if (p == NULL) { + return NULL; + } + + while (1) { + va_start(ap, fmt); + n = vsnprintf(p, size, fmt, ap); + va_end(ap); + if (n < 0) { + return NULL; + } + if (n < size) { + return p; + } + size = n + 2; + if ((np = realloc (p, size)) == NULL) { + free(p); + return NULL; + } else { + p = np; + } + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.h index c095eb6..affb3c3 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.h +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/string-utils.h @@ -34,4 +34,8 @@ int validate_container_id(const char* input); */ int get_numbers_split_by_comma(const char* input, int** numbers, size_t* n_numbers); +/* + * String format utility + */ +char *make_string(const char *fmt, ...); #endif 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 35b7873..82872d6 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 **)) { + size_t buff_len = sysconf(_SC_ARG_MAX); + 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); 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); 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); 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]; + const int buff_len = sysconf(_SC_ARG_MAX); + 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)); } } } @@ -142,12 +172,12 @@ namespace ContainerExecutor { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=inspect\n format={{.State.Status}}\n name=container_e1_12312_11111_02_000001", - "inspect --format={{.State.Status}} container_e1_12312_11111_02_000001")); + "/usr/bin/docker inspect --format={{.State.Status}} container_e1_12312_11111_02_000001")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=inspect\n" " format={{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}}\n" " name=container_e1_12312_11111_02_000001", - "inspect --format={{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}} container_e1_12312_11111_02_000001")); + "/usr/bin/docker inspect --format={{range(.NetworkSettings.Networks)}}{{.IPAddress}},{{end}}{{.Config.Hostname}} container_e1_12312_11111_02_000001")); std::vector > bad_file_cmd_vec; bad_file_cmd_vec.push_back(std::make_pair( @@ -179,7 +209,7 @@ namespace ContainerExecutor { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=load\n image=image-id", - "load --i='image-id' ")); + "/usr/bin/docker load --i=image-id")); std::vector > bad_file_cmd_vec; bad_file_cmd_vec.push_back(std::make_pair( @@ -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' ")); + "/usr/bin/docker pull image-id")); std::vector > bad_file_cmd_vec; bad_file_cmd_vec.push_back(std::make_pair( @@ -269,7 +299,7 @@ namespace ContainerExecutor { file_cmd_vec.push_back( std::make_pair( "[docker-command-execution]\n docker-command=rm\n name=container_e1_12312_11111_02_000001", - "rm container_e1_12312_11111_02_000001")); + "/usr/bin/docker rm container_e1_12312_11111_02_000001")); std::vector > bad_file_cmd_vec; bad_file_cmd_vec.push_back(std::make_pair( @@ -289,10 +319,10 @@ namespace ContainerExecutor { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=stop\n name=container_e1_12312_11111_02_000001", - "stop container_e1_12312_11111_02_000001")); + "/usr/bin/docker stop container_e1_12312_11111_02_000001")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=stop\n name=container_e1_12312_11111_02_000001\ntime=25", - "stop --time=25 container_e1_12312_11111_02_000001")); + "/usr/bin/docker stop --time=25 container_e1_12312_11111_02_000001")); std::vector > bad_file_cmd_vec; bad_file_cmd_vec.push_back(std::make_pair( @@ -316,10 +346,10 @@ namespace ContainerExecutor { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=kill\n name=container_e1_12312_11111_02_000001", - "kill container_e1_12312_11111_02_000001")); + "/usr/bin/docker kill container_e1_12312_11111_02_000001")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=kill\n name=container_e1_12312_11111_02_000001\nsignal=SIGQUIT", - "kill --signal=SIGQUIT container_e1_12312_11111_02_000001")); + "/usr/bin/docker kill --signal=SIGQUIT container_e1_12312_11111_02_000001")); std::vector > bad_file_cmd_vec; bad_file_cmd_vec.push_back(std::make_pair( @@ -361,7 +391,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", "")); @@ -371,7 +401,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", "")); @@ -381,7 +411,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", "")); @@ -392,7 +422,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", "")); @@ -402,7 +432,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", "")); @@ -412,7 +442,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", "")); @@ -422,14 +452,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); @@ -442,14 +473,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"); @@ -457,10 +489,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); @@ -468,16 +500,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", @@ -490,7 +523,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( @@ -506,25 +539,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); } } @@ -540,14 +575,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( @@ -558,14 +594,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); } } } @@ -611,7 +648,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", @@ -639,24 +677,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=nobody\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); } @@ -677,25 +717,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" @@ -703,19 +744,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); @@ -724,25 +765,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); @@ -750,16 +791,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" @@ -767,22 +808,22 @@ 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\n" "devices=/dev/nvidiactl:/dev/nvidiactl", - "--device='/dev/nvidiactl:/dev/nvidiactl' ")); + "--device=/dev/nvidiactl:/dev/nvidiactl")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=run\n image=hadoop/image\n" "devices=/dev/nvidia1:/dev/nvidia1,/dev/gpu-uvm-tools:/dev/gpu-uvm-tools", - "--device='/dev/nvidia1:/dev/nvidia1' --device='/dev/gpu-uvm-tools:/dev/gpu-uvm-tools' ")); + "--device=/dev/nvidia1:/dev/nvidia1 --device=/dev/gpu-uvm-tools:/dev/gpu-uvm-tools")); 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); @@ -794,74 +835,75 @@ 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); write_command_file("[docker-command-execution]\n docker-command=run\n image=hadoop/image\n devices=/dev/testnvidia:/dev/testnvidia"); 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/gpu-nvidia-uvm:/dev/gpu-nvidia-uvm"); 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); @@ -869,37 +911,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", "")); @@ -923,14 +966,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; @@ -948,15 +992,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 @@ -965,15 +1010,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'; @@ -989,46 +1035,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); @@ -1047,14 +1092,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; @@ -1069,15 +1115,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"; @@ -1087,10 +1134,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) { @@ -1113,14 +1160,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=nobody", - "run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'hadoop/docker-image' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody --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=nobody", - "run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'nothadoop/docker-image' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody --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=nobody\n" " launch-command=bash,test_script.sh,arg1,arg2", - "run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'hadoop/docker-image' 'bash' 'test_script.sh' 'arg1' 'arg2' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody --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( @@ -1130,10 +1177,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='nobody' -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' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -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=nobody\n hostname=host-id\n" @@ -1141,8 +1188,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='nobody' -d --rm" - " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -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( @@ -1152,10 +1199,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='nobody' -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' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -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=nobody\n hostname=host-id\n" @@ -1163,8 +1210,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='nobody' -d --rm --net='bridge'" - " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -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( @@ -1174,10 +1221,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' ")); + "/usr/bin/docker 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" @@ -1186,10 +1233,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' ")); + "/usr/bin/docker 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" @@ -1197,9 +1244,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='nobody' -d --rm --net='bridge' --cap-drop='ALL' " - "--hostname='host-id' --group-add '1000' --group-add '1001' " - "'docker-image' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -d --rm --net=bridge --cap-drop=ALL " + "--hostname=host-id --group-add 1000 --group-add 1001 " + "docker-image")); std::vector > bad_file_cmd_vec; @@ -1274,6 +1321,50 @@ namespace ContainerExecutor { run_docker_command_test(file_cmd_vec, bad_file_cmd_vec, get_docker_run_command); } + TEST_F(TestDockerUtil, test_docker_run_entry_point) { + + std::string container_executor_contents = "[docker]\n" + " docker.allowed.ro-mounts=/var,/etc,/usr/bin/cut\n" + " docker.allowed.rw-mounts=/tmp\n docker.allowed.networks=bridge\n " + " docker.privileged-containers.enabled=1\n docker.allowed.capabilities=CHOWN,SETUID\n" + " docker.allowed.devices=/dev/test\n docker.privileged-containers.registries=hadoop\n"; + write_file(container_executor_cfg_file, container_executor_contents); + int ret = read_config(container_executor_cfg_file.c_str(), &container_executor_cfg); + if (ret != 0) { + FAIL(); + } + ret = create_ce_file(); + if (ret != 0) { + std::cerr << "Could not create ce file, skipping test" << std::endl; + return; + } + + std::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=nobody\n" + " use-entry-point=true\n" + "[docker-command-environment]\n" + " HADOOP_CONF_DIR=/etc/hadoop/conf\n" + " LANG=en_US.UTF-8\n", + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody --cap-drop=ALL " + "-e HADOOP_CONF_DIR=/etc/hadoop/conf -e LANG=en_US.UTF-8 hadoop/docker-image")); + + std::vector > bad_file_cmd_vec; + + bad_file_cmd_vec.push_back(std::make_pair( + "[docker-command-execution]\n" + " docker-command=run\n" + " image=hadoop/docker-image\n" + " user=nobody", + static_cast(INVALID_DOCKER_CONTAINER_NAME))); + + 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" @@ -1302,11 +1393,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=nobody", - "run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'docker-image' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody --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=nobody\n launch-command=bash,test_script.sh,arg1,arg2", - "run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'docker-image' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody --cap-drop=ALL docker-image")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n" @@ -1315,10 +1406,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='nobody' -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' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -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=nobody\n hostname=host-id\n" @@ -1326,8 +1417,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='nobody' -d --rm" - " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -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" @@ -1336,10 +1427,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='nobody' -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' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -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=nobody\n hostname=host-id\n" @@ -1347,8 +1438,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='nobody' -d --rm --net='bridge'" - " --cgroup-parent='ctr-cgroup' --cap-drop='ALL' --hostname='host-id' 'nothadoop/docker-image' ")); + "/usr/bin/docker run --name=container_e1_12312_11111_02_000001 --user=nobody -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( @@ -1365,37 +1456,38 @@ namespace ContainerExecutor { } TEST_F(TestDockerUtil, test_docker_config_param) { + int buff_len = sysconf(_SC_ARG_MAX); std::vector > input_output_map; 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")); + "/usr/bin/docker --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' ")); + "/usr/bin/docker --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' ")); + "/usr/bin/docker --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")); + "/usr/bin/docker --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")); + "/usr/bin/docker --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=nobody", - "--config='/my-config' run --name='container_e1_12312_11111_02_000001' --user='nobody' --cap-drop='ALL' 'docker-image' ")); + "/usr/bin/docker --config=/my-config run --name=container_e1_12312_11111_02_000001 --user=nobody --cap-drop=ALL docker-image")); std::vector >::const_iterator itr; - char buffer[4096]; + char **buffer = (char **) calloc(buff_len, sizeof(char*)); struct configuration cfg = {0, NULL}; for (itr = input_output_map.begin(); itr != input_output_map.end(); ++itr) { - memset(buffer, 0, 4096); + memset(buffer, 0, buff_len); write_command_file(itr->first); - int ret = get_docker_command(docker_command_file.c_str(), &cfg, buffer, 4096); + int ret = get_docker_command(docker_command_file.c_str(), &cfg, buffer); ASSERT_EQ(0, ret) << "for input " << itr->first; - ASSERT_STREQ(itr->second.c_str(), buffer); + ASSERT_STREQ(itr->second.c_str(), flatten(buffer)); } } @@ -1430,10 +1522,10 @@ namespace ContainerExecutor { std::vector > file_cmd_vec; file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=volume\n sub-command=create\n volume=volume1 \n driver=driver1", - "volume create --name=volume1 --driver=driver1")); + "/usr/bin/docker volume create --name=volume1 --driver=driver1")); file_cmd_vec.push_back(std::make_pair( "[docker-command-execution]\n docker-command=volume\n format={{.Name}},{{.Driver}}\n sub-command=ls", - "volume ls --format={{.Name}},{{.Driver}}")); + "/usr/bin/docker volume ls --format={{.Name}},{{.Driver}}")); std::vector > bad_file_cmd_vec;