YARN-8648. Container cgroups are leaked when using docker. Contributed by Jim Brennan
This commit is contained in:
parent
295cce39ed
commit
2df0a8dcb3
@ -937,7 +937,8 @@ public class LinuxContainerExecutor extends ContainerExecutor {
|
|||||||
DockerCommandExecutor.getContainerStatus(containerId, privOpExecutor,
|
DockerCommandExecutor.getContainerStatus(containerId, privOpExecutor,
|
||||||
nmContext))) {
|
nmContext))) {
|
||||||
LOG.info("Removing Docker container : " + containerId);
|
LOG.info("Removing Docker container : " + containerId);
|
||||||
DockerRmCommand dockerRmCommand = new DockerRmCommand(containerId);
|
DockerRmCommand dockerRmCommand = new DockerRmCommand(containerId,
|
||||||
|
ResourceHandlerModule.getCgroupsRelativeRoot());
|
||||||
DockerCommandExecutor.executeDockerCommand(dockerRmCommand, containerId,
|
DockerCommandExecutor.executeDockerCommand(dockerRmCommand, containerId,
|
||||||
null, privOpExecutor, false, nmContext);
|
null, privOpExecutor, false, nmContext);
|
||||||
}
|
}
|
||||||
|
@ -101,6 +101,21 @@ public class ResourceHandlerModule {
|
|||||||
return cGroupsHandler;
|
return cGroupsHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns relative root for cgroups. Returns null if cGroupsHandler is
|
||||||
|
* not initialized, or if the path is empty.
|
||||||
|
*/
|
||||||
|
public static String getCgroupsRelativeRoot() {
|
||||||
|
if (cGroupsHandler == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String cGroupPath = cGroupsHandler.getRelativePathForCGroup("");
|
||||||
|
if (cGroupPath == null || cGroupPath.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return cGroupPath.replaceAll("/$", "");
|
||||||
|
}
|
||||||
|
|
||||||
public static NetworkPacketTaggingHandlerImpl
|
public static NetworkPacketTaggingHandlerImpl
|
||||||
getNetworkResourceHandler() {
|
getNetworkResourceHandler() {
|
||||||
return networkPacketTaggingHandlerImpl;
|
return networkPacketTaggingHandlerImpl;
|
||||||
|
@ -1382,7 +1382,8 @@ public class DockerLinuxContainerRuntime implements LinuxContainerRuntime {
|
|||||||
DockerCommandExecutor.getContainerStatus(containerId,
|
DockerCommandExecutor.getContainerStatus(containerId,
|
||||||
privilegedOperationExecutor, nmContext);
|
privilegedOperationExecutor, nmContext);
|
||||||
if (DockerCommandExecutor.isRemovable(containerStatus)) {
|
if (DockerCommandExecutor.isRemovable(containerStatus)) {
|
||||||
DockerRmCommand dockerRmCommand = new DockerRmCommand(containerId);
|
DockerRmCommand dockerRmCommand = new DockerRmCommand(containerId,
|
||||||
|
ResourceHandlerModule.getCgroupsRelativeRoot());
|
||||||
DockerCommandExecutor.executeDockerCommand(dockerRmCommand, containerId,
|
DockerCommandExecutor.executeDockerCommand(dockerRmCommand, containerId,
|
||||||
env, privilegedOperationExecutor, false, nmContext);
|
env, privilegedOperationExecutor, false, nmContext);
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,16 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class DockerRmCommand extends DockerCommand {
|
public class DockerRmCommand extends DockerCommand {
|
||||||
private static final String RM_COMMAND = "rm";
|
private static final String RM_COMMAND = "rm";
|
||||||
|
private static final String CGROUP_HIERARCHY = "hierarchy";
|
||||||
|
private String cGroupArg;
|
||||||
|
|
||||||
public DockerRmCommand(String containerName) {
|
public DockerRmCommand(String containerName, String hierarchy) {
|
||||||
super(RM_COMMAND);
|
super(RM_COMMAND);
|
||||||
super.addCommandArguments("name", containerName);
|
super.addCommandArguments("name", containerName);
|
||||||
|
if ((hierarchy != null) && !hierarchy.isEmpty()) {
|
||||||
|
super.addCommandArguments(CGROUP_HIERARCHY, hierarchy);
|
||||||
|
this.cGroupArg = hierarchy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -39,6 +45,9 @@ public class DockerRmCommand extends DockerCommand {
|
|||||||
String> env, Context nmContext) {
|
String> env, Context nmContext) {
|
||||||
PrivilegedOperation dockerOp = new PrivilegedOperation(
|
PrivilegedOperation dockerOp = new PrivilegedOperation(
|
||||||
PrivilegedOperation.OperationType.REMOVE_DOCKER_CONTAINER);
|
PrivilegedOperation.OperationType.REMOVE_DOCKER_CONTAINER);
|
||||||
|
if (this.cGroupArg != null) {
|
||||||
|
dockerOp.appendArgs(cGroupArg);
|
||||||
|
}
|
||||||
dockerOp.appendArgs(containerName);
|
dockerOp.appendArgs(containerName);
|
||||||
return dockerOp;
|
return dockerOp;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
#ifndef HAVE_FCHMODAT
|
#ifndef HAVE_FCHMODAT
|
||||||
#include "compat/fchmodat.h"
|
#include "compat/fchmodat.h"
|
||||||
@ -1374,17 +1375,16 @@ int run_docker(const char *command_file) {
|
|||||||
return exit_code;
|
return exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int exec_docker_command(char *docker_command, char **argv,
|
int exec_docker_command(char *docker_command, char **argv, int argc) {
|
||||||
int argc, int optind) {
|
|
||||||
int i;
|
int i;
|
||||||
char* docker_binary = get_docker_binary(&CFG);
|
char* docker_binary = get_docker_binary(&CFG);
|
||||||
size_t command_size = argc - optind + 2;
|
size_t command_size = argc + 2;
|
||||||
|
|
||||||
char **args = alloc_and_clear_memory(command_size + 1, sizeof(char));
|
char **args = alloc_and_clear_memory(command_size + 1, sizeof(char *));
|
||||||
args[0] = docker_binary;
|
args[0] = docker_binary;
|
||||||
args[1] = docker_command;
|
args[1] = docker_command;
|
||||||
for(i = 2; i < command_size; i++) {
|
for(i = 2; i < command_size; i++) {
|
||||||
args[i] = (char *) argv[i];
|
args[i] = (char *) argv[i - 2];
|
||||||
}
|
}
|
||||||
args[i] = NULL;
|
args[i] = NULL;
|
||||||
|
|
||||||
@ -2565,4 +2565,147 @@ char* flatten(char **args) {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int clean_docker_cgroups_internal(const char *mount_table,
|
||||||
|
const char *yarn_hierarchy,
|
||||||
|
const char* container_id) {
|
||||||
|
#ifndef __linux
|
||||||
|
fprintf(LOGFILE, "Failed to clean cgroups, not supported\n");
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
const char * cgroup_mount_type = "cgroup";
|
||||||
|
char *mnt_type = NULL;
|
||||||
|
char *mnt_dir = NULL;
|
||||||
|
char *full_path = NULL;
|
||||||
|
char *lineptr = NULL;
|
||||||
|
FILE *fp = NULL;
|
||||||
|
int rc = 0;
|
||||||
|
size_t buf_size = 0;
|
||||||
|
|
||||||
|
if (!mount_table || mount_table[0] == 0) {
|
||||||
|
fprintf(ERRORFILE, "clean_docker_cgroups: Invalid mount table\n");
|
||||||
|
rc = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!yarn_hierarchy || yarn_hierarchy[0] == 0) {
|
||||||
|
fprintf(ERRORFILE, "clean_docker_cgroups: Invalid yarn_hierarchy\n");
|
||||||
|
rc = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!validate_container_id(container_id)) {
|
||||||
|
fprintf(ERRORFILE, "clean_docker_cgroups: Invalid container_id: %s\n",
|
||||||
|
(container_id == NULL) ? "null" : container_id);
|
||||||
|
rc = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
fp = fopen(mount_table, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
fprintf(ERRORFILE, "clean_docker_cgroups: failed to open %s, error %d: %s\n",
|
||||||
|
mount_table, errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk /proc/mounts and find cgroup mounts
|
||||||
|
while (getline(&lineptr, &buf_size, fp) != -1) {
|
||||||
|
// Free these from the last iteration, if set
|
||||||
|
free(mnt_type);
|
||||||
|
free(mnt_dir);
|
||||||
|
int ret = 0;
|
||||||
|
ret = sscanf(lineptr, " %ms %ms %*s %*s %*s %*s", &mnt_type, &mnt_dir);
|
||||||
|
if (ret != 2) {
|
||||||
|
fprintf(ERRORFILE, "clean_docker_cgroups: Failed to parse line: %s\n", lineptr);
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((mnt_type == NULL) || (strcmp(mnt_type, cgroup_mount_type) != 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((mnt_dir == NULL) || (mnt_dir[0] == 0)) {
|
||||||
|
fprintf(ERRORFILE, "clean_docker_cgroups: skipping mount entry with invalid mnt_dir\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(full_path); // from previous iteration
|
||||||
|
full_path = make_string("%s/%s/%s", mnt_dir, yarn_hierarchy, container_id);
|
||||||
|
if (full_path == NULL) {
|
||||||
|
fprintf(ERRORFILE, "clean_docker_cgroups: Failed to allocate cgroup path.\n");
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure path is clean
|
||||||
|
if (!verify_path_safety(full_path)) {
|
||||||
|
fprintf(ERRORFILE,
|
||||||
|
"clean_docker_cgroups: skipping invalid path: %s\n", full_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rmdir(full_path);
|
||||||
|
if ((ret == -1) && (errno != ENOENT)) {
|
||||||
|
fprintf(ERRORFILE, "clean_docker_cgroups: Failed to rmdir cgroup, %s (error=%s)\n",
|
||||||
|
full_path, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ferror(fp)) {
|
||||||
|
fprintf(ERRORFILE, "clean_docker_cgroups: Error reading %s, error=%d (%s) \n",
|
||||||
|
mount_table, errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
free(lineptr);
|
||||||
|
free(mnt_type);
|
||||||
|
free(mnt_dir);
|
||||||
|
free(full_path);
|
||||||
|
if (fp != NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int clean_docker_cgroups(const char *yarn_hierarchy, const char* container_id) {
|
||||||
|
const char *proc_mount_path = "/proc/mounts";
|
||||||
|
return clean_docker_cgroups_internal(proc_mount_path, yarn_hierarchy, container_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int remove_docker_container(char**argv, int argc) {
|
||||||
|
int exit_code = 0;
|
||||||
|
const char *yarn_hierarchy = NULL;
|
||||||
|
const char *container_id = NULL;
|
||||||
|
|
||||||
|
int start_index = 0;
|
||||||
|
if (argc == 2) {
|
||||||
|
yarn_hierarchy = argv[0];
|
||||||
|
container_id = argv[1];
|
||||||
|
// Skip the yarn_hierarchy argument for exec_docker_command
|
||||||
|
start_index = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t child_pid = fork();
|
||||||
|
if (child_pid == -1) {
|
||||||
|
fprintf (ERRORFILE,
|
||||||
|
"Failed to fork for docker remove command\n");
|
||||||
|
fflush(ERRORFILE);
|
||||||
|
return DOCKER_RUN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child_pid == 0) { // child
|
||||||
|
int rc = exec_docker_command("rm", argv + start_index, argc - start_index);
|
||||||
|
return rc; // Only get here if exec fails
|
||||||
|
|
||||||
|
} else { // parent
|
||||||
|
exit_code = wait_and_get_exit_code(child_pid);
|
||||||
|
if (exit_code != 0) {
|
||||||
|
exit_code = DOCKER_RUN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up cgroups if necessary
|
||||||
|
if (yarn_hierarchy != NULL) {
|
||||||
|
exit_code = clean_docker_cgroups(yarn_hierarchy, container_id);
|
||||||
|
}
|
||||||
|
return exit_code;
|
||||||
|
}
|
@ -271,8 +271,7 @@ int run_docker(const char *command_file);
|
|||||||
/**
|
/**
|
||||||
* Run a docker command without a command file
|
* Run a docker command without a command file
|
||||||
*/
|
*/
|
||||||
int exec_docker_command(char *docker_command, char **argv,
|
int exec_docker_command(char *docker_command, char **argv, int argc);
|
||||||
int argc, int optind);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compile the regex_str and determine if the input string matches.
|
* Compile the regex_str and determine if the input string matches.
|
||||||
@ -292,3 +291,8 @@ struct configuration* get_cfg();
|
|||||||
* Flatten docker launch command
|
* Flatten docker launch command
|
||||||
*/
|
*/
|
||||||
char* flatten(char **args);
|
char* flatten(char **args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove docker container
|
||||||
|
*/
|
||||||
|
int remove_docker_container(char **argv, int argc);
|
@ -54,12 +54,14 @@ static void display_usage(FILE *stream) {
|
|||||||
if(is_docker_support_enabled()) {
|
if(is_docker_support_enabled()) {
|
||||||
fprintf(stream,
|
fprintf(stream,
|
||||||
" container-executor --run-docker <command-file>\n"
|
" container-executor --run-docker <command-file>\n"
|
||||||
" container-executor --remove-docker-container <container_id>\n"
|
" container-executor --remove-docker-container [hierarchy] "
|
||||||
|
"<container_id>\n"
|
||||||
" container-executor --inspect-docker-container <container_id>\n");
|
" container-executor --inspect-docker-container <container_id>\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stream,
|
fprintf(stream,
|
||||||
"[DISABLED] container-executor --run-docker <command-file>\n"
|
"[DISABLED] container-executor --run-docker <command-file>\n"
|
||||||
"[DISABLED] container-executor --remove-docker-container <container_id>\n"
|
"[DISABLED] container-executor --remove-docker-container [hierarchy] "
|
||||||
|
"<container_id>\n"
|
||||||
"[DISABLED] container-executor --inspect-docker-container "
|
"[DISABLED] container-executor --inspect-docker-container "
|
||||||
"<format> ... <container_id>\n");
|
"<format> ... <container_id>\n");
|
||||||
}
|
}
|
||||||
@ -351,7 +353,7 @@ static int validate_arguments(int argc, char **argv , int *operation) {
|
|||||||
|
|
||||||
if (strcmp("--remove-docker-container", argv[1]) == 0) {
|
if (strcmp("--remove-docker-container", argv[1]) == 0) {
|
||||||
if(is_docker_support_enabled()) {
|
if(is_docker_support_enabled()) {
|
||||||
if (argc != 3) {
|
if ((argc != 3) && (argc != 4)) {
|
||||||
display_usage(stdout);
|
display_usage(stdout);
|
||||||
return INVALID_ARGUMENT_NUMBER;
|
return INVALID_ARGUMENT_NUMBER;
|
||||||
}
|
}
|
||||||
@ -594,10 +596,10 @@ int main(int argc, char **argv) {
|
|||||||
exit_code = run_docker(cmd_input.docker_command_file);
|
exit_code = run_docker(cmd_input.docker_command_file);
|
||||||
break;
|
break;
|
||||||
case REMOVE_DOCKER_CONTAINER:
|
case REMOVE_DOCKER_CONTAINER:
|
||||||
exit_code = exec_docker_command("rm", argv, argc, optind);
|
exit_code = remove_docker_container(argv + optind, argc - optind);
|
||||||
break;
|
break;
|
||||||
case INSPECT_DOCKER_CONTAINER:
|
case INSPECT_DOCKER_CONTAINER:
|
||||||
exit_code = exec_docker_command("inspect", argv, argc, optind);
|
exit_code = exec_docker_command("inspect", argv + optind, argc - optind);
|
||||||
break;
|
break;
|
||||||
case RUN_AS_USER_INITIALIZE_CONTAINER:
|
case RUN_AS_USER_INITIALIZE_CONTAINER:
|
||||||
exit_code = set_user(cmd_input.run_as_user_name);
|
exit_code = set_user(cmd_input.run_as_user_name);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "test/test-container-executor-common.h"
|
#include "test/test-container-executor-common.h"
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -32,6 +33,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
|
||||||
static char* username = NULL;
|
static char* username = NULL;
|
||||||
static char* yarn_username = NULL;
|
static char* yarn_username = NULL;
|
||||||
@ -1224,6 +1227,148 @@ void test_is_empty() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define TCE_FAKE_CGROOT TEST_ROOT "/cgroup_root"
|
||||||
|
#define TCE_NUM_CG_CONTROLLERS 6
|
||||||
|
extern int clean_docker_cgroups_internal(const char *mount_table,
|
||||||
|
const char *yarn_hierarchy,
|
||||||
|
const char* container_id);
|
||||||
|
|
||||||
|
void test_cleaning_docker_cgroups() {
|
||||||
|
const char *controllers[TCE_NUM_CG_CONTROLLERS] = { "blkio", "cpu", "cpuset", "devices", "memory", "systemd" };
|
||||||
|
const char *yarn_hierarchy = "hadoop-yarn";
|
||||||
|
const char *fake_mount_table = TEST_ROOT "/fake_mounts";
|
||||||
|
const char *container_id = "container_1410901177871_0001_01_000005";
|
||||||
|
const char *other_container_id = "container_e17_1410901177871_0001_01_000005";
|
||||||
|
char cgroup_paths[TCE_NUM_CG_CONTROLLERS][PATH_MAX];
|
||||||
|
char container_paths[TCE_NUM_CG_CONTROLLERS][PATH_MAX];
|
||||||
|
char other_container_paths[TCE_NUM_CG_CONTROLLERS][PATH_MAX];
|
||||||
|
|
||||||
|
printf("\nTesting clean_docker_cgroups\n");
|
||||||
|
|
||||||
|
// Setup fake mount table
|
||||||
|
FILE *file;
|
||||||
|
file = fopen(fake_mount_table, "w");
|
||||||
|
if (file == NULL) {
|
||||||
|
printf("Failed to open %s.\n", fake_mount_table);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
fprintf(file, "rootfs " TEST_ROOT "/fake_root rootfs rw 0 0\n");
|
||||||
|
fprintf(file, "sysfs " TEST_ROOT "/fake_sys sysfs rw,nosuid,nodev,noexec,relatime 0 0\n");
|
||||||
|
fprintf(file, "proc " TEST_ROOT "/fake_proc proc rw,nosuid,nodev,noexec,relatime 0 0\n");
|
||||||
|
for (int i = 0; i < TCE_NUM_CG_CONTROLLERS; i++) {
|
||||||
|
fprintf(file, "cgroup %s/%s cgroup rw,nosuid,nodev,noexec,relatime,%s 0 0\n",
|
||||||
|
TCE_FAKE_CGROOT, controllers[i], controllers[i]);
|
||||||
|
}
|
||||||
|
fprintf(file, "/dev/vda " TEST_ROOT "/fake_root ext4 rw,relatime,data=ordered 0 0\n");
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
// Test with null inputs
|
||||||
|
int ret = clean_docker_cgroups_internal(NULL, yarn_hierarchy, container_id);
|
||||||
|
if (ret != -1) {
|
||||||
|
printf("FAIL: clean_docker_cgroups_internal with NULL mount table should fail\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ret = clean_docker_cgroups_internal(fake_mount_table, NULL, container_id);
|
||||||
|
if (ret != -1) {
|
||||||
|
printf("FAIL: clean_docker_cgroups_internal with NULL yarn_hierarchy should fail\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ret = clean_docker_cgroups_internal(fake_mount_table, yarn_hierarchy, NULL);
|
||||||
|
if (ret != -1) {
|
||||||
|
printf("FAIL: clean_docker_cgroups_internal with NULL container_id should fail\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with invalid container_id
|
||||||
|
ret = clean_docker_cgroups_internal(fake_mount_table, yarn_hierarchy, "not_a_container_123");
|
||||||
|
if (ret != -1) {
|
||||||
|
printf("FAIL: clean_docker_cgroups_internal with invalid container_id should fail\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (mkdir(TCE_FAKE_CGROOT, 0755) != 0) {
|
||||||
|
printf("FAIL: failed to mkdir " TCE_FAKE_CGROOT "\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < TCE_NUM_CG_CONTROLLERS; i++) {
|
||||||
|
snprintf(cgroup_paths[i], PATH_MAX, TCE_FAKE_CGROOT "/%s/%s", controllers[i], yarn_hierarchy);
|
||||||
|
if (mkdirs(cgroup_paths[i], 0755) != 0) {
|
||||||
|
printf("FAIL: failed to mkdir %s\n", cgroup_paths[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < TCE_NUM_CG_CONTROLLERS; i++) {
|
||||||
|
DIR *dir = NULL;
|
||||||
|
dir = opendir(cgroup_paths[i]);
|
||||||
|
if (dir == NULL) {
|
||||||
|
printf("FAIL: failed to open dir %s\n", cgroup_paths[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
// Test before creating any containers
|
||||||
|
ret = clean_docker_cgroups_internal(fake_mount_table, yarn_hierarchy, container_id);
|
||||||
|
if (ret != 0) {
|
||||||
|
printf("FAIL: failed to clean cgroups: mt=%s, yh=%s, cId=%s\n",
|
||||||
|
fake_mount_table, yarn_hierarchy, container_id);
|
||||||
|
}
|
||||||
|
// make sure hadoop-yarn dirs are still there
|
||||||
|
for (int i = 0; i < TCE_NUM_CG_CONTROLLERS; i++) {
|
||||||
|
DIR *dir = NULL;
|
||||||
|
dir = opendir(cgroup_paths[i]);
|
||||||
|
if (dir == NULL) {
|
||||||
|
printf("FAIL: failed to open dir %s\n", cgroup_paths[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
// Create container dirs
|
||||||
|
for (int i = 0; i < TCE_NUM_CG_CONTROLLERS; i++) {
|
||||||
|
snprintf(container_paths[i], PATH_MAX, TCE_FAKE_CGROOT "/%s/%s/%s",
|
||||||
|
controllers[i], yarn_hierarchy, container_id);
|
||||||
|
if (mkdirs(container_paths[i], 0755) != 0) {
|
||||||
|
printf("FAIL: failed to mkdir %s\n", container_paths[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
snprintf(other_container_paths[i], PATH_MAX, TCE_FAKE_CGROOT "/%s/%s/%s",
|
||||||
|
controllers[i], yarn_hierarchy, other_container_id);
|
||||||
|
if (mkdirs(other_container_paths[i], 0755) != 0) {
|
||||||
|
printf("FAIL: failed to mkdir %s\n", other_container_paths[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = clean_docker_cgroups_internal(fake_mount_table, yarn_hierarchy, container_id);
|
||||||
|
// make sure hadoop-yarn dirs are still there
|
||||||
|
for (int i = 0; i < TCE_NUM_CG_CONTROLLERS; i++) {
|
||||||
|
DIR *dir = NULL;
|
||||||
|
dir = opendir(cgroup_paths[i]);
|
||||||
|
if (dir == NULL) {
|
||||||
|
printf("FAIL: failed to open dir %s\n", cgroup_paths[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
// make sure container dirs deleted
|
||||||
|
for (int i = 0; i < TCE_NUM_CG_CONTROLLERS; i++) {
|
||||||
|
DIR *dir = NULL;
|
||||||
|
dir = opendir(container_paths[i]);
|
||||||
|
if (dir != NULL) {
|
||||||
|
printf("FAIL: container cgroup %s not deleted\n", container_paths[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
// make sure other container dirs are still there
|
||||||
|
for (int i = 0; i < TCE_NUM_CG_CONTROLLERS; i++) {
|
||||||
|
DIR *dir = NULL;
|
||||||
|
dir = opendir(other_container_paths[i]);
|
||||||
|
if (dir == NULL) {
|
||||||
|
printf("FAIL: container cgroup %s should not be deleted\n", other_container_paths[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This test is expected to be executed either by a regular
|
// This test is expected to be executed either by a regular
|
||||||
// user or by root. If executed by a regular user it doesn't
|
// user or by root. If executed by a regular user it doesn't
|
||||||
// test all the functions that would depend on changing the
|
// test all the functions that would depend on changing the
|
||||||
@ -1328,6 +1473,8 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
test_check_user(0);
|
test_check_user(0);
|
||||||
|
|
||||||
|
test_cleaning_docker_cgroups();
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
printf("OS X: disabling CrashReporter\n");
|
printf("OS X: disabling CrashReporter\n");
|
||||||
/*
|
/*
|
||||||
|
@ -66,6 +66,7 @@ public class TestDockerCommandExecutor {
|
|||||||
"container_e11_1861047502093_13763105_01_000001";
|
"container_e11_1861047502093_13763105_01_000001";
|
||||||
private static final String MOCK_LOCAL_IMAGE_NAME = "local_image_name";
|
private static final String MOCK_LOCAL_IMAGE_NAME = "local_image_name";
|
||||||
private static final String MOCK_IMAGE_NAME = "image_name";
|
private static final String MOCK_IMAGE_NAME = "image_name";
|
||||||
|
private static final String MOCK_CGROUP_HIERARCHY = "hadoop-yarn";
|
||||||
|
|
||||||
private PrivilegedOperationExecutor mockExecutor;
|
private PrivilegedOperationExecutor mockExecutor;
|
||||||
private CGroupsHandler mockCGroupsHandler;
|
private CGroupsHandler mockCGroupsHandler;
|
||||||
@ -148,7 +149,8 @@ public class TestDockerCommandExecutor {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExecuteDockerRm() throws Exception {
|
public void testExecuteDockerRm() throws Exception {
|
||||||
DockerRmCommand dockerCommand = new DockerRmCommand(MOCK_CONTAINER_ID);
|
DockerRmCommand dockerCommand =
|
||||||
|
new DockerRmCommand(MOCK_CONTAINER_ID, null);
|
||||||
DockerCommandExecutor.executeDockerCommand(dockerCommand, MOCK_CONTAINER_ID,
|
DockerCommandExecutor.executeDockerCommand(dockerCommand, MOCK_CONTAINER_ID,
|
||||||
env, mockExecutor, false, nmContext);
|
env, mockExecutor, false, nmContext);
|
||||||
List<PrivilegedOperation> ops = MockPrivilegedOperationCaptor
|
List<PrivilegedOperation> ops = MockPrivilegedOperationCaptor
|
||||||
@ -163,6 +165,25 @@ public class TestDockerCommandExecutor {
|
|||||||
assertEquals(MOCK_CONTAINER_ID, args.get(0));
|
assertEquals(MOCK_CONTAINER_ID, args.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExecuteDockerRmWithCgroup() throws Exception {
|
||||||
|
DockerRmCommand dockerCommand =
|
||||||
|
new DockerRmCommand(MOCK_CONTAINER_ID, MOCK_CGROUP_HIERARCHY);
|
||||||
|
DockerCommandExecutor.executeDockerCommand(dockerCommand, MOCK_CONTAINER_ID,
|
||||||
|
env, mockExecutor, false, nmContext);
|
||||||
|
List<PrivilegedOperation> ops = MockPrivilegedOperationCaptor
|
||||||
|
.capturePrivilegedOperations(mockExecutor, 1, true);
|
||||||
|
PrivilegedOperation privOp = ops.get(0);
|
||||||
|
List<String> args = privOp.getArguments();
|
||||||
|
assertEquals(1, ops.size());
|
||||||
|
assertEquals(PrivilegedOperation.OperationType.
|
||||||
|
REMOVE_DOCKER_CONTAINER.name(),
|
||||||
|
privOp.getOperationType().name());
|
||||||
|
assertEquals(2, args.size());
|
||||||
|
assertEquals(MOCK_CGROUP_HIERARCHY, args.get(0));
|
||||||
|
assertEquals(MOCK_CONTAINER_ID, args.get(1));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExecuteDockerStop() throws Exception {
|
public void testExecuteDockerStop() throws Exception {
|
||||||
DockerStopCommand dockerCommand = new DockerStopCommand(MOCK_CONTAINER_ID);
|
DockerStopCommand dockerCommand = new DockerStopCommand(MOCK_CONTAINER_ID);
|
||||||
|
@ -29,12 +29,19 @@ import org.junit.Test;
|
|||||||
public class TestDockerRmCommand {
|
public class TestDockerRmCommand {
|
||||||
|
|
||||||
private DockerRmCommand dockerRmCommand;
|
private DockerRmCommand dockerRmCommand;
|
||||||
|
private DockerRmCommand dockerRmCommandWithCgroupArg;
|
||||||
|
private DockerRmCommand dockerRmCommandWithEmptyCgroupArg;
|
||||||
|
|
||||||
private static final String CONTAINER_NAME = "foo";
|
private static final String CONTAINER_NAME = "foo";
|
||||||
|
private static final String CGROUP_HIERARCHY_NAME = "hadoop-yarn";
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
dockerRmCommand = new DockerRmCommand(CONTAINER_NAME);
|
dockerRmCommand = new DockerRmCommand(CONTAINER_NAME, null);
|
||||||
|
dockerRmCommandWithCgroupArg =
|
||||||
|
new DockerRmCommand(CONTAINER_NAME, CGROUP_HIERARCHY_NAME);
|
||||||
|
dockerRmCommandWithEmptyCgroupArg =
|
||||||
|
new DockerRmCommand(CONTAINER_NAME, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -51,4 +58,30 @@ public class TestDockerRmCommand {
|
|||||||
assertEquals(2, dockerRmCommand.getDockerCommandWithArguments().size());
|
assertEquals(2, dockerRmCommand.getDockerCommandWithArguments().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCommandWithCgroup() {
|
||||||
|
assertEquals("rm", StringUtils.join(",",
|
||||||
|
dockerRmCommandWithCgroupArg.getDockerCommandWithArguments()
|
||||||
|
.get("docker-command")));
|
||||||
|
assertEquals("foo", StringUtils.join(",",
|
||||||
|
dockerRmCommandWithCgroupArg.getDockerCommandWithArguments()
|
||||||
|
.get("name")));
|
||||||
|
assertEquals(CGROUP_HIERARCHY_NAME, StringUtils.join(",",
|
||||||
|
dockerRmCommandWithCgroupArg.getDockerCommandWithArguments()
|
||||||
|
.get("hierarchy")));
|
||||||
|
assertEquals(3,
|
||||||
|
dockerRmCommandWithCgroupArg.getDockerCommandWithArguments().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCommandWithEmptyCgroup() {
|
||||||
|
assertEquals("rm", StringUtils.join(",",
|
||||||
|
dockerRmCommandWithEmptyCgroupArg
|
||||||
|
.getDockerCommandWithArguments().get("docker-command")));
|
||||||
|
assertEquals("foo", StringUtils.join(",",
|
||||||
|
dockerRmCommandWithEmptyCgroupArg
|
||||||
|
.getDockerCommandWithArguments().get("name")));
|
||||||
|
assertEquals(2, dockerRmCommandWithEmptyCgroupArg.
|
||||||
|
getDockerCommandWithArguments().size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user