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 wa...@apache.org on 2017/09/28 23:46:00 UTC
[2/4] hadoop git commit: YARN-6623. Add support to turn off launching
privileged containers in the container-executor. (Varun Vasudev via wangda)
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d3b1c631/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
new file mode 100644
index 0000000..c627ca8
--- /dev/null
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/test/utils/test_docker_util.cc
@@ -0,0 +1,1122 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <fstream>
+#include "errno.h"
+
+extern "C" {
+#include "utils/docker-util.c"
+}
+
+namespace ContainerExecutor {
+
+ class TestDockerUtil : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ docker_command_file = "docker-command.cmd";
+ container_executor_cfg_file = "container-executor.cfg";
+ container_executor_cfg.size = 0;
+ container_executor_cfg.sections = NULL;
+ }
+
+ virtual void TearDown() {
+ remove(docker_command_file.c_str());
+ remove(container_executor_cfg_file.c_str());
+ delete_ce_file();
+ }
+
+ struct configuration container_executor_cfg;
+ std::string docker_command_file;
+ std::string container_executor_cfg_file;
+
+
+ void write_file(const std::string fname, const std::string contents) {
+ std::ofstream command_file;
+ command_file.open(fname.c_str());
+ command_file << contents;
+ command_file.close();
+ }
+
+ int create_ce_file() {
+ int ret = 0;
+ const char *fname = HADOOP_CONF_DIR "/" CONF_FILENAME;
+ if (strcmp("../etc/hadoop/container-executor.cfg", fname) == 0) {
+ ret = mkdir("../etc", 0755);
+ if (ret == 0 || errno == EEXIST) {
+ ret = mkdir("../etc/hadoop", 0755);
+ if (ret == 0 || errno == EEXIST) {
+ write_file("../etc/hadoop/container-executor.cfg", "");
+ return 0;
+ } else {
+ std::cerr << "Could not create ../etc/hadoop, " << strerror(errno) << std::endl;
+ }
+ } else {
+ std::cerr << "Could not create ../etc, " << strerror(errno) << std::endl;
+ }
+ }
+ std::cerr << "Could not create " << fname << std::endl;
+ return 1;
+ }
+
+ void delete_ce_file() {
+ const char *fname = HADOOP_CONF_DIR "/" CONF_FILENAME;
+ if (strcmp("../etc/hadoop/container-executor.cfg", fname) == 0) {
+ struct stat buffer;
+ if (stat(fname, &buffer) == 0) {
+ remove("../etc/hadoop/container-executor.cfg");
+ rmdir("../etc/hadoop");
+ rmdir("../etc");
+ }
+ }
+ }
+
+ void write_container_executor_cfg(const std::string contents) {
+ write_file(container_executor_cfg_file, contents);
+ }
+
+ void write_command_file(const std::string contents) {
+ write_file(docker_command_file, contents);
+ }
+
+ void run_docker_command_test(const std::vector<std::pair<std::string, std::string> > &file_cmd_vec,
+ const std::vector<std::pair<std::string, int> > &bad_file_cmd_vec,
+ int (*docker_func)(const char *, const struct configuration *, char *, const size_t)) {
+ char tmp[8192];
+ std::vector<std::pair<std::string, std::string> >::const_iterator itr;
+ for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
+ memset(tmp, 0, 8192);
+ write_command_file(itr->first);
+ int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, tmp, 8192);
+ ASSERT_EQ(0, ret) << "error message: " << get_docker_error_message(ret) << " for input " << itr->first;
+ ASSERT_STREQ(itr->second.c_str(), tmp);
+ }
+
+ std::vector<std::pair<std::string, int> >::const_iterator itr2;
+ for (itr2 = bad_file_cmd_vec.begin(); itr2 != bad_file_cmd_vec.end(); ++itr2) {
+ memset(tmp, 0, 8192);
+ write_command_file(itr2->first);
+ int ret = (*docker_func)(docker_command_file.c_str(), &container_executor_cfg, tmp, 8192);
+ ASSERT_EQ(itr2->second, ret) << " for " << itr2->first << std::endl;
+ ASSERT_EQ(0, strlen(tmp));
+ }
+ int ret = (*docker_func)("unknown-file", &container_executor_cfg, tmp, 8192);
+ ASSERT_EQ(static_cast<int>(INVALID_COMMAND_FILE), ret);
+ }
+
+ void run_docker_run_helper_function(const std::vector<std::pair<std::string, std::string> > &file_cmd_vec,
+ int (*helper_func)(const struct configuration *, char *, const size_t)) {
+ std::vector<std::pair<std::string, std::string> >::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];
+ 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);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+ }
+ }
+ };
+
+ TEST_F(TestDockerUtil, test_docker_inspect) {
+ 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=inspect\n format={{.State.Status}}\n name=container_e1_12312_11111_02_000001",
+ "inspect --format={{.State.Status}} container_e1_12312_11111_02_000001"));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[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"));
+
+ 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=run\n format='{{.State.Status}}'",
+ static_cast<int>(INCORRECT_COMMAND)));
+ bad_file_cmd_vec.push_back(
+ std::make_pair<std::string, int>("docker-command=inspect\n format='{{.State.Status}}'",
+ static_cast<int>(INCORRECT_COMMAND)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=inspect\n format={{.State.Status}}\n name=",
+ static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=inspect\n format={{.State.Status}}",
+ static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=inspect\n format=\n name=container_e1_12312_11111_02_000001",
+ static_cast<int>(INVALID_DOCKER_INSPECT_FORMAT)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=inspect\n name=container_e1_12312_11111_02_000001",
+ static_cast<int>(INVALID_DOCKER_INSPECT_FORMAT)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=inspect\n format={{.IPAddress}}\n name=container_e1_12312_11111_02_000001",
+ static_cast<int>(INVALID_DOCKER_INSPECT_FORMAT)));
+
+ run_docker_command_test(file_cmd_vec, bad_file_cmd_vec, get_docker_inspect_command);
+ }
+
+ TEST_F(TestDockerUtil, test_docker_load) {
+ 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=load\n image=image-id",
+ "load --i='image-id' "));
+
+ 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=run\n image=image-id", static_cast<int>(INCORRECT_COMMAND)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "docker-command=load\n image=image-id", static_cast<int>(INCORRECT_COMMAND)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=load\n image=", static_cast<int>(INVALID_DOCKER_IMAGE_NAME)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>("[docker-command-execution]\n docker-command=load",
+ static_cast<int>(INVALID_DOCKER_IMAGE_NAME)));
+
+ run_docker_command_test(file_cmd_vec, bad_file_cmd_vec, get_docker_load_command);
+ }
+
+ TEST_F(TestDockerUtil, test_docker_validate_image_name) {
+ const char *good_input[] = {
+ "ubuntu",
+ "ubuntu:latest",
+ "ubuntu:14.04",
+ "ubuntu:LATEST",
+ "registry.com:5000/user/ubuntu",
+ "registry.com:5000/user/ubuntu:latest",
+ "registry.com:5000/user/ubuntu:0.1.2.3",
+ "registry.com/user/ubuntu",
+ "registry.com/user/ubuntu:latest",
+ "registry.com/user/ubuntu:0.1.2.3",
+ "registry.com/user/ubuntu:test-image",
+ "registry.com/user/ubuntu:test_image",
+ "registry.com/ubuntu",
+ "user/ubuntu",
+ "user/ubuntu:0.1.2.3",
+ "user/ubuntu:latest",
+ "user/ubuntu:test_image",
+ "user/ubuntu.test:test_image",
+ "user/ubuntu-test:test-image",
+ "registry.com/ubuntu/ubuntu/ubuntu"
+ };
+
+ const char *bad_input[] = {
+ "UBUNTU",
+ "registry.com|5000/user/ubuntu",
+ "registry.com | 5000/user/ubuntu",
+ "ubuntu' || touch /tmp/file #",
+ "ubuntu || touch /tmp/file #",
+ "''''''''",
+ "bad_host_name:5000/user/ubuntu",
+ "registry.com:foo/ubuntu/ubuntu/ubuntu",
+ "registry.com/ubuntu:foo/ubuntu/ubuntu"
+ };
+
+ int good_input_size = sizeof(good_input) / sizeof(char *);
+ int i = 0;
+ for (i = 0; i < good_input_size; i++) {
+ int op = validate_docker_image_name(good_input[i]);
+ ASSERT_EQ(0, op);
+ }
+
+ int bad_input_size = sizeof(bad_input) / sizeof(char *);
+ int j = 0;
+ for (j = 0; j < bad_input_size; j++) {
+ int op = validate_docker_image_name(bad_input[j]);
+ ASSERT_EQ(1, op);
+ }
+ }
+
+ TEST_F(TestDockerUtil, test_docker_pull) {
+ 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=pull\n image=image-id",
+ "pull 'image-id' "));
+
+ 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=run\n image=image-id", static_cast<int>(INCORRECT_COMMAND)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "docker-command=pull\n image=image-id", static_cast<int>(INCORRECT_COMMAND)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=pull\n image=", static_cast<int>(INVALID_DOCKER_IMAGE_NAME)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>("[docker-command-execution]\n docker-command=pull",
+ static_cast<int>(INVALID_DOCKER_IMAGE_NAME)));
+
+ run_docker_command_test(file_cmd_vec, bad_file_cmd_vec, get_docker_pull_command);
+ }
+
+ TEST_F(TestDockerUtil, test_docker_rm) {
+ 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=rm\n name=container_e1_12312_11111_02_000001",
+ "rm container_e1_12312_11111_02_000001"));
+
+ 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=run\n name=container_e1_12312_11111_02_000001",
+ static_cast<int>(INCORRECT_COMMAND)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "docker-command=rm\n name=ctr-id", static_cast<int>(INCORRECT_COMMAND)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=rm\n name=", static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=rm", static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
+
+ run_docker_command_test(file_cmd_vec, bad_file_cmd_vec, get_docker_rm_command);
+ }
+
+ TEST_F(TestDockerUtil, test_docker_stop) {
+ 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=stop\n name=container_e1_12312_11111_02_000001",
+ "stop container_e1_12312_11111_02_000001"));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[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"));
+
+ 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=run\n name=container_e1_12312_11111_02_000001",
+ static_cast<int>(INCORRECT_COMMAND)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "docker-command=stop\n name=ctr-id", static_cast<int>(INCORRECT_COMMAND)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=stop\n name=", static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=stop", static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=stop\n name=container_e1_12312_11111_02_000001\n time=abcd",
+ static_cast<int>(INVALID_DOCKER_STOP_COMMAND)));
+
+
+ run_docker_command_test(file_cmd_vec, bad_file_cmd_vec, get_docker_stop_command);
+ }
+
+ TEST_F(TestDockerUtil, test_detach_container) {
+ 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=run\n detach=true", "-d "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run", ""));
+
+ run_docker_run_helper_function(file_cmd_vec, detach_container);
+ }
+
+ TEST_F(TestDockerUtil, test_rm_container) {
+ 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=run\n rm=true", "--rm "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run", ""));
+
+ run_docker_run_helper_function(file_cmd_vec, rm_container_on_exit);
+ }
+
+ TEST_F(TestDockerUtil, test_set_container_workdir) {
+ 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=run\n workdir=/tmp/test", "--workdir='/tmp/test' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run", ""));
+
+ run_docker_run_helper_function(file_cmd_vec, set_container_workdir);
+ }
+
+ TEST_F(TestDockerUtil, test_set_cgroup_parent) {
+ 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=run\n cgroup-parent=/sys/fs/cgroup/yarn",
+ "--cgroup-parent='/sys/fs/cgroup/yarn' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run", ""));
+
+ run_docker_run_helper_function(file_cmd_vec, set_cgroup_parent);
+ }
+
+ TEST_F(TestDockerUtil, test_set_hostname) {
+ 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=run\n hostname=ctr-id", "--hostname='ctr-id' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run", ""));
+
+ run_docker_run_helper_function(file_cmd_vec, set_hostname);
+ }
+
+ TEST_F(TestDockerUtil, test_set_group_add) {
+ 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=run\n group-add=1000,1001", "--group-add '1000' --group-add '1001' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run", ""));
+
+ run_docker_run_helper_function(file_cmd_vec, set_group_add);
+ }
+
+ TEST_F(TestDockerUtil, test_set_network) {
+ struct configuration container_cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ int ret = 0;
+ std::string container_executor_cfg_contents = "[docker]\n docker.allowed.networks=sdn1,bridge";
+ 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=run\n net=bridge", "--net='bridge' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n net=sdn1", "--net='sdn1' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run", ""));
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+
+ std::vector<std::pair<std::string, std::string> >::const_iterator itr;
+ if (ret != 0) {
+ FAIL();
+ }
+ for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
+ struct configuration cmd_cfg;
+ 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_network(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+ struct configuration cmd_cfg_1;
+ write_command_file("[docker-command-execution]\n docker-command=run\n net=sdn2");
+ ret = read_config(docker_command_file.c_str(), &cmd_cfg_1);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = set_network(&cmd_cfg_1, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_NETWORK, ret);
+ ASSERT_EQ(0, strlen(buff));
+
+ container_executor_cfg_contents = "[docker]\n";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = set_network(&cmd_cfg_1, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_NETWORK, ret);
+ ASSERT_EQ(0, strlen(buff));
+ }
+
+ TEST_F(TestDockerUtil, test_check_mount_permitted) {
+ const char *permitted_mounts[] = {"/usr/", "/bin/ls", NULL};
+ std::vector<std::pair<std::string, int> > test_data;
+ test_data.push_back(std::make_pair<std::string, int>("/usr", 1));
+ test_data.push_back(std::make_pair<std::string, int>("/usr/", 1));
+ test_data.push_back(std::make_pair<std::string, int>("/bin/ls", 1));
+ test_data.push_back(std::make_pair<std::string, int>("//bin/", 0));
+ test_data.push_back(std::make_pair<std::string, int>("/tmp/random-file", -1));
+
+ std::vector<std::pair<std::string, int> >::const_iterator itr;
+ for (itr = test_data.begin(); itr != test_data.end(); ++itr) {
+ int ret = check_mount_permitted(permitted_mounts, itr->first.c_str());
+ ASSERT_EQ(itr->second, ret) << "for input " << itr->first;
+ }
+ }
+
+ TEST_F(TestDockerUtil, test_normalize_mounts) {
+ const int entries = 4;
+ const char *permitted_mounts[] = {"/home", "/usr", "/bin/ls", NULL};
+ const char *expected[] = {"/home/", "/usr/", "/bin/ls", NULL};
+ char **ptr = static_cast<char **>(malloc(entries * sizeof(char *)));
+ for (int i = 0; i < entries; ++i) {
+ if (permitted_mounts[i] != NULL) {
+ ptr[i] = strdup(permitted_mounts[i]);
+ } else {
+ ptr[i] = NULL;
+ }
+ }
+ normalize_mounts(ptr);
+ for (int i = 0; i < entries; ++i) {
+ ASSERT_STREQ(expected[i], ptr[i]);
+ }
+ }
+
+ TEST_F(TestDockerUtil, test_set_privileged) {
+ struct configuration container_cfg, cmd_cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ int ret = 0;
+ std::string container_executor_cfg_contents[] = {"[docker]\n docker.privileged-containers.enabled=1",
+ "[docker]\n docker.privileged-containers.enabled=0",
+ "[docker]\n"};
+ 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=run\n privileged=true", "--privileged "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n privileged=false", ""));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run", ""));
+ write_container_executor_cfg(container_executor_cfg_contents[0]);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+
+ std::vector<std::pair<std::string, std::string> >::const_iterator itr;
+ if (ret != 0) {
+ FAIL();
+ }
+ for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
+ 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);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+
+ // check default case and when it's turned off
+ for (int i = 1; i < 3; ++i) {
+ write_container_executor_cfg(container_executor_cfg_contents[i]);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ file_cmd_vec.clear();
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n privileged=false", ""));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run", ""));
+ for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
+ 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);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+ write_command_file("[docker-command-execution]\n docker-command=run\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);
+ ASSERT_EQ(PRIVILEGED_CONTAINERS_DISABLED, ret);
+ ASSERT_EQ(0, strlen(buff));
+ }
+ }
+
+ TEST_F(TestDockerUtil, test_set_capabilities) {
+ struct configuration container_cfg, cmd_cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ int ret = 0;
+ std::string container_executor_cfg_contents = "[docker]\n docker.allowed.capabilities=CHROOT,MKNOD";
+ 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=run\n cap-add=CHROOT,MKNOD",
+ "--cap-drop='ALL' --cap-add='CHROOT' --cap-add='MKNOD' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n cap-add=CHROOT", "--cap-drop='ALL' --cap-add='CHROOT' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run", "--cap-drop='ALL' "));
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+
+ std::vector<std::pair<std::string, std::string> >::const_iterator itr;
+ if (ret != 0) {
+ FAIL();
+ }
+ for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
+ 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);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+ write_command_file("[docker-command-execution]\n docker-command=run\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);
+ ASSERT_EQ(INVALID_DOCKER_CAPABILITY, ret);
+ ASSERT_EQ(0, strlen(buff));
+
+ container_executor_cfg_contents = "[docker]\n";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = set_capabilities(&cmd_cfg, &container_cfg, buff, buff_len);
+ 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];
+ int ret = 0;
+ std::string container_executor_cfg_contents = "[docker]\n docker.allowed.devices=/dev/test-device,/dev/device2";
+ 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=run\n devices=/dev/test-device:/dev/test-device",
+ "--device='/dev/test-device:/dev/test-device' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n devices=/dev/device2:/dev/device2",
+ "--device='/dev/device2:/dev/device2' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n "
+ "devices=/dev/test-device:/dev/test-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<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n", ""));
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+
+ std::vector<std::pair<std::string, std::string> >::const_iterator itr;
+ if (ret != 0) {
+ FAIL();
+ }
+ for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
+ 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_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+ write_command_file("[docker-command-execution]\n docker-command=run\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);
+ ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
+ ASSERT_EQ(0, strlen(buff));
+
+ write_command_file("[docker-command-execution]\n docker-command=run\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);
+ ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
+ ASSERT_EQ(0, strlen(buff));
+
+ container_executor_cfg_contents = "[docker]\n";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = set_devices(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_DEVICE, ret);
+ ASSERT_EQ(0, strlen(buff));
+ }
+
+
+ TEST_F(TestDockerUtil, test_add_rw_mounts) {
+ struct configuration container_cfg, cmd_cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ int ret = 0;
+ std::string container_executor_cfg_contents = "[docker]\n docker.allowed.rw-mounts=/usr,/var,/bin/ls,..\n "
+ "docker.allowed.ro-mounts=/bin/cat";
+ 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=run\n rw-mounts=/var:/var", "-v '/var:/var' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n rw-mounts=/var/:/var/", "-v '/var/:/var/' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n rw-mounts=/usr:/usr", "-v '/usr:/usr' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n rw-mounts=/usr/:/usr", "-v '/usr/:/usr' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n rw-mounts=/bin/ls:/bin/ls", "-v '/bin/ls:/bin/ls' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n rw-mounts=/usr/bin:/mydisk1,/var/log/:/mydisk2",
+ "-v '/usr/bin:/mydisk1' -v '/var/log/:/mydisk2' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n", ""));
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_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> >::const_iterator itr;
+
+ for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
+ 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 = add_rw_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+
+ std::vector<std::pair<std::string, int> > bad_file_cmds_vec;
+ bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=run\n rw-mounts=/home:/home",
+ static_cast<int>(INVALID_DOCKER_RW_MOUNT)));
+ bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=run\n rw-mounts=/bin/cat:/bin/cat",
+ static_cast<int>(INVALID_DOCKER_RW_MOUNT)));
+ bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=run\n rw-mounts=/blah:/blah",
+ static_cast<int>(INVALID_DOCKER_MOUNT)));
+
+ std::vector<std::pair<std::string, int> >::const_iterator itr2;
+
+ for (itr2 = bad_file_cmds_vec.begin(); itr2 != bad_file_cmds_vec.end(); ++itr2) {
+ memset(buff, 0, buff_len);
+ 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);
+ ASSERT_EQ(itr2->second, ret);
+ ASSERT_STREQ("", buff);
+ }
+
+ // verify that you can't mount any directory in the container-executor.cfg path
+ char *ce_path = realpath("../etc/hadoop/container-executor.cfg", NULL);
+ while (strlen(ce_path) != 0) {
+ std::string cmd_file_contents = "[docker-command-execution]\n docker-command=run\n rw-mounts=";
+ cmd_file_contents.append(ce_path).append(":").append("/etc/hadoop");
+ memset(buff, 0, buff_len);
+ 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);
+ ASSERT_EQ(INVALID_DOCKER_RW_MOUNT, ret) << " for input " << cmd_file_contents;
+ ASSERT_STREQ("", buff);
+ char *tmp = strrchr(ce_path, '/');
+ if (tmp != NULL) {
+ *tmp = '\0';
+ }
+ }
+ free(ce_path);
+
+ container_executor_cfg_contents = "[docker]\n";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ strcpy(buff, "test string");
+ ret = add_rw_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_RW_MOUNT, ret);
+ ASSERT_EQ(0, strlen(buff));
+ }
+
+ TEST_F(TestDockerUtil, test_add_ro_mounts) {
+ struct configuration container_cfg, cmd_cfg;
+ const int buff_len = 1024;
+ char buff[buff_len];
+ int ret = 0;
+ std::string container_executor_cfg_contents = "[docker]\n docker.allowed.rw-mounts=/usr,/var,/bin/ls\n "
+ "docker.allowed.ro-mounts=/bin/cat,/bin/ln";
+ 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=run\n ro-mounts=/var:/var", "-v '/var:/var:ro' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n ro-mounts=/var/:/var/", "-v '/var/:/var/:ro' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n ro-mounts=/usr:/usr", "-v '/usr:/usr:ro' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n ro-mounts=/usr/:/usr", "-v '/usr/:/usr:ro' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n ro-mounts=/bin/ls:/bin/ls", "-v '/bin/ls:/bin/ls:ro' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n ro-mounts=/bin/ln:/bin/ln", "-v '/bin/ln:/bin/ln:ro' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n ro-mounts=/bin/cat:/bin/cat",
+ "-v '/bin/cat:/bin/cat:ro' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n ro-mounts=/usr/bin:/mydisk1,/bin/cat:/bin/cat",
+ "-v '/usr/bin:/mydisk1:ro' -v '/bin/cat:/bin/cat:ro' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n", ""));
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_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> >::const_iterator itr;
+
+ for (itr = file_cmd_vec.begin(); itr != file_cmd_vec.end(); ++itr) {
+ 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 = add_ro_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(0, ret);
+ ASSERT_STREQ(itr->second.c_str(), buff);
+ }
+
+ std::vector<std::pair<std::string, int> > bad_file_cmds_vec;
+ bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=run\n ro-mounts=/home:/home",
+ static_cast<int>(INVALID_DOCKER_RO_MOUNT)));
+ bad_file_cmds_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=run\n ro-mounts=/blah:/blah",
+ static_cast<int>(INVALID_DOCKER_MOUNT)));
+
+ std::vector<std::pair<std::string, int> >::const_iterator itr2;
+
+ for (itr2 = bad_file_cmds_vec.begin(); itr2 != bad_file_cmds_vec.end(); ++itr2) {
+ memset(buff, 0, buff_len);
+ 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);
+ ASSERT_EQ(itr2->second, ret);
+ ASSERT_STREQ("", buff);
+ }
+
+ container_executor_cfg_contents = "[docker]\n";
+ write_container_executor_cfg(container_executor_cfg_contents);
+ ret = read_config(container_executor_cfg_file.c_str(), &container_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ write_command_file("[docker-command-execution]\n docker-command=run\n ro-mounts=/home:/home");
+ strcpy(buff, "test string");
+ ret = add_ro_mounts(&cmd_cfg, &container_cfg, buff, buff_len);
+ ASSERT_EQ(INVALID_DOCKER_RO_MOUNT, ret);
+ ASSERT_EQ(0, strlen(buff));
+ }
+
+ TEST_F(TestDockerUtil, test_docker_run_privileged) {
+
+ std::string container_executor_contents = "[docker]\n docker.allowed.ro-mounts=/var,/etc,/bin/ls\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";
+ 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=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test",
+ "run --name='container_e1_12312_11111_02_000001' --user='test' --cap-drop='ALL' 'docker-image' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n"
+ " launch-command=bash,test_script.sh,arg1,arg2",
+ "run --name='container_e1_12312_11111_02_000001' --user='test' --cap-drop='ALL' 'docker-image' 'bash' 'test_script.sh' 'arg1' 'arg2' "));
+
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n"
+ " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2",
+ "run --name='container_e1_12312_11111_02_000001' --user='test' -d --rm -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
+ " -v '/bin/ls:/bin/ls: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' 'docker-image' 'bash' "
+ "'test_script.sh' 'arg1' 'arg2' "));
+
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n"
+ " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n net=bridge\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2",
+ "run --name='container_e1_12312_11111_02_000001' --user='test' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
+ " -v '/bin/ls:/bin/ls: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' 'docker-image' 'bash'"
+ " 'test_script.sh' 'arg1' 'arg2' "));
+
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n"
+ " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " 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' --user='test' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
+ " -v '/bin/ls:/bin/ls: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' 'docker-image' "
+ "'bash' 'test_script.sh' 'arg1' 'arg2' "));
+
+
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n"
+ " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " 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' --user='test' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
+ " -v '/bin/ls:/bin/ls:ro' -v '/tmp:/tmp' --cgroup-parent='ctr-cgroup' --privileged --cap-drop='ALL' "
+ "--cap-add='CHOWN' --cap-add='SETUID' --hostname='host-id' --group-add '1000' --group-add '1001' "
+ "--device='/dev/test:/dev/test' 'docker-image' 'bash' 'test_script.sh' 'arg1' 'arg2' "));
+
+
+ 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=run\n image=docker-image\n user=test",
+ static_cast<int>(INVALID_DOCKER_CONTAINER_NAME)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=run\n name=container_e1_12312_11111_02_000001\n user=test\n",
+ static_cast<int>(INVALID_DOCKER_IMAGE_NAME)));
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n",
+ static_cast<int>(INVALID_DOCKER_USER_NAME)));
+
+ // invalid rw mount
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n"
+ " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/var/log:/var/log\n"
+ " 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",
+ static_cast<int>(INVALID_DOCKER_RW_MOUNT)));
+
+ // invalid ro mount
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n"
+ " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/bin:/bin,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " 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",
+ static_cast<int>(INVALID_DOCKER_RO_MOUNT)));
+
+ // invalid capability
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n"
+ " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n"
+ " cap-add=CHOWN,SETUID,SETGID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2",
+ static_cast<int>(INVALID_DOCKER_CAPABILITY)));
+
+ // invalid device
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n"
+ " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/dev1:/dev/dev1\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",
+ static_cast<int>(INVALID_DOCKER_DEVICE)));
+
+ // invalid network
+ bad_file_cmd_vec.push_back(std::make_pair<std::string, int>(
+ "[docker-command-execution]\n"
+ " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n privileged=true\n net=host\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",
+ static_cast<int>(INVALID_DOCKER_NETWORK)));
+
+ 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,/bin/ls\n"
+ " docker.allowed.rw-mounts=/tmp\n docker.allowed.networks=bridge\n "
+ " docker.allowed.capabilities=CHOWN,SETUID\n"
+ " docker.allowed.devices=/dev/test",
+ "[docker]\n docker.allowed.ro-mounts=/var,/etc,/bin/ls\n"
+ " docker.allowed.rw-mounts=/tmp\n docker.allowed.networks=bridge\n "
+ " docker.allowed.capabilities=CHOWN,SETUID\n"
+ " privileged=0\n"
+ " docker.allowed.devices=/dev/test"};
+ for (int i = 0; i < 2; ++i) {
+ write_file(container_executor_cfg_file, container_executor_contents[i]);
+ 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=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test",
+ "run --name='container_e1_12312_11111_02_000001' --user='test' --cap-drop='ALL' 'docker-image' "));
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n"
+ " user=test\n launch-command=bash,test_script.sh,arg1,arg2",
+ "run --name='container_e1_12312_11111_02_000001' --user='test' --cap-drop='ALL' 'docker-image' 'bash' 'test_script.sh' 'arg1' 'arg2' "));
+
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n"
+ " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2",
+ "run --name='container_e1_12312_11111_02_000001' --user='test' -d --rm -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
+ " -v '/bin/ls:/bin/ls: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' 'docker-image' 'bash' "
+ "'test_script.sh' 'arg1' 'arg2' "));
+
+ file_cmd_vec.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n"
+ " docker-command=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " network=bridge\n devices=/dev/test:/dev/test\n net=bridge\n"
+ " cap-add=CHOWN,SETUID\n cgroup-parent=ctr-cgroup\n detach=true\n rm=true\n"
+ " launch-command=bash,test_script.sh,arg1,arg2",
+ "run --name='container_e1_12312_11111_02_000001' --user='test' -d --rm --net='bridge' -v '/var/log:/var/log:ro' -v '/var/lib:/lib:ro'"
+ " -v '/bin/ls:/bin/ls: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' 'docker-image' 'bash'"
+ " 'test_script.sh' 'arg1' 'arg2' "));
+
+ 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=run\n name=container_e1_12312_11111_02_000001\n image=docker-image\n user=test\n hostname=host-id\n"
+ " ro-mounts=/var/log:/var/log,/var/lib:/lib,/bin/ls:/bin/ls\n rw-mounts=/tmp:/tmp\n"
+ " 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",
+ static_cast<int>(PRIVILEGED_CONTAINERS_DISABLED)));
+
+ run_docker_command_test(file_cmd_vec, bad_file_cmd_vec, get_docker_run_command);
+ }
+ }
+
+ TEST_F(TestDockerUtil, test_docker_config_param) {
+ std::vector<std::pair<std::string, std::string> > input_output_map;
+ input_output_map.push_back(std::make_pair<std::string, std::string>(
+ "[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"));
+ input_output_map.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=load\n docker-config=/my-config\n image=image-id",
+ "--config='/my-config' load --i='image-id' "));
+ input_output_map.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=pull\n docker-config=/my-config\n image=image-id",
+ "--config='/my-config' pull 'image-id' "));
+ input_output_map.push_back(std::make_pair<std::string, std::string>(
+ "[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"));
+ input_output_map.push_back(std::make_pair<std::string, std::string>(
+ "[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"));
+ input_output_map.push_back(std::make_pair<std::string, std::string>(
+ "[docker-command-execution]\n docker-command=run\n docker-config=/my-config\n name=container_e1_12312_11111_02_000001\n"
+ " image=docker-image\n user=test",
+ "--config='/my-config' run --name='container_e1_12312_11111_02_000001' --user='test' --cap-drop='ALL' 'docker-image' "));
+
+ std::vector<std::pair<std::string, std::string> >::const_iterator itr;
+ char buffer[4096];
+ struct configuration cfg = {0, NULL};
+ for (itr = input_output_map.begin(); itr != input_output_map.end(); ++itr) {
+ memset(buffer, 0, 4096);
+ write_command_file(itr->first);
+ int ret = get_docker_command(docker_command_file.c_str(), &cfg, buffer, 4096);
+ ASSERT_EQ(0, ret) << "for input " << itr->first;
+ ASSERT_STREQ(itr->second.c_str(), buffer);
+ }
+ }
+
+ TEST_F(TestDockerUtil, test_docker_module_enabled) {
+
+ std::vector<std::pair<std::string, int> > input_out_vec;
+ input_out_vec.push_back(std::make_pair<std::string, int>("[docker]\n module.enabled=true", 1));
+ input_out_vec.push_back(std::make_pair<std::string, int>("[docker]\n module.enabled=false", 0));
+ input_out_vec.push_back(std::make_pair<std::string, int>("[docker]\n module.enabled=1", 0));
+ input_out_vec.push_back(std::make_pair<std::string, int>("[docker]\n", 0));
+
+ for (size_t i = 0; i < input_out_vec.size(); ++i) {
+ write_file(container_executor_cfg_file, input_out_vec[i].first);
+ int ret = read_config(container_executor_cfg_file.c_str(), &container_executor_cfg);
+ if (ret != 0) {
+ FAIL();
+ }
+ ret = docker_module_enabled(&container_executor_cfg);
+ ASSERT_EQ(input_out_vec[i].second, ret) << " incorrect output for "
+ << input_out_vec[i].first;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/hadoop/blob/d3b1c631/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java
----------------------------------------------------------------------
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java
index e548790..fbfee54 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/runtime/TestDockerContainerRuntime.java
@@ -295,32 +295,37 @@ public class TestDockerContainerRuntime {
List<String> args = op.getArguments();
String dockerCommandFile = args.get(11);
- //This is the expected docker invocation for this case
- StringBuffer expectedCommandTemplate = new StringBuffer("run --name=%1$s ")
- .append("--user=%2$s -d ")
- .append("--workdir=%3$s ")
- .append("--net=host ")
- .append("--hostname=" + defaultHostname + " ")
- .append(getExpectedTestCapabilitiesArgumentString())
- .append(getExpectedCGroupsMountString())
- .append("-v %4$s:%4$s ")
- .append("-v %5$s:%5$s ")
- .append("-v %6$s:%6$s ")
- .append("-v %7$s:%7$s ")
- .append("-v %8$s:%8$s ").append("%9$s ")
- .append("bash %10$s/launch_container.sh");
-
- String expectedCommand = String
- .format(expectedCommandTemplate.toString(), containerId, runAsUser,
- containerWorkDir, containerLocalDirs.get(0), filecacheDirs.get(0),
- containerWorkDir, containerLogDirs.get(0), userLocalDirs.get(0),
- image, containerWorkDir);
-
List<String> dockerCommands = Files.readAllLines(Paths.get
(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals(expectedCommand, dockerCommands.get(0));
+ int expected = 13;
+ int counter = 0;
+ Assert.assertEquals(expected, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(counter++));
+ Assert.assertEquals(" detach=true", dockerCommands.get(counter++));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(counter++));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" image=busybox:latest", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(counter++));
+ Assert.assertEquals(" net=host", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(counter++));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(counter++));
}
@Test
@@ -347,10 +352,13 @@ public class TestDockerContainerRuntime {
String uid = "";
String gid = "";
+ String[] groups = {};
Shell.ShellCommandExecutor shexec1 = new Shell.ShellCommandExecutor(
new String[]{"id", "-u", runAsUser});
Shell.ShellCommandExecutor shexec2 = new Shell.ShellCommandExecutor(
new String[]{"id", "-g", runAsUser});
+ Shell.ShellCommandExecutor shexec3 = new Shell.ShellCommandExecutor(
+ new String[]{"id", "-G", runAsUser});
try {
shexec1.execute();
// get rid of newline at the end
@@ -365,37 +373,48 @@ public class TestDockerContainerRuntime {
} catch (Exception e) {
LOG.info("Could not run id -g command: " + e);
}
+ try {
+ shexec3.execute();
+ groups = shexec3.getOutput().replace("\n", " ").split(" ");
+ } catch (Exception e) {
+ LOG.info("Could not run id -G command: " + e);
+ }
uidGidPair = uid + ":" + gid;
- //This is the expected docker invocation for this case
- StringBuffer expectedCommandTemplate = new StringBuffer("run --name=%1$s ")
- .append("--user=%2$s -d ")
- .append("--workdir=%3$s ")
- .append("--net=host ")
- .append("--hostname=" + defaultHostname + " ")
- .append(getExpectedTestCapabilitiesArgumentString())
- .append(getExpectedCGroupsMountString())
- .append("-v %4$s:%4$s ")
- .append("-v %5$s:%5$s ")
- .append("-v %6$s:%6$s ")
- .append("-v %7$s:%7$s ")
- .append("-v %8$s:%8$s ")
- .append("(--group-add \\d+ )*")
- .append("%9$s ")
- .append("bash %10$s/launch_container.sh");
-
- String expectedCommand = String
- .format(expectedCommandTemplate.toString(), containerId, uidGidPair,
- containerWorkDir, containerLocalDirs.get(0), filecacheDirs.get(0),
- containerWorkDir, containerLogDirs.get(0), userLocalDirs.get(0),
- image, containerWorkDir);
-
List<String> dockerCommands = Files.readAllLines(
Paths.get(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
- //Assert.assertEquals(expectedCommand, dockerCommands.get(0));
- Assert.assertTrue(dockerCommands.get(0).matches(expectedCommand));
+ Assert.assertEquals(14, dockerCommands.size());
+ int counter = 0;
+ Assert.assertEquals("[docker-command-execution]",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(counter++));
+ Assert.assertEquals(" detach=true", dockerCommands.get(counter++));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(counter++));
+ Assert.assertEquals(" group-add=" + String.join(",", groups),
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" hostname=ctr-id",
+ dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" image=busybox:latest", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" net=host", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" user=" + uidGidPair, dockerCommands.get(counter++));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(counter++));
}
@Test
@@ -481,29 +500,38 @@ public class TestDockerContainerRuntime {
String dockerCommandFile = args.get(11);
//This is the expected docker invocation for this case
- StringBuffer expectedCommandTemplate =
- new StringBuffer("run --name=%1$s ").append("--user=%2$s -d ")
- .append("--workdir=%3$s ")
- .append("--net=" + allowedNetwork + " ")
- .append("--hostname=" + expectedHostname + " ")
- .append(getExpectedTestCapabilitiesArgumentString())
- .append(getExpectedCGroupsMountString())
- .append("-v %4$s:%4$s ").append("-v %5$s:%5$s ")
- .append("-v %6$s:%6$s ").append("-v %7$s:%7$s ")
- .append("-v %8$s:%8$s ").append("%9$s ")
- .append("bash %10$s/launch_container.sh");
-
- String expectedCommand = String
- .format(expectedCommandTemplate.toString(), containerId, runAsUser,
- containerWorkDir, containerLocalDirs.get(0), filecacheDirs.get(0),
- containerWorkDir, containerLogDirs.get(0), userLocalDirs.get(0),
- image, containerWorkDir);
-
List<String> dockerCommands = Files
.readAllLines(Paths.get(dockerCommandFile), Charset.forName("UTF-8"));
-
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals(expectedCommand, dockerCommands.get(0));
+ int expected = 13;
+ int counter = 0;
+ Assert.assertEquals(expected, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(counter++));
+ Assert.assertEquals(" detach=true", dockerCommands.get(counter++));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(counter++));
+ Assert.assertEquals(" hostname=test.hostname",
+ dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" image=busybox:latest", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" net=" + allowedNetwork, dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(counter++));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(counter++));
}
@Test
@@ -537,30 +565,37 @@ public class TestDockerContainerRuntime {
//This is the expected docker invocation for this case. customNetwork1
// ("sdn1") is the expected network to be used in this case
- StringBuffer expectedCommandTemplate =
- new StringBuffer("run --name=%1$s ").append("--user=%2$s -d ")
- .append("--workdir=%3$s ")
- .append("--net=" + customNetwork1 + " ")
- .append("--hostname=" + defaultHostname + " ")
- .append(getExpectedTestCapabilitiesArgumentString())
- .append(getExpectedCGroupsMountString())
- .append("-v %4$s:%4$s ").append("-v %5$s:%5$s ")
- .append("-v %6$s:%6$s ").append("-v %7$s:%7$s ")
- .append("-v %8$s:%8$s ").append("%9$s ")
- .append("bash %10$s/launch_container.sh");
-
- String expectedCommand = String
- .format(expectedCommandTemplate.toString(), containerId, runAsUser,
- containerWorkDir, containerLocalDirs.get(0), filecacheDirs.get(0),
- containerWorkDir, containerLogDirs.get(0), userLocalDirs.get(0),
- image, containerWorkDir);
-
List<String> dockerCommands = Files
.readAllLines(Paths.get(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals(expectedCommand, dockerCommands.get(0));
-
+ int expected = 13;
+ int counter = 0;
+ Assert.assertEquals(expected, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(counter++));
+ Assert.assertEquals(" detach=true", dockerCommands.get(counter++));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(counter++));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" image=busybox:latest", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(counter++));
+ Assert.assertEquals(" net=sdn1", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(counter++));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(counter++));
//now set an explicit (non-default) allowedNetwork and ensure that it is
// used.
@@ -575,28 +610,37 @@ public class TestDockerContainerRuntime {
//This is the expected docker invocation for this case. customNetwork2
// ("sdn2") is the expected network to be used in this case
- expectedCommandTemplate =
- new StringBuffer("run --name=%1$s ").append("--user=%2$s -d ")
- .append("--workdir=%3$s ")
- .append("--net=" + customNetwork2 + " ")
- .append("--hostname=" + defaultHostname + " ")
- .append(getExpectedTestCapabilitiesArgumentString())
- .append(getExpectedCGroupsMountString())
- .append("-v %4$s:%4$s ").append("-v %5$s:%5$s ")
- .append("-v %6$s:%6$s ").append("-v %7$s:%7$s ")
- .append("-v %8$s:%8$s ").append("%9$s ")
- .append("bash %10$s/launch_container.sh");
-
- expectedCommand = String
- .format(expectedCommandTemplate.toString(), containerId, runAsUser,
- containerWorkDir, containerLocalDirs.get(0), filecacheDirs.get(0),
- containerWorkDir, containerLogDirs.get(0), userLocalDirs.get(0),
- image, containerWorkDir);
dockerCommands = Files
.readAllLines(Paths.get(dockerCommandFile), Charset.forName("UTF-8"));
+ counter = 0;
+ Assert.assertEquals(expected, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(counter++));
+ Assert.assertEquals(" detach=true", dockerCommands.get(counter++));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(counter++));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" image=busybox:latest", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(counter++));
+
+ Assert.assertEquals(" name=container_id", dockerCommands.get(counter++));
+ Assert.assertEquals(" net=sdn2", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(counter++));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(counter++));
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals(expectedCommand, dockerCommands.get(0));
//disallowed network should trigger a launch failure
@@ -630,7 +674,8 @@ public class TestDockerContainerRuntime {
List<String> dockerCommands = Files.readAllLines(Paths.get
(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
+ int expected = 13;
+ Assert.assertEquals(expected, dockerCommands.size());
String command = dockerCommands.get(0);
@@ -738,13 +783,35 @@ public class TestDockerContainerRuntime {
List<String> dockerCommands = Files.readAllLines(Paths.get
(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
-
- String command = dockerCommands.get(0);
-
- //submitting user is whitelisted. ensure --privileged is in the invocation
- Assert.assertTrue("Did not find expected '--privileged' in docker run args "
- + ": " + command, command.contains("--privileged"));
+ int expected = 14;
+ int counter = 0;
+ Assert.assertEquals(expected, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(counter++));
+ Assert.assertEquals(" detach=true", dockerCommands.get(counter++));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(counter++));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(counter++));
+ Assert
+ .assertEquals(" image=busybox:latest", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(counter++));
+ Assert.assertEquals(" net=host", dockerCommands.get(counter++));
+ Assert.assertEquals(" privileged=true", dockerCommands.get(counter++));
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(counter++));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(counter++));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(counter++));
}
@Test
@@ -833,15 +900,33 @@ public class TestDockerContainerRuntime {
List<String> dockerCommands = Files.readAllLines(Paths.get
(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
-
- String command = dockerCommands.get(0);
-
- Assert.assertTrue("Did not find expected " +
- "/test_local_dir/test_resource_file:test_mount mount in docker " +
- "run args : " + command,
- command.contains(" -v /test_local_dir/test_resource_file:test_mount" +
- ":ro "));
+ Assert.assertEquals(14, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(1));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(2));
+ Assert.assertEquals(" detach=true", dockerCommands.get(3));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(4));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(5));
+ Assert.assertEquals(" image=busybox:latest", dockerCommands.get(6));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(7));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(8));
+ Assert.assertEquals(" net=host", dockerCommands.get(9));
+ Assert.assertEquals(
+ " ro-mounts=/test_local_dir/test_resource_file:test_mount",
+ dockerCommands.get(10));
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(11));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(12));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(13));
}
@Test
@@ -885,20 +970,35 @@ public class TestDockerContainerRuntime {
List<String> dockerCommands = Files.readAllLines(Paths.get
(dockerCommandFile), Charset.forName("UTF-8"));
- Assert.assertEquals(1, dockerCommands.size());
-
- String command = dockerCommands.get(0);
+ Assert.assertEquals(14, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ Assert.assertEquals(" cap-add=SYS_CHROOT,NET_BIND_SERVICE",
+ dockerCommands.get(1));
+ Assert.assertEquals(" cap-drop=ALL", dockerCommands.get(2));
+ Assert.assertEquals(" detach=true", dockerCommands.get(3));
+ Assert.assertEquals(" docker-command=run", dockerCommands.get(4));
+ Assert.assertEquals(" hostname=ctr-id", dockerCommands.get(5));
+ Assert.assertEquals(" image=busybox:latest", dockerCommands.get(6));
+ Assert.assertEquals(
+ " launch-command=bash,/test_container_work_dir/launch_container.sh",
+ dockerCommands.get(7));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(8));
+ Assert.assertEquals(" net=host", dockerCommands.get(9));
+ Assert.assertEquals(
+ " ro-mounts=/test_local_dir/test_resource_file:test_mount1,"
+ + "/test_local_dir/test_resource_file:test_mount2",
+ dockerCommands.get(10));
+ Assert.assertEquals(
+ " rw-mounts=/test_container_local_dir:/test_container_local_dir,"
+ + "/test_filecache_dir:/test_filecache_dir,"
+ + "/test_container_work_dir:/test_container_work_dir,"
+ + "/test_container_log_dir:/test_container_log_dir,"
+ + "/test_user_local_dir:/test_user_local_dir",
+ dockerCommands.get(11));
+ Assert.assertEquals(" user=run_as_user", dockerCommands.get(12));
+ Assert.assertEquals(" workdir=/test_container_work_dir",
+ dockerCommands.get(13));
- Assert.assertTrue("Did not find expected " +
- "/test_local_dir/test_resource_file:test_mount1 mount in docker " +
- "run args : " + command,
- command.contains(" -v /test_local_dir/test_resource_file:test_mount1" +
- ":ro "));
- Assert.assertTrue("Did not find expected " +
- "/test_local_dir/test_resource_file:test_mount2 mount in docker " +
- "run args : " + command,
- command.contains(" -v /test_local_dir/test_resource_file:test_mount2" +
- ":ro "));
}
@Test
@@ -930,8 +1030,10 @@ public class TestDockerContainerRuntime {
IOException {
List<String> dockerCommands = getDockerCommandsForSignal(
ContainerExecutor.Signal.TERM);
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals("stop container_id", dockerCommands.get(0));
+ Assert.assertEquals(3, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ Assert.assertEquals(" docker-command=stop", dockerCommands.get(1));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(2));
}
@Test
@@ -940,8 +1042,10 @@ public class TestDockerContainerRuntime {
IOException {
List<String> dockerCommands = getDockerCommandsForSignal(
ContainerExecutor.Signal.KILL);
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals("stop container_id", dockerCommands.get(0));
+ Assert.assertEquals(3, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ Assert.assertEquals(" docker-command=stop", dockerCommands.get(1));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(2));
}
@Test
@@ -950,8 +1054,10 @@ public class TestDockerContainerRuntime {
IOException {
List<String> dockerCommands = getDockerCommandsForSignal(
ContainerExecutor.Signal.QUIT);
- Assert.assertEquals(1, dockerCommands.size());
- Assert.assertEquals("stop container_id", dockerCommands.get(0));
+ Assert.assertEquals(3, dockerCommands.size());
+ Assert.assertEquals("[docker-command-execution]", dockerCommands.get(0));
+ Assert.assertEquals(" docker-command=stop", dockerCommands.get(1));
+ Assert.assertEquals(" name=container_id", dockerCommands.get(2));
}
private List<String> getDockerCommandsForSignal(
---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org