From 72e7c6a489858ea48e94dc015752de620f8d6da1 Mon Sep 17 00:00:00 2001 From: Billie Rinaldi Date: Wed, 12 Dec 2018 18:18:57 -0800 Subject: [PATCH] YARN-8962. Add ability to use interactive shell with normal yarn container. Contributed by Eric Yang --- .../linux/privileged/PrivilegedOperation.java | 2 +- .../runtime/DefaultLinuxContainerRuntime.java | 100 +++++++++++++++- .../executor/ContainerExecContext.java | 14 +++ .../webapp/ContainerShellWebSocket.java | 1 + .../impl/container-executor.c | 112 +++++++++++++----- .../impl/container-executor.h | 9 +- .../native/container-executor/impl/main.c | 31 ++++- .../test/test-container-executor.c | 50 ++++++++ 8 files changed, 281 insertions(+), 38 deletions(-) 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/privileged/PrivilegedOperation.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/privileged/PrivilegedOperation.java index b4c8fb82cf9..a1fdb91f9a3 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/privileged/PrivilegedOperation.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/privileged/PrivilegedOperation.java @@ -44,7 +44,7 @@ public class PrivilegedOperation { INITIALIZE_CONTAINER(""), //no CLI switch supported yet LAUNCH_CONTAINER(""), //no CLI switch supported yet SIGNAL_CONTAINER(""), //no CLI switch supported yet - EXEC_CONTAINER("--run-docker"), //no CLI switch supported yet + EXEC_CONTAINER("--exec-container"), //no CLI switch supported yet DELETE_AS_USER(""), //no CLI switch supported yet LAUNCH_DOCKER_CONTAINER(""), //no CLI switch supported yet TC_MODIFY_STATE("--tc-modify-state"), 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/DefaultLinuxContainerRuntime.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/DefaultLinuxContainerRuntime.java index 837db62e231..8b00d4c99de 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/DefaultLinuxContainerRuntime.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/DefaultLinuxContainerRuntime.java @@ -33,6 +33,7 @@ import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Cont import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationException; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperationExecutor; +import org.apache.hadoop.yarn.server.nodemanager.containermanager.localizer.ResourceLocalizationService; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntime; import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerRuntimeConstants; @@ -41,6 +42,14 @@ import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerExecContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -57,6 +66,8 @@ import static org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.r public class DefaultLinuxContainerRuntime implements LinuxContainerRuntime { private static final Logger LOG = LoggerFactory.getLogger(DefaultLinuxContainerRuntime.class); + private static final String TMP_FILE_PREFIX = "yarn."; + private static final String TMP_FILE_SUFFIX = ".cmd"; private final PrivilegedOperationExecutor privilegedOperationExecutor; private Configuration conf; @@ -198,8 +209,93 @@ public class DefaultLinuxContainerRuntime implements LinuxContainerRuntime { } @Override - public IOStreamPair execContainer(ContainerExecContext containerExecContext) + public IOStreamPair execContainer(ContainerExecContext ctx) throws ContainerExecutionException { - throw new ContainerExecutionException("Unsupported operation."); + IOStreamPair output; + try { + PrivilegedOperation privOp = new PrivilegedOperation( + PrivilegedOperation.OperationType.EXEC_CONTAINER); + String commandFile = writeCommandToTempFile(ctx); + privOp.appendArgs(commandFile); + privOp.disableFailureLogging(); + output = + privilegedOperationExecutor.executePrivilegedInteractiveOperation( + null, privOp); + } catch (PrivilegedOperationException e) { + throw new ContainerExecutionException( + "Execute container interactive shell failed", e.getExitCode(), + e.getOutput(), e.getErrorOutput()); + } catch (InterruptedException ie) { + LOG.warn("InterruptedException executing command: ", ie); + throw new ContainerExecutionException(ie.getMessage()); + } + return output; + } + + private String writeCommandToTempFile(ContainerExecContext ctx) + throws ContainerExecutionException { + Container container = ctx.getContainer(); + File cmdDir = null; + String appId = container.getContainerId().getApplicationAttemptId() + .getApplicationId().toString(); + String containerId = container.getContainerId().toString(); + String filePrefix = containerId.toString(); + try { + String cmdDirPath = ctx.getLocalDirsHandlerService().getLocalPathForWrite( + ResourceLocalizationService.NM_PRIVATE_DIR + Path.SEPARATOR + + appId + Path.SEPARATOR + filePrefix + Path.SEPARATOR).toString(); + cmdDir = new File(cmdDirPath); + if (!cmdDir.mkdirs() && !cmdDir.exists()) { + throw new IOException("Cannot create container private directory " + + cmdDir); + } + File commandFile = File.createTempFile(TMP_FILE_PREFIX + filePrefix, + TMP_FILE_SUFFIX, cmdDir); + try ( + Writer writer = new OutputStreamWriter( + new FileOutputStream(commandFile.toString()), "UTF-8"); + PrintWriter printWriter = new PrintWriter(writer); + ) { + Map> cmd = new HashMap>(); + // command = exec + List exec = new ArrayList(); + exec.add("exec"); + cmd.put("command", exec); + // user = foobar + List user = new ArrayList(); + user.add(container.getUser()); + cmd.put("user", user); + // launch-command = bash,-i + List commands = new ArrayList(); + commands.add("/bin/bash"); + commands.add("-ir"); + cmd.put("launch-command", commands); + // workdir = ../nm-local-dir/usercache/appcache/appid/containerid + List workdir = new ArrayList(); + workdir.add(container.getWorkDir()); + cmd.put("workdir", workdir); + // generate cmd file + printWriter.println("[command-execution]"); + for (Map.Entry> entry : + cmd.entrySet()) { + if (entry.getKey().contains("=")) { + throw new ContainerExecutionException( + "'=' found in entry for docker command file, key = " + entry + .getKey() + "; value = " + entry.getValue()); + } + if (entry.getValue().contains("\n")) { + throw new ContainerExecutionException( + "'\\n' found in entry for docker command file, key = " + entry + .getKey() + "; value = " + entry.getValue()); + } + printWriter.println(" " + entry.getKey() + "=" + StringUtils + .join(",", entry.getValue())); + } + return commandFile.toString(); + } + } catch (IOException e) { + LOG.warn("Unable to write command to " + cmdDir); + throw new ContainerExecutionException(e); + } } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerExecContext.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerExecContext.java index dbc1a2d5b3c..0a2228f44f9 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerExecContext.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/executor/ContainerExecContext.java @@ -22,6 +22,7 @@ package org.apache.hadoop.yarn.server.nodemanager.executor; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.yarn.server.nodemanager.LocalDirsHandlerService; import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container; /** @@ -34,6 +35,7 @@ public final class ContainerExecContext { private final String user; private final String appId; private final Container container; + private final LocalDirsHandlerService localDirsHandler; /** * Builder for ContainerExecContext. @@ -42,6 +44,7 @@ public final class ContainerExecContext { private String user; private String appId; private Container container; + private LocalDirsHandlerService localDirsHandler; public Builder() { } @@ -64,12 +67,19 @@ public final class ContainerExecContext { public ContainerExecContext build() { return new ContainerExecContext(this); } + + public Builder setNMLocalPath( + LocalDirsHandlerService ldhs) { + this.localDirsHandler = ldhs; + return this; + } } private ContainerExecContext(Builder builder) { this.container = builder.container; this.user = builder.user; this.appId = builder.appId; + this.localDirsHandler = builder.localDirsHandler; } public String getUser() { @@ -83,4 +93,8 @@ public final class ContainerExecContext { public Container getContainer() { return this.container; } + + public LocalDirsHandlerService getLocalDirsHandlerService() { + return this.localDirsHandler; + } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/ContainerShellWebSocket.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/ContainerShellWebSocket.java index 4ca4db5a2e6..b1c389b1f0d 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/ContainerShellWebSocket.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/webapp/ContainerShellWebSocket.java @@ -112,6 +112,7 @@ public class ContainerShellWebSocket { ContainerExecContext execContext = new ContainerExecContext .Builder() .setContainer(container) + .setNMLocalPath(nmContext.getLocalDirsHandler()) .build(); pair = exec.execContainer(execContext); } catch (Exception e) { 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 a22b9fac5fe..dcbfb0fda92 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 @@ -1374,28 +1374,12 @@ char **construct_docker_command(const char *command_file) { } int run_docker(const char *command_file) { - struct configuration command_config = {0, NULL}; - - int ret = read_config(command_file, &command_config); - if (ret != 0) { - free_configuration(&command_config); - return INVALID_COMMAND_FILE; - } - char *value = get_configuration_value("docker-command", DOCKER_COMMAND_FILE_SECTION, &command_config); - if (value != NULL && strcasecmp(value, "exec") == 0) { - free(value); - free_configuration(&command_config); - return run_docker_with_pty(command_file); - } - free_configuration(&command_config); - free(value); - char **args = construct_docker_command(command_file); - char* docker_binary = get_docker_binary(&CFG); + char *docker_binary = get_docker_binary(&CFG); int exit_code = -1; if (execvp(docker_binary, args) != 0) { - fprintf(ERRORFILE, "Couldn't execute the container launch with args %s - %s", + fprintf(ERRORFILE, "Couldn't execute the container launch with args %s - %s\n", docker_binary, strerror(errno)); fflush(LOGFILE); fflush(ERRORFILE); @@ -1409,12 +1393,55 @@ int run_docker(const char *command_file) { return exit_code; } -int run_docker_with_pty(const char *command_file) { +int exec_container(const char *command_file) { int exit_code = -1; - char **args = construct_docker_command(command_file); - char* docker_binary = get_docker_binary(&CFG); + struct configuration command_config = {0, NULL}; + char **args = NULL; + char **env = NULL; + char *workdir = NULL; + char *docker_binary = get_docker_binary(&CFG); + char *binary = NULL; int fdm, fds, rc; char input[4000]; + int docker = 0; + char *user = NULL; + + int ret = read_config(command_file, &command_config); + if (ret != 0) { + free_configuration(&command_config); + return INVALID_COMMAND_FILE; + } + + char *value = get_configuration_value("docker-command", DOCKER_COMMAND_FILE_SECTION, &command_config); + if (value != NULL && strcasecmp(value, "exec") == 0) { + args = construct_docker_command(command_file); + binary = docker_binary; + docker = 1; + } else { + value = get_configuration_value("command", COMMAND_FILE_SECTION, &command_config); + if (value != NULL && strcasecmp(value, "exec") == 0) { + args = get_configuration_values_delimiter("launch-command", + COMMAND_FILE_SECTION, &command_config, ","); + if (args == NULL) { + goto cleanup; + } + binary = strdup(args[0]); + workdir = get_configuration_value("workdir", COMMAND_FILE_SECTION, &command_config); + if (workdir == NULL) { + goto cleanup; + } + env = (char **) alloc_and_clear_memory(3, sizeof(char *)); + env[0] = make_string("PWD=%s", workdir); + env[1] = make_string("TERM=%s", "xterm-256color"); + env[2] = NULL; + user = get_configuration_value("user", COMMAND_FILE_SECTION, &command_config); + if (user == NULL) { + goto cleanup; + } + } else { + goto cleanup; + } + } fdm = posix_openpt(O_RDWR); if (fdm < 0) { @@ -1513,6 +1540,9 @@ int run_docker_with_pty(const char *command_file) { // Set raw mode on the slave side of the PTY new_term_settings = slave_orig_term_settings; cfmakeraw (&new_term_settings); + if (!docker) { + new_term_settings.c_lflag |= ECHO; + } tcsetattr (fds, TCSANOW, &new_term_settings); // The slave side of the PTY becomes the standard input and outputs of the child process @@ -1537,24 +1567,48 @@ int run_docker_with_pty(const char *command_file) { close(fds); // Make the current process a new session leader - setsid(); + if (docker) { + setsid(); + } else { + exit_code = set_user(user); + if (exit_code!=0) { + goto cleanup; + } + } // As the child is a session leader, set the controlling terminal to be the slave side of the PTY // (Mandatory for programs like the shell to make them manage correctly their outputs) ioctl(0, TIOCSCTTY, 1); - - if (execvp(docker_binary, args) != 0) { - fprintf(ERRORFILE, "Couldn't execute the container launch with args %s - %s", - docker_binary, strerror(errno)); - free(docker_binary); - free_values(args); + if (docker) { + ret = execvp(binary, args); + } else { + if (change_user(user_detail->pw_uid, user_detail->pw_gid) != 0) { + exit_code = DOCKER_EXEC_FAILED; + goto cleanup; + } + ret = chdir(workdir); + if (ret != 0) { + exit_code = DOCKER_EXEC_FAILED; + goto cleanup; + } + ret = execve(binary, args, env); + } + if (ret != 0) { + fprintf(ERRORFILE, "Couldn't execute the container launch with args %s - %s\n", + binary, strerror(errno)); exit_code = DOCKER_EXEC_FAILED; } else { - free_values(args); exit_code = 0; } } +cleanup: + free(docker_binary); + free(binary); + free(user); + free(workdir); + free_values(args); + free_configuration(&command_config); return exit_code; } 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 1415830680f..bf994522dde 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 @@ -51,7 +51,8 @@ enum operations { RUN_AS_USER_LIST = 12, REMOVE_DOCKER_CONTAINER = 13, INSPECT_DOCKER_CONTAINER = 14, - RUN_AS_USER_SYNC_YARN_SYSFS = 15 + RUN_AS_USER_SYNC_YARN_SYSFS = 15, + EXEC_CONTAINER = 16 }; #define NM_GROUP_KEY "yarn.nodemanager.linux-container-executor.group" @@ -71,6 +72,7 @@ enum operations { #define MOUNT_CGROUP_SUPPORT_ENABLED_KEY "feature.mount-cgroup.enabled" #define YARN_SYSFS_SUPPORT_ENABLED_KEY "feature.yarn.sysfs.enabled" #define TMP_DIR "tmp" +#define COMMAND_FILE_SECTION "command-execution" extern struct passwd *user_detail; @@ -296,6 +298,11 @@ int run_docker_with_pty(const char *command_file); */ int exec_docker_command(char *docker_command, char **argv, int argc); +/** + * Exec a container terminal. + */ +int exec_container(const char *command_file); + /** Check if yarn sysfs is enabled in configuration. */ int is_yarn_sysfs_support_enabled(); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c index 7b13e7ca848..512489076d8 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/main.c @@ -54,12 +54,14 @@ static void display_usage(FILE *stream) { if(is_docker_support_enabled()) { fprintf(stream, " container-executor --run-docker \n" + " container-executor --exec-container \n" " container-executor --remove-docker-container [hierarchy] " "\n" " container-executor --inspect-docker-container \n"); } else { fprintf(stream, "[DISABLED] container-executor --run-docker \n" + "[DISABLED] container-executor --exec-container \n" "[DISABLED] container-executor --remove-docker-container [hierarchy] " "\n" "[DISABLED] container-executor --inspect-docker-container " @@ -247,7 +249,7 @@ static struct { const char *target_dir; int container_pid; int signal; - const char *docker_command_file; + const char *command_file; } cmd_input; static int validate_run_as_user_commands(int argc, char **argv, int *operation); @@ -348,6 +350,22 @@ static int validate_arguments(int argc, char **argv , int *operation) { } } + if (strcmp("--exec-container", argv[1]) == 0) { + if(is_docker_support_enabled()) { + if (argc != 3) { + display_usage(stdout); + return INVALID_ARGUMENT_NUMBER; + } + optind++; + cmd_input.command_file = argv[optind++]; + *operation = EXEC_CONTAINER; + return 0; + } else { + display_feature_disabled_message("docker"); + return FEATURE_DISABLED; + } + } + if (strcmp("--run-docker", argv[1]) == 0) { if(is_docker_support_enabled()) { if (argc != 3) { @@ -355,7 +373,7 @@ static int validate_arguments(int argc, char **argv , int *operation) { return INVALID_ARGUMENT_NUMBER; } optind++; - cmd_input.docker_command_file = argv[optind++]; + cmd_input.command_file = argv[optind++]; *operation = RUN_DOCKER; return 0; } else { @@ -469,7 +487,7 @@ static int validate_run_as_user_commands(int argc, char **argv, int *operation) cmd_input.local_dirs = argv[optind++]; // good log dirs as a comma separated list cmd_input.log_dirs = argv[optind++]; - cmd_input.docker_command_file = argv[optind++]; + cmd_input.command_file = argv[optind++]; //network isolation through tc if ((argc == 15 && !cmd_input.https) || (argc == 17 && cmd_input.https)) { if(is_tc_support_enabled()) { @@ -624,8 +642,11 @@ int main(int argc, char **argv) { case TRAFFIC_CONTROL_READ_STATS: exit_code = traffic_control_read_stats(cmd_input.traffic_control_command_file); break; + case EXEC_CONTAINER: + exit_code = exec_container(cmd_input.command_file); + break; case RUN_DOCKER: - exit_code = run_docker(cmd_input.docker_command_file); + exit_code = run_docker(cmd_input.command_file); break; case REMOVE_DOCKER_CONTAINER: exit_code = remove_docker_container(argv + optind, argc - optind); @@ -674,7 +695,7 @@ int main(int argc, char **argv) { cmd_input.pid_file, split(cmd_input.local_dirs), split(cmd_input.log_dirs), - cmd_input.docker_command_file); + cmd_input.command_file); break; case RUN_AS_USER_LAUNCH_CONTAINER: if (cmd_input.traffic_control_command_file != NULL) { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c index 437850d3745..279d1c700e6 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/test-container-executor.c @@ -1472,6 +1472,53 @@ void test_cleaning_docker_cgroups() { } } +void test_exec_container() { + int ret = -1; + char* filename = TEST_ROOT "/exec_container.cmd"; + FILE *file = fopen(filename, "w"); + if (file == NULL) { + printf("FAIL: Could not write to command file: %s\n", filename); + exit(1); + } + // Test missing user + fprintf(file, "[command-execution]\n"); + fprintf(file, "workdir=/tmp/container_1541184499854_0001_01_000001\n"); + fprintf(file, "launch-command=/bin/bash,-ir\n"); + fprintf(file, "command=exec\n"); + fclose(file); + ret = exec_container(filename); + if (ret!=-1) { + printf("FAIL: broken command file should not pass.\n"); + exit(1); + } + + // Test missing workdir + file = fopen(filename, "w"); + fprintf(file, "[command-execution]\n"); + fprintf(file, "launch-command=/bin/bash,-ir\n"); + fprintf(file, "user=test\n"); + fprintf(file, "command=exec\n"); + fclose(file); + ret = exec_container(filename); + if (ret!=-1) { + printf("FAIL: broken command file should not pass.\n"); + exit(1); + } + + // Test missing launch-command + file = fopen(filename, "w"); + fprintf(file, "[command-execution]\n"); + fprintf(file, "workdir=/tmp/container_1541184499854_0001_01_000001\n"); + fprintf(file, "user=test\n"); + fprintf(file, "command=exec\n"); + fclose(file); + ret = exec_container(filename); + if (ret!=-1) { + printf("FAIL: broken command file should not pass.\n"); + exit(1); + } +} + // This test is expected to be executed either by a regular // user or by root. If executed by a regular user it doesn't // test all the functions that would depend on changing the @@ -1612,6 +1659,9 @@ int main(int argc, char **argv) { printf("\nTesting yarn sysfs\n"); test_yarn_sysfs(); + printf("\nTesting exec_container()\n"); + test_exec_container(); + test_check_user(0); test_cleaning_docker_cgroups();