blob: 1d09be7f3c39f69cc43a104ec35d811564db70c0 [file] [log] [blame]
/* -*- Mode: C; tab-width:8 ; c-basic-offset:8 ; indent-tabs-mode:t -*- */
/*****************************************************************************\
* read_config.c - read the overall slurm configuration file
*****************************************************************************
* Copyright (C) 2002-2007 The Regents of the University of California.
* Copyright (C) 2008-2010 Lawrence Livermore National Security.
* Portions Copyright (C) 2008 Vijay Ramasubramanian.
* Portions Copyright (C) 2010-2013 SchedMD <http://www.schedmd.com>.
* Portions (boards) copyright (C) 2012 Bull, <rod.schultz@bull.com>
* Copyright (C) 2012-2013 Los Alamos National Security, LLC.
* Copyright (C) 2013 Intel, Inc.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Morris Jette <jette1@llnl.gov>.
* CODE-OCEC-09-009. All rights reserved.
*
* This file is part of SLURM, a resource management program.
* For details, see <http://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.
\*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "slurm/slurm.h"
#include "src/common/hostlist.h"
#include "src/common/log.h"
#include "src/common/macros.h"
#include "src/common/node_conf.h"
#include "src/common/parse_config.h"
#include "src/common/parse_spec.h"
#include "src/common/parse_time.h"
#include "src/common/read_config.h"
#include "src/common/slurm_accounting_storage.h"
#include "src/common/slurm_protocol_api.h"
#include "src/common/slurm_protocol_defs.h"
#include "src/common/slurm_rlimits_info.h"
#include "src/common/slurm_selecttype_info.h"
#include "src/common/slurm_strcasestr.h"
#include "src/common/strlcpy.h"
#include "src/common/uid.h"
#include "src/common/util-net.h"
#include "src/common/xmalloc.h"
#include "src/common/xstring.h"
/*
** Define slurm-specific aliases for use by plugins, see slurm_xlator.h
** for details.
*/
strong_alias(destroy_config_key_pair, slurm_destroy_config_key_pair);
strong_alias(get_extra_conf_path, slurm_get_extra_conf_path);
strong_alias(sort_key_pairs, slurm_sort_key_pairs);
strong_alias(run_in_daemon, slurm_run_in_daemon);
/* Instantiation of the "extern slurm_ctl_conf_t slurmcltd_conf"
* found in slurmctld.h */
slurm_ctl_conf_t slurmctld_conf;
static pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER;
static s_p_hashtbl_t *conf_hashtbl = NULL;
static slurm_ctl_conf_t *conf_ptr = &slurmctld_conf;
static bool conf_initialized = false;
static s_p_hashtbl_t *default_frontend_tbl;
static s_p_hashtbl_t *default_nodename_tbl;
static s_p_hashtbl_t *default_partition_tbl;
inline static void _normalize_debug_level(uint16_t *level);
static int _init_slurm_conf(const char *file_name);
#define NAME_HASH_LEN 512
typedef struct names_ll_s {
char *alias; /* NodeName */
char *hostname; /* NodeHostname */
char *address; /* NodeAddr */
uint16_t port;
uint16_t cpus;
uint16_t boards;
uint16_t sockets;
uint16_t cores;
uint16_t threads;
slurm_addr_t addr;
bool addr_initialized;
struct names_ll_s *next_alias;
struct names_ll_s *next_hostname;
} names_ll_t;
static bool nodehash_initialized = false;
static names_ll_t *host_to_node_hashtbl[NAME_HASH_LEN] = {NULL};
static names_ll_t *node_to_host_hashtbl[NAME_HASH_LEN] = {NULL};
static void _destroy_nodename(void *ptr);
static int _parse_frontend(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover);
static int _parse_nodename(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover);
static bool _is_valid_path(char *path, char *msg);
static int _parse_partitionname(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover);
static void _destroy_partitionname(void *ptr);
static int _parse_downnodes(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover);
static void _destroy_downnodes(void *ptr);
static int _defunct_option(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover);
static int _validate_and_set_defaults(slurm_ctl_conf_t *conf,
s_p_hashtbl_t *hashtbl);
s_p_options_t slurm_conf_options[] = {
{"AccountingStorageEnforce", S_P_STRING},
{"AccountingStorageHost", S_P_STRING},
{"AccountingStorageBackupHost", S_P_STRING},
{"AccountingStorageLoc", S_P_STRING},
{"AccountingStoragePass", S_P_STRING},
{"AccountingStoragePort", S_P_UINT32},
{"AccountingStorageType", S_P_STRING},
{"AccountingStorageUser", S_P_STRING},
{"AccountingStoreJobComment", S_P_BOOLEAN},
{"AcctGatherEnergyType", S_P_STRING},
{"AcctGatherNodeFreq", S_P_UINT16},
{"AcctGatherProfileType", S_P_STRING},
{"AcctGatherInfinibandType", S_P_STRING},
{"AcctGatherFilesystemType", S_P_STRING},
{"AuthInfo", S_P_STRING},
{"AuthType", S_P_STRING},
{"BackupAddr", S_P_STRING},
{"BackupController", S_P_STRING},
{"BatchStartTimeout", S_P_UINT16},
{"CheckpointType", S_P_STRING},
{"CacheGroups", S_P_UINT16},
{"CoreSpecPlugin", S_P_STRING},
{"ClusterName", S_P_STRING},
{"CompleteWait", S_P_UINT16},
{"ControlAddr", S_P_STRING},
{"ControlMachine", S_P_STRING},
{"CryptoType", S_P_STRING},
{"DebugFlags", S_P_STRING},
{"DefaultStorageHost", S_P_STRING},
{"DefaultStorageLoc", S_P_STRING},
{"DefaultStoragePass", S_P_STRING},
{"DefaultStoragePort", S_P_UINT32},
{"DefaultStorageType", S_P_STRING},
{"DefaultStorageUser", S_P_STRING},
{"DefMemPerCPU", S_P_UINT32},
{"DefMemPerNode", S_P_UINT32},
{"DisableRootJobs", S_P_BOOLEAN},
{"DynAllocPort", S_P_UINT16},
{"EnforcePartLimits", S_P_BOOLEAN},
{"Epilog", S_P_STRING},
{"EpilogMsgTime", S_P_UINT32},
{"EpilogSlurmctld", S_P_STRING},
{"ExtSensorsType", S_P_STRING},
{"ExtSensorsFreq", S_P_UINT16},
{"FairShareDampeningFactor", S_P_UINT16},
{"FastSchedule", S_P_UINT16},
{"FirstJobId", S_P_UINT32},
{"GetEnvTimeout", S_P_UINT16},
{"GresTypes", S_P_STRING},
{"GroupUpdateForce", S_P_UINT16},
{"GroupUpdateTime", S_P_UINT16},
{"HealthCheckInterval", S_P_UINT16},
{"HealthCheckNodeState", S_P_STRING},
{"HealthCheckProgram", S_P_STRING},
{"InactiveLimit", S_P_UINT16},
{"JobAcctGatherType", S_P_STRING},
{"JobAcctGatherFrequency", S_P_STRING},
{"JobAcctGatherParams", S_P_STRING},
{"JobCheckpointDir", S_P_STRING},
{"JobCompHost", S_P_STRING},
{"JobCompLoc", S_P_STRING},
{"JobCompPass", S_P_STRING},
{"JobCompPort", S_P_UINT32},
{"JobCompType", S_P_STRING},
{"JobContainerType", S_P_STRING},
{"JobCompUser", S_P_STRING},
{"JobCredentialPrivateKey", S_P_STRING},
{"JobCredentialPublicCertificate", S_P_STRING},
{"JobFileAppend", S_P_UINT16},
{"JobRequeue", S_P_UINT16},
{"JobSubmitPlugins", S_P_STRING},
{"KeepAliveTime", S_P_UINT16},
{"KillOnBadExit", S_P_UINT16},
{"KillWait", S_P_UINT16},
{"LaunchType", S_P_STRING},
{"Licenses", S_P_STRING},
{"LogTimeFormat", S_P_STRING},
{"MailProg", S_P_STRING},
{"MaxArraySize", S_P_UINT32},
{"MaxJobCount", S_P_UINT32},
{"MaxJobId", S_P_UINT32},
{"MaxMemPerCPU", S_P_UINT32},
{"MaxMemPerNode", S_P_UINT32},
{"MaxStepCount", S_P_UINT32},
{"MaxTasksPerNode", S_P_UINT16},
{"MessageTimeout", S_P_UINT16},
{"MinJobAge", S_P_UINT16},
{"MpiDefault", S_P_STRING},
{"MpiParams", S_P_STRING},
{"OverTimeLimit", S_P_UINT16},
{"PluginDir", S_P_STRING},
{"PlugStackConfig", S_P_STRING},
{"PreemptMode", S_P_STRING},
{"PreemptType", S_P_STRING},
{"PriorityDecayHalfLife", S_P_STRING},
{"PriorityCalcPeriod", S_P_STRING},
{"PriorityFavorSmall", S_P_BOOLEAN},
{"PriorityMaxAge", S_P_STRING},
{"PriorityUsageResetPeriod", S_P_STRING},
{"PriorityType", S_P_STRING},
{"PriorityFlags", S_P_STRING},
{"PriorityWeightAge", S_P_UINT32},
{"PriorityWeightFairshare", S_P_UINT32},
{"PriorityWeightJobSize", S_P_UINT32},
{"PriorityWeightPartition", S_P_UINT32},
{"PriorityWeightQOS", S_P_UINT32},
{"PrivateData", S_P_STRING},
{"ProctrackType", S_P_STRING},
{"Prolog", S_P_STRING},
{"PrologSlurmctld", S_P_STRING},
{"PrologFlags", S_P_STRING},
{"PropagatePrioProcess", S_P_UINT16},
{"PropagateResourceLimitsExcept", S_P_STRING},
{"PropagateResourceLimits", S_P_STRING},
{"RebootProgram", S_P_STRING},
{"ReconfigFlags", S_P_STRING},
{"ResumeProgram", S_P_STRING},
{"ResumeRate", S_P_UINT16},
{"ResumeTimeout", S_P_UINT16},
{"ResvEpilog", S_P_STRING},
{"ResvOverRun", S_P_UINT16},
{"ResvProlog", S_P_STRING},
{"ReturnToService", S_P_UINT16},
{"SallocDefaultCommand", S_P_STRING},
{"SchedulerAuth", S_P_STRING, _defunct_option},
{"SchedulerParameters", S_P_STRING},
{"SchedulerPort", S_P_UINT16},
{"SchedulerRootFilter", S_P_UINT16},
{"SchedulerTimeSlice", S_P_UINT16},
{"SchedulerType", S_P_STRING},
{"SelectType", S_P_STRING},
{"SelectTypeParameters", S_P_STRING},
{"SlurmUser", S_P_STRING},
{"SlurmdUser", S_P_STRING},
{"SlurmctldDebug", S_P_STRING},
{"SlurmctldLogFile", S_P_STRING},
{"SlurmctldPidFile", S_P_STRING},
{"SlurmctldPlugstack", S_P_STRING},
{"SlurmctldPort", S_P_STRING},
{"SlurmctldTimeout", S_P_UINT16},
{"SlurmdDebug", S_P_STRING},
{"SlurmdLogFile", S_P_STRING},
{"SlurmdPidFile", S_P_STRING},
{"SlurmdPlugstack", S_P_STRING},
{"SlurmdPort", S_P_UINT32},
{"SlurmdSpoolDir", S_P_STRING},
{"SlurmdTimeout", S_P_UINT16},
{"SlurmSchedLogFile", S_P_STRING},
{"SlurmSchedLogLevel", S_P_UINT16},
{"SrunEpilog", S_P_STRING},
{"SrunProlog", S_P_STRING},
{"StateSaveLocation", S_P_STRING},
{"SuspendExcNodes", S_P_STRING},
{"SuspendExcParts", S_P_STRING},
{"SuspendProgram", S_P_STRING},
{"SuspendRate", S_P_UINT16},
{"SuspendTime", S_P_LONG},
{"SuspendTimeout", S_P_UINT16},
{"SwitchType", S_P_STRING},
{"TaskEpilog", S_P_STRING},
{"TaskProlog", S_P_STRING},
{"TaskPlugin", S_P_STRING},
{"TaskPluginParam", S_P_STRING},
{"TmpFS", S_P_STRING},
{"TopologyPlugin", S_P_STRING},
{"TrackWCKey", S_P_BOOLEAN},
{"TreeWidth", S_P_UINT16},
{"UnkillableStepProgram", S_P_STRING},
{"UnkillableStepTimeout", S_P_UINT16},
{"UsePAM", S_P_BOOLEAN},
{"VSizeFactor", S_P_UINT16},
{"WaitTime", S_P_UINT16},
{"FrontendName", S_P_ARRAY, _parse_frontend, destroy_frontend},
{"NodeName", S_P_ARRAY, _parse_nodename, _destroy_nodename},
{"PartitionName", S_P_ARRAY, _parse_partitionname,
_destroy_partitionname},
{"DownNodes", S_P_ARRAY, _parse_downnodes, _destroy_downnodes},
{NULL}
};
static bool _is_valid_path (char *path, char *msg)
{
/*
* Allocate temporary space for walking the list of dirs:
*/
int pathlen;
char *buf = NULL, *p, *entry;
if (path == NULL) {
error ("is_valid_path: path is NULL!");
goto out_false;
}
pathlen = strlen (path);
buf = xmalloc (pathlen + 2);
if (strlcpy (buf, path, pathlen + 1) > pathlen + 1) {
error ("is_valid_path: Failed to copy path!");
goto out_false;
}
/*
* Ensure the path ends with a ':'
*/
if (buf [pathlen - 1] != ':') {
buf [pathlen] = ':';
buf [pathlen + 1] = '\0';
}
entry = buf;
while ((p = strchr (entry, ':'))) {
struct stat st;
/*
* NUL terminate colon and advance p
*/
*(p++) = '\0';
/*
* Check to see if current path element is a valid dir
*/
if (stat (entry, &st) < 0) {
error ("%s: %s: %m", msg, entry);
goto out_false;
}
else if (!S_ISDIR (st.st_mode)) {
error ("%s: %s: Not a directory", msg, entry);
goto out_false;
}
/*
* Otherwise path element is valid, continue..
*/
entry = p;
}
xfree (buf);
return true;
out_false:
xfree (buf);
return false;
}
static int _defunct_option(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover)
{
error("The option \"%s\" is defunct, see man slurm.conf.", key);
return 0;
}
/* Used to get the general name of the machine, used primarily
* for bluegene systems. Not in general use because some systems
* have multiple prefix's such as foo[1-1000],bar[1-1000].
*/
/* Caller must be holding slurm_conf_lock() */
static void _set_node_prefix(const char *nodenames)
{
int i;
char *tmp;
xassert(nodenames != NULL);
for (i = 1; nodenames[i] != '\0'; i++) {
if ((nodenames[i-1] == '[')
|| (nodenames[i-1] <= '9'
&& nodenames[i-1] >= '0'))
break;
}
if (i == 1) {
error("In your Node definition in your slurm.conf you "
"gave a nodelist '%s' without a prefix. "
"Please try something like bg%s.", nodenames, nodenames);
}
xfree(conf_ptr->node_prefix);
if (nodenames[i] == '\0')
conf_ptr->node_prefix = xstrdup(nodenames);
else {
tmp = xmalloc(sizeof(char)*i+1);
memset(tmp, 0, i+1);
snprintf(tmp, i, "%s", nodenames);
conf_ptr->node_prefix = tmp;
tmp = NULL;
}
debug3("Prefix is %s %s %d", conf_ptr->node_prefix, nodenames, i);
}
static int _parse_frontend(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover)
{
s_p_hashtbl_t *tbl, *dflt;
slurm_conf_frontend_t *n;
char *node_state = NULL;
static s_p_options_t _frontend_options[] = {
{"AllowGroups", S_P_STRING},
{"AllowUsers", S_P_STRING},
{"DenyGroups", S_P_STRING},
{"DenyUsers", S_P_STRING},
{"FrontendAddr", S_P_STRING},
{"Port", S_P_UINT16},
{"Reason", S_P_STRING},
{"State", S_P_STRING},
{NULL}
};
#ifndef HAVE_FRONT_END
fatal("Use of FrontendName in slurm.conf without SLURM being "
"configured/built with the --enable-front-end option");
#endif
tbl = s_p_hashtbl_create(_frontend_options);
s_p_parse_line(tbl, *leftover, leftover);
/* s_p_dump_values(tbl, _frontend_options); */
if (strcasecmp(value, "DEFAULT") == 0) {
char *tmp;
if (s_p_get_string(&tmp, "FrontendAddr", tbl)) {
error("FrontendAddr not allowed with "
"FrontendName=DEFAULT");
xfree(tmp);
s_p_hashtbl_destroy(tbl);
return -1;
}
if (default_frontend_tbl != NULL) {
s_p_hashtbl_merge(tbl, default_frontend_tbl);
s_p_hashtbl_destroy(default_frontend_tbl);
}
default_frontend_tbl = tbl;
return 0;
} else {
n = xmalloc(sizeof(slurm_conf_frontend_t));
dflt = default_frontend_tbl;
n->frontends = xstrdup(value);
(void) s_p_get_string(&n->allow_groups, "AllowGroups", tbl);
(void) s_p_get_string(&n->allow_users, "AllowUsers", tbl);
(void) s_p_get_string(&n->deny_groups, "DenyGroups", tbl);
(void) s_p_get_string(&n->deny_users, "DenyUsers", tbl);
if (n->allow_groups && n->deny_groups)
fatal("FrontEnd options AllowGroups and DenyGroups "
"are incompatible");
if (n->allow_users && n->deny_users)
fatal("FrontEnd options AllowUsers and DenyUsers "
"are incompatible");
if (!s_p_get_string(&n->addresses, "FrontendAddr", tbl))
n->addresses = xstrdup(n->frontends);
if (!s_p_get_uint16(&n->port, "Port", tbl) &&
!s_p_get_uint16(&n->port, "Port", dflt)) {
/* This gets resolved in slurm_conf_get_port()
* and slurm_conf_get_addr(). For now just
* leave with a value of zero */
n->port = 0;
}
if (!s_p_get_string(&n->reason, "Reason", tbl))
s_p_get_string(&n->reason, "Reason", dflt);
if (!s_p_get_string(&node_state, "State", tbl) &&
!s_p_get_string(&node_state, "State", dflt)) {
n->node_state = NODE_STATE_UNKNOWN;
} else {
n->node_state = state_str2int(node_state,
(char *) value);
if (n->node_state == (uint16_t) NO_VAL)
n->node_state = NODE_STATE_UNKNOWN;
xfree(node_state);
}
*dest = (void *)n;
s_p_hashtbl_destroy(tbl);
return 1;
}
/* should not get here */
}
static int _parse_nodename(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover)
{
s_p_hashtbl_t *tbl, *dflt;
slurm_conf_node_t *n;
int computed_procs;
static s_p_options_t _nodename_options[] = {
{"Boards", S_P_UINT16},
{"CoresPerSocket", S_P_UINT16},
{"CPUs", S_P_UINT16},
{"Feature", S_P_STRING},
{"Gres", S_P_STRING},
{"NodeAddr", S_P_STRING},
{"NodeHostname", S_P_STRING},
{"Port", S_P_STRING},
{"Procs", S_P_UINT16},
{"RealMemory", S_P_UINT32},
{"Reason", S_P_STRING},
{"Sockets", S_P_UINT16},
{"SocketsPerBoard", S_P_UINT16},
{"State", S_P_STRING},
{"ThreadsPerCore", S_P_UINT16},
{"TmpDisk", S_P_UINT32},
{"Weight", S_P_UINT32},
{NULL}
};
tbl = s_p_hashtbl_create(_nodename_options);
s_p_parse_line(tbl, *leftover, leftover);
/* s_p_dump_values(tbl, _nodename_options); */
if (strcasecmp(value, "DEFAULT") == 0) {
char *tmp;
if (s_p_get_string(&tmp, "NodeHostname", tbl)) {
error("NodeHostname not allowed with "
"NodeName=DEFAULT");
xfree(tmp);
s_p_hashtbl_destroy(tbl);
return -1;
}
if (s_p_get_string(&tmp, "NodeAddr", tbl)) {
error("NodeAddr not allowed with NodeName=DEFAULT");
xfree(tmp);
s_p_hashtbl_destroy(tbl);
return -1;
}
if (default_nodename_tbl != NULL) {
s_p_hashtbl_merge(tbl, default_nodename_tbl);
s_p_hashtbl_destroy(default_nodename_tbl);
}
default_nodename_tbl = tbl;
return 0;
} else {
bool no_cpus = false;
bool no_boards = false;
bool no_sockets = false;
bool no_cores = false;
bool no_threads = false;
bool no_sockets_per_board = false;
uint16_t sockets_per_board = 0;
n = xmalloc(sizeof(slurm_conf_node_t));
dflt = default_nodename_tbl;
n->nodenames = xstrdup(value);
if ((slurmdb_setup_cluster_name_dims() > 1)
&& conf_ptr->node_prefix == NULL)
_set_node_prefix(n->nodenames);
if (!s_p_get_string(&n->hostnames, "NodeHostname", tbl))
n->hostnames = xstrdup(n->nodenames);
if (!s_p_get_string(&n->addresses, "NodeAddr", tbl))
n->addresses = xstrdup(n->hostnames);
if (!s_p_get_uint16(&n->boards, "Boards", tbl)
&& !s_p_get_uint16(&n->boards, "Boards", dflt)) {
n->boards = 1;
no_boards = true;
}
if (!s_p_get_uint16(&n->cores, "CoresPerSocket", tbl)
&& !s_p_get_uint16(&n->cores, "CoresPerSocket", dflt)) {
n->cores = 1;
no_cores = true;
}
if (!s_p_get_string(&n->feature, "Feature", tbl))
s_p_get_string(&n->feature, "Feature", dflt);
if (!s_p_get_string(&n->gres, "Gres", tbl))
s_p_get_string(&n->gres, "Gres", dflt);
if (!s_p_get_string(&n->port_str, "Port", tbl) &&
!s_p_get_string(&n->port_str, "Port", dflt)) {
/* This gets resolved in slurm_conf_get_port()
* and slurm_conf_get_addr(). For now just
* leave with a value of NULL */
}
if (!s_p_get_uint16(&n->cpus, "CPUs", tbl) &&
!s_p_get_uint16(&n->cpus, "CPUs", dflt) &&
!s_p_get_uint16(&n->cpus, "Procs", tbl) &&
!s_p_get_uint16(&n->cpus, "Procs", dflt)) {
n->cpus = 1;
no_cpus = true;
}
if (!s_p_get_uint32(&n->real_memory, "RealMemory", tbl)
&& !s_p_get_uint32(&n->real_memory, "RealMemory", dflt))
n->real_memory = 1;
if (!s_p_get_string(&n->reason, "Reason", tbl))
s_p_get_string(&n->reason, "Reason", dflt);
if (!s_p_get_uint16(&n->sockets, "Sockets", tbl)
&& !s_p_get_uint16(&n->sockets, "Sockets", dflt)) {
n->sockets = 1;
no_sockets = true;
}
if (!s_p_get_uint16(&sockets_per_board, "SocketsPerBoard", tbl)
&& !s_p_get_uint16(&sockets_per_board, "SocketsPerBoard",
dflt)) {
sockets_per_board = 1;
no_sockets_per_board = true;
}
if (!s_p_get_string(&n->state, "State", tbl)
&& !s_p_get_string(&n->state, "State", dflt))
n->state = NULL;
if (!s_p_get_uint16(&n->threads, "ThreadsPerCore", tbl)
&& !s_p_get_uint16(&n->threads, "ThreadsPerCore", dflt)) {
n->threads = 1;
no_threads = true;
}
if (!s_p_get_uint32(&n->tmp_disk, "TmpDisk", tbl)
&& !s_p_get_uint32(&n->tmp_disk, "TmpDisk", dflt))
n->tmp_disk = 0;
if (!s_p_get_uint32(&n->weight, "Weight", tbl)
&& !s_p_get_uint32(&n->weight, "Weight", dflt))
n->weight = 1;
s_p_hashtbl_destroy(tbl);
if (n->cores == 0) { /* make sure cores is non-zero */
error("NodeNames=%s CoresPerSocket=0 is invalid, "
"reset to 1", n->nodenames);
n->cores = 1;
}
if (n->threads == 0) { /* make sure threads is non-zero */
error("NodeNames=%s ThreadsPerCore=0 is invalid, "
"reset to 1", n->nodenames);
n->threads = 1;
}
if (!no_sockets_per_board && sockets_per_board==0) {
/* make sure sockets_per_boards is non-zero */
error("NodeNames=%s SocketsPerBoards=0 is invalid, "
"reset to 1", n->nodenames);
sockets_per_board = 1;
}
if (no_boards) {
/* This case is exactly like if was without boards,
* Except SocketsPerBoard=# can be used,
* But it can't be used with Sockets=# */
n->boards = 1;
if (!no_sockets && !no_sockets_per_board) {
error("NodeNames=%s Sockets=# and "
"SocketsPerBoard=# is invalid"
", using SocketsPerBoard",
n->nodenames);
n->sockets = sockets_per_board;
}
if (!no_sockets_per_board) {
n->sockets = sockets_per_board;
}
if (!no_cpus && /* infer missing Sockets= */
no_sockets) {
n->sockets = n->cpus / (n->cores * n->threads);
}
if (n->sockets == 0) { /* make sure sockets != 0 */
error("NodeNames=%s Sockets=0 is invalid, "
"reset to 1", n->nodenames);
n->sockets = 1;
}
if (no_cpus) { /* infer missing CPUs= */
n->cpus = n->sockets * n->cores * n->threads;
}
/* if only CPUs= and Sockets=
* specified check for match */
if (!no_cpus && !no_sockets &&
no_cores && no_threads &&
(n->cpus != n->sockets)) {
n->sockets = n->cpus;
error("NodeNames=%s CPUs doesn't match "
"Sockets, setting Sockets to %d",
n->nodenames, n->sockets);
}
computed_procs = n->sockets * n->cores * n->threads;
if ((n->cpus != n->sockets) &&
(n->cpus != n->sockets * n->cores) &&
(n->cpus != computed_procs)) {
error("NodeNames=%s CPUs=%d doesn't match "
"Sockets*CoresPerSocket*ThreadsPerCore "
"(%d), resetting CPUs",
n->nodenames, n->cpus, computed_procs);
n->cpus = computed_procs;
}
} else {
/* In this case Boards=# is used.
* CPUs=# or Procs=# are ignored.
*/
if (!no_cpus) {
error("NodeNames=%s CPUs=# or Procs=# "
"with Boards=# is invalid and "
"is ignored.", n->nodenames);
}
if (n->boards == 0) {
/* make sure boards is non-zero */
error("NodeNames=%s Boards=0 is "
"invalid, reset to 1",
n->nodenames);
n->boards = 1;
}
if (!no_sockets && !no_sockets_per_board) {
error("NodeNames=%s Sockets=# and "
"SocketsPerBoard=# is invalid, "
"using SocketsPerBoard", n->nodenames);
n->sockets = n->boards * sockets_per_board;
} else if (!no_sockets_per_board) {
n->sockets = n->boards * sockets_per_board;
} else if (!no_sockets) {
error("NodeNames=%s Sockets=# with Boards=# is"
" not recommended, assume "
"SocketsPerBoard was meant",
n->nodenames);
if (n->sockets == 0) {
/* make sure sockets is non-zero */
error("NodeNames=%s Sockets=0 is "
"invalid, reset to 1",
n->nodenames);
n->sockets = 1;
}
n->sockets = n->boards * n->sockets;
} else {
n->sockets = n->boards;
}
/* Node boards factored into sockets */
n->cpus = n->sockets * n->cores * n->threads;
}
*dest = (void *)n;
return 1;
}
/* should not get here */
}
/* Destroy a front_end record built by slurm_conf_frontend_array() */
extern void destroy_frontend(void *ptr)
{
slurm_conf_frontend_t *n = (slurm_conf_frontend_t *) ptr;
xfree(n->allow_groups);
xfree(n->allow_users);
xfree(n->deny_groups);
xfree(n->deny_users);
xfree(n->frontends);
xfree(n->addresses);
xfree(n->reason);
xfree(ptr);
}
/*
* list_find_frontend - find an entry in the front_end list, see list.h for
* documentation
* IN key - is feature name or NULL for all features
* RET 1 if found, 0 otherwise
*/
extern int list_find_frontend (void *front_end_entry, void *key)
{
slurm_conf_frontend_t *front_end_ptr;
if (key == NULL)
return 1;
front_end_ptr = (slurm_conf_frontend_t *) front_end_entry;
if (strcmp(front_end_ptr->frontends, (char *) key) == 0)
return 1;
return 0;
}
static void _destroy_nodename(void *ptr)
{
slurm_conf_node_t *n = (slurm_conf_node_t *)ptr;
xfree(n->addresses);
xfree(n->feature);
xfree(n->hostnames);
xfree(n->gres);
xfree(n->nodenames);
xfree(n->port_str);
xfree(n->reason);
xfree(n->state);
xfree(ptr);
}
int slurm_conf_frontend_array(slurm_conf_frontend_t **ptr_array[])
{
int count;
slurm_conf_frontend_t **ptr;
if (s_p_get_array((void ***)&ptr, &count, "FrontendName",
conf_hashtbl)) {
*ptr_array = ptr;
return count;
} else {
#ifdef HAVE_FRONT_END
/* No FrontendName in slurm.conf. Take the NodeAddr and
* NodeHostName from the first node's record and use that to
* build an equivalent structure to that constructed when
* FrontendName is configured. This is intended for backward
* compatibility with SLURM version 2.2. */
static slurm_conf_frontend_t local_front_end;
static slurm_conf_frontend_t *local_front_end_array[2] =
{NULL, NULL};
static char addresses[1024], hostnames[1024];
if (local_front_end_array[0] == NULL) {
slurm_conf_node_t **node_ptr;
int node_count = 0;
if (!s_p_get_array((void ***)&node_ptr, &node_count,
"NodeName", conf_hashtbl) ||
(node_count == 0))
fatal("No front end nodes configured");
strncpy(addresses, node_ptr[0]->addresses,
sizeof(addresses));
strncpy(hostnames, node_ptr[0]->hostnames,
sizeof(hostnames));
local_front_end.addresses = addresses;
local_front_end.frontends = hostnames;
if (node_ptr[0]->port_str) {
local_front_end.port = atoi(node_ptr[0]->
port_str);
}
local_front_end.reason = NULL;
local_front_end.node_state = NODE_STATE_UNKNOWN;
local_front_end_array[0] = &local_front_end;
}
*ptr_array = local_front_end_array;
return 1;
#else
*ptr_array = NULL;
return 0;
#endif
}
}
int slurm_conf_nodename_array(slurm_conf_node_t **ptr_array[])
{
int count;
slurm_conf_node_t **ptr;
if (s_p_get_array((void ***)&ptr, &count, "NodeName", conf_hashtbl)) {
*ptr_array = ptr;
return count;
} else {
*ptr_array = NULL;
return 0;
}
}
static int _parse_partitionname(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover)
{
s_p_hashtbl_t *tbl, *dflt;
slurm_conf_partition_t *p;
char *tmp = NULL;
static s_p_options_t _partition_options[] = {
{"AllocNodes", S_P_STRING},
{"AllowAccounts",S_P_STRING},
{"AllowGroups", S_P_STRING},
{"AllowQos", S_P_STRING},
{"Alternate", S_P_STRING},
{"DefMemPerCPU", S_P_UINT32},
{"DefMemPerNode", S_P_UINT32},
{"Default", S_P_BOOLEAN}, /* YES or NO */
{"DefaultTime", S_P_STRING},
{"DenyAccounts", S_P_STRING},
{"DenyQos", S_P_STRING},
{"DisableRootJobs", S_P_BOOLEAN}, /* YES or NO */
{"GraceTime", S_P_UINT32},
{"Hidden", S_P_BOOLEAN}, /* YES or NO */
{"LLN", S_P_BOOLEAN}, /* YES or NO */
{"MaxCPUsPerNode", S_P_UINT32},
{"MaxMemPerCPU", S_P_UINT32},
{"MaxMemPerNode", S_P_UINT32},
{"MaxTime", S_P_STRING},
{"MaxNodes", S_P_UINT32}, /* INFINITE or a number */
{"MinNodes", S_P_UINT32},
{"Nodes", S_P_STRING},
{"PreemptMode", S_P_STRING},
{"Priority", S_P_UINT16},
{"RootOnly", S_P_BOOLEAN}, /* YES or NO */
{"ReqResv", S_P_BOOLEAN}, /* YES or NO */
{"SelectTypeParameters", S_P_STRING}, /* CR_Socket, CR_Core */
{"Shared", S_P_STRING}, /* YES, NO, or FORCE */
{"State", S_P_STRING}, /* UP, DOWN, INACTIVE or DRAIN */
{NULL}
};
tbl = s_p_hashtbl_create(_partition_options);
s_p_parse_line(tbl, *leftover, leftover);
/* s_p_dump_values(tbl, _partition_options); */
if (strcasecmp(value, "DEFAULT") == 0) {
if (default_partition_tbl != NULL) {
s_p_hashtbl_merge(tbl, default_partition_tbl);
s_p_hashtbl_destroy(default_partition_tbl);
}
default_partition_tbl = tbl;
return 0;
} else {
p = xmalloc(sizeof(slurm_conf_partition_t));
dflt = default_partition_tbl;
p->name = xstrdup(value);
if (!s_p_get_string(&p->allow_accounts, "AllowAccounts",tbl))
s_p_get_string(&p->allow_accounts, "AllowAccounts", dflt);
if (p->allow_accounts &&
(strcasecmp(p->allow_accounts, "ALL") == 0))
xfree(p->allow_accounts);
if (!s_p_get_string(&p->allow_groups, "AllowGroups", tbl))
s_p_get_string(&p->allow_groups, "AllowGroups", dflt);
if (p->allow_groups &&
(strcasecmp(p->allow_groups, "ALL") == 0))
xfree(p->allow_groups);
if (!s_p_get_string(&p->allow_qos, "AllowQos", tbl))
s_p_get_string(&p->allow_qos, "AllowQos", dflt);
if (p->allow_qos && (strcasecmp(p->allow_qos, "ALL") == 0))
xfree(p->allow_qos);
if (!s_p_get_string(&p->deny_accounts, "DenyAccounts", tbl))
s_p_get_string(&p->deny_accounts, "DenyAccounts", dflt);
if (p->allow_accounts && p->deny_accounts) {
error("Both AllowAccounts and DenyAccounts are "
"defined, DenyAccounts will be ignored");
}
if (!s_p_get_string(&p->deny_qos, "DenyQos", tbl))
s_p_get_string(&p->deny_qos, "DenyQos", dflt);
if (p->allow_qos && p->deny_qos) {
error("Both AllowQos and DenyQos are defined, "
"DenyQos will be ignored");
}
if (!s_p_get_string(&p->allow_alloc_nodes, "AllocNodes", tbl)) {
s_p_get_string(&p->allow_alloc_nodes, "AllocNodes",
dflt);
if (p->allow_alloc_nodes &&
(strcasecmp(p->allow_alloc_nodes, "ALL") == 0))
xfree(p->allow_alloc_nodes);
}
if (!s_p_get_string(&p->alternate, "Alternate", tbl))
s_p_get_string(&p->alternate, "Alternate", dflt);
if (!s_p_get_boolean(&p->default_flag, "Default", tbl)
&& !s_p_get_boolean(&p->default_flag, "Default", dflt))
p->default_flag = false;
if (!s_p_get_uint32(&p->max_cpus_per_node, "MaxCPUsPerNode",
tbl) &&
!s_p_get_uint32(&p->max_cpus_per_node, "MaxCPUsPerNode",
dflt))
p->max_cpus_per_node = INFINITE;
if (!s_p_get_uint32(&p->def_mem_per_cpu, "DefMemPerNode",
tbl) &&
!s_p_get_uint32(&p->def_mem_per_cpu, "DefMemPerNode",
dflt)) {
if (s_p_get_uint32(&p->def_mem_per_cpu,
"DefMemPerCPU", tbl) ||
s_p_get_uint32(&p->def_mem_per_cpu,
"DefMemPerCPU", dflt)) {
p->def_mem_per_cpu |= MEM_PER_CPU;
} else {
p->def_mem_per_cpu = 0;
}
}
if (!s_p_get_uint32(&p->max_mem_per_cpu, "MaxMemPerNode",
tbl) &&
!s_p_get_uint32(&p->max_mem_per_cpu, "MaxMemPerNode",
dflt)) {
if (s_p_get_uint32(&p->max_mem_per_cpu,
"MaxMemPerCPU", tbl) ||
s_p_get_uint32(&p->max_mem_per_cpu,
"MaxMemPerCPU", dflt)) {
p->max_mem_per_cpu |= MEM_PER_CPU;
} else {
p->max_mem_per_cpu = 0;
}
}
if (!s_p_get_boolean((bool *)&p->disable_root_jobs,
"DisableRootJobs", tbl))
p->disable_root_jobs = (uint16_t)NO_VAL;
if (!s_p_get_boolean(&p->hidden_flag, "Hidden", tbl) &&
!s_p_get_boolean(&p->hidden_flag, "Hidden", dflt))
p->hidden_flag = false;
if (!s_p_get_string(&tmp, "MaxTime", tbl) &&
!s_p_get_string(&tmp, "MaxTime", dflt))
p->max_time = INFINITE;
else {
int max_time = time_str2mins(tmp);
if ((max_time < 0) && (max_time != INFINITE)) {
error("Bad value \"%s\" for MaxTime", tmp);
_destroy_partitionname(p);
s_p_hashtbl_destroy(tbl);
xfree(tmp);
return -1;
}
p->max_time = max_time;
xfree(tmp);
}
if (!s_p_get_uint32(&p->grace_time, "GraceTime", tbl) &&
!s_p_get_uint32(&p->grace_time, "GraceTime", dflt))
p->grace_time = 0;
if (!s_p_get_string(&tmp, "DefaultTime", tbl) &&
!s_p_get_string(&tmp, "DefaultTime", dflt))
p->default_time = NO_VAL;
else {
int default_time = time_str2mins(tmp);
if ((default_time < 0) && (default_time != INFINITE)) {
error("Bad value \"%s\" for DefaultTime", tmp);
_destroy_partitionname(p);
s_p_hashtbl_destroy(tbl);
xfree(tmp);
return -1;
}
p->default_time = default_time;
xfree(tmp);
}
if (!s_p_get_uint32(&p->max_nodes, "MaxNodes", tbl)
&& !s_p_get_uint32(&p->max_nodes, "MaxNodes", dflt))
p->max_nodes = INFINITE;
if (!s_p_get_uint32(&p->min_nodes, "MinNodes", tbl)
&& !s_p_get_uint32(&p->min_nodes, "MinNodes", dflt))
p->min_nodes = 1;
#ifndef HAVE_ALPS_CRAY
if (!p->min_nodes)
fatal("Partition '%s' has invalid MinNodes=0, this is "
"currently valid only on a ALPS Cray system.",
p->name);
#endif
if (!s_p_get_string(&p->nodes, "Nodes", tbl)
&& !s_p_get_string(&p->nodes, "Nodes", dflt))
p->nodes = NULL;
else {
int i;
for (i=0; p->nodes[i]; i++) {
if (isspace((int)p->nodes[i]))
p->nodes[i] = ',';
}
}
if (!s_p_get_boolean(&p->root_only_flag, "RootOnly", tbl)
&& !s_p_get_boolean(&p->root_only_flag, "RootOnly", dflt))
p->root_only_flag = false;
if (!s_p_get_boolean(&p->req_resv_flag, "ReqResv", tbl)
&& !s_p_get_boolean(&p->req_resv_flag, "ReqResv", dflt))
p->req_resv_flag = false;
if (!s_p_get_boolean(&p->lln_flag, "LLN", tbl) &&
!s_p_get_boolean(&p->lln_flag, "LLN", dflt))
p->lln_flag = false;
if (s_p_get_string(&tmp, "PreemptMode", tbl) ||
s_p_get_string(&tmp, "PreemptMode", dflt)) {
p->preempt_mode = preempt_mode_num(tmp);
if (p->preempt_mode == (uint16_t) NO_VAL) {
error("Bad value \"%s\" for PreemptMode", tmp);
xfree(tmp);
return -1;
}
xfree(tmp);
} else
p->preempt_mode = (uint16_t) NO_VAL;
if (!s_p_get_uint16(&p->priority, "Priority", tbl) &&
!s_p_get_uint16(&p->priority, "Priority", dflt))
p->priority = 1;
if (s_p_get_string(&tmp, "SelectTypeParameters", tbl)) {
if (strncasecmp(tmp, "CR_Socket", 9) == 0)
p->cr_type = CR_SOCKET;
else if (strncasecmp(tmp, "CR_Core", 7) == 0)
p->cr_type = CR_CORE;
else {
error("Bad value for SelectTypeParameters: %s",
tmp);
_destroy_partitionname(p);
s_p_hashtbl_destroy(tbl);
xfree(tmp);
return -1;
}
xfree(tmp);
} else
p->cr_type = 0;
if (s_p_get_string(&tmp, "Shared", tbl) ||
s_p_get_string(&tmp, "Shared", dflt)) {
if (strcasecmp(tmp, "NO") == 0)
p->max_share = 1;
#ifndef HAVE_XCPU
/* Only "Shared=NO" is valid on XCPU systems */
else if (strcasecmp(tmp, "EXCLUSIVE") == 0)
p->max_share = 0;
else if (strncasecmp(tmp, "YES:", 4) == 0) {
int i = strtol(&tmp[4], (char **) NULL, 10);
if (i <= 1) {
error("Ignoring bad Shared value: %s",
tmp);
p->max_share = 1; /* Shared=NO */
} else
p->max_share = i;
} else if (strcasecmp(tmp, "YES") == 0)
p->max_share = 4;
else if (strncasecmp(tmp, "FORCE:", 6) == 0) {
int i = strtol(&tmp[6], (char **) NULL, 10);
if (i < 1) {
error("Ignoring bad Shared value: %s",
tmp);
p->max_share = 1; /* Shared=NO */
} else
p->max_share = i | SHARED_FORCE;
} else if (strcasecmp(tmp, "FORCE") == 0)
p->max_share = 4 | SHARED_FORCE;
#endif
else {
error("Bad value \"%s\" for Shared", tmp);
_destroy_partitionname(p);
s_p_hashtbl_destroy(tbl);
xfree(tmp);
return -1;
}
xfree(tmp);
} else
p->max_share = 1;
if (s_p_get_string(&tmp, "State", tbl) ||
s_p_get_string(&tmp, "State", dflt)) {
if (strncasecmp(tmp, "DOWN", 4) == 0)
p->state_up = PARTITION_DOWN;
else if (strncasecmp(tmp, "UP", 2) == 0)
p->state_up = PARTITION_UP;
else if (strncasecmp(tmp, "DRAIN", 5) == 0)
p->state_up = PARTITION_DRAIN;
else if (strncasecmp(tmp, "INACTIVE", 8) == 0)
p->state_up = PARTITION_INACTIVE;
else {
error("Bad value \"%s\" for State", tmp);
_destroy_partitionname(p);
s_p_hashtbl_destroy(tbl);
xfree(tmp);
return -1;
}
xfree(tmp);
} else
p->state_up = PARTITION_UP;
s_p_hashtbl_destroy(tbl);
*dest = (void *)p;
return 1;
}
/* should not get here */
}
static void _destroy_partitionname(void *ptr)
{
slurm_conf_partition_t *p = (slurm_conf_partition_t *)ptr;
xfree(p->allow_alloc_nodes);
xfree(p->allow_accounts);
xfree(p->allow_groups);
xfree(p->allow_qos);
xfree(p->deny_accounts);
xfree(p->deny_qos);
xfree(p->alternate);
xfree(p->name);
xfree(p->nodes);
xfree(ptr);
}
int slurm_conf_partition_array(slurm_conf_partition_t **ptr_array[])
{
int count;
slurm_conf_partition_t **ptr;
if (s_p_get_array((void ***)&ptr, &count, "PartitionName",
conf_hashtbl)) {
*ptr_array = ptr;
return count;
} else {
*ptr_array = NULL;
return 0;
}
}
static int _parse_downnodes(void **dest, slurm_parser_enum_t type,
const char *key, const char *value,
const char *line, char **leftover)
{
s_p_hashtbl_t *tbl;
slurm_conf_downnodes_t *n;
static s_p_options_t _downnodes_options[] = {
{"Reason", S_P_STRING},
{"State", S_P_STRING},
{NULL}
};
tbl = s_p_hashtbl_create(_downnodes_options);
s_p_parse_line(tbl, *leftover, leftover);
/* s_p_dump_values(tbl, _downnodes_options); */
n = xmalloc(sizeof(slurm_conf_node_t));
n->nodenames = xstrdup(value);
if (!s_p_get_string(&n->reason, "Reason", tbl))
n->reason = xstrdup("Set in slurm.conf");
if (!s_p_get_string(&n->state, "State", tbl))
n->state = NULL;
s_p_hashtbl_destroy(tbl);
*dest = (void *)n;
return 1;
}
static void _destroy_downnodes(void *ptr)
{
slurm_conf_downnodes_t *n = (slurm_conf_downnodes_t *)ptr;
xfree(n->nodenames);
xfree(n->reason);
xfree(n->state);
xfree(ptr);
}
extern int slurm_conf_downnodes_array(slurm_conf_downnodes_t **ptr_array[])
{
int count;
slurm_conf_downnodes_t **ptr;
if (s_p_get_array((void ***)&ptr, &count, "DownNodes", conf_hashtbl)) {
*ptr_array = ptr;
return count;
} else {
*ptr_array = NULL;
return 0;
}
}
static void _free_name_hashtbl(void)
{
int i;
names_ll_t *p, *q;
for (i=0; i<NAME_HASH_LEN; i++) {
p = node_to_host_hashtbl[i];
while (p) {
xfree(p->alias);
xfree(p->hostname);
xfree(p->address);
q = p->next_alias;
xfree(p);
p = q;
}
node_to_host_hashtbl[i] = NULL;
host_to_node_hashtbl[i] = NULL;
}
nodehash_initialized = false;
}
static void _init_name_hashtbl(void)
{
return;
}
static int _get_hash_idx(const char *name)
{
int index = 0;
int j;
if (name == NULL)
return 0; /* degenerate case */
/* Multiply each character by its numerical position in the
* name string to add a bit of entropy, because host names such
* as cluster[0001-1000] can cause excessive index collisions.
*/
for (j = 1; *name; name++, j++)
index += (int)*name * j;
index %= NAME_HASH_LEN;
if (index < 0)
index += NAME_HASH_LEN;
return index;
}
static void _push_to_hashtbls(char *alias, char *hostname,
char *address, uint16_t port,
uint16_t cpus, uint16_t boards,
uint16_t sockets, uint16_t cores,
uint16_t threads, bool front_end)
{
int hostname_idx, alias_idx;
names_ll_t *p, *new;
alias_idx = _get_hash_idx(alias);
hostname_idx = _get_hash_idx(hostname);
#if !defined(HAVE_FRONT_END) && !defined(MULTIPLE_SLURMD)
/* Ensure only one slurmd configured on each host */
p = host_to_node_hashtbl[hostname_idx];
while (p) {
if (strcmp(p->hostname, hostname) == 0) {
error("Duplicated NodeHostName %s in the config file",
hostname);
return;
}
p = p->next_hostname;
}
#endif
/* Ensure only one instance of each NodeName */
p = node_to_host_hashtbl[alias_idx];
while (p) {
if (strcmp(p->alias, alias)==0) {
if (front_end)
fatal("Frontend not configured correctly "
"in slurm.conf. See man slurm.conf "
"look for frontendname.");
fatal("Duplicated NodeName %s in the config file",
p->alias);
return;
}
p = p->next_alias;
}
/* Create the new data structure and link it into the hash tables */
new = (names_ll_t *)xmalloc(sizeof(names_ll_t));
new->alias = xstrdup(alias);
new->hostname = xstrdup(hostname);
new->address = xstrdup(address);
new->port = port;
new->cpus = cpus;
new->boards = boards;
new->sockets = sockets;
new->cores = cores;
new->threads = threads;
new->addr_initialized = false;
/* Put on end of each list */
new->next_alias = NULL;
if (node_to_host_hashtbl[alias_idx]) {
p = node_to_host_hashtbl[alias_idx];
while (p->next_alias)
p = p->next_alias;
p->next_alias = new;
} else {
node_to_host_hashtbl[alias_idx] = new;
}
new->next_hostname = NULL;
if (host_to_node_hashtbl[hostname_idx]) {
p = host_to_node_hashtbl[hostname_idx];
while (p->next_hostname)
p = p->next_hostname;
p->next_hostname = new;
} else {
host_to_node_hashtbl[hostname_idx] = new;
}
}
/*
* Register the given NodeName in the alias table.
* If node_hostname is NULL, only node_name will be used and
* no lookup table record is created.
*/
static int _register_conf_node_aliases(slurm_conf_node_t *node_ptr)
{
hostlist_t address_list = NULL;
hostlist_t alias_list = NULL;
hostlist_t hostname_list = NULL;
hostlist_t port_list = NULL;
char *address = NULL;
char *alias = NULL;
char *hostname = NULL;
char *port_str = NULL;
int error_code = SLURM_SUCCESS;
int address_count, alias_count, hostname_count, port_count, port_int;
uint16_t port = 0;
if ((node_ptr->nodenames == NULL) || (node_ptr->nodenames[0] == '\0'))
return -1;
if ((address_list = hostlist_create(node_ptr->addresses)) == NULL) {
error("Unable to create NodeAddr list from %s",
node_ptr->addresses);
error_code = errno;
goto cleanup;
}
if ((alias_list = hostlist_create(node_ptr->nodenames)) == NULL) {
error("Unable to create NodeName list from %s",
node_ptr->nodenames);
error_code = errno;
goto cleanup;
}
if ((hostname_list = hostlist_create(node_ptr->hostnames)) == NULL) {
error("Unable to create NodeHostname list from %s",
node_ptr->hostnames);
error_code = errno;
goto cleanup;
}
if (node_ptr->port_str && node_ptr->port_str[0] &&
(node_ptr->port_str[0] != '[') &&
(strchr(node_ptr->port_str, '-') ||
strchr(node_ptr->port_str, ','))) {
xstrfmtcat(port_str, "[%s]", node_ptr->port_str);
port_list = hostlist_create(port_str);
xfree(port_str);
} else {
port_list = hostlist_create(node_ptr->port_str);
}
if (port_list == NULL) {
error("Unable to create Port list from %s",
node_ptr->port_str);
error_code = errno;
goto cleanup;
}
if ((slurmdb_setup_cluster_name_dims() > 1)
&& conf_ptr->node_prefix == NULL)
_set_node_prefix(node_ptr->nodenames);
/* some sanity checks */
address_count = hostlist_count(address_list);
alias_count = hostlist_count(alias_list);
hostname_count = hostlist_count(hostname_list);
port_count = hostlist_count(port_list);
#ifdef HAVE_FRONT_END
if ((address_count != alias_count) && (address_count != 1)) {
error("NodeAddr count must equal that of NodeName "
"records of there must be no more than one");
goto cleanup;
}
if ((hostname_count != alias_count) && (hostname_count != 1)) {
error("NodeHostname count must equal that of NodeName "
"records of there must be no more than one");
goto cleanup;
}
#else
#ifdef MULTIPLE_SLURMD
if ((address_count != alias_count) && (address_count != 1)) {
error("NodeAddr count must equal that of NodeName "
"records of there must be no more than one");
goto cleanup;
}
#else
if (address_count < alias_count) {
error("At least as many NodeAddr are required as NodeName");
goto cleanup;
}
if (hostname_count < alias_count) {
error("At least as many NodeHostname are required "
"as NodeName");
goto cleanup;
}
#endif /* MULTIPLE_SLURMD */
#endif /* HAVE_FRONT_END */
if ((port_count != alias_count) && (port_count > 1)) {
error("Port count must equal that of NodeName "
"records or there must be no more than one (%u != %u)",
port_count, alias_count);
goto cleanup;
}
/* now build the individual node structures */
while ((alias = hostlist_shift(alias_list))) {
if (address_count > 0) {
address_count--;
if (address)
free(address);
address = hostlist_shift(address_list);
}
if (hostname_count > 0) {
hostname_count--;
if (hostname)
free(hostname);
hostname = hostlist_shift(hostname_list);
}
if (port_count > 0) {
port_count--;
if (port_str)
free(port_str);
port_str = hostlist_shift(port_list);
port_int = atoi(port_str);
if ((port_int <= 0) || (port_int > 0xffff))
fatal("Invalid Port %s", node_ptr->port_str);
port = port_int;
}
_push_to_hashtbls(alias, hostname, address, port,
node_ptr->cpus, node_ptr->boards,
node_ptr->sockets, node_ptr->cores,
node_ptr->threads, 0);
free(alias);
}
if (address)
free(address);
if (hostname)
free(hostname);
if (port_str)
free(port_str);
/* free allocated storage */
cleanup:
if (address_list)
hostlist_destroy(address_list);
if (alias_list)
hostlist_destroy(alias_list);
if (hostname_list)
hostlist_destroy(hostname_list);
if (port_list)
hostlist_destroy(port_list);
return error_code;
}
static int _register_front_ends(slurm_conf_frontend_t *front_end_ptr)
{
hostlist_t hostname_list = NULL;
hostlist_t address_list = NULL;
char *hostname = NULL;
char *address = NULL;
int error_code = SLURM_SUCCESS;
if ((front_end_ptr->frontends == NULL) ||
(front_end_ptr->frontends[0] == '\0'))
return -1;
if ((hostname_list = hostlist_create(front_end_ptr->frontends))
== NULL) {
error("Unable to create FrontendNames list from %s",
front_end_ptr->frontends);
error_code = errno;
goto cleanup;
}
if ((address_list = hostlist_create(front_end_ptr->addresses))
== NULL) {
error("Unable to create FrontendAddr list from %s",
front_end_ptr->addresses);
error_code = errno;
goto cleanup;
}
if (hostlist_count(address_list) != hostlist_count(hostname_list)) {
error("Node count mismatch between FrontendNames and "
"FrontendAddr");
goto cleanup;
}
while ((hostname = hostlist_shift(hostname_list))) {
address = hostlist_shift(address_list);
_push_to_hashtbls(hostname, hostname, address,
front_end_ptr->port, 1, 1, 1, 1, 1, 1);
free(hostname);
free(address);
}
/* free allocated storage */
cleanup:
if (hostname_list)
hostlist_destroy(hostname_list);
if (address_list)
hostlist_destroy(address_list);
return error_code;
}
static void _init_slurmd_nodehash(void)
{
slurm_conf_node_t **ptr_array;
slurm_conf_frontend_t **ptr_front_end;
int count, i;
if (nodehash_initialized)
return;
else
nodehash_initialized = true;
if (!conf_initialized) {
if (_init_slurm_conf(NULL) != SLURM_SUCCESS)
fatal("Unable to process slurm.conf file");
conf_initialized = true;
}
count = slurm_conf_nodename_array(&ptr_array);
for (i = 0; i < count; i++)
_register_conf_node_aliases(ptr_array[i]);
count = slurm_conf_frontend_array(&ptr_front_end);
for (i = 0; i < count; i++)
_register_front_ends(ptr_front_end[i]);
}
/*
* Caller needs to call slurm_conf_lock() and hold the lock before
* calling this function (and call slurm_conf_unlock() afterwards).
*/
static char *_internal_get_hostname(const char *node_name)
{
int idx;
names_ll_t *p;
_init_slurmd_nodehash();
idx = _get_hash_idx(node_name);
p = node_to_host_hashtbl[idx];
while (p) {
if (strcmp(p->alias, node_name) == 0) {
return xstrdup(p->hostname);
}
p = p->next_alias;
}
return NULL;
}
/*
* slurm_conf_get_hostname - Return the NodeHostname for given NodeName
*/
extern char *slurm_conf_get_hostname(const char *node_name)
{
char *hostname = NULL;
slurm_conf_lock();
hostname = _internal_get_hostname(node_name);
slurm_conf_unlock();
return hostname;
}
/*
* slurm_conf_get_nodename - Return the NodeName for given NodeHostname
*
* NOTE: Call xfree() to release returned value's memory.
* NOTE: Caller must NOT be holding slurm_conf_lock().
*/
extern char *slurm_conf_get_nodename(const char *node_hostname)
{
char *alias = NULL;
int idx;
names_ll_t *p;
#ifdef HAVE_FRONT_END
slurm_conf_frontend_t *front_end_ptr = NULL;
slurm_conf_lock();
if (!front_end_list) {
debug("front_end_list is NULL");
} else {
front_end_ptr = list_find_first(front_end_list,
list_find_frontend,
(char *) node_hostname);
if (front_end_ptr) {
alias = xstrdup(front_end_ptr->frontends);
slurm_conf_unlock();
return alias;
}
}
#else
slurm_conf_lock();
#endif
_init_slurmd_nodehash();
idx = _get_hash_idx(node_hostname);
p = host_to_node_hashtbl[idx];
while (p) {
if (strcmp(p->hostname, node_hostname) == 0) {
alias = xstrdup(p->alias);
break;
}
p = p->next_hostname;
}
slurm_conf_unlock();
return alias;
}
/*
* slurm_conf_get_aliases - Return all the nodes NodeName value
* associated to a given NodeHostname (usefull in case of multiple-slurmd
* to get the list of virtual nodes associated with a real node)
*
* NOTE: Call xfree() to release returned value's memory.
* NOTE: Caller must NOT be holding slurm_conf_lock().
*/
extern char *slurm_conf_get_aliases(const char *node_hostname)
{
int idx;
names_ll_t *p;
char *aliases = NULL;
char *s = NULL;
slurm_conf_lock();
_init_slurmd_nodehash();
idx = _get_hash_idx(node_hostname);
p = host_to_node_hashtbl[idx];
while (p) {
if (strcmp(p->hostname, node_hostname) == 0) {
if ( aliases == NULL )
aliases = xstrdup(p->alias);
else {
s = xstrdup_printf("%s %s",aliases,p->alias);
xfree(aliases);
aliases = s;
}
}
p = p->next_hostname;
}
slurm_conf_unlock();
return aliases;
}
/*
* slurm_conf_get_nodeaddr - Return the NodeAddr for given NodeHostname
*
* NOTE: Call xfree() to release returned value's memory.
* NOTE: Caller must NOT be holding slurm_conf_lock().
*/
extern char *slurm_conf_get_nodeaddr(const char *node_hostname)
{
int idx;
names_ll_t *p;
slurm_conf_lock();
_init_slurmd_nodehash();
idx = _get_hash_idx(node_hostname);
p = host_to_node_hashtbl[idx];
while (p) {
if (strcmp(p->hostname, node_hostname) == 0) {
char *nodeaddr;
if (p->address != NULL)
nodeaddr = xstrdup(p->address);
else
nodeaddr = NULL;
slurm_conf_unlock();
return nodeaddr;
}
p = p->next_hostname;
}
slurm_conf_unlock();
return NULL;
}
/*
* slurm_conf_get_nodename_from_addr - Return the NodeName for given NodeAddr
*
* NOTE: Call xfree() to release returned value's memory.
* NOTE: Caller must NOT be holding slurm_conf_lock().
*/
extern char *slurm_conf_get_nodename_from_addr(const char *node_addr)
{
unsigned char buf[HOSTENT_SIZE];
struct hostent *hptr;
unsigned long addr = inet_addr(node_addr);
char *start_name, *ret_name = NULL, *dot_ptr;
if (!(hptr = get_host_by_addr((char *)&addr, sizeof(addr), AF_INET,
buf, sizeof(buf), NULL))) {
error("No node found with addr %s", node_addr);
return NULL;
}
if (!strcmp(hptr->h_name, "localhost")) {
start_name = xshort_hostname();
} else {
start_name = xstrdup(hptr->h_name);
dot_ptr = strchr(start_name, '.');
if (dot_ptr == NULL)
dot_ptr = start_name + strlen(start_name);
else
dot_ptr[0] = '\0';
}
ret_name = slurm_conf_get_aliases(start_name);
xfree(start_name);
return ret_name;
}
/*
* slurm_conf_get_aliased_nodename - Return the NodeName for the
* complete hostname string returned by gethostname if there is
* such a match, otherwise iterate through any aliases returned
* by get_host_by_name
*/
extern char *slurm_conf_get_aliased_nodename()
{
char hostname_full[1024];
int error_code;
char *nodename;
error_code = gethostname(hostname_full, sizeof(hostname_full));
/* we shouldn't have any problem here since by the time
* this function has been called, gethostname_short,
* which invokes gethostname, has probably already been called
* successfully, so just return NULL if something weird
* happens at this point
*/
if (error_code)
return NULL;
nodename = slurm_conf_get_nodename(hostname_full);
/* if the full hostname did not match a nodename */
if (nodename == NULL) {
/* use get_host_by_name; buffer sizes, semantics, etc.
* copied from slurm_protocol_socket_implementation.c
*/
struct hostent * he = NULL;
char * h_buf[4096];
int h_err;
he = get_host_by_name(hostname_full, (void *)&h_buf,
sizeof(h_buf), &h_err);
if (he != NULL) {
unsigned int i = 0;
/* check the "official" host name first */
nodename = slurm_conf_get_nodename(he->h_name);
while ((nodename == NULL) &&
(he->h_aliases[i] != NULL)) {
/* the "official" name still didn't match --
* iterate through the aliases */
nodename =
slurm_conf_get_nodename(he->h_aliases[i]);
i++;
}
}
}
return nodename;
}
/*
* slurm_conf_get_port - Return the port for a given NodeName
*/
extern uint16_t slurm_conf_get_port(const char *node_name)
{
int idx;
names_ll_t *p;
slurm_conf_lock();
_init_slurmd_nodehash();
idx = _get_hash_idx(node_name);
p = node_to_host_hashtbl[idx];
while (p) {
if (strcmp(p->alias, node_name) == 0) {
uint16_t port;
if (!p->port)
p->port = (uint16_t) conf_ptr->slurmd_port;
port = p->port;
slurm_conf_unlock();
return port;
}
p = p->next_alias;
}
slurm_conf_unlock();
return 0;
}
/*
* slurm_reset_alias - Reset the address and hostname of a specific node name
*/
extern void slurm_reset_alias(char *node_name, char *node_addr,
char *node_hostname)
{
int idx;
names_ll_t *p;
slurm_conf_lock();
_init_slurmd_nodehash();
idx = _get_hash_idx(node_name);
p = node_to_host_hashtbl[idx];
while (p) {
if (strcmp(p->alias, node_name) == 0) {
if (node_addr) {
xfree(p->address);
p->address = xstrdup(node_addr);
p->addr_initialized = false;
}
if (node_hostname) {
xfree(p->hostname);
p->hostname = xstrdup(node_hostname);
}
break;
}
p = p->next_alias;
}
slurm_conf_unlock();
return;
}
/*
* slurm_conf_get_addr - Return the slurm_addr_t for a given NodeName
* Returns SLURM_SUCCESS on success, SLURM_FAILURE on failure.
*/
extern int slurm_conf_get_addr(const char *node_name, slurm_addr_t *address)
{
int idx;
names_ll_t *p;
slurm_conf_lock();
_init_slurmd_nodehash();
idx = _get_hash_idx(node_name);
p = node_to_host_hashtbl[idx];
while (p) {
if (strcmp(p->alias, node_name) == 0) {
if (!p->port)
p->port = (uint16_t) conf_ptr->slurmd_port;
if (!p->addr_initialized) {
slurm_set_addr(&p->addr, p->port, p->address);
if (p->addr.sin_family == 0 &&
p->addr.sin_port == 0) {
slurm_conf_unlock();
return SLURM_FAILURE;
}
p->addr_initialized = true;
}
*address = p->addr;
slurm_conf_unlock();
return SLURM_SUCCESS;
}
p = p->next_alias;
}
slurm_conf_unlock();
return SLURM_FAILURE;
}
/*
* slurm_conf_get_cpus_bsct -
* Return the cpus, boards, sockets, cores, and threads configured for a
* given NodeName
* Returns SLURM_SUCCESS on success, SLURM_FAILURE on failure.
*/
extern int slurm_conf_get_cpus_bsct(const char *node_name,
uint16_t *cpus, uint16_t *boards,
uint16_t *sockets, uint16_t *cores,
uint16_t *threads)
{
int idx;
names_ll_t *p;
slurm_conf_lock();
_init_slurmd_nodehash();
idx = _get_hash_idx(node_name);
p = node_to_host_hashtbl[idx];
while (p) {
if (strcmp(p->alias, node_name) == 0) {
if (cpus)
*cpus = p->cpus;
if (boards)
*boards = p->boards;
if (sockets)
*sockets = p->sockets;
if (cores)
*cores = p->cores;
if (threads)
*threads = p->threads;
slurm_conf_unlock();
return SLURM_SUCCESS;
}
p = p->next_alias;
}
slurm_conf_unlock();
return SLURM_FAILURE;
}
/* gethostname_short - equivalent to gethostname, but return only the first
* component of the fully qualified name
* (e.g. "linux123.foo.bar" becomes "linux123")
* OUT name
*/
int
gethostname_short (char *name, size_t len)
{
int error_code, name_len;
char *dot_ptr, path_name[1024];
error_code = gethostname (path_name, sizeof(path_name));
if (error_code)
return error_code;
dot_ptr = strchr (path_name, '.');
if (dot_ptr == NULL)
dot_ptr = path_name + strlen(path_name);
else
dot_ptr[0] = '\0';
name_len = (dot_ptr - path_name);
if (name_len > len)
return ENAMETOOLONG;
strcpy (name, path_name);
return 0;
}
/*
* free_slurm_conf - free all storage associated with a slurm_ctl_conf_t.
* IN/OUT ctl_conf_ptr - pointer to data structure to be freed
* IN purge_node_hash - purge system-wide node hash table if set,
* set to zero if clearing private copy of config data
*/
extern void
free_slurm_conf (slurm_ctl_conf_t *ctl_conf_ptr, bool purge_node_hash)
{
xfree (ctl_conf_ptr->accounting_storage_backup_host);
xfree (ctl_conf_ptr->accounting_storage_host);
xfree (ctl_conf_ptr->accounting_storage_loc);
xfree (ctl_conf_ptr->accounting_storage_pass);
xfree (ctl_conf_ptr->accounting_storage_type);
xfree (ctl_conf_ptr->accounting_storage_user);
if (ctl_conf_ptr->acct_gather_conf)
list_destroy((List)ctl_conf_ptr->acct_gather_conf);
xfree (ctl_conf_ptr->acct_gather_energy_type);
xfree (ctl_conf_ptr->acct_gather_profile_type);
xfree (ctl_conf_ptr->acct_gather_infiniband_type);
xfree (ctl_conf_ptr->acct_gather_filesystem_type);
xfree (ctl_conf_ptr->authinfo);
xfree (ctl_conf_ptr->authtype);
xfree (ctl_conf_ptr->backup_addr);
xfree (ctl_conf_ptr->backup_controller);
xfree (ctl_conf_ptr->checkpoint_type);
xfree (ctl_conf_ptr->cluster_name);
xfree (ctl_conf_ptr->control_addr);
xfree (ctl_conf_ptr->control_machine);
xfree (ctl_conf_ptr->core_spec_plugin);
xfree (ctl_conf_ptr->crypto_type);
xfree (ctl_conf_ptr->epilog);
xfree (ctl_conf_ptr->epilog_slurmctld);
if (ctl_conf_ptr->ext_sensors_conf)
list_destroy((List)ctl_conf_ptr->ext_sensors_conf);
xfree (ctl_conf_ptr->ext_sensors_type);
xfree (ctl_conf_ptr->gres_plugins);
xfree (ctl_conf_ptr->health_check_program);
xfree (ctl_conf_ptr->job_acct_gather_freq);
xfree (ctl_conf_ptr->job_acct_gather_type);
xfree (ctl_conf_ptr->job_acct_gather_params);
xfree (ctl_conf_ptr->job_ckpt_dir);
xfree (ctl_conf_ptr->job_comp_host);
xfree (ctl_conf_ptr->job_comp_loc);
xfree (ctl_conf_ptr->job_comp_pass);
xfree (ctl_conf_ptr->job_comp_type);
xfree (ctl_conf_ptr->job_comp_user);
xfree (ctl_conf_ptr->job_container_plugin);
xfree (ctl_conf_ptr->job_credential_private_key);
xfree (ctl_conf_ptr->job_credential_public_certificate);
xfree (ctl_conf_ptr->job_submit_plugins);
xfree (ctl_conf_ptr->launch_type);
xfree (ctl_conf_ptr->licenses);
xfree (ctl_conf_ptr->licenses_used);
xfree (ctl_conf_ptr->mail_prog);
xfree (ctl_conf_ptr->mpi_default);
xfree (ctl_conf_ptr->mpi_params);
xfree (ctl_conf_ptr->node_prefix);
xfree (ctl_conf_ptr->plugindir);
xfree (ctl_conf_ptr->plugstack);
xfree (ctl_conf_ptr->preempt_type);
xfree (ctl_conf_ptr->priority_type);
xfree (ctl_conf_ptr->proctrack_type);
xfree (ctl_conf_ptr->prolog);
xfree (ctl_conf_ptr->prolog_slurmctld);
xfree (ctl_conf_ptr->propagate_rlimits);
xfree (ctl_conf_ptr->propagate_rlimits_except);
xfree (ctl_conf_ptr->reboot_program);
xfree (ctl_conf_ptr->resume_program);
xfree (ctl_conf_ptr->resv_epilog);
xfree (ctl_conf_ptr->resv_prolog);
xfree (ctl_conf_ptr->salloc_default_command);
xfree (ctl_conf_ptr->sched_logfile);
xfree (ctl_conf_ptr->sched_params);
xfree (ctl_conf_ptr->schedtype);
xfree (ctl_conf_ptr->select_type);
if (ctl_conf_ptr->select_conf_key_pairs)
list_destroy((List)ctl_conf_ptr->select_conf_key_pairs);
xfree (ctl_conf_ptr->slurm_conf);
xfree (ctl_conf_ptr->slurm_user_name);
xfree (ctl_conf_ptr->slurmctld_logfile);
xfree (ctl_conf_ptr->slurmctld_pidfile);
xfree (ctl_conf_ptr->slurmctld_plugstack);
xfree (ctl_conf_ptr->slurmd_logfile);
xfree (ctl_conf_ptr->slurmd_pidfile);
xfree (ctl_conf_ptr->slurmd_plugstack);
xfree (ctl_conf_ptr->slurmd_spooldir);
xfree (ctl_conf_ptr->slurmd_user_name);
xfree (ctl_conf_ptr->srun_epilog);
xfree (ctl_conf_ptr->srun_prolog);
xfree (ctl_conf_ptr->state_save_location);
xfree (ctl_conf_ptr->suspend_exc_nodes);
xfree (ctl_conf_ptr->suspend_exc_parts);
xfree (ctl_conf_ptr->suspend_program);
xfree (ctl_conf_ptr->switch_type);
xfree (ctl_conf_ptr->task_epilog);
xfree (ctl_conf_ptr->task_plugin);
xfree (ctl_conf_ptr->task_prolog);
xfree (ctl_conf_ptr->tmp_fs);
xfree (ctl_conf_ptr->topology_plugin);
xfree (ctl_conf_ptr->unkillable_program);
xfree (ctl_conf_ptr->version);
xfree (ctl_conf_ptr->z_char);
if (purge_node_hash)
_free_name_hashtbl();
}
/*
* init_slurm_conf - initialize or re-initialize the slurm configuration
* values to defaults (NULL or NO_VAL). Note that the configuration
* file pathname (slurm_conf) is not changed.
* IN/OUT ctl_conf_ptr - pointer to data structure to be initialized
*/
void
init_slurm_conf (slurm_ctl_conf_t *ctl_conf_ptr)
{
ctl_conf_ptr->last_update = time(NULL);
xfree (ctl_conf_ptr->accounting_storage_backup_host);
ctl_conf_ptr->accounting_storage_enforce = 0;
xfree (ctl_conf_ptr->accounting_storage_host);
xfree (ctl_conf_ptr->accounting_storage_loc);
xfree (ctl_conf_ptr->accounting_storage_pass);
ctl_conf_ptr->accounting_storage_port = 0;
xfree (ctl_conf_ptr->accounting_storage_type);
xfree (ctl_conf_ptr->accounting_storage_user);
xfree (ctl_conf_ptr->authinfo);
xfree (ctl_conf_ptr->authtype);
xfree (ctl_conf_ptr->backup_addr);
xfree (ctl_conf_ptr->backup_controller);
ctl_conf_ptr->batch_start_timeout = 0;
xfree (ctl_conf_ptr->checkpoint_type);
xfree (ctl_conf_ptr->cluster_name);
ctl_conf_ptr->complete_wait = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->control_addr);
xfree (ctl_conf_ptr->control_machine);
xfree (ctl_conf_ptr->core_spec_plugin);
xfree (ctl_conf_ptr->crypto_type);
ctl_conf_ptr->def_mem_per_cpu = 0;
ctl_conf_ptr->debug_flags = 0;
ctl_conf_ptr->disable_root_jobs = 0;
ctl_conf_ptr->acct_gather_node_freq = 0;
xfree (ctl_conf_ptr->acct_gather_energy_type);
xfree (ctl_conf_ptr->acct_gather_profile_type);
xfree (ctl_conf_ptr->acct_gather_infiniband_type);
xfree (ctl_conf_ptr->acct_gather_filesystem_type);
ctl_conf_ptr->ext_sensors_freq = 0;
xfree (ctl_conf_ptr->ext_sensors_type);
ctl_conf_ptr->dynalloc_port = (uint16_t) NO_VAL;
ctl_conf_ptr->enforce_part_limits = 0;
xfree (ctl_conf_ptr->epilog);
ctl_conf_ptr->epilog_msg_time = (uint32_t) NO_VAL;
ctl_conf_ptr->fast_schedule = (uint16_t) NO_VAL;
ctl_conf_ptr->first_job_id = NO_VAL;
ctl_conf_ptr->get_env_timeout = 0;
xfree(ctl_conf_ptr->gres_plugins);
ctl_conf_ptr->group_info = (uint16_t) NO_VAL;
ctl_conf_ptr->hash_val = (uint32_t) NO_VAL;
ctl_conf_ptr->health_check_interval = 0;
xfree(ctl_conf_ptr->health_check_program);
ctl_conf_ptr->inactive_limit = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->job_acct_gather_freq);
xfree (ctl_conf_ptr->job_acct_gather_type);
xfree (ctl_conf_ptr->job_acct_gather_params);
xfree (ctl_conf_ptr->job_ckpt_dir);
xfree (ctl_conf_ptr->job_comp_loc);
xfree (ctl_conf_ptr->job_comp_pass);
ctl_conf_ptr->job_comp_port = 0;
xfree (ctl_conf_ptr->job_comp_type);
xfree (ctl_conf_ptr->job_comp_user);
xfree (ctl_conf_ptr->job_container_plugin);
xfree (ctl_conf_ptr->job_credential_private_key);
xfree (ctl_conf_ptr->job_credential_public_certificate);
ctl_conf_ptr->job_file_append = (uint16_t) NO_VAL;
ctl_conf_ptr->job_requeue = (uint16_t) NO_VAL;
xfree(ctl_conf_ptr->job_submit_plugins);
ctl_conf_ptr->keep_alive_time = (uint16_t) NO_VAL;
ctl_conf_ptr->kill_wait = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->launch_type);
xfree (ctl_conf_ptr->licenses);
xfree (ctl_conf_ptr->mail_prog);
ctl_conf_ptr->max_array_sz = (uint32_t) NO_VAL;
ctl_conf_ptr->max_job_cnt = (uint32_t) NO_VAL;
ctl_conf_ptr->max_job_id = NO_VAL;
ctl_conf_ptr->max_mem_per_cpu = 0;
ctl_conf_ptr->max_step_cnt = (uint32_t) NO_VAL;
ctl_conf_ptr->min_job_age = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->mpi_default);
xfree (ctl_conf_ptr->mpi_params);
ctl_conf_ptr->msg_timeout = (uint16_t) NO_VAL;
ctl_conf_ptr->next_job_id = (uint32_t) NO_VAL;
xfree (ctl_conf_ptr->node_prefix);
ctl_conf_ptr->over_time_limit = 0;
xfree (ctl_conf_ptr->plugindir);
xfree (ctl_conf_ptr->plugstack);
ctl_conf_ptr->preempt_mode = 0;
xfree (ctl_conf_ptr->preempt_type);
ctl_conf_ptr->private_data = 0;
xfree (ctl_conf_ptr->proctrack_type);
xfree (ctl_conf_ptr->prolog);
ctl_conf_ptr->prolog_flags = 0;
ctl_conf_ptr->propagate_prio_process = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->propagate_rlimits);
xfree (ctl_conf_ptr->propagate_rlimits_except);
xfree (ctl_conf_ptr->reboot_program);
ctl_conf_ptr->reconfig_flags = 0;
ctl_conf_ptr->resume_timeout = 0;
xfree (ctl_conf_ptr->resume_program);
ctl_conf_ptr->resume_rate = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->resv_epilog);
ctl_conf_ptr->resv_over_run = 0;
xfree (ctl_conf_ptr->resv_prolog);
ctl_conf_ptr->ret2service = (uint16_t) NO_VAL;
xfree( ctl_conf_ptr->salloc_default_command);
xfree( ctl_conf_ptr->sched_params );
ctl_conf_ptr->sched_time_slice = (uint16_t) NO_VAL;
xfree( ctl_conf_ptr->schedtype );
ctl_conf_ptr->schedport = (uint16_t) NO_VAL;
ctl_conf_ptr->schedrootfltr = (uint16_t) NO_VAL;
xfree( ctl_conf_ptr->select_type );
ctl_conf_ptr->select_type_param = (uint16_t) NO_VAL;
ctl_conf_ptr->slurm_user_id = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->slurm_user_name);
ctl_conf_ptr->slurmd_user_id = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->slurmd_user_name);
ctl_conf_ptr->slurmctld_debug = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->slurmctld_logfile);
xfree (ctl_conf_ptr->sched_logfile);
ctl_conf_ptr->sched_log_level = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->slurmctld_pidfile);
xfree (ctl_conf_ptr->slurmctld_plugstack);
ctl_conf_ptr->slurmctld_port = (uint32_t) NO_VAL;
ctl_conf_ptr->slurmctld_port_count = 1;
ctl_conf_ptr->slurmctld_timeout = (uint16_t) NO_VAL;
ctl_conf_ptr->slurmd_debug = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->slurmd_logfile);
xfree (ctl_conf_ptr->slurmd_pidfile);
xfree (ctl_conf_ptr->slurmd_plugstack);
ctl_conf_ptr->slurmd_port = (uint32_t) NO_VAL;
xfree (ctl_conf_ptr->slurmd_spooldir);
ctl_conf_ptr->slurmd_timeout = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->srun_prolog);
xfree (ctl_conf_ptr->srun_epilog);
xfree (ctl_conf_ptr->state_save_location);
xfree (ctl_conf_ptr->suspend_exc_nodes);
xfree (ctl_conf_ptr->suspend_exc_parts);
xfree (ctl_conf_ptr->suspend_program);
ctl_conf_ptr->suspend_rate = (uint16_t) NO_VAL;
ctl_conf_ptr->suspend_time = (uint16_t) NO_VAL;
ctl_conf_ptr->suspend_timeout = 0;
xfree (ctl_conf_ptr->switch_type);
xfree (ctl_conf_ptr->task_epilog);
xfree (ctl_conf_ptr->task_plugin);
ctl_conf_ptr->task_plugin_param = 0;
xfree (ctl_conf_ptr->task_prolog);
xfree (ctl_conf_ptr->tmp_fs);
xfree (ctl_conf_ptr->topology_plugin);
ctl_conf_ptr->tree_width = (uint16_t) NO_VAL;
xfree (ctl_conf_ptr->unkillable_program);
ctl_conf_ptr->unkillable_timeout = (uint16_t) NO_VAL;
ctl_conf_ptr->use_pam = 0;
ctl_conf_ptr->vsize_factor = 0;
ctl_conf_ptr->wait_time = (uint16_t) NO_VAL;
ctl_conf_ptr->kill_on_bad_exit = 0;
_free_name_hashtbl();
_init_name_hashtbl();
return;
}
/* handle config name in form (example) slurmdbd:cluster0:10.0.0.254:6819
*
* NOTE: Changes are required in the accounting_storage/slurmdbd plugin in
* order for this to work as desired. Andriy Grytsenko (Massive Solutions
* Limited) has a private accounting_storage plugin with this functionality */
static int _config_is_storage(s_p_hashtbl_t *hashtbl, char *name)
{
char *cluster, *host, *port;
void *db_conn;
config_key_pair_t *pair;
List config;
ListIterator iter;
int rc = -1;
cluster = strchr(name, ':');
if (cluster == NULL)
return (-1);
host = strchr(&cluster[1], ':');
if (host == NULL)
return (-1);
port = strrchr(&host[1], ':');
if (port == NULL)
return (-1);
conf_ptr->accounting_storage_type =
xstrdup_printf("accounting_storage/%.*s",
(int)(cluster - name), name);
cluster++;
cluster = xstrndup(cluster, host - cluster);
host++;
conf_ptr->accounting_storage_host = xstrndup(host, port - host);
port++;
debug3("trying retrieve config via %s from host %s on port %s",
conf_ptr->accounting_storage_type,
conf_ptr->accounting_storage_host, port);
conf_ptr->accounting_storage_port = atoi(port);
conf_ptr->plugindir = xstrdup(default_plugin_path);
/* unlock conf_lock and set as initialized before accessing it */
conf_initialized = true;
pthread_mutex_unlock(&conf_lock);
db_conn = acct_storage_g_get_connection(NULL, 0, false, NULL);
if (db_conn == NULL)
goto end; /* plugin will out error itself */
config = acct_storage_g_get_config(db_conn, "slurm.conf");
acct_storage_g_close_connection(&db_conn); /* ignore error code */
if (config == NULL) {
error("cannot retrieve config from storage");
goto end;
}
iter = list_iterator_create(config);
while ((pair = list_next(iter)) != NULL)
s_p_parse_pair(hashtbl, pair->name, pair->value);
list_iterator_destroy(iter);
list_destroy(config);
rc = 0; /* done */
end:
/* restore status quo now */
pthread_mutex_lock(&conf_lock);
conf_initialized = false;
xfree(cluster);
xfree(conf_ptr->accounting_storage_type);
xfree(conf_ptr->accounting_storage_host);
xfree(conf_ptr->plugindir);
conf_ptr->accounting_storage_type = NULL;
conf_ptr->accounting_storage_host = NULL;
conf_ptr->plugindir = NULL;
return (rc);
}
/* caller must lock conf_lock */
static int _init_slurm_conf(const char *file_name)
{
char *name = (char *)file_name;
/* conf_ptr = (slurm_ctl_conf_t *)xmalloc(sizeof(slurm_ctl_conf_t)); */
if (name == NULL) {
name = getenv("SLURM_CONF");
if (name == NULL)
name = default_slurm_config_file;
}
if (conf_initialized)
error("the conf_hashtbl is already inited");
debug("Reading slurm.conf file: %s", name);
conf_hashtbl = s_p_hashtbl_create(slurm_conf_options);
conf_ptr->last_update = time(NULL);
/* init hash to 0 */
conf_ptr->hash_val = 0;
if ((_config_is_storage(conf_hashtbl, name) < 0) &&
(s_p_parse_file(conf_hashtbl, &conf_ptr->hash_val, name, false)
== SLURM_ERROR)) {
return SLURM_ERROR;
}
/* s_p_dump_values(conf_hashtbl, slurm_conf_options); */
if (_validate_and_set_defaults(conf_ptr, conf_hashtbl) == SLURM_ERROR)
return SLURM_ERROR;
conf_ptr->slurm_conf = xstrdup(name);
return SLURM_SUCCESS;
}
/* caller must lock conf_lock */
static void
_destroy_slurm_conf(void)
{
s_p_hashtbl_destroy(conf_hashtbl);
if (default_frontend_tbl != NULL) {
s_p_hashtbl_destroy(default_frontend_tbl);
default_frontend_tbl = NULL;
}
if (default_nodename_tbl != NULL) {
s_p_hashtbl_destroy(default_nodename_tbl);
default_nodename_tbl = NULL;
}
if (default_partition_tbl != NULL) {
s_p_hashtbl_destroy(default_partition_tbl);
default_partition_tbl = NULL;
}
free_slurm_conf(conf_ptr, true);
conf_initialized = false;
/* xfree(conf_ptr); */
}
/*
* slurm_conf_init - load the slurm configuration from the a file.
* IN file_name - name of the slurm configuration file to be read
* If file_name is NULL, then this routine tries to use
* the value in the SLURM_CONF env variable. Failing that,
* it uses the compiled-in default file name.
* If the conf structures have already been initialized by a call to
* slurm_conf_init, any subsequent calls will do nothing until
* slurm_conf_destroy is called.
* RET SLURM_SUCCESS if conf file is initialized. If the slurm conf
* was already initialied, return SLURM_ERROR.
*/
extern int
slurm_conf_init(const char *file_name)
{
pthread_mutex_lock(&conf_lock);
if (conf_initialized) {
pthread_mutex_unlock(&conf_lock);
return SLURM_ERROR;
}
init_slurm_conf(conf_ptr);
if (_init_slurm_conf(file_name) != SLURM_SUCCESS)
fatal("Unable to process configuration file");
conf_initialized = true;
pthread_mutex_unlock(&conf_lock);
return SLURM_SUCCESS;
}
static int _internal_reinit(const char *file_name)
{
char *name = (char *)file_name;
int rc = SLURM_SUCCESS;
if (name == NULL) {
name = getenv("SLURM_CONF");
if (name == NULL)
name = default_slurm_config_file;
}
if (conf_initialized) {
/* could check modified time on slurm.conf here */
_destroy_slurm_conf();
}
if (_init_slurm_conf(name) != SLURM_SUCCESS)
fatal("Unable to process configuration file");
conf_initialized = true;
return rc;
}
/*
* slurm_conf_reinit - reload the slurm configuration from a file.
* IN file_name - name of the slurm configuration file to be read
* If file_name is NULL, then this routine tries to use
* the value in the SLURM_CONF env variable. Failing that,
* it uses the compiled-in default file name.
* Unlike slurm_conf_init, slurm_conf_reinit will always reread the
* file and reinitialize the configuration structures.
* RET SLURM_SUCCESS if conf file is reinitialized, otherwise SLURM_ERROR.
*/
extern int
slurm_conf_reinit(const char *file_name)
{
int rc;
pthread_mutex_lock(&conf_lock);
rc = _internal_reinit(file_name);
pthread_mutex_unlock(&conf_lock);
return rc;
}
extern void
slurm_conf_mutex_init(void)
{
pthread_mutex_init(&conf_lock, NULL);
}
extern void
slurm_conf_install_fork_handlers(void)
{
int err;
if ((err = pthread_atfork(NULL, NULL, &slurm_conf_mutex_init)))
fatal("can't install slurm_conf atfork handler");
return;
}
extern int
slurm_conf_destroy(void)
{
pthread_mutex_lock(&conf_lock);
if (!conf_initialized) {
pthread_mutex_unlock(&conf_lock);
return SLURM_SUCCESS;
}
_destroy_slurm_conf();
pthread_mutex_unlock(&conf_lock);
return SLURM_SUCCESS;
}
extern slurm_ctl_conf_t *
slurm_conf_lock(void)
{
pthread_mutex_lock(&conf_lock);
if (!conf_initialized) {
if (_init_slurm_conf(NULL) != SLURM_SUCCESS) {
/* Clearing backup_addr and control_addr results in
* error for most APIs without generating a fatal
* error and exiting. Slurm commands and daemons
* should call slurm_conf_init() to get a fatal
* error instead. */
xfree(conf_ptr->backup_addr);
xfree(conf_ptr->control_addr);
}
conf_initialized = true;
}
return conf_ptr;
}
extern void
slurm_conf_unlock(void)
{
pthread_mutex_unlock(&conf_lock);
}
/* Normalize supplied debug level to be in range per log.h definitions */
static void _normalize_debug_level(uint16_t *level)
{
if (*level > LOG_LEVEL_END) {
error("Normalizing debug level from %u to %d",
*level, (LOG_LEVEL_END - 1));
*level = (LOG_LEVEL_END - 1);
}
/* level is uint16, always > LOG_LEVEL_QUIET(0), can't underflow */
}
/* Convert HealthCheckNodeState string to numeric value */
static uint16_t _health_node_state(char *state_str)
{
uint16_t state_num = 0;
char *tmp_str = xstrdup(state_str);
char *token, *last = NULL;
token = strtok_r(tmp_str, ",", &last);
while (token) {
if (!strcasecmp(token, "ANY"))
state_num |= HEALTH_CHECK_NODE_ANY;
else if (!strcasecmp(token, "ALLOC"))
state_num |= HEALTH_CHECK_NODE_ALLOC;
else if (!strcasecmp(token, "IDLE"))
state_num |= HEALTH_CHECK_NODE_IDLE;
else if (!strcasecmp(token, "MIXED"))
state_num |= HEALTH_CHECK_NODE_MIXED;
else {
error("Invalid HealthCheckNodeState value %s ignored",
token);
}
token = strtok_r(NULL, ",", &last);
}
xfree(tmp_str);
return state_num;
}
/*
*
* IN/OUT ctl_conf_ptr - a configuration as loaded by read_slurm_conf_ctl
*
* NOTE: a backup_controller or control_machine of "localhost" are over-written
* with this machine's name.
* NOTE: if backup_addr is NULL, it is over-written by backup_controller
* NOTE: if control_addr is NULL, it is over-written by control_machine
*/
static int
_validate_and_set_defaults(slurm_ctl_conf_t *conf, s_p_hashtbl_t *hashtbl)
{
char *temp_str = NULL;
long long_suspend_time;
bool truth;
char *default_storage_type = NULL, *default_storage_host = NULL;
char *default_storage_user = NULL, *default_storage_pass = NULL;
char *default_storage_loc = NULL;
uint32_t default_storage_port = 0;
uint16_t uint16_tmp;
if (s_p_get_string(&conf->backup_controller, "BackupController",
hashtbl)
&& strcasecmp("localhost", conf->backup_controller) == 0) {
xfree(conf->backup_controller);
conf->backup_controller = xmalloc (MAX_SLURM_NAME);
if (gethostname_short(conf->backup_controller, MAX_SLURM_NAME)){
error("getnodename: %m");
return SLURM_ERROR;
}
}
if (s_p_get_string(&conf->backup_addr, "BackupAddr", hashtbl)) {
if (conf->backup_controller == NULL) {
error("BackupAddr specified without BackupController");
xfree(conf->backup_addr);
}
} else {
if (conf->backup_controller != NULL)
conf->backup_addr = xstrdup(conf->backup_controller);
}
if (!s_p_get_uint16(&conf->batch_start_timeout, "BatchStartTimeout",
hashtbl))
conf->batch_start_timeout = DEFAULT_BATCH_START_TIMEOUT;
s_p_get_string(&conf->cluster_name, "ClusterName", hashtbl);
/* Some databases are case sensitive so we have to make sure
* the cluster name is lower case since sacctmgr makes sure
* this is the case as well.
*/
if (conf->cluster_name) {
int i;
for (i = 0; conf->cluster_name[i] != '\0'; i++)
conf->cluster_name[i] =
(char)tolower((int)conf->cluster_name[i]);
}
if (!s_p_get_uint16(&conf->complete_wait, "CompleteWait", hashtbl))
conf->complete_wait = DEFAULT_COMPLETE_WAIT;
if (!s_p_get_string(&conf->control_machine, "ControlMachine", hashtbl)){
error("ControlMachine not specified.");
return SLURM_ERROR;
}
else if (strcasecmp("localhost", conf->control_machine) == 0) {
xfree (conf->control_machine);
conf->control_machine = xmalloc(MAX_SLURM_NAME);
if (gethostname_short(conf->control_machine, MAX_SLURM_NAME)) {
error("getnodename: %m");
return SLURM_ERROR;
}
}
if (!s_p_get_string(&conf->control_addr, "ControlAddr", hashtbl) &&
(conf->control_machine != NULL)) {
if (strchr(conf->control_machine, ',')) {
error("ControlMachine has multiple host names so "
"ControlAddr must be specified");
return SLURM_ERROR;
}
conf->control_addr = xstrdup (conf->control_machine);
}
if ((conf->backup_controller != NULL) &&
(strcmp(conf->backup_controller, conf->control_machine) == 0)) {
error("ControlMachine and BackupController identical");
xfree(conf->backup_addr);
xfree(conf->backup_controller);
}
if (!s_p_get_string(&conf->acct_gather_energy_type,
"AcctGatherEnergyType", hashtbl))
conf->acct_gather_energy_type =
xstrdup(DEFAULT_ACCT_GATHER_ENERGY_TYPE);
if (!s_p_get_string(&conf->acct_gather_profile_type,
"AcctGatherProfileType", hashtbl))
conf->acct_gather_profile_type =
xstrdup(DEFAULT_ACCT_GATHER_PROFILE_TYPE);
if (!s_p_get_string(&conf->acct_gather_infiniband_type,
"AcctGatherInfinibandType", hashtbl))
conf->acct_gather_infiniband_type =
xstrdup(DEFAULT_ACCT_GATHER_INFINIBAND_TYPE);
if (!s_p_get_string(&conf->acct_gather_filesystem_type,
"AcctGatherFilesystemType", hashtbl))
conf->acct_gather_filesystem_type =
xstrdup(DEFAULT_ACCT_GATHER_FILESYSTEM_TYPE);
if (!s_p_get_uint16(&conf->acct_gather_node_freq,
"AcctGatherNodeFreq", hashtbl))
conf->acct_gather_node_freq = 0;
s_p_get_string(&default_storage_type, "DefaultStorageType", hashtbl);
s_p_get_string(&default_storage_host, "DefaultStorageHost", hashtbl);
s_p_get_string(&default_storage_user, "DefaultStorageUser", hashtbl);
s_p_get_string(&default_storage_pass, "DefaultStoragePass", hashtbl);
s_p_get_string(&default_storage_loc, "DefaultStorageLoc", hashtbl);
s_p_get_uint32(&default_storage_port, "DefaultStoragePort", hashtbl);
s_p_get_string(&conf->job_credential_private_key,
"JobCredentialPrivateKey", hashtbl);
s_p_get_string(&conf->job_credential_public_certificate,
"JobCredentialPublicCertificate", hashtbl);
s_p_get_string(&conf->authinfo, "AuthInfo", hashtbl);
if (!s_p_get_string(&conf->authtype, "AuthType", hashtbl))
conf->authtype = xstrdup(DEFAULT_AUTH_TYPE);
if (s_p_get_uint16(&uint16_tmp, "GroupUpdateTime", hashtbl)) {
if (uint16_tmp > GROUP_TIME_MASK) {
error("GroupUpdateTime exceeds limit of %u",
GROUP_TIME_MASK);
return SLURM_ERROR;
}
conf->group_info = uint16_tmp;
} else
conf->group_info = DEFAULT_GROUP_INFO;
if (s_p_get_uint16(&uint16_tmp, "CacheGroups", hashtbl) && uint16_tmp)
conf->group_info |= GROUP_CACHE;
if (!s_p_get_string(&conf->core_spec_plugin, "CoreSpecPlugin",
hashtbl)) {
conf->core_spec_plugin =
xstrdup(DEFAULT_CORE_SPEC_PLUGIN);
}
if (s_p_get_uint16(&uint16_tmp, "GroupUpdateForce", hashtbl) &&
uint16_tmp)
conf->group_info |= GROUP_FORCE;
if (!s_p_get_string(&conf->checkpoint_type, "CheckpointType", hashtbl))
conf->checkpoint_type = xstrdup(DEFAULT_CHECKPOINT_TYPE);
if (!s_p_get_string(&conf->crypto_type, "CryptoType", hashtbl))
conf->crypto_type = xstrdup(DEFAULT_CRYPTO_TYPE);
if ((strcmp(conf->crypto_type, "crypto/openssl") == 0) &&
((conf->job_credential_private_key == NULL) ||
(conf->job_credential_public_certificate == NULL))) {
error("CryptoType=crypto/openssl requires that both "
"JobCredentialPrivateKey and "
"JobCredentialPublicCertificate be set");
return SLURM_ERROR;
}
if (s_p_get_uint32(&conf->def_mem_per_cpu, "DefMemPerCPU", hashtbl))
conf->def_mem_per_cpu |= MEM_PER_CPU;
else if (!s_p_get_uint32(&conf->def_mem_per_cpu, "DefMemPerNode",
hashtbl))
conf->def_mem_per_cpu = DEFAULT_MEM_PER_CPU;
if (s_p_get_string(&temp_str, "DebugFlags", hashtbl)) {
conf->debug_flags = debug_str2flags(temp_str);
if (conf->debug_flags == NO_VAL) {
error("DebugFlags invalid: %s", temp_str);
return SLURM_ERROR;
}
xfree(temp_str);
} else /* Default: no DebugFlags */
conf->debug_flags = 0;
if (!s_p_get_boolean((bool *) &conf->disable_root_jobs,
"DisableRootJobs", hashtbl))
conf->disable_root_jobs = DEFAULT_DISABLE_ROOT_JOBS;
if (s_p_get_uint16(&conf->dynalloc_port, "DynAllocPort", hashtbl)) {
if (conf->dynalloc_port == 0) {
error("DynAllocPort=0 is invalid");
}
} else {
conf->dynalloc_port = 0;
}
if (!s_p_get_boolean((bool *) &conf->enforce_part_limits,
"EnforcePartLimits", hashtbl))
conf->enforce_part_limits = DEFAULT_ENFORCE_PART_LIMITS;
s_p_get_string(&conf->epilog, "Epilog", hashtbl);
if (!s_p_get_uint32(&conf->epilog_msg_time, "EpilogMsgTime", hashtbl))
conf->epilog_msg_time = DEFAULT_EPILOG_MSG_TIME;
s_p_get_string(&conf->epilog_slurmctld, "EpilogSlurmctld", hashtbl);
if (!s_p_get_string(&conf->ext_sensors_type,
"ExtSensorsType", hashtbl))
conf->ext_sensors_type =
xstrdup(DEFAULT_EXT_SENSORS_TYPE);
if (!s_p_get_uint16(&conf->ext_sensors_freq,
"ExtSensorsFreq", hashtbl))
conf->ext_sensors_freq = 0;
if (!s_p_get_uint16(&conf->fs_dampening_factor,
"FairShareDampeningFactor", hashtbl))
conf->fs_dampening_factor = 1;
if (!s_p_get_uint16(&conf->fast_schedule, "FastSchedule", hashtbl))
conf->fast_schedule = DEFAULT_FAST_SCHEDULE;
if (!s_p_get_uint32(&conf->first_job_id, "FirstJobId", hashtbl))
conf->first_job_id = DEFAULT_FIRST_JOB_ID;
s_p_get_string(&conf->gres_plugins, "GresTypes", hashtbl);
if (s_p_get_uint16(&conf->inactive_limit, "InactiveLimit", hashtbl)) {
#ifdef HAVE_BG_L_P
/* Inactive limit must be zero on BlueGene L/P */
if (conf->inactive_limit) {
error("InactiveLimit=%d is invalid on BlueGene L/P",
conf->inactive_limit);
}
conf->inactive_limit = 0;
#endif
} else {
#ifdef HAVE_BG_L_P
conf->inactive_limit = 0;
#endif
conf->inactive_limit = DEFAULT_INACTIVE_LIMIT;
}
if (!s_p_get_string(&conf->job_acct_gather_freq,
"JobAcctGatherFrequency", hashtbl))
conf->job_acct_gather_freq =
xstrdup(DEFAULT_JOB_ACCT_GATHER_FREQ);
if (!s_p_get_string(&conf->job_acct_gather_type,
"JobAcctGatherType", hashtbl))
conf->job_acct_gather_type =
xstrdup(DEFAULT_JOB_ACCT_GATHER_TYPE);
s_p_get_string(&conf->job_acct_gather_params, "JobAcctGatherParams",
hashtbl);
if (!s_p_get_string(&conf->job_ckpt_dir, "JobCheckpointDir", hashtbl))
conf->job_ckpt_dir = xstrdup(DEFAULT_JOB_CKPT_DIR);
if (!s_p_get_string(&conf->job_comp_type, "JobCompType", hashtbl)) {
if (default_storage_type) {
if (!strcasecmp("slurmdbd", default_storage_type)) {
error("Can not use the default storage type "
"specified for jobcomp since there is "
"not slurmdbd type. We are using %s "
"as the type. To disable this message "
"set JobCompType in your slurm.conf",
DEFAULT_JOB_COMP_TYPE);
conf->job_comp_type =
xstrdup(DEFAULT_JOB_COMP_TYPE);
} else
conf->job_comp_type =
xstrdup_printf("jobcomp/%s",
default_storage_type);
} else
conf->job_comp_type = xstrdup(DEFAULT_JOB_COMP_TYPE);
}
if (!s_p_get_string(&conf->job_comp_loc, "JobCompLoc", hashtbl)) {
if (default_storage_loc)
conf->job_comp_loc = xstrdup(default_storage_loc);
else if (!strcmp(conf->job_comp_type, "jobcomp/mysql"))
conf->job_comp_loc = xstrdup(DEFAULT_JOB_COMP_DB);
else
conf->job_comp_loc = xstrdup(DEFAULT_JOB_COMP_LOC);
}
if (!s_p_get_string(&conf->job_comp_host, "JobCompHost",
hashtbl)) {
if (default_storage_host)
conf->job_comp_host = xstrdup(default_storage_host);
else
conf->job_comp_host = xstrdup(DEFAULT_STORAGE_HOST);
}
if (!s_p_get_string(&conf->job_comp_user, "JobCompUser",
hashtbl)) {
if (default_storage_user)
conf->job_comp_user = xstrdup(default_storage_user);
else
conf->job_comp_user = xstrdup(DEFAULT_STORAGE_USER);
}
if (!s_p_get_string(&conf->job_comp_pass, "JobCompPass",
hashtbl)) {
if (default_storage_pass)
conf->job_comp_pass = xstrdup(default_storage_pass);
}
if (!s_p_get_uint32(&conf->job_comp_port, "JobCompPort",
hashtbl)) {
if (default_storage_port)
conf->job_comp_port = default_storage_port;
else if (!strcmp(conf->job_comp_type, "job_comp/mysql"))
conf->job_comp_port = DEFAULT_MYSQL_PORT;
else
conf->job_comp_port = DEFAULT_STORAGE_PORT;
}
if (!s_p_get_string(&conf->job_container_plugin, "JobContainerType",
hashtbl)) {
conf->job_container_plugin =
xstrdup(DEFAULT_JOB_CONTAINER_PLUGIN);
}
if (!s_p_get_uint16(&conf->job_file_append, "JobFileAppend", hashtbl))
conf->job_file_append = 0;
if (!s_p_get_uint16(&conf->job_requeue, "JobRequeue", hashtbl))
conf->job_requeue = 1;
else if (conf->job_requeue > 1)
conf->job_requeue = 1;
s_p_get_string(&conf->job_submit_plugins, "JobSubmitPlugins",
hashtbl);
if (!s_p_get_uint16(&conf->get_env_timeout, "GetEnvTimeout", hashtbl))
conf->get_env_timeout = DEFAULT_GET_ENV_TIMEOUT;
s_p_get_uint16(&conf->health_check_interval, "HealthCheckInterval",
hashtbl);
if (s_p_get_string(&temp_str, "HealthCheckNodeState", hashtbl)) {
conf->health_check_node_state = _health_node_state(temp_str);
xfree(temp_str);
} else
conf->health_check_node_state = HEALTH_CHECK_NODE_ANY;
s_p_get_string(&conf->health_check_program, "HealthCheckProgram",
hashtbl);
if (!s_p_get_uint16(&conf->keep_alive_time, "KeepAliveTime", hashtbl))
conf->keep_alive_time = DEFAULT_KEEP_ALIVE_TIME;
if (!s_p_get_uint16(&conf->kill_on_bad_exit, "KillOnBadExit", hashtbl))
conf->kill_on_bad_exit = DEFAULT_KILL_ON_BAD_EXIT;
if (!s_p_get_uint16(&conf->kill_wait, "KillWait", hashtbl))
conf->kill_wait = DEFAULT_KILL_WAIT;
if (!s_p_get_string(&conf->launch_type, "LaunchType", hashtbl))
conf->launch_type = xstrdup(DEFAULT_LAUNCH_TYPE);
s_p_get_string(&conf->licenses, "Licenses", hashtbl);
if (s_p_get_string(&temp_str, "LogTimeFormat", hashtbl)) {
if (slurm_strcasestr(temp_str, "iso8601_ms"))
conf->log_fmt = LOG_FMT_ISO8601_MS;
else if (slurm_strcasestr(temp_str, "iso8601"))
conf->log_fmt = LOG_FMT_ISO8601;
else if (slurm_strcasestr(temp_str, "rfc5424_ms"))
conf->log_fmt = LOG_FMT_RFC5424_MS;
else if (slurm_strcasestr(temp_str, "rfc5424"))
conf->log_fmt = LOG_FMT_RFC5424;
else if (slurm_strcasestr(temp_str, "clock"))
conf->log_fmt = LOG_FMT_CLOCK;
else if (slurm_strcasestr(temp_str, "short"))
conf->log_fmt = LOG_FMT_SHORT;
else if (slurm_strcasestr(temp_str, "thread_id"))
conf->log_fmt = LOG_FMT_THREAD_ID;
xfree(temp_str);
} else
conf->log_fmt = LOG_FMT_ISO8601_MS;
if (!s_p_get_string(&conf->mail_prog, "MailProg", hashtbl))
conf->mail_prog = xstrdup(DEFAULT_MAIL_PROG);
if (!s_p_get_uint32(&conf->max_array_sz, "MaxArraySize", hashtbl))
conf->max_array_sz = DEFAULT_MAX_ARRAY_SIZE;
else if (conf->max_array_sz > 65533) {
/* Slurm really can not handle more job array elements
* without adding a new job array data structure */
error("MaxArraySize value (%u) is greater than 65533",
conf->max_array_sz);
}
if (!s_p_get_uint32(&conf->max_job_cnt, "MaxJobCount", hashtbl))
conf->max_job_cnt = DEFAULT_MAX_JOB_COUNT;
else if (conf->max_job_cnt < 1) {
error("MaxJobCount=%u, No jobs permitted", conf->max_job_cnt);
return SLURM_ERROR;
}
if (!s_p_get_uint32(&conf->max_job_id, "MaxJobId", hashtbl))
conf->max_job_id = DEFAULT_MAX_JOB_ID;
if (conf->first_job_id > conf->max_job_id) {
error("FirstJobId > MaxJobId");
return SLURM_ERROR;
} else {
uint32_t tmp32 = conf->max_job_id - conf->first_job_id + 1;
if (conf->max_job_cnt > tmp32) {
/* Needed for job array support */
info("Resetting MaxJobCnt from %u to %u "
"(MaxJobId - FirstJobId + 1)",
conf->max_job_cnt, tmp32);
conf->max_job_cnt = tmp32;
}
}
if (s_p_get_uint32(&conf->max_mem_per_cpu,
"MaxMemPerCPU", hashtbl)) {
conf->max_mem_per_cpu |= MEM_PER_CPU;
} else if (!s_p_get_uint32(&conf->max_mem_per_cpu,
"MaxMemPerNode", hashtbl)) {
conf->max_mem_per_cpu = DEFAULT_MAX_MEM_PER_CPU;
}
if (!s_p_get_uint32(&conf->max_step_cnt, "MaxStepCount", hashtbl))
conf->max_step_cnt = DEFAULT_MAX_STEP_COUNT;
else if (conf->max_step_cnt < 1) {
error("MaxStepCount=%u, No steps permitted",
conf->max_step_cnt);
return SLURM_ERROR;
}
if (!s_p_get_uint16(&conf->max_tasks_per_node, "MaxTasksPerNode",
hashtbl)) {
conf->max_tasks_per_node = DEFAULT_MAX_TASKS_PER_NODE;
}
if (!s_p_get_uint16(&conf->msg_timeout, "MessageTimeout", hashtbl))
conf->msg_timeout = DEFAULT_MSG_TIMEOUT;
else if (conf->msg_timeout > 100) {
if (getuid() == 0) {
info("WARNING: MessageTimeout is too high for "
"effective fault-tolerance");
} else {
debug("WARNING: MessageTimeout is too high for "
"effective fault-tolerance");
}
}
if (!s_p_get_uint16(&conf->min_job_age, "MinJobAge", hashtbl))
conf->min_job_age = DEFAULT_MIN_JOB_AGE;
else if (conf->min_job_age < 2) {
if (getuid() == 0)
info("WARNING: MinJobAge must be at least 2");
else
debug("WARNING: MinJobAge must be at least 2");
conf->min_job_age = 2;
}
if (!s_p_get_string(&conf->mpi_default, "MpiDefault", hashtbl))
conf->mpi_default = xstrdup(DEFAULT_MPI_DEFAULT);
s_p_get_string(&conf->mpi_params, "MpiParams", hashtbl);
if (!s_p_get_boolean((bool *)&conf->track_wckey,
"TrackWCKey", hashtbl))
conf->track_wckey = false;
if (!s_p_get_string(&conf->accounting_storage_type,
"AccountingStorageType", hashtbl)) {
if (default_storage_type)
conf->accounting_storage_type =
xstrdup_printf("accounting_storage/%s",
default_storage_type);
else
conf->accounting_storage_type =
xstrdup(DEFAULT_ACCOUNTING_STORAGE_TYPE);
}
if (s_p_get_string(&temp_str, "AccountingStorageEnforce", hashtbl)) {
if (slurm_strcasestr(temp_str, "1")
|| slurm_strcasestr(temp_str, "associations"))
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_ASSOCS;
if (slurm_strcasestr(temp_str, "2")
|| slurm_strcasestr(temp_str, "limits")) {
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_ASSOCS;
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_LIMITS;
}
if (slurm_strcasestr(temp_str, "safe")) {
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_ASSOCS;
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_LIMITS;
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_SAFE;
}
if (slurm_strcasestr(temp_str, "wckeys")) {
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_ASSOCS;
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_WCKEYS;
conf->track_wckey = true;
}
if (slurm_strcasestr(temp_str, "qos")) {
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_ASSOCS;
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_QOS;
}
if (slurm_strcasestr(temp_str, "all")) {
conf->accounting_storage_enforce = 0xffff;
conf->track_wckey = true;
/* If all is used, nojobs and nosteps aren't
part of it. They must be requested as well.
*/
conf->accounting_storage_enforce
&= (~ACCOUNTING_ENFORCE_NO_JOBS);
conf->accounting_storage_enforce
&= (~ACCOUNTING_ENFORCE_NO_STEPS);
}
/* Everything that "all" doesn't mean should be put here */
if (slurm_strcasestr(temp_str, "nojobs")) {
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_NO_JOBS;
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_NO_STEPS;
}
if (slurm_strcasestr(temp_str, "nosteps")) {
conf->accounting_storage_enforce
|= ACCOUNTING_ENFORCE_NO_STEPS;
}
xfree(temp_str);
} else
conf->accounting_storage_enforce = 0;
/* if no backup we don't care */
s_p_get_string(&conf->accounting_storage_backup_host,
"AccountingStorageBackupHost", hashtbl);
if (!s_p_get_string(&conf->accounting_storage_host,
"AccountingStorageHost", hashtbl)) {
if (default_storage_host)
conf->accounting_storage_host =
xstrdup(default_storage_host);
else
conf->accounting_storage_host =
xstrdup(DEFAULT_STORAGE_HOST);
}
if (!s_p_get_string(&conf->accounting_storage_loc,
"AccountingStorageLoc", hashtbl)) {
if (default_storage_loc)
conf->accounting_storage_loc =
xstrdup(default_storage_loc);
else if (!strcmp(conf->accounting_storage_type,
"accounting_storage/mysql"))
conf->accounting_storage_loc =
xstrdup(DEFAULT_ACCOUNTING_DB);
else
conf->accounting_storage_loc =
xstrdup(DEFAULT_STORAGE_LOC);
}
if (!s_p_get_string(&conf->accounting_storage_user,
"AccountingStorageUser", hashtbl)) {
if (default_storage_user)
conf->accounting_storage_user =
xstrdup(default_storage_user);
else
conf->accounting_storage_user =
xstrdup(DEFAULT_STORAGE_USER);
}
if (!s_p_get_string(&conf->accounting_storage_pass,
"AccountingStoragePass", hashtbl)) {
if (default_storage_pass)
conf->accounting_storage_pass =
xstrdup(default_storage_pass);
}
if (s_p_get_boolean(&truth, "AccountingStoreJobComment", hashtbl)
&& !truth)
conf->acctng_store_job_comment = 0;
else
conf->acctng_store_job_comment = 1;
if (!s_p_get_uint32(&conf->accounting_storage_port,
"AccountingStoragePort", hashtbl)) {
if (default_storage_port)
conf->accounting_storage_port = default_storage_port;
else if (!strcmp(conf->accounting_storage_type,
"accounting_storage/slurmdbd"))
conf->accounting_storage_port = SLURMDBD_PORT;
else if (!strcmp(conf->accounting_storage_type,
"accounting_storage/mysql"))
conf->accounting_storage_port = DEFAULT_MYSQL_PORT;
else
conf->accounting_storage_port = DEFAULT_STORAGE_PORT;
}
/* remove the user and loc if using slurmdbd */
if (!strcmp(conf->accounting_storage_type,
"accounting_storage/slurmdbd")) {
xfree(conf->accounting_storage_loc);
conf->accounting_storage_loc = xstrdup("N/A");
xfree(conf->accounting_storage_user);
conf->accounting_storage_user = xstrdup("N/A");
}
s_p_get_uint16(&conf->over_time_limit, "OverTimeLimit", hashtbl);
if (!s_p_get_string(&conf->plugindir, "PluginDir", hashtbl))
conf->plugindir = xstrdup(default_plugin_path);
if (!_is_valid_path(conf->plugindir, "PluginDir")) {
error("Bad value \"%s\" for PluginDir", conf->plugindir);
return SLURM_ERROR;
}
if (!s_p_get_string(&conf->plugstack, "PlugStackConfig", hashtbl))
conf->plugstack = xstrdup(default_plugstack);
if (s_p_get_string(&temp_str, "PreemptMode", hashtbl)) {
conf->preempt_mode = preempt_mode_num(temp_str);
if (conf->preempt_mode == (uint16_t) NO_VAL) {
error("PreemptMode=%s invalid", temp_str);
return SLURM_ERROR;
}
if (conf->preempt_mode == PREEMPT_MODE_SUSPEND) {
error("PreemptMode=SUSPEND requires GANG too");
return SLURM_ERROR;
}
xfree(temp_str);
} else {
conf->preempt_mode = PREEMPT_MODE_OFF;
}
if (!s_p_get_string(&conf->preempt_type, "PreemptType", hashtbl))
conf->preempt_type = xstrdup(DEFAULT_PREEMPT_TYPE);
if (strcmp(conf->preempt_type, "preempt/qos") == 0) {
int preempt_mode = conf->preempt_mode & (~PREEMPT_MODE_GANG);
if ((preempt_mode == PREEMPT_MODE_OFF) ||
(preempt_mode == PREEMPT_MODE_SUSPEND)) {
error("PreemptType and PreemptMode values "
"incompatible");
return SLURM_ERROR;
}
} else if (strcmp(conf->preempt_type, "preempt/partition_prio") == 0) {
int preempt_mode = conf->preempt_mode & (~PREEMPT_MODE_GANG);
if (preempt_mode == PREEMPT_MODE_OFF) {
error("PreemptType and PreemptMode values "
"incompatible");
return SLURM_ERROR;
}
} else if (strcmp(conf->preempt_type, "preempt/none") == 0) {
int preempt_mode = conf->preempt_mode & (~PREEMPT_MODE_GANG);
if (preempt_mode != PREEMPT_MODE_OFF) {
error("PreemptType and PreemptMode values "
"incompatible");
return SLURM_ERROR;
}
}
#ifdef HAVE_BG
if ((conf->preempt_mode & PREEMPT_MODE_GANG) ||
(conf->preempt_mode & PREEMPT_MODE_SUSPEND)) {
error("PreemptMode incompatible with BlueGene systems");
return SLURM_ERROR;
}
#endif
if (s_p_get_string(&temp_str, "PriorityDecayHalfLife", hashtbl)) {
int max_time = time_str2mins(temp_str);
if ((max_time < 0) && (max_time != INFINITE)) {
error("Bad value \"%s\" for PriorityDecayHalfLife",
temp_str);
return SLURM_ERROR;
}
conf->priority_decay_hl = max_time * 60;
xfree(temp_str);
} else
conf->priority_decay_hl = DEFAULT_PRIORITY_DECAY;
if (s_p_get_string(&temp_str, "PriorityCalcPeriod", hashtbl)) {
int calc_period = time_str2mins(temp_str);
if (calc_period < 1) {
error("Bad value \"%s\" for PriorityCalcPeriod",
temp_str);
return SLURM_ERROR;
}
conf->priority_calc_period = calc_period * 60;
xfree(temp_str);
} else
conf->priority_calc_period = DEFAULT_PRIORITY_CALC_PERIOD;
if (s_p_get_boolean(&truth, "PriorityFavorSmall", hashtbl) && truth)
conf->priority_favor_small = 1;
else
conf->priority_favor_small = 0;
conf->priority_flags = 0;
if (s_p_get_string(&temp_str, "PriorityFlags", hashtbl)) {
if (slurm_strcasestr(temp_str, "ACCRUE_ALWAYS"))
conf->priority_flags |= PRIORITY_FLAGS_ACCRUE_ALWAYS;
if (slurm_strcasestr(temp_str, "SMALL_RELATIVE_TO_TIME"))
conf->priority_flags |= PRIORITY_FLAGS_SIZE_RELATIVE;
if (slurm_strcasestr(temp_str, "TICKET_BASED"))
conf->priority_flags |= PRIORITY_FLAGS_TICKET_BASED;
else if (slurm_strcasestr(temp_str, "DEPTH_OBLIVIOUS"))
conf->priority_flags |= PRIORITY_FLAGS_DEPTH_OBLIVIOUS;
xfree(temp_str);
}
if (s_p_get_string(&temp_str, "PriorityMaxAge", hashtbl)) {
int max_time = time_str2mins(temp_str);
if ((max_time < 0) && (max_time != INFINITE)) {
error("Bad value \"%s\" for PriorityMaxAge",
temp_str);
return SLURM_ERROR;
}
conf->priority_max_age = max_time * 60;
xfree(temp_str);
} else
conf->priority_max_age = DEFAULT_PRIORITY_DECAY;
if (s_p_get_string(&temp_str, "PriorityUsageResetPeriod", hashtbl)) {
if (strcasecmp(temp_str, "none") == 0)
conf->priority_reset_period = PRIORITY_RESET_NONE;
else if (strcasecmp(temp_str, "now") == 0)
conf->priority_reset_period = PRIORITY_RESET_NOW;
else if (strcasecmp(temp_str, "daily") == 0)
conf->priority_reset_period = PRIORITY_RESET_DAILY;
else if (strcasecmp(temp_str, "weekly") == 0)
conf->priority_reset_period = PRIORITY_RESET_WEEKLY;
else if (strcasecmp(temp_str, "monthly") == 0)
conf->priority_reset_period = PRIORITY_RESET_MONTHLY;
else if (strcasecmp(temp_str, "quarterly") == 0)
conf->priority_reset_period = PRIORITY_RESET_QUARTERLY;
else if (strcasecmp(temp_str, "yearly") == 0)
conf->priority_reset_period = PRIORITY_RESET_YEARLY;
else {
error("Bad value \"%s\" for PriorityUsageResetPeriod",
temp_str);
return SLURM_ERROR;
}
xfree(temp_str);
} else {
conf->priority_reset_period = PRIORITY_RESET_NONE;
if (!conf->priority_decay_hl) {
error("You have to either have "
"PriorityDecayHalfLife != 0 or "
"PriorityUsageResetPeriod set to something "
"or the priority plugin will result in "
"rolling over.");
return SLURM_ERROR;
}
}
if (!s_p_get_string(&conf->priority_type, "PriorityType", hashtbl))
conf->priority_type = xstrdup(DEFAULT_PRIORITY_TYPE);
if (!strcasecmp(conf->priority_type, "priority/multifactor2")) {
error("PriorityType=priority/multifactor2 is deprecated. "
"In the future use\nPriorityType=priority/multifactor\n"
"PriortyFlags=Ticket_Based\nThis is what is loaded now.");
xfree(conf->priority_type);
conf->priority_type = xstrdup("priority/multifactor");
conf->priority_flags |= PRIORITY_FLAGS_TICKET_BASED;
}
if (!s_p_get_uint32(&conf->priority_weight_age,
"PriorityWeightAge", hashtbl))
conf->priority_weight_age = 0;
if (!s_p_get_uint32(&conf->priority_weight_fs,
"PriorityWeightFairshare", hashtbl))
conf->priority_weight_fs = 0;
if (!s_p_get_uint32(&conf->priority_weight_js,
"PriorityWeightJobSize", hashtbl))
conf->priority_weight_js = 0;
if (!s_p_get_uint32(&conf->priority_weight_part,
"PriorityWeightPartition", hashtbl))
conf->priority_weight_part = 0;
if (!s_p_get_uint32(&conf->priority_weight_qos,
"PriorityWeightQOS", hashtbl))
conf->priority_weight_qos = 0;
/* Out of order due to use with ProctrackType */
if (!s_p_get_string(&conf->switch_type, "SwitchType", hashtbl))
conf->switch_type = xstrdup(DEFAULT_SWITCH_TYPE);
if (!s_p_get_string(&conf->proctrack_type, "ProctrackType", hashtbl)) {
if (!strcmp(conf->switch_type,"switch/elan"))
conf->proctrack_type = xstrdup("proctrack/rms");
else
conf->proctrack_type =
xstrdup(DEFAULT_PROCTRACK_TYPE);
}
#ifdef HAVE_NATIVE_CRAY
if (strcmp(conf->proctrack_type, "proctrack/cray")) {
error("On a native Cray ProctrackType=proctrack/cray "
"is required");
return SLURM_ERROR;
}
#else
#ifdef HAVE_REAL_CRAY
if (strcmp(conf->proctrack_type, "proctrack/sgi_job")) {
error("On Cray ProctrackType=proctrack/sgi_job is required");
return SLURM_ERROR;
}
#endif
#endif
if ((!strcmp(conf->switch_type, "switch/elan"))
&& (!strcmp(conf->proctrack_type,"proctrack/linuxproc"))) {
error("proctrack/linuxproc is incompatible with switch/elan");
return SLURM_ERROR;
}
conf->private_data = 0; /* Set to default before parsing PrivateData */
if (s_p_get_string(&temp_str, "PrivateData", hashtbl)) {
if (slurm_strcasestr(temp_str, "account"))
conf->private_data |= PRIVATE_DATA_ACCOUNTS;
if (slurm_strcasestr(temp_str, "job"))
conf->private_data |= PRIVATE_DATA_JOBS;
if (slurm_strcasestr(temp_str, "node"))
conf->private_data |= PRIVATE_DATA_NODES;
if (slurm_strcasestr(temp_str, "partition"))
conf->private_data |= PRIVATE_DATA_PARTITIONS;
if (slurm_strcasestr(temp_str, "reservation"))
conf->private_data |= PRIVATE_DATA_RESERVATIONS;
if (slurm_strcasestr(temp_str, "usage"))
conf->private_data |= PRIVATE_DATA_USAGE;
if (slurm_strcasestr(temp_str, "user"))
conf->private_data |= PRIVATE_DATA_USERS;
if (slurm_strcasestr(temp_str, "all"))
conf->private_data = 0xffff;
xfree(temp_str);
}
s_p_get_string(&conf->prolog, "Prolog", hashtbl);
s_p_get_string(&conf->prolog_slurmctld, "PrologSlurmctld", hashtbl);
if (s_p_get_string(&temp_str, "PrologFlags", hashtbl)) {
conf->prolog_flags = prolog_str2flags(temp_str);
if (conf->prolog_flags == (uint16_t) NO_VAL) {
fatal("PrologFlags invalid: %s", temp_str);
}
if (conf->prolog_flags & PROLOG_FLAG_NOHOLD) {
conf->prolog_flags |= PROLOG_FLAG_ALLOC;
#ifdef HAVE_ALPS_CRAY
error("PrologFlags=NoHold is not compatible when "
"running on ALPS/Cray systems");
conf->prolog_flags &= (~PROLOG_FLAG_NOHOLD);
return SLURM_ERROR;
#endif
}
xfree(temp_str);
} else { /* Default: no Prolog Flags are set */
conf->prolog_flags = 0;
}
if (!s_p_get_uint16(&conf->propagate_prio_process,
"PropagatePrioProcess", hashtbl)) {
conf->propagate_prio_process = PROP_PRIO_OFF;
} else if (conf->propagate_prio_process > PROP_PRIO_NICER) {
error("Bad PropagatePrioProcess: %u",
conf->propagate_prio_process);
return SLURM_ERROR;
}
if (s_p_get_string(&conf->propagate_rlimits_except,
"PropagateResourceLimitsExcept", hashtbl)) {
if ((parse_rlimits(conf->propagate_rlimits_except,
NO_PROPAGATE_RLIMITS)) < 0) {
error("Bad PropagateResourceLimitsExcept: %s",
conf->propagate_rlimits_except);
return SLURM_ERROR;
}
} else {
if (!s_p_get_string(&conf->propagate_rlimits,
"PropagateResourceLimits", hashtbl))
conf->propagate_rlimits = xstrdup( "ALL" );
if ((parse_rlimits(conf->propagate_rlimits,
PROPAGATE_RLIMITS )) < 0) {
error("Bad PropagateResourceLimits: %s",
conf->propagate_rlimits);
return SLURM_ERROR;
}
}
if (s_p_get_string(&temp_str, "ReconfigFlags", hashtbl)) {
conf->reconfig_flags = reconfig_str2flags(temp_str);
if (conf->reconfig_flags == 0xffff) {
error("ReconfigFlags invalid: %s", temp_str);
return SLURM_ERROR;
}
xfree(temp_str);
} else /* Default: no ReconfigFlags */
conf->reconfig_flags = 0;
if (!s_p_get_uint16(&conf->ret2service, "ReturnToService", hashtbl))
conf->ret2service = DEFAULT_RETURN_TO_SERVICE;
#ifdef HAVE_ALPS_CRAY
if (conf->ret2service > 1) {
error("ReturnToService > 1 is not supported on ALPS Cray");
return SLURM_ERROR;
}
#endif
s_p_get_string(&conf->resv_epilog, "ResvEpilog", hashtbl);
s_p_get_uint16(&conf->resv_over_run, "ResvOverRun", hashtbl);
s_p_get_string(&conf->resv_prolog, "ResvProlog", hashtbl);
s_p_get_string(&conf->resume_program, "ResumeProgram", hashtbl);
if (!s_p_get_uint16(&conf->resume_rate, "ResumeRate", hashtbl))
conf->resume_rate = DEFAULT_RESUME_RATE;
if (!s_p_get_uint16(&conf->resume_timeout, "ResumeTimeout", hashtbl))
conf->resume_timeout = DEFAULT_RESUME_TIMEOUT;
s_p_get_string(&conf->reboot_program, "RebootProgram", hashtbl);
s_p_get_string(&conf->salloc_default_command, "SallocDefaultCommand",
hashtbl);
s_p_get_string(&conf->sched_params, "SchedulerParameters", hashtbl);
if (s_p_get_uint16(&conf->schedport, "SchedulerPort", hashtbl)) {
if (conf->schedport == 0) {
error("SchedulerPort=0 is invalid");
conf->schedport = DEFAULT_SCHEDULER_PORT;
}
} else {
conf->schedport = DEFAULT_SCHEDULER_PORT;
}
if (!s_p_get_uint16(&conf->schedrootfltr,
"SchedulerRootFilter", hashtbl))
conf->schedrootfltr = DEFAULT_SCHEDROOTFILTER;
if (!s_p_get_uint16(&conf->sched_time_slice, "SchedulerTimeSlice",
hashtbl))
conf->sched_time_slice = DEFAULT_SCHED_TIME_SLICE;
else if (conf->sched_time_slice < 5) {
error("SchedulerTimeSlice must be at least 5 seconds");
conf->sched_time_slice = DEFAULT_SCHED_TIME_SLICE;
}
if (!s_p_get_string(&conf->schedtype, "SchedulerType", hashtbl))
conf->schedtype = xstrdup(DEFAULT_SCHEDTYPE);
if (strcmp(conf->priority_type, "priority/multifactor") == 0) {
if ((strcmp(conf->schedtype, "sched/wiki") == 0) ||
(strcmp(conf->schedtype, "sched/wiki2") == 0)) {
error("PriorityType=priority/multifactor is "
"incompatible with SchedulerType=%s",
conf->schedtype);
return SLURM_ERROR;
}
}
if (conf->preempt_mode) {
if ((strcmp(conf->schedtype, "sched/wiki") == 0) ||
(strcmp(conf->schedtype, "sched/wiki2") == 0)) {
error("Job preemption is incompatible with "
"SchedulerType=%s",
conf->schedtype);
return SLURM_ERROR;
}
}
if (!s_p_get_string(&conf->select_type, "SelectType", hashtbl))
conf->select_type = xstrdup(DEFAULT_SELECT_TYPE);
if (s_p_get_string(&temp_str,
"SelectTypeParameters", hashtbl)) {
uint16_t type_param;
if ((parse_select_type_param(temp_str, &type_param) < 0)) {
error("Bad SelectTypeParameter: %s", temp_str);
xfree(temp_str);
return SLURM_ERROR;
}
conf->select_type_param = type_param;
xfree(temp_str);
} else
conf->select_type_param = 0;
/* If not running linear default to be CR_CPU */
if (!(conf->select_type_param & (CR_CPU | CR_SOCKET | CR_CORE))
&& (!strcmp(conf->select_type, "select/cons_res") ||
!strcmp(conf->select_type, "select/serial") ||
(conf->select_type_param & CR_OTHER_CONS_RES)))
conf->select_type_param |= CR_CPU;
if (!s_p_get_string( &conf->slurm_user_name, "SlurmUser", hashtbl)) {
conf->slurm_user_name = xstrdup("root");
conf->slurm_user_id = 0;
} else {
uid_t my_uid;
if (uid_from_string (conf->slurm_user_name, &my_uid) < 0) {
error ("Invalid user for SlurmUser %s, ignored",
conf->slurm_user_name);
xfree(conf->slurm_user_name);
return SLURM_ERROR;
} else {
conf->slurm_user_id = my_uid;
}
}
#ifdef HAVE_REAL_CRAY
/*
* This requirement derives from Cray ALPS:
* - ALPS reservations can only be created by the job owner or root
* (confirmation may be done by other non-privileged users);
* - freeing a reservation always requires root privileges.
* Even when running on Native Cray the SlurmUser must be root
* to access the needed libraries.
*/
if (conf->slurm_user_id != 0) {
error("Cray requires SlurmUser=root (default), but have '%s'.",
conf->slurm_user_name);
return SLURM_ERROR;
}
#endif
if (!s_p_get_string( &conf->slurmd_user_name, "SlurmdUser", hashtbl)) {
conf->slurmd_user_name = xstrdup("root");
conf->slurmd_user_id = 0;
} else {
uid_t my_uid;
if (uid_from_string (conf->slurmd_user_name, &my_uid) < 0) {
error("Invalid user for SlurmdUser %s, ignored",
conf->slurmd_user_name);
xfree(conf->slurmd_user_name);
return SLURM_ERROR;
} else {
conf->slurmd_user_id = my_uid;
}
}
if (s_p_get_string(&temp_str, "SlurmctldDebug", hashtbl)) {
conf->slurmctld_debug = log_string2num(temp_str);
if (conf->slurmctld_debug == (uint16_t) NO_VAL) {
error("Invalid SlurmctldDebug %s", temp_str);
return SLURM_ERROR;
}
xfree(temp_str);
_normalize_debug_level(&conf->slurmctld_debug);
} else
conf->slurmctld_debug = LOG_LEVEL_INFO;
if (!s_p_get_string(&conf->slurmctld_pidfile,
"SlurmctldPidFile", hashtbl))
conf->slurmctld_pidfile = xstrdup(DEFAULT_SLURMCTLD_PIDFILE);
s_p_get_string(&conf->slurmctld_plugstack, "SlurmctldPlugstack",
hashtbl);
s_p_get_string(&conf->slurmctld_logfile, "SlurmctldLogFile", hashtbl);
if (s_p_get_string(&temp_str, "SlurmctldPort", hashtbl)) {
char *end_ptr = NULL;
long port_long;
slurm_seterrno(0);
port_long = strtol(temp_str, &end_ptr, 10);
if ((port_long == LONG_MIN) || (port_long == LONG_MAX) ||
(port_long <= 0) || errno) {
error("Invalid SlurmctldPort %s", temp_str);
return SLURM_ERROR;
}
conf->slurmctld_port = port_long;
if (end_ptr[0] == '-') {
port_long = strtol(end_ptr+1, NULL, 10);
if ((port_long == LONG_MIN) ||
(port_long == LONG_MAX) ||
(port_long <= conf->slurmctld_port) || errno) {
error("Invalid SlurmctldPort %s", temp_str);
return SLURM_ERROR;
}
conf->slurmctld_port_count = port_long + 1 -
conf->slurmctld_port;
} else if (end_ptr[0] != '\0') {
error("Invalid SlurmctldPort %s", temp_str);
return SLURM_ERROR;
} else {
conf->slurmctld_port_count = 1;
}
xfree(temp_str);
} else {
conf->slurmctld_port = SLURMCTLD_PORT;
conf->slurmctld_port_count = SLURMCTLD_PORT_COUNT;
}
if (!s_p_get_uint16(&conf->slurmctld_timeout,
"SlurmctldTimeout", hashtbl))
conf->slurmctld_timeout = DEFAULT_SLURMCTLD_TIMEOUT;
if (s_p_get_string(&temp_str, "SlurmdDebug", hashtbl)) {
conf->slurmd_debug = log_string2num(temp_str);
if (conf->slurmd_debug == (uint16_t) NO_VAL) {
error("Invalid SlurmdDebug %s", temp_str);
return SLURM_ERROR;
}
xfree(temp_str);
_normalize_debug_level(&conf->slurmd_debug);
} else
conf->slurmd_debug = LOG_LEVEL_INFO;
s_p_get_string(&conf->slurmd_logfile, "SlurmdLogFile", hashtbl);
if (!s_p_get_string(&conf->slurmd_pidfile, "SlurmdPidFile", hashtbl))
conf->slurmd_pidfile = xstrdup(DEFAULT_SLURMD_PIDFILE);
if (!s_p_get_uint32(&conf->slurmd_port, "SlurmdPort", hashtbl))
conf->slurmd_port = SLURMD_PORT;
s_p_get_string(&conf->slurmd_plugstack, "SlurmdPlugstack",
hashtbl);
s_p_get_string(&conf->sched_logfile, "SlurmSchedLogFile", hashtbl);
if (!s_p_get_uint16(&conf->sched_log_level,
"SlurmSchedLogLevel", hashtbl))
conf->sched_log_level = DEFAULT_SCHED_LOG_LEVEL;
if (conf->sched_log_level && !conf->sched_logfile) {
error("SlurmSchedLogLevel requires SlurmSchedLogFile value");
return SLURM_ERROR;
}
if (!s_p_get_string(&conf->slurmd_spooldir, "SlurmdSpoolDir", hashtbl))
conf->slurmd_spooldir = xstrdup(DEFAULT_SPOOLDIR);
if (!s_p_get_uint16(&conf->slurmd_timeout, "SlurmdTimeout", hashtbl))
conf->slurmd_timeout = DEFAULT_SLURMD_TIMEOUT;
s_p_get_string(&conf->srun_prolog, "SrunProlog", hashtbl);
s_p_get_string(&conf->srun_epilog, "SrunEpilog", hashtbl);
if (!s_p_get_string(&conf->state_save_location,
"StateSaveLocation", hashtbl))
conf->state_save_location = xstrdup(DEFAULT_SAVE_STATE_LOC);
s_p_get_string(&conf->suspend_exc_nodes, "SuspendExcNodes", hashtbl);
s_p_get_string(&conf->suspend_exc_parts, "SuspendExcParts", hashtbl);
s_p_get_string(&conf->suspend_program, "SuspendProgram", hashtbl);
if (!s_p_get_uint16(&conf->suspend_rate, "SuspendRate", hashtbl))
conf->suspend_rate = DEFAULT_SUSPEND_RATE;
if (s_p_get_long(&long_suspend_time, "SuspendTime", hashtbl)) {
if (long_suspend_time < -1) {
error("SuspendTime value (%ld) is less than -1",
long_suspend_time);
} else if ((long_suspend_time > -1) &&
(!strcmp(conf->select_type, "select/bluegene"))) {
error("SuspendTime (power save mode) incomptible with "
"select/bluegene");
return SLURM_ERROR;
} else
conf->suspend_time = long_suspend_time + 1;
} else
conf->suspend_time = 0;
if (!s_p_get_uint16(&conf->suspend_timeout, "SuspendTimeout", hashtbl))
conf->suspend_timeout = DEFAULT_SUSPEND_TIMEOUT;
/* see above for switch_type, order dependent */
if (!s_p_get_string(&conf->task_plugin, "TaskPlugin", hashtbl))
conf->task_plugin = xstrdup(DEFAULT_TASK_PLUGIN);
if (s_p_get_string(&temp_str, "TaskPluginParam", hashtbl)) {
char *last = NULL, *tok;
bool set_mode = false, set_unit = false;
tok = strtok_r(temp_str, ",", &last);
while (tok) {
if (strcasecmp(tok, "none") == 0) {
if (set_unit) {
error("Bad TaskPluginParam: %s", tok);
return SLURM_ERROR;
}
set_unit = true;
conf->task_plugin_param |= CPU_BIND_NONE;
} else if (strcasecmp(tok, "boards") == 0) {
if (set_unit) {
error("Bad TaskPluginParam: %s", tok);
return SLURM_ERROR;
}
set_unit = true;
conf->task_plugin_param |= CPU_BIND_TO_BOARDS;
} else if (strcasecmp(tok, "sockets") == 0) {
if (set_unit) {
error("Bad TaskPluginParam: %s", tok);
return SLURM_ERROR;
}
set_unit = true;
conf->task_plugin_param |= CPU_BIND_TO_SOCKETS;
} else if (strcasecmp(tok, "cores") == 0) {
if (set_unit) {
error("Bad TaskPluginParam: %s", tok);
return SLURM_ERROR;
}
set_unit = true;
conf->task_plugin_param |= CPU_BIND_TO_CORES;
} else if (strcasecmp(tok, "threads") == 0) {
if (set_unit) {
error("Bad TaskPluginParam: %s", tok);
return SLURM_ERROR;
}
set_unit = true;
conf->task_plugin_param |= CPU_BIND_TO_THREADS;
} else if (strcasecmp(tok, "cpusets") == 0) {
if (set_mode) {
error("Bad TaskPluginParam: %s", tok);
return SLURM_ERROR;
}
set_mode = true;
conf->task_plugin_param |= CPU_BIND_CPUSETS;
} else if (strcasecmp(tok, "sched") == 0) {
if (set_mode) {
error("Bad TaskPluginParam: %s", tok);
return SLURM_ERROR;
}
set_mode = true;
/* No change to task_plugin_param,
* this is the default */
} else if (strcasecmp(tok, "verbose") == 0) {
conf->task_plugin_param |= CPU_BIND_VERBOSE;
} else {
error("Bad TaskPluginParam: %s", tok);
return SLURM_ERROR;
}
tok = strtok_r(NULL, ",", &last);
}
xfree(temp_str);
}
s_p_get_string(&conf->task_epilog, "TaskEpilog", hashtbl);
s_p_get_string(&conf->task_prolog, "TaskProlog", hashtbl);
if (!s_p_get_string(&conf->tmp_fs, "TmpFS", hashtbl))
conf->tmp_fs = xstrdup(DEFAULT_TMP_FS);
if (!s_p_get_uint16(&conf->wait_time, "WaitTime", hashtbl))
conf->wait_time = DEFAULT_WAIT_TIME;
if (!s_p_get_string(&conf->topology_plugin, "TopologyPlugin", hashtbl))
conf->topology_plugin = xstrdup(DEFAULT_TOPOLOGY_PLUGIN);
#ifdef HAVE_BG
if (strcmp(conf->topology_plugin, "topology/none")) {
error("On IBM BlueGene systems TopologyPlugin=topology/none "
"is required");
return SLURM_ERROR;
}
#endif
if (s_p_get_uint16(&conf->tree_width, "TreeWidth", hashtbl)) {
if (conf->tree_width == 0) {
error("TreeWidth=0 is invalid");
conf->tree_width = DEFAULT_TREE_WIDTH;
}
} else {
conf->tree_width = DEFAULT_TREE_WIDTH;
}
if (s_p_get_boolean(&truth, "UsePAM", hashtbl) && truth) {
conf->use_pam = 1;
} else {
conf->use_pam = 0;
}
s_p_get_string(&conf->unkillable_program,
"UnkillableStepProgram", hashtbl);
if (!s_p_get_uint16(&conf->unkillable_timeout,
"UnkillableStepTimeout", hashtbl))
conf->unkillable_timeout = DEFAULT_UNKILLABLE_TIMEOUT;
s_p_get_uint16(&conf->vsize_factor, "VSizeFactor", hashtbl);
#ifdef HAVE_BG
if (conf->node_prefix == NULL) {
error("No valid node name prefix identified");
return SLURM_ERROR;
}
#endif
xfree(default_storage_type);
xfree(default_storage_loc);
xfree(default_storage_host);
xfree(default_storage_user);
xfree(default_storage_pass);
return SLURM_SUCCESS;
}
/*
* Replace first "%h" in path string with NodeHostname.
* Replace first "%n" in path string with NodeName.
*
* NOTE: Caller should be holding slurm_conf_lock() when calling this function.
*
* Returns an xmalloc()ed string which the caller must free with xfree().
*/
extern char *
slurm_conf_expand_slurmd_path(const char *path, const char *node_name)
{
char *hostname;
char *dir = NULL;
dir = xstrdup(path);
hostname = _internal_get_hostname(node_name);
xstrsubstitute(dir, "%h", hostname);
xfree(hostname);
xstrsubstitute(dir, "%n", node_name);
return dir;
}
/*
* prolog_flags2str - convert a PrologFlags uint16_t to the equivalent string
* Keep in sync with prolog_str2flags() below
*/
extern char * prolog_flags2str(uint16_t prolog_flags)
{
char *rc = NULL;
if (prolog_flags & PROLOG_FLAG_ALLOC) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Alloc");
}
if (prolog_flags & PROLOG_FLAG_NOHOLD) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "NoHold");
}
return rc;
}
/*
* prolog_str2flags - Convert a PrologFlags string to the equivalent uint16_t
* Keep in sync with prolog_flags2str() above
* Returns NO_VAL if invalid
*/
extern uint16_t prolog_str2flags(char *prolog_flags)
{
uint16_t rc = 0;
char *tmp_str, *tok, *last = NULL;
if (!prolog_flags)
return rc;
tmp_str = xstrdup(prolog_flags);
tok = strtok_r(tmp_str, ",", &last);
while (tok) {
if (strcasecmp(tok, "Alloc") == 0)
rc |= PROLOG_FLAG_ALLOC;
else if (strcasecmp(tok, "NoHold") == 0)
rc |= PROLOG_FLAG_NOHOLD;
else {
error("Invalid PrologFlag: %s", tok);
rc = (uint16_t)NO_VAL;
break;
}
tok = strtok_r(NULL, ",", &last);
}
xfree(tmp_str);
return rc;
}
/*
* debug_flags2str - convert a DebugFlags uint32_t to the equivalent string
* Keep in sync with debug_str2flags() below
*/
extern char * debug_flags2str(uint32_t debug_flags)
{
char *rc = NULL;
/* When adding to this please attempt to keep flags in
* alphabetical order.
*/
if (debug_flags & DEBUG_FLAG_BACKFILL) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Backfill");
}
if (debug_flags & DEBUG_FLAG_BACKFILL_MAP) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "BackfillMap");
}
if (debug_flags & DEBUG_FLAG_BG_ALGO) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "BGBlockAlgo");
}
if (debug_flags & DEBUG_FLAG_BG_ALGO_DEEP) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "BGBlockAlgoDeep");
}
if (debug_flags & DEBUG_FLAG_BG_PICK) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "BGBlockPick");
}
if (debug_flags & DEBUG_FLAG_BG_WIRES) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "BGBlockWires");
}
if (debug_flags & DEBUG_FLAG_CPU_BIND) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "CPU_Bind");
}
if (debug_flags & DEBUG_FLAG_ENERGY) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Energy");
}
if (debug_flags & DEBUG_FLAG_EXT_SENSORS) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "ExtSensors");
}
if (debug_flags & DEBUG_FLAG_FILESYSTEM) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Filesystem");
}
if (debug_flags & DEBUG_FLAG_FRONT_END) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "FrontEnd");
}
if (debug_flags & DEBUG_FLAG_GANG) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Gang");
}
if (debug_flags & DEBUG_FLAG_GRES) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Gres");
}
if (debug_flags & DEBUG_FLAG_INFINIBAND) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Infiniband");
}
if (debug_flags & DEBUG_FLAG_JOB_CONT) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "JobContainer");
}
if (debug_flags & DEBUG_FLAG_LICENSE) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "License");
}
if (debug_flags & DEBUG_FLAG_NO_CONF_HASH) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "NO_CONF_HASH");
}
if (debug_flags & DEBUG_FLAG_NO_REALTIME) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "NoRealTime");
}
if (debug_flags & DEBUG_FLAG_PRIO) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Priority");
}
if (debug_flags & DEBUG_FLAG_PROFILE) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Profile");
}
if (debug_flags & DEBUG_FLAG_RESERVATION) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Reservation");
}
if (debug_flags & DEBUG_FLAG_SELECT_TYPE) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "SelectType");
}
if (debug_flags & DEBUG_FLAG_STEPS) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Steps");
}
if (debug_flags & DEBUG_FLAG_SWITCH) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Switch");
}
if (debug_flags & DEBUG_FLAG_TASK) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Task");
}
if (debug_flags & DEBUG_FLAG_TRIGGERS) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Triggers");
}
if (debug_flags & DEBUG_FLAG_WIKI) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "Wiki");
}
if (debug_flags & DEBUG_FLAG_PROTOCOL) {
}
return rc;
}
/*
* debug_str2flags - Convert a DebugFlags string to the equivalent uint32_t
* Keep in sycn with debug_flags2str() above
* Returns NO_VAL if invalid
*/
extern uint32_t debug_str2flags(char *debug_flags)
{
uint32_t rc = 0;
char *tmp_str, *tok, *last = NULL;
if (!debug_flags)
return rc;
tmp_str = xstrdup(debug_flags);
tok = strtok_r(tmp_str, ",", &last);
while (tok) {
if (strcasecmp(tok, "Backfill") == 0)
rc |= DEBUG_FLAG_BACKFILL;
else if (strcasecmp(tok, "BackfillMap") == 0)
rc |= DEBUG_FLAG_BACKFILL_MAP;
else if (strcasecmp(tok, "BGBlockAlgo") == 0)
rc |= DEBUG_FLAG_BG_ALGO;
else if (strcasecmp(tok, "BGBlockAlgoDeep") == 0)
rc |= DEBUG_FLAG_BG_ALGO_DEEP;
else if (strcasecmp(tok, "BGBlockPick") == 0)
rc |= DEBUG_FLAG_BG_PICK;
else if (strcasecmp(tok, "BGBlockWires") == 0)
rc |= DEBUG_FLAG_BG_WIRES;
else if (strcasecmp(tok, "CPU_Bind") == 0)
rc |= DEBUG_FLAG_CPU_BIND;
else if (strcasecmp(tok, "Energy") == 0)
rc |= DEBUG_FLAG_ENERGY;
else if (strcasecmp(tok, "ExtSensors") == 0)
rc |= DEBUG_FLAG_EXT_SENSORS;
else if (strcasecmp(tok, "FrontEnd") == 0)
rc |= DEBUG_FLAG_FRONT_END;
else if (strcasecmp(tok, "Gang") == 0)
rc |= DEBUG_FLAG_GANG;
else if (strcasecmp(tok, "Gres") == 0)
rc |= DEBUG_FLAG_GRES;
else if (strcasecmp(tok, "Infiniband") == 0)
rc |= DEBUG_FLAG_INFINIBAND;
else if (strcasecmp(tok, "Filesystem") == 0)
rc |= DEBUG_FLAG_FILESYSTEM;
else if (strcasecmp(tok, "JobContainer") == 0)
rc |= DEBUG_FLAG_JOB_CONT;
else if (strcasecmp(tok, "License") == 0)
rc |= DEBUG_FLAG_LICENSE;
else if (strcasecmp(tok, "NO_CONF_HASH") == 0)
rc |= DEBUG_FLAG_NO_CONF_HASH;
else if (strcasecmp(tok, "NoRealTime") == 0)
rc |= DEBUG_FLAG_NO_REALTIME;
else if (strcasecmp(tok, "Priority") == 0)
rc |= DEBUG_FLAG_PRIO;
else if (strcasecmp(tok, "Profile") == 0)
rc |= DEBUG_FLAG_PROFILE;
else if (strcasecmp(tok, "Reservation") == 0)
rc |= DEBUG_FLAG_RESERVATION;
else if (strcasecmp(tok, "SelectType") == 0)
rc |= DEBUG_FLAG_SELECT_TYPE;
else if (strcasecmp(tok, "Steps") == 0)
rc |= DEBUG_FLAG_STEPS;
else if (strcasecmp(tok, "Switch") == 0)
rc |= DEBUG_FLAG_SWITCH;
else if (strcasecmp(tok, "Task") == 0)
rc |= DEBUG_FLAG_TASK;
else if (strcasecmp(tok, "Trigger") == 0)
rc |= DEBUG_FLAG_TRIGGERS;
else if (strcasecmp(tok, "Triggers") == 0)
rc |= DEBUG_FLAG_TRIGGERS;
else if (strcasecmp(tok, "Wiki") == 0)
rc |= DEBUG_FLAG_WIKI;
else if (strcasecmp(tok, "Protocol") == 0)
rc |= DEBUG_FLAG_PROTOCOL;
else {
error("Invalid DebugFlag: %s", tok);
rc = NO_VAL;
break;
}
tok = strtok_r(NULL, ",", &last);
}
xfree(tmp_str);
return rc;
}
/*
* reconfig_flags2str - convert a ReconfFlags uint16_t to the equivalent string
* Keep in sync with reconfig_str2flags() below
*/
extern char * reconfig_flags2str(uint16_t reconfig_flags)
{
char *rc = NULL;
if (reconfig_flags & RECONFIG_KEEP_PART_INFO) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "KeepPartInfo");
}
if (reconfig_flags & RECONFIG_KEEP_PART_STAT) {
if (rc)
xstrcat(rc, ",");
xstrcat(rc, "KeepPartState");
}
return rc;
}
/*
* reconfig_str2flags - Convert a ReconfFlags string to the equivalent uint16_t
* Keep in sync with reconfig_flags2str() above
* Returns NO_VAL if invalid
*/
extern uint16_t reconfig_str2flags(char *reconfig_flags)
{
uint16_t rc = 0;
char *tmp_str, *tok, *last = NULL;
if (!reconfig_flags)
return rc;
tmp_str = xstrdup(reconfig_flags);
tok = strtok_r(tmp_str, ",", &last);
while (tok) {
if (strcasecmp(tok, "KeepPartInfo") == 0)
rc |= RECONFIG_KEEP_PART_INFO;
else if (strcasecmp(tok, "KeepPartState") == 0)
rc |= RECONFIG_KEEP_PART_STAT;
else {
error("Invalid ReconfigFlag: %s", tok);
rc = (uint16_t) NO_VAL;
break;
}
tok = strtok_r(NULL, ",", &last);
}
xfree(tmp_str);
return rc;
}
extern void destroy_config_key_pair(void *object)
{
config_key_pair_t *key_pair_ptr = (config_key_pair_t *)object;
if (key_pair_ptr) {
xfree(key_pair_ptr->name);
xfree(key_pair_ptr->value);
xfree(key_pair_ptr);
}
}
extern void pack_config_key_pair(void *in, uint16_t rpc_version, Buf buffer)
{
config_key_pair_t *object = (config_key_pair_t *)in;
packstr(object->name, buffer);
packstr(object->value, buffer);
}
extern int unpack_config_key_pair(void **object, uint16_t rpc_version,
Buf buffer)
{
uint32_t uint32_tmp;
config_key_pair_t *object_ptr = xmalloc(sizeof(config_key_pair_t));
*object = object_ptr;
safe_unpackstr_xmalloc(&object_ptr->name, &uint32_tmp, buffer);
safe_unpackstr_xmalloc(&object_ptr->value, &uint32_tmp, buffer);
return SLURM_SUCCESS;
unpack_error:
destroy_config_key_pair(object_ptr);
*object = NULL;
return SLURM_ERROR;
}
extern int sort_key_pairs(void *v1, void *v2)
{
config_key_pair_t *key_a = *(config_key_pair_t **)v1;
config_key_pair_t *key_b = *(config_key_pair_t **)v2;
int size_a = strcmp(key_a->name, key_b->name);
if (size_a < 0)
return -1;
else if (size_a > 0)
return 1;
return 0;
}
/*
* Return the pathname of the extra .conf file
*/
extern char *get_extra_conf_path(char *conf_name)
{
char *val = getenv("SLURM_CONF");
char *rc = NULL, *slash;
if (!val)
val = default_slurm_config_file;
/* Replace file name on end of path */
rc = xstrdup(val);
if ((slash = strrchr(rc, '/')))
slash[1] = '\0';
else
rc[0] = '\0';
xstrcat(rc, conf_name);
return rc;
}
extern bool run_in_daemon(char *daemons)
{
char *full, *start_char, *end_char;
xassert(slurm_prog_name);
if (!strcmp(daemons, slurm_prog_name))
return true;
full = xstrdup(daemons);
start_char = full;
while (start_char && (end_char = strstr(start_char, ","))) {
*end_char = 0;
if (!strcmp(start_char, slurm_prog_name)) {
xfree(full);
return true;
}
start_char = end_char + 1;
}
if (start_char && !strcmp(start_char, slurm_prog_name)) {
xfree(full);
return true;
}
xfree(full);
return false;
}