blob: bbff92636ce0131b853aed55c8e4720212d7df11 [file] [log] [blame]
/*****************************************************************************\
* read_jcconf.c - parse job_container.conf configuration file.
*****************************************************************************
* Copyright (C) 2019-2021 Regents of the University of California
* Produced at Lawrence Berkeley National Laboratory
* Written by Aditi Gaur <agaur@lbl.gov>
* 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 <unistd.h>
#include <sys/stat.h>
#include "slurm/slurm_errno.h"
#include "src/common/xstring.h"
#include "src/common/log.h"
#include "src/common/parse_config.h"
#include "src/common/read_config.h"
#include "src/common/xmalloc.h"
#include "read_jcconf.h"
char *tmpfs_conf_file = "job_container.conf";
static slurm_jc_conf_t slurm_jc_conf;
static buf_t *slurm_jc_conf_buf = NULL;
static bool slurm_jc_conf_inited = false;
static bool auto_basepath_set = false;
static bool shared_set = false;
static bool entire_step_in_ns_set = false;
static bool clonensscript_wait_set = false;
static bool clonensepilog_wait_set = false;
static s_p_hashtbl_t *_create_ns_hashtbl(void)
{
static s_p_options_t ns_options[] = {
{"AutoBasePath", S_P_BOOLEAN},
{"BasePath", S_P_STRING},
{"Dirs", S_P_STRING},
{"EntireStepInNS", S_P_BOOLEAN},
{"InitScript", S_P_STRING},
{"Shared", S_P_BOOLEAN},
{"CloneNSScript", S_P_STRING},
{"CloneNSEpilog", S_P_STRING},
{"CloneNSScript_Wait", S_P_UINT32},
{"CloneNSEpilog_Wait", S_P_UINT32},
{NULL}
};
return s_p_hashtbl_create(ns_options);
}
static void _dump_jc_conf(void)
{
if (!(slurm_conf.debug_flags & DEBUG_FLAG_JOB_CONT))
return;
log_flag(JOB_CONT, "AutoBasePath=%d", slurm_jc_conf.auto_basepath);
log_flag(JOB_CONT, "BasePath=%s", slurm_jc_conf.basepath);
log_flag(JOB_CONT, "Dirs=%s", slurm_jc_conf.dirs);
log_flag(JOB_CONT, "EntireStepInNS=%d",
slurm_jc_conf.entire_step_in_ns);
log_flag(JOB_CONT, "Shared=%d", slurm_jc_conf.shared);
log_flag(JOB_CONT, "InitScript=%s", slurm_jc_conf.initscript);
log_flag(JOB_CONT, "CloneNSScript=%s", slurm_jc_conf.clonensscript);
log_flag(JOB_CONT, "CloneNSEpilog=%s", slurm_jc_conf.clonensepilog);
log_flag(JOB_CONT, "CloneNSScript_Wait=%u",
slurm_jc_conf.clonensscript_wait);
log_flag(JOB_CONT, "CloneNSEpilog_Wait=%u",
slurm_jc_conf.clonensepilog_wait);
}
static void _pack_slurm_jc_conf_buf(void)
{
if (slurm_jc_conf_buf)
FREE_NULL_BUFFER(slurm_jc_conf_buf);
slurm_jc_conf_buf = init_buf(0);
packbool(slurm_jc_conf.auto_basepath, slurm_jc_conf_buf);
packstr(slurm_jc_conf.basepath, slurm_jc_conf_buf);
packstr(slurm_jc_conf.dirs, slurm_jc_conf_buf);
packbool(slurm_jc_conf.entire_step_in_ns, slurm_jc_conf_buf);
packstr(slurm_jc_conf.initscript, slurm_jc_conf_buf);
packbool(slurm_jc_conf.shared, slurm_jc_conf_buf);
packstr(slurm_jc_conf.clonensscript, slurm_jc_conf_buf);
packstr(slurm_jc_conf.clonensepilog, slurm_jc_conf_buf);
pack32(slurm_jc_conf.clonensscript_wait, slurm_jc_conf_buf);
pack32(slurm_jc_conf.clonensepilog_wait, slurm_jc_conf_buf);
}
static int _parse_jc_conf_internal(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover)
{
char *basepath = NULL;
int rc = 1;
s_p_hashtbl_t *tbl = _create_ns_hashtbl();
s_p_parse_line(tbl, *leftover, leftover);
if (value) {
basepath = xstrdup(value);
} else if (!s_p_get_string(&basepath, "BasePath", tbl)) {
fatal("empty basepath detected, please verify %s is correct",
tmpfs_conf_file);
rc = 0;
goto end_it;
}
slurm_jc_conf.basepath = slurm_conf_expand_slurmd_path(basepath,
conf->node_name,
NULL);
xfree(basepath);
#ifdef MULTIPLE_SLURMD
xstrfmtcat(slurm_jc_conf.basepath, "/%s", conf->node_name);
#endif
if (s_p_get_boolean(&slurm_jc_conf.auto_basepath, "AutoBasePath", tbl))
auto_basepath_set = true;
if (!s_p_get_string(&slurm_jc_conf.dirs, "Dirs", tbl))
debug3("empty Dirs detected");
if (s_p_get_boolean(&slurm_jc_conf.entire_step_in_ns, "EntireStepInNS",
tbl))
entire_step_in_ns_set = true;
if (!s_p_get_string(&slurm_jc_conf.initscript, "InitScript", tbl))
debug3("empty init script detected");
if (s_p_get_boolean(&slurm_jc_conf.shared, "Shared", tbl))
shared_set = true;
if (!s_p_get_string(&slurm_jc_conf.clonensscript, "CloneNSScript", tbl))
debug3("empty post clone ns script detected");
if (!s_p_get_string(&slurm_jc_conf.clonensepilog, "CloneNSEpilog", tbl))
debug3("empty post clone ns epilog script detected");
if (s_p_get_uint32(&slurm_jc_conf.clonensscript_wait,
"CloneNSScript_Wait", tbl))
clonensscript_wait_set = true;
if (s_p_get_uint32(&slurm_jc_conf.clonensepilog_wait,
"CloneNSEpilog_Wait", tbl))
clonensepilog_wait_set = true;
end_it:
s_p_hashtbl_destroy(tbl);
/* Nothing to free on this line in parse_config.c when freeing table. */
*dest = NULL;
return rc;
}
static int _parse_jc_conf(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover)
{
if (value) {
bool match = false;
hostlist_t *hl = hostlist_create(value);
if (hl) {
match = (hostlist_find(hl, conf->node_name) >= 0);
hostlist_destroy(hl);
}
if (!match) {
s_p_hashtbl_t *tbl = _create_ns_hashtbl();
s_p_parse_line(tbl, *leftover, leftover);
s_p_hashtbl_destroy(tbl);
debug("skipping NS for NodeName=%s %s", value, line);
return 0;
}
}
return _parse_jc_conf_internal(dest, type, key, NULL, line, leftover);
}
static int _read_slurm_jc_conf(void)
{
char *conf_path = NULL;
s_p_hashtbl_t *tbl = NULL;
struct stat buf;
int rc = SLURM_SUCCESS;
static s_p_options_t options[] = {
{"AutoBasePath", S_P_BOOLEAN},
{"BasePath", S_P_ARRAY, _parse_jc_conf_internal, NULL},
{"Dirs", S_P_STRING},
{"EntireStepInNS", S_P_BOOLEAN},
{"NodeName", S_P_ARRAY, _parse_jc_conf, NULL},
{"Shared", S_P_BOOLEAN},
{"CloneNSScript", S_P_STRING},
{"CloneNSEpilog", S_P_STRING},
{"CloneNSScript_Wait", S_P_UINT32},
{"CloneNSEpilog_Wait", S_P_UINT32},
{NULL}
};
xassert(conf->node_name);
conf_path = get_extra_conf_path(tmpfs_conf_file);
if ((!conf_path) || (stat(conf_path, &buf) == -1)) {
error("No %s file", tmpfs_conf_file);
rc = ENOENT;
goto end_it;
}
debug("Reading %s file %s", tmpfs_conf_file, conf_path);
tbl = s_p_hashtbl_create(options);
if (s_p_parse_file(tbl, NULL, conf_path, 0, NULL) == SLURM_ERROR) {
fatal("Could not open/read/parse %s file %s",
tmpfs_conf_file, conf_path);
goto end_it;
}
/* If AutoBasePath wasn't set on the line see if it was on the global */
if (!auto_basepath_set)
s_p_get_boolean(&slurm_jc_conf.auto_basepath,
"AutoBasePath", tbl);
if (!slurm_jc_conf.dirs &&
!s_p_get_string(&slurm_jc_conf.dirs, "Dirs", tbl))
slurm_jc_conf.dirs = xstrdup(SLURM_TMPFS_DEF_DIRS);
if (!slurm_jc_conf.basepath) {
debug("Config not found in %s. Disabling plugin on this node",
tmpfs_conf_file);
} else if (!xstrncasecmp(slurm_jc_conf.basepath, "none", 4)) {
debug("Plugin is disabled on this node per %s.",
tmpfs_conf_file);
}
if (!entire_step_in_ns_set)
s_p_get_boolean(&slurm_jc_conf.entire_step_in_ns,
"EntireStepInNS", tbl);
if (!shared_set)
s_p_get_boolean(&slurm_jc_conf.shared, "Shared", tbl);
if (!clonensscript_wait_set) {
if (!s_p_get_uint32(&slurm_jc_conf.clonensscript_wait,
"CloneNSScript_Wait", tbl))
slurm_jc_conf.clonensscript_wait = 10;
}
if (!clonensepilog_wait_set) {
if (!s_p_get_uint32(&slurm_jc_conf.clonensepilog_wait,
"CloneNSEpilog_Wait", tbl))
slurm_jc_conf.clonensepilog_wait = 10;
}
end_it:
s_p_hashtbl_destroy(tbl);
xfree(conf_path);
return rc;
}
extern slurm_jc_conf_t *init_slurm_jc_conf(void)
{
int rc;
if (!slurm_jc_conf_inited) {
char *save_ptr = NULL, *token, *buffer;
memset(&slurm_jc_conf, 0, sizeof(slurm_jc_conf_t));
rc = _read_slurm_jc_conf();
if (rc != SLURM_SUCCESS)
return NULL;
xassert(slurm_jc_conf.dirs);
/* BasePath cannot be in "Dirs" */
buffer = xstrdup(slurm_jc_conf.dirs);
token = strtok_r(buffer, ",", &save_ptr);
while (token) {
char *found = xstrstr(token, slurm_jc_conf.basepath);
if (found == token)
fatal("BasePath(%s) cannot also be in Dirs.",
slurm_jc_conf.basepath);
token = strtok_r(NULL, ",", &save_ptr);
}
xfree(buffer);
_pack_slurm_jc_conf_buf();
slurm_jc_conf_inited = true;
_dump_jc_conf();
}
return &slurm_jc_conf;
}
extern slurm_jc_conf_t *set_slurm_jc_conf(buf_t *buf)
{
xassert(buf);
safe_unpackbool(&slurm_jc_conf.auto_basepath, buf);
safe_unpackstr(&slurm_jc_conf.basepath, buf);
safe_unpackstr(&slurm_jc_conf.dirs, buf);
safe_unpackbool(&slurm_jc_conf.entire_step_in_ns, buf);
safe_unpackstr(&slurm_jc_conf.initscript, buf);
safe_unpackbool(&slurm_jc_conf.shared, buf);
safe_unpackstr(&slurm_jc_conf.clonensscript, buf);
safe_unpackstr(&slurm_jc_conf.clonensepilog, buf);
safe_unpack32(&slurm_jc_conf.clonensscript_wait, buf);
safe_unpack32(&slurm_jc_conf.clonensepilog_wait, buf);
slurm_jc_conf_inited = true;
return &slurm_jc_conf;
unpack_error:
return NULL;
}
extern slurm_jc_conf_t *get_slurm_jc_conf(void)
{
if (!slurm_jc_conf_inited)
return NULL;
return &slurm_jc_conf;
}
extern buf_t *get_slurm_jc_conf_buf(void)
{
return slurm_jc_conf_buf;
}
extern void free_jc_conf(void)
{
if (slurm_jc_conf_inited) {
xfree(slurm_jc_conf.basepath);
xfree(slurm_jc_conf.initscript);
xfree(slurm_jc_conf.dirs);
xfree(slurm_jc_conf.clonensscript);
xfree(slurm_jc_conf.clonensepilog);
FREE_NULL_BUFFER(slurm_jc_conf_buf);
slurm_jc_conf_inited = false;
}
return;
}