| /*****************************************************************************\ |
| * oci_config.c - parse oci.conf configuration file. |
| ***************************************************************************** |
| * Copyright (C) SchedMD LLC. |
| * All rights reserved. |
| * |
| * This file is part of Slurm, a resource management program. |
| * For details, see <https://slurm.schedmd.com/>. |
| * Please also read the included file: DISCLAIMER. |
| * |
| * SLURM is free software; you can redistribute it and/or modify it under |
| * the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * In addition, as a special exception, the copyright holders give permission |
| * to link the code of portions of this program with the OpenSSL library under |
| * certain conditions as described in each individual source file, and |
| * distribute linked combinations including the two. You must obey the GNU |
| * General Public License in all respects for all of the code used other than |
| * OpenSSL. If you modify file(s) with this exception, you may extend this |
| * exception to your version of the file(s), but you are not obligated to do |
| * so. If you do not wish to do so, delete this exception statement from your |
| * version. If you delete this exception statement from all source files in |
| * the program, then also delete it here. |
| * |
| * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| * details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with SLURM; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| \*****************************************************************************/ |
| |
| #include <sys/stat.h> |
| #include <unistd.h> |
| |
| #include "slurm/slurm_errno.h" |
| |
| #include "src/common/log.h" |
| #include "src/common/oci_config.h" |
| #include "src/common/parse_config.h" |
| #include "src/common/read_config.h" |
| #include "src/common/xmalloc.h" |
| #include "src/common/xstring.h" |
| |
| #define OCI_CONF "oci.conf" |
| |
| static s_p_options_t options[] = { |
| {"ContainerPath", S_P_STRING}, |
| {"CreateEnvFile", S_P_STRING}, |
| {"DisableHooks", S_P_STRING}, |
| {"EnvExclude", S_P_STRING}, |
| {"MountSpoolDir", S_P_STRING}, |
| {"RunTimeCreate", S_P_STRING}, |
| {"RunTimeDelete", S_P_STRING}, |
| {"RunTimeKill", S_P_STRING}, |
| {"RunTimeEnvExclude", S_P_STRING}, |
| {"RunTimeQuery", S_P_STRING}, |
| {"RunTimeRun", S_P_STRING}, |
| {"RunTimeStart", S_P_STRING}, |
| {"SrunPath", S_P_STRING}, |
| {"SrunArgs", S_P_ARRAY}, |
| {"DisableCleanup", S_P_BOOLEAN}, |
| {"StdIODebug", S_P_STRING}, |
| {"SyslogDebug", S_P_STRING}, |
| {"FileDebug", S_P_STRING}, |
| {"DebugFlags", S_P_STRING}, |
| {"IgnoreFileConfigJson", S_P_BOOLEAN}, |
| {NULL} |
| }; |
| |
| extern int get_oci_conf(oci_conf_t **oci_ptr) |
| { |
| s_p_hashtbl_t *tbl = NULL; |
| struct stat buf; |
| int rc = SLURM_SUCCESS; |
| oci_conf_t *oci = NULL; |
| char *conf_path = get_extra_conf_path(OCI_CONF); |
| char *disable_hooks = NULL; |
| char **srun_args = NULL; |
| int srun_args_count = 0; |
| char *debug_stdio = NULL, *debug_syslog = NULL; |
| char *debug_flags = NULL, *debug_file = NULL; |
| char *create_env_file = NULL; |
| char *runtime_env_exclude = NULL, *env_exclude = NULL; |
| |
| if ((stat(conf_path, &buf) == -1)) { |
| error("No %s file", OCI_CONF); |
| xfree(conf_path); |
| return ENOENT; |
| } |
| |
| oci = xmalloc(sizeof(*oci)); |
| |
| debug("Reading %s file %s", OCI_CONF, conf_path); |
| tbl = s_p_hashtbl_create(options); |
| if (s_p_parse_file(tbl, NULL, conf_path, 0, NULL) == SLURM_ERROR) |
| fatal("Could not parse %s file: %s", OCI_CONF, conf_path); |
| |
| (void) s_p_get_string(&oci->container_path, "ContainerPath", tbl); |
| (void) s_p_get_string(&create_env_file, "CreateEnvFile", tbl); |
| (void) s_p_get_string(&disable_hooks, "DisableHooks", tbl); |
| (void) s_p_get_boolean(&oci->ignore_config_json, "IgnoreFileConfigJson", tbl); |
| (void) s_p_get_string(&env_exclude, "EnvExclude", tbl); |
| (void) s_p_get_string(&oci->mount_spool_dir, "MountSpoolDir", tbl); |
| (void) s_p_get_string(&oci->runtime_create, "RunTimeCreate", tbl); |
| (void) s_p_get_string(&oci->runtime_delete, "RunTimeDelete", tbl); |
| (void) s_p_get_string(&oci->runtime_kill, "RunTimeKill", tbl); |
| (void) s_p_get_string(&runtime_env_exclude, "RunTimeEnvExclude", tbl); |
| (void) s_p_get_string(&oci->runtime_query, "RunTimeQuery", tbl); |
| (void) s_p_get_string(&oci->runtime_run, "RunTimeRun", tbl); |
| (void) s_p_get_string(&oci->runtime_start, "RunTimeStart", tbl); |
| (void) s_p_get_string(&oci->srun_path, "SrunPath", tbl); |
| (void) s_p_get_array((void ***) &srun_args, &srun_args_count, |
| "SrunArgs", tbl); |
| (void) s_p_get_boolean(&oci->disable_cleanup, "DisableCleanup", tbl); |
| (void) s_p_get_string(&debug_stdio, "StdIODebug", tbl); |
| (void) s_p_get_string(&debug_syslog, "SyslogDebug", tbl); |
| (void) s_p_get_string(&debug_file, "FileDebug", tbl); |
| (void) s_p_get_string(&debug_flags, "DebugFlags", tbl); |
| |
| if (debug_stdio) { |
| oci->stdio_log_level = log_string2num(debug_stdio); |
| xfree(debug_stdio); |
| } |
| if (debug_syslog) { |
| oci->syslog_log_level = log_string2num(debug_syslog); |
| xfree(debug_syslog); |
| } |
| if (debug_file) { |
| oci->file_log_level = log_string2num(debug_file); |
| xfree(debug_file); |
| } |
| if (debug_flags) { |
| int rc; |
| |
| if ((rc = debug_str2flags(debug_flags, &oci->debug_flags))) |
| fatal("%s: unable to parse oci.conf debugflags=%s: %m", |
| __func__, debug_flags); |
| |
| xfree(debug_flags); |
| } |
| |
| if (srun_args_count) { |
| oci->srun_args = xcalloc((srun_args_count + 1), |
| sizeof(*oci->srun_args)); |
| |
| for (int i = 0; i < srun_args_count; i++) |
| oci->srun_args[i] = xstrdup(srun_args[i]); |
| } |
| |
| if (disable_hooks) { |
| char *ptr1 = NULL, *ptr2 = NULL; |
| int i = 0; |
| |
| /* NULL terminated array of char* */ |
| oci->disable_hooks = xmalloc(sizeof(*oci->disable_hooks)); |
| |
| ptr1 = strtok_r(disable_hooks, ",", &ptr2); |
| while (ptr1) { |
| i++; |
| |
| xrecalloc(oci->disable_hooks, (i + 1), |
| sizeof(*oci->disable_hooks)); |
| |
| oci->disable_hooks[i] = xstrdup(ptr1); |
| debug("%s: disable hook type %s", |
| __func__, oci->disable_hooks[i]); |
| ptr1 = strtok_r(NULL, ",", &ptr2); |
| } |
| |
| xfree(disable_hooks); |
| } |
| |
| if (oci->ignore_config_json) { |
| /* |
| * If site has enabled ignore config.json then sanity checking |
| * the runtime commands is not required as the site is faking an |
| * OCI runtime any way. |
| */ |
| debug("OCI container activated with IgnoreFileConfigJson=True"); |
| } else if (!oci->runtime_create && !oci->runtime_delete && |
| !oci->runtime_kill && !oci->runtime_query && |
| !oci->runtime_run && !oci->runtime_start) { |
| error("oci.conf present but missing required options. Rejecting invalid configuration."); |
| rc = EINVAL; |
| } else if (oci->runtime_create && oci->runtime_delete && |
| oci->runtime_kill && oci->runtime_query && |
| !oci->runtime_run && oci->runtime_start) { |
| debug("OCI container activated with create/start"); |
| } else if (!oci->runtime_create && oci->runtime_delete && |
| oci->runtime_kill && oci->runtime_run && |
| !oci->runtime_start) { |
| debug("OCI container activated with run"); |
| } else { |
| error("RunTimeRun and RunCreate/RunTimeStart are mutually exclusive. All other RunTime* configurations items must be populated."); |
| rc = SLURM_ERROR; |
| } |
| |
| if (!xstrcasecmp(create_env_file, "null") || |
| !xstrcasecmp(create_env_file, "true") || |
| !xstrcasecmp(create_env_file, "Y") || |
| !xstrcasecmp(create_env_file, "Yes") || |
| !xstrcasecmp(create_env_file, "1")) { |
| oci->create_env_file = NULL_TERMINATED_ENV_FILE; |
| } else if (!xstrcasecmp(create_env_file, "newline")) { |
| oci->create_env_file = NEWLINE_TERMINATED_ENV_FILE; |
| } else if (!create_env_file || !xstrcasecmp(create_env_file, "false") || |
| !xstrcasecmp(create_env_file, "disabled") || |
| !xstrcasecmp(create_env_file, "N") || |
| !xstrcasecmp(create_env_file, "No") || |
| !xstrcasecmp(create_env_file, "0")) { |
| oci->create_env_file = DISABLED_ENV_FILE; |
| } else { |
| error("Invalid value of CreateEnvFile=%s", create_env_file); |
| rc = SLURM_ERROR; |
| } |
| |
| xfree(create_env_file); |
| s_p_hashtbl_destroy(tbl); |
| xfree(conf_path); |
| |
| if (!rc && env_exclude) { |
| if ((rc = regcomp(&oci->env_exclude, env_exclude, |
| REG_EXTENDED))) |
| dump_regex_error(rc, &oci->env_exclude, "compile %s", |
| env_exclude); |
| else |
| oci->env_exclude_set = true; |
| } |
| xfree(env_exclude); |
| |
| if (!rc && runtime_env_exclude) { |
| if ((rc = regcomp(&oci->runtime_env_exclude, runtime_env_exclude, |
| REG_EXTENDED))) |
| dump_regex_error(rc, &oci->runtime_env_exclude, |
| "compile %s", runtime_env_exclude); |
| else |
| oci->runtime_env_exclude_set = true; |
| } |
| xfree(runtime_env_exclude); |
| |
| if (!rc) { |
| const char *envfile = "disabled"; |
| free_oci_conf(*oci_ptr); |
| *oci_ptr = oci; |
| |
| if (oci->create_env_file == NULL_TERMINATED_ENV_FILE) |
| envfile = "null"; |
| else if (oci->create_env_file == NEWLINE_TERMINATED_ENV_FILE) |
| envfile = "newline"; |
| |
| debug("%s: oci.conf loaded: ContainerPath=%s CreateEnvFile=%s RunTimeCreate=%s RunTimeDelete=%s RunTimeKill=%s RunTimeQuery=%s RunTimeRun=%s RunTimeStart=%s IgnoreFileConfigJson=%c", |
| __func__, oci->container_path, envfile, |
| oci->runtime_create, oci->runtime_delete, |
| oci->runtime_kill, oci->runtime_query, oci->runtime_run, |
| oci->runtime_start, |
| (oci->ignore_config_json ? 'T' : 'F')); |
| } else { |
| free_oci_conf(oci); |
| } |
| |
| return rc; |
| } |
| |
| extern void free_oci_conf(oci_conf_t *oci) |
| { |
| if (!oci) |
| return; |
| |
| xfree(oci->container_path); |
| regfree(&oci->runtime_env_exclude); |
| xfree(oci->mount_spool_dir); |
| xfree(oci->runtime_create); |
| xfree(oci->runtime_delete); |
| xfree(oci->runtime_kill); |
| regfree(&oci->runtime_env_exclude); |
| xfree(oci->runtime_query); |
| xfree(oci->runtime_run); |
| xfree(oci->runtime_start); |
| xfree(oci->srun_path); |
| for (int i = 0; oci->srun_args && oci->srun_args[i]; i++) |
| xfree(oci->srun_args[i]); |
| xfree(oci->srun_args); |
| |
| if (oci->disable_hooks) { |
| for (int i = 0; oci->disable_hooks[i]; i++) |
| xfree(oci->disable_hooks[i]); |
| xfree(oci->disable_hooks); |
| } |
| |
| xfree(oci); |
| } |