/** * Mount a cgroup controller at the requested mount point and create * a hierarchy for the Hadoop NodeManager to manage. * pair: a key-value pair of the form "controller=mount-path" * hierarchy: the top directory of the hierarchy for the NM */ int mount_cgroup(const char *pair, const char *hierarchy) { #ifndef __linux fprintf(LOGFILE, "Failed to mount cgroup controller, not supported\n"); return -1; #else char *controller = malloc(strlen(pair)); char *mount_path = malloc(strlen(pair)); char hier_path[PATH_MAX]; int result = 0; if (get_kv_key(pair, controller, strlen(pair)) < 0 || get_kv_value(pair, mount_path, strlen(pair)) < 0) { fprintf(LOGFILE, "Failed to mount cgroup controller; invalid option: %s\n", pair); result = -1; } else { if (mount("none", mount_path, "cgroup", 0, controller) == 0) { char *buf = stpncpy(hier_path, mount_path, strlen(mount_path)); *buf++ = '/'; snprintf(buf, PATH_MAX - (buf - hier_path), "%s", hierarchy); // create hierarchy as 0750 and chown to Hadoop NM user const mode_t perms = S_IRWXU | S_IRGRP | S_IXGRP; if (mkdirs(hier_path, perms) == 0) { change_owner(hier_path, nm_uid, nm_gid); chown_dir_contents(hier_path, nm_uid, nm_gid); } } else { fprintf(LOGFILE, "Failed to mount cgroup controller %s at %s - %s\n", controller, mount_path, strerror(errno)); // if controller is already mounted, don't stop trying to mount others if (errno != EBUSY) { result = -1; } } } free(controller); free(mount_path); return result; #endif }
/* Parse/validate 'run as user' commands */ static int validate_run_as_user_commands(int argc, char **argv, int *operation) { /* We need at least the following arguments in order to proceed further : <user>, <yarn-user> <command> - i.e at argc should be at least 4 */ if (argc < 4) { display_usage(stdout); return INVALID_ARGUMENT_NUMBER; } cmd_input.run_as_user_name = argv[optind++]; cmd_input.yarn_user_name = argv[optind++]; int command = atoi(argv[optind++]); fprintf(LOGFILE, "main : command provided %d\n", command); fprintf(LOGFILE, "main : run as user is %s\n", cmd_input.run_as_user_name); fprintf(LOGFILE, "main : requested yarn user is %s\n", cmd_input.yarn_user_name); fflush(LOGFILE); char * resources = NULL;// key,value pair describing resources char * resources_key = NULL; char * resources_value = NULL; switch (command) { case INITIALIZE_CONTAINER: if (argc < 9) { fprintf(ERRORFILE, "Too few arguments (%d vs 9) for initialize container\n", argc); fflush(ERRORFILE); return INVALID_ARGUMENT_NUMBER; } cmd_input.app_id = argv[optind++]; cmd_input.cred_file = argv[optind++]; cmd_input.local_dirs = argv[optind++];// good local dirs as a comma separated list cmd_input.log_dirs = argv[optind++];// good log dirs as a comma separated list *operation = RUN_AS_USER_INITIALIZE_CONTAINER; return 0; case LAUNCH_DOCKER_CONTAINER: //kill me now. if (!(argc == 14 || argc == 15)) { fprintf(ERRORFILE, "Wrong number of arguments (%d vs 14 or 15) for launch docker container\n", argc); fflush(ERRORFILE); return INVALID_ARGUMENT_NUMBER; } cmd_input.app_id = argv[optind++]; cmd_input.container_id = argv[optind++]; cmd_input.current_dir = argv[optind++]; cmd_input.script_file = argv[optind++]; cmd_input.cred_file = argv[optind++]; cmd_input.pid_file = argv[optind++]; cmd_input.local_dirs = argv[optind++];// good local dirs as a comma separated list cmd_input.log_dirs = argv[optind++];// good log dirs as a comma separated list cmd_input.docker_command_file = argv[optind++]; resources = argv[optind++];// key,value pair describing resources resources_key = malloc(strlen(resources)); resources_value = malloc(strlen(resources)); if (get_kv_key(resources, resources_key, strlen(resources)) < 0 || get_kv_value(resources, resources_value, strlen(resources)) < 0) { fprintf(ERRORFILE, "Invalid arguments for cgroups resources: %s", resources); fflush(ERRORFILE); free(resources_key); free(resources_value); return INVALID_ARGUMENT_NUMBER; } //network isolation through tc if (argc == 15) { cmd_input.traffic_control_command_file = argv[optind++]; } cmd_input.resources_key = resources_key; cmd_input.resources_value = resources_value; cmd_input.resources_values = extract_values(resources_value); *operation = RUN_AS_USER_LAUNCH_DOCKER_CONTAINER; return 0; case LAUNCH_CONTAINER: //kill me now. if (!(argc == 13 || argc == 14)) { fprintf(ERRORFILE, "Wrong number of arguments (%d vs 13 or 14) for launch container\n", argc); fflush(ERRORFILE); return INVALID_ARGUMENT_NUMBER; } cmd_input.app_id = argv[optind++]; cmd_input.container_id = argv[optind++]; cmd_input.current_dir = argv[optind++]; cmd_input.script_file = argv[optind++]; cmd_input.cred_file = argv[optind++]; cmd_input.pid_file = argv[optind++]; cmd_input.local_dirs = argv[optind++];// good local dirs as a comma separated list cmd_input.log_dirs = argv[optind++];// good log dirs as a comma separated list resources = argv[optind++];// key,value pair describing resources resources_key = malloc(strlen(resources)); resources_value = malloc(strlen(resources)); if (get_kv_key(resources, resources_key, strlen(resources)) < 0 || get_kv_value(resources, resources_value, strlen(resources)) < 0) { fprintf(ERRORFILE, "Invalid arguments for cgroups resources: %s", resources); fflush(ERRORFILE); free(resources_key); free(resources_value); return INVALID_ARGUMENT_NUMBER; } //network isolation through tc if (argc == 14) { cmd_input.traffic_control_command_file = argv[optind++]; } cmd_input.resources_key = resources_key; cmd_input.resources_value = resources_value; cmd_input.resources_values = extract_values(resources_value); *operation = RUN_AS_USER_LAUNCH_CONTAINER; return 0; case SIGNAL_CONTAINER: if (argc != 6) { fprintf(ERRORFILE, "Wrong number of arguments (%d vs 6) for " \ "signal container\n", argc); fflush(ERRORFILE); return INVALID_ARGUMENT_NUMBER; } char* end_ptr = NULL; char* option = argv[optind++]; cmd_input.container_pid = strtol(option, &end_ptr, 10); if (option == end_ptr || *end_ptr != '\0') { fprintf(ERRORFILE, "Illegal argument for container pid %s\n", option); fflush(ERRORFILE); return INVALID_ARGUMENT_NUMBER; } option = argv[optind++]; cmd_input.signal = strtol(option, &end_ptr, 10); if (option == end_ptr || *end_ptr != '\0') { fprintf(ERRORFILE, "Illegal argument for signal %s\n", option); fflush(ERRORFILE); return INVALID_ARGUMENT_NUMBER; } *operation = RUN_AS_USER_SIGNAL_CONTAINER; return 0; case DELETE_AS_USER: cmd_input.dir_to_be_deleted = argv[optind++]; *operation = RUN_AS_USER_DELETE; return 0; default: fprintf(ERRORFILE, "Invalid command %d not supported.",command); fflush(ERRORFILE); return INVALID_COMMAND_PROVIDED; } }
int main(int argc, char **argv) { int invalid_args = 0; int do_check_setup = 0; int do_mount_cgroups = 0; LOGFILE = stdout; ERRORFILE = stderr; if (argc > 1) { if (strcmp("--mount-cgroups", argv[1]) == 0) { do_mount_cgroups = 1; } } // Minimum number of arguments required to run // the std. container-executor commands is 4 // 4 args not needed for checksetup option if (argc < 4 && !do_mount_cgroups) { invalid_args = 1; if (argc == 2) { const char *arg1 = argv[1]; if (strcmp("--checksetup", arg1) == 0) { invalid_args = 0; do_check_setup = 1; } } } if (invalid_args != 0) { display_usage(stdout); return INVALID_ARGUMENT_NUMBER; } int command; const char * app_id = NULL; const char * container_id = NULL; const char * cred_file = NULL; const char * script_file = NULL; const char * current_dir = NULL; const char * pid_file = NULL; int exit_code = 0; char * dir_to_be_deleted = NULL; char *executable_file = get_executable(); char *orig_conf_file = HADOOP_CONF_DIR "/" CONF_FILENAME; char *conf_file = resolve_config_path(orig_conf_file, argv[0]); char *local_dirs, *log_dirs; char *resources, *resources_key, *resources_value; if (conf_file == NULL) { fprintf(ERRORFILE, "Configuration file %s not found.\n", orig_conf_file); exit(INVALID_CONFIG_FILE); } if (check_configuration_permissions(conf_file) != 0) { exit(INVALID_CONFIG_FILE); } read_config(conf_file); free(conf_file); // look up the node manager group in the config file char *nm_group = get_value(NM_GROUP_KEY); if (nm_group == NULL) { fprintf(ERRORFILE, "Can't get configured value for %s.\n", NM_GROUP_KEY); exit(INVALID_CONFIG_FILE); } struct group *group_info = getgrnam(nm_group); if (group_info == NULL) { fprintf(ERRORFILE, "Can't get group information for %s - %s.\n", nm_group, strerror(errno)); fflush(LOGFILE); exit(INVALID_CONFIG_FILE); } set_nm_uid(getuid(), group_info->gr_gid); // if we are running from a setuid executable, make the real uid root setuid(0); // set the real and effective group id to the node manager group setgid(group_info->gr_gid); if (check_executor_permissions(executable_file) != 0) { fprintf(ERRORFILE, "Invalid permissions on container-executor binary.\n"); return INVALID_CONTAINER_EXEC_PERMISSIONS; } if (do_check_setup != 0) { // basic setup checks done // verified configs available and valid // verified executor permissions return 0; } if (do_mount_cgroups) { optind++; char *hierarchy = argv[optind++]; int result = 0; while (optind < argc && result == 0) { result = mount_cgroup(argv[optind++], hierarchy); } return result; } //checks done for user name if (argv[optind] == NULL) { fprintf(ERRORFILE, "Invalid user name.\n"); return INVALID_USER_NAME; } int ret = set_user(argv[optind]); if (ret != 0) { return ret; } // this string is used for building pathnames, the // process management is done based on the 'user_detail' // global, which was set by 'set_user()' above optind = optind + 1; char *yarn_user_name = argv[optind]; if (yarn_user_name == NULL) { fprintf(ERRORFILE, "Invalid yarn user name.\n"); return INVALID_USER_NAME; } optind = optind + 1; command = atoi(argv[optind++]); fprintf(LOGFILE, "main : command provided %d\n",command); fprintf(LOGFILE, "main : user is %s\n", user_detail->pw_name); fprintf(LOGFILE, "main : requested yarn user is %s\n", yarn_user_name); fflush(LOGFILE); switch (command) { case INITIALIZE_CONTAINER: if (argc < 9) { fprintf(ERRORFILE, "Too few arguments (%d vs 9) for initialize container\n", argc); fflush(ERRORFILE); return INVALID_ARGUMENT_NUMBER; } app_id = argv[optind++]; cred_file = argv[optind++]; local_dirs = argv[optind++];// good local dirs as a comma separated list log_dirs = argv[optind++];// good log dirs as a comma separated list exit_code = initialize_app(yarn_user_name, app_id, cred_file, extract_values(local_dirs), extract_values(log_dirs), argv + optind); break; case LAUNCH_CONTAINER: if (argc != 13) { fprintf(ERRORFILE, "Wrong number of arguments (%d vs 13) for launch container\n", argc); fflush(ERRORFILE); return INVALID_ARGUMENT_NUMBER; } app_id = argv[optind++]; container_id = argv[optind++]; current_dir = argv[optind++]; script_file = argv[optind++]; cred_file = argv[optind++]; pid_file = argv[optind++]; local_dirs = argv[optind++];// good local dirs as a comma separated list log_dirs = argv[optind++];// good log dirs as a comma separated list resources = argv[optind++];// key,value pair describing resources char *resources_key = malloc(strlen(resources)); char *resources_value = malloc(strlen(resources)); if (get_kv_key(resources, resources_key, strlen(resources)) < 0 || get_kv_value(resources, resources_value, strlen(resources)) < 0) { fprintf(ERRORFILE, "Invalid arguments for cgroups resources: %s", resources); fflush(ERRORFILE); free(resources_key); free(resources_value); return INVALID_ARGUMENT_NUMBER; } char** resources_values = extract_values(resources_value); exit_code = launch_container_as_user(yarn_user_name, app_id, container_id, current_dir, script_file, cred_file, pid_file, extract_values(local_dirs), extract_values(log_dirs), resources_key, resources_values); free(resources_key); free(resources_value); break; case SIGNAL_CONTAINER: if (argc != 6) { fprintf(ERRORFILE, "Wrong number of arguments (%d vs 6) for " \ "signal container\n", argc); fflush(ERRORFILE); return INVALID_ARGUMENT_NUMBER; } else { char* end_ptr = NULL; char* option = argv[optind++]; int container_pid = strtol(option, &end_ptr, 10); if (option == end_ptr || *end_ptr != '\0') { fprintf(ERRORFILE, "Illegal argument for container pid %s\n", option); fflush(ERRORFILE); return INVALID_ARGUMENT_NUMBER; } option = argv[optind++]; int signal = strtol(option, &end_ptr, 10); if (option == end_ptr || *end_ptr != '\0') { fprintf(ERRORFILE, "Illegal argument for signal %s\n", option); fflush(ERRORFILE); return INVALID_ARGUMENT_NUMBER; } exit_code = signal_container_as_user(yarn_user_name, container_pid, signal); } break; case DELETE_AS_USER: dir_to_be_deleted = argv[optind++]; exit_code= delete_as_user(yarn_user_name, dir_to_be_deleted, argv + optind); break; default: fprintf(ERRORFILE, "Invalid command %d not supported.",command); fflush(ERRORFILE); exit_code = INVALID_COMMAND_PROVIDED; } fclose(LOGFILE); fclose(ERRORFILE); return exit_code; }