You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by bi...@apache.org on 2018/10/11 16:38:08 UTC
hadoop git commit: YARN-8777. Container Executor C binary change to
execute interactive docker command. Contributed by Eric Yang
Repository: hadoop
Updated Branches:
refs/heads/trunk 47eeb3eb7 -> 96d28b475
YARN-8777. Container Executor C binary change to execute interactive docker command. Contributed by Eric Yang
Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/96d28b47
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/96d28b47
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/96d28b47
Branch: refs/heads/trunk
Commit: 96d28b4750f1088f2a10c83991b5a8149c97ef86
Parents: 47eeb3e
Author: Billie Rinaldi <bi...@apache.org>
Authored: Thu Oct 11 09:25:21 2018 -0700
Committer: Billie Rinaldi <bi...@apache.org>
Committed: Thu Oct 11 09:25:21 2018 -0700
----------------------------------------------------------------------
.../impl/container-executor.c | 164 ++++++++++++++++++-
.../impl/container-executor.h | 7 +-
.../main/native/container-executor/impl/util.h | 3 +-
.../container-executor/impl/utils/docker-util.c | 53 ++++++
.../container-executor/impl/utils/docker-util.h | 10 ++
.../test/utils/test_docker_util.cc | 29 ++++
6 files changed, 263 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hadoop/blob/96d28b47/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c
----------------------------------------------------------------------
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 7765308..1f7ae3f 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
@@ -47,6 +47,7 @@
#include <sys/wait.h>
#include <getopt.h>
#include <sys/param.h>
+#include <termios.h>
#ifndef HAVE_FCHMODAT
#include "compat/fchmodat.h"
@@ -1357,8 +1358,25 @@ 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);
+
int exit_code = -1;
if (execvp(docker_binary, args) != 0) {
fprintf(ERRORFILE, "Couldn't execute the container launch with args %s - %s",
@@ -1375,6 +1393,150 @@ int run_docker(const char *command_file) {
return exit_code;
}
+int run_docker_with_pty(const char *command_file) {
+ int exit_code = -1;
+ char **args = construct_docker_command(command_file);
+ char* docker_binary = get_docker_binary(&CFG);
+ int fdm, fds, rc;
+ char input[4000];
+
+ fdm = posix_openpt(O_RDWR);
+ if (fdm < 0) {
+ fprintf(stderr, "Error %d on posix_openpt()\n", errno);
+ return DOCKER_EXEC_FAILED;
+ }
+
+ rc = grantpt(fdm);
+ if (rc != 0) {
+ fprintf(stderr, "Error %d on grantpt()\n", errno);
+ return DOCKER_EXEC_FAILED;
+ }
+
+ rc = unlockpt(fdm);
+ if (rc != 0) {
+ fprintf(stderr, "Error %d on unlockpt()\n", errno);
+ return DOCKER_EXEC_FAILED;
+ }
+
+ // Open the slave PTY
+ fds = open(ptsname(fdm), O_RDWR);
+
+ // Creation of a child process
+ if (fork()) {
+ fd_set fd_in;
+ // Parent
+
+ // Close the slave side of the PTY
+ close(fds);
+ while (1) {
+ // Wait for data from standard input and master side of PTY
+ FD_ZERO(&fd_in);
+ FD_SET(0, &fd_in);
+ FD_SET(fdm, &fd_in);
+ rc = select(fdm + 1, &fd_in, NULL, NULL, NULL);
+ switch(rc) {
+ case -1 : fprintf(stderr, "Error %d on select()\n", errno);
+ exit(1);
+ default :
+ {
+ // If data on standard input
+ if (FD_ISSET(0, &fd_in)) {
+ rc = read(0, input, sizeof(input));
+ if (rc > 0) {
+ // Send data on the master side of PTY
+ ssize_t written = write(fdm, input, rc);
+ if (written == -1) {
+ fprintf(stderr, "Error %d writing to container.\n", errno);
+ exit(DOCKER_EXEC_FAILED);
+ }
+ } else {
+ if (rc < 0) {
+ fprintf(stderr, "Error %d on read standard input\n", errno);
+ exit(DOCKER_EXEC_FAILED);
+ }
+ }
+ }
+
+ // If data on master side of PTY
+ if (FD_ISSET(fdm, &fd_in)) {
+ rc = read(fdm, input, sizeof(input));
+ if (rc > 0) {
+ // Send data on standard output
+ ssize_t written = write(1, input, rc);
+ if (written == -1) {
+ fprintf(stderr, "Error %d writing to terminal.\n", errno);
+ exit(DOCKER_EXEC_FAILED);
+ }
+ } else {
+ if (rc < 0) {
+ fprintf(stderr, "Error %d on read master PTY\n", errno);
+ exit(DOCKER_EXEC_FAILED);
+ }
+ }
+ }
+ }
+ } // End switch
+ } // End while
+ } else {
+ struct termios slave_orig_term_settings; // Saved terminal settings
+ struct termios new_term_settings; // Current terminal settings
+
+ // Child
+
+ // Close the master side of the PTY
+ close(fdm);
+
+ // Save the default parameters of the slave side of the PTY
+ rc = tcgetattr(fds, &slave_orig_term_settings);
+
+ // Set raw mode on the slave side of the PTY
+ new_term_settings = slave_orig_term_settings;
+ cfmakeraw (&new_term_settings);
+ tcsetattr (fds, TCSANOW, &new_term_settings);
+
+ // The slave side of the PTY becomes the standard input and outputs of the child process
+ close(0); // Close standard input (current terminal)
+ close(1); // Close standard output (current terminal)
+ close(2); // Close standard error (current terminal)
+
+ if (dup(fds) == -1) {
+ // PTY becomes standard input (0)
+ exit(DOCKER_EXEC_FAILED);
+ }
+ if (dup(fds) == -1) {
+ // PTY becomes standard output (1)
+ exit(DOCKER_EXEC_FAILED);
+ }
+ if (dup(fds) == -1) {
+ // PTY becomes standard error (2)
+ exit(DOCKER_EXEC_FAILED);
+ }
+
+ // Now the original file descriptor is useless
+ close(fds);
+
+ // Make the current process a new session leader
+ setsid();
+
+ // 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);
+ exit_code = DOCKER_EXEC_FAILED;
+ } else {
+ free_values(args);
+ exit_code = 0;
+ }
+ }
+
+ return exit_code;
+}
+
int exec_docker_command(char *docker_command, char **argv, int argc) {
int i;
char* docker_binary = get_docker_binary(&CFG);
@@ -2708,4 +2870,4 @@ int remove_docker_container(char**argv, int argc) {
exit_code = clean_docker_cgroups(yarn_hierarchy, container_id);
}
return exit_code;
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/96d28b47/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.h
----------------------------------------------------------------------
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 cd09e1e..ce05c57 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
@@ -269,6 +269,11 @@ int is_docker_support_enabled();
int run_docker(const char *command_file);
/**
+ * Run a docker command passing the command file as an argument with terminal.
+ */
+int run_docker_with_pty(const char *command_file);
+
+/**
* Run a docker command without a command file
*/
int exec_docker_command(char *docker_command, char **argv, int argc);
@@ -295,4 +300,4 @@ char* flatten(char **args);
/**
* Remove docker container
*/
-int remove_docker_container(char **argv, int argc);
\ No newline at end of file
+int remove_docker_container(char **argv, int argc);
http://git-wip-us.apache.org/repos/asf/hadoop/blob/96d28b47/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.h
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.h b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.h
index 6aac1fe..372c17a 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.h
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/util.h
@@ -68,7 +68,8 @@ enum errorcodes {
DOCKER_IMAGE_INVALID = 40,
// DOCKER_CONTAINER_NAME_INVALID = 41, (NOT USED)
ERROR_COMPILING_REGEX = 42,
- INVALID_CONTAINER_ID = 43
+ INVALID_CONTAINER_ID = 43,
+ DOCKER_EXEC_FAILED = 44
};
/* Macros for min/max. */
http://git-wip-us.apache.org/repos/asf/hadoop/blob/96d28b47/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/utils/docker-util.c
----------------------------------------------------------------------
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 69f27ba..c0aa80b 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
@@ -432,6 +432,8 @@ int get_docker_command(const char *command_file, const struct configuration *con
ret = get_docker_volume_command(command_file, conf, args);
} else if (strcmp(DOCKER_START_COMMAND, command) == 0) {
ret = get_docker_start_command(command_file, conf, args);
+ } else if (strcmp(DOCKER_EXEC_COMMAND, command) == 0) {
+ ret = get_docker_exec_command(command_file, conf, args);
} else {
ret = UNKNOWN_DOCKER_COMMAND;
}
@@ -820,6 +822,57 @@ free_and_exit:
return ret;
}
+int get_docker_exec_command(const char *command_file, const struct configuration *conf, args *args) {
+ int ret = 0, i = 0;
+ char *container_name = NULL;
+ char **launch_command = NULL;
+ struct configuration command_config = {0, NULL};
+ ret = read_and_verify_command_file(command_file, DOCKER_EXEC_COMMAND, &command_config);
+ if (ret != 0) {
+ goto free_and_exit;
+ }
+
+ container_name = get_configuration_value("name", DOCKER_COMMAND_FILE_SECTION, &command_config);
+ if (container_name == NULL || validate_container_name(container_name) != 0) {
+ ret = INVALID_DOCKER_CONTAINER_NAME;
+ goto free_and_exit;
+ }
+
+ ret = add_to_args(args, DOCKER_EXEC_COMMAND);
+ if (ret != 0) {
+ goto free_and_exit;
+ }
+
+ ret = add_to_args(args, "-it");
+ if (ret != 0) {
+ goto free_and_exit;
+ }
+
+ ret = add_to_args(args, container_name);
+ if (ret != 0) {
+ goto free_and_exit;
+ }
+
+ launch_command = get_configuration_values_delimiter("launch-command", DOCKER_COMMAND_FILE_SECTION, &command_config,
+ ",");
+ if (launch_command != NULL) {
+ for (i = 0; launch_command[i] != NULL; ++i) {
+ ret = add_to_args(args, launch_command[i]);
+ if (ret != 0) {
+ ret = BUFFER_TOO_SMALL;
+ goto free_and_exit;
+ }
+ }
+ } else {
+ ret = INVALID_COMMAND_FILE;
+ }
+free_and_exit:
+ free(container_name);
+ free_configuration(&command_config);
+ free_values(launch_command);
+ return ret;
+}
+
static int detach_container(const struct configuration *command_config, args *args) {
return add_param_to_command(command_config, "detach", "-d", 0, args);
}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/96d28b47/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-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 7b7322d..fc7b4cc 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
@@ -34,6 +34,7 @@
#define DOCKER_KILL_COMMAND "kill"
#define DOCKER_VOLUME_COMMAND "volume"
#define DOCKER_START_COMMAND "start"
+#define DOCKER_EXEC_COMMAND "exec"
#define DOCKER_ARG_MAX 1024
#define ARGS_INITIAL_VALUE { 0 };
@@ -176,6 +177,15 @@ int get_docker_volume_command(const char *command_file, const struct configurati
int get_docker_start_command(const char* command_file, const struct configuration* conf, args *args);
/**
+ * Get the Docker exec command line string. The function will verify that the params file is meant for the exec command.
+ * @param command_file File containing the params for the Docker start command
+ * @param conf Configuration struct containing the container-executor.cfg details
+ * @param args Buffer to construct argv
+ * @return Return code with 0 indicating success and non-zero codes indicating error
+ */
+int get_docker_exec_command(const char* command_file, const struct configuration* conf, args *args);
+
+/**
* Give an error message for the supplied error code
* @param error_code the error code
* @return const string containing the error message
http://git-wip-us.apache.org/repos/asf/hadoop/blob/96d28b47/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc
----------------------------------------------------------------------
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 b289857..2817e0c 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
@@ -1762,4 +1762,33 @@ namespace ContainerExecutor {
free_configuration(&container_executor_cfg);
}
}
+
+ TEST_F(TestDockerUtil, test_docker_exec) {
+ std::string container_executor_contents = "[docker]\n"
+ " docker.allowed.devices=/dev/test\n docker.trusted.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<std::pair<std::string, std::string> > file_cmd_vec;
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n"
+ " docker-command=exec\n name=container_e1_12312_11111_02_000001\n launch-command=bash",
+ "exec -it container_e1_12312_11111_02_000001 bash"));
+
+ std::vector<std::pair<std::string, int> > bad_file_cmd_vec;
+
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=exec\n image=hadoop/docker-image\n user=nobody",
+ static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
+ run_docker_command_test(file_cmd_vec, bad_file_cmd_vec, get_docker_exec_command);
+ free_configuration(&container_executor_cfg);
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org