| /*****************************************************************************\ |
| * 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. |
| * Copyright (C) SchedMD LLC. |
| * Portions (boards) copyright (C) 2012 Bull, <rod.schultz@bull.com> |
| * Portions (route) copyright (C) 2014 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 <https://slurm.schedmd.com/>. |
| * Please also read the included file: DISCLAIMER. |
| * |
| * Slurm is free software; you can redistribute it and/or modify it under |
| * the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * In addition, as a special exception, the copyright holders give permission |
| * to link the code of portions of this program with the OpenSSL library under |
| * certain conditions as described in each individual source file, and |
| * distribute linked combinations including the two. You must obey the GNU |
| * General Public License in all respects for all of the code used other than |
| * OpenSSL. If you modify file(s) with this exception, you may extend this |
| * exception to your version of the file(s), but you are not obligated to do |
| * so. If you do not wish to do so, delete this exception statement from your |
| * version. If you delete this exception statement from all source files in |
| * the program, then also delete it here. |
| * |
| * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| * details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with Slurm; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| \*****************************************************************************/ |
| |
| #include "config.h" |
| |
| #include <arpa/inet.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/cpu_frequency.h" |
| #include "src/common/extra_constraints.h" |
| #include "src/common/fetch_config.h" |
| #include "src/common/hostlist.h" |
| #include "src/common/list.h" |
| #include "src/common/log.h" |
| #include "src/common/macros.h" |
| #include "src/common/node_conf.h" |
| #include "src/interfaces/node_features.h" |
| #include "src/common/parse_config.h" |
| #include "src/common/parse_time.h" |
| #include "src/common/proc_args.h" |
| #include "src/common/read_config.h" |
| #include "src/interfaces/accounting_storage.h" |
| #include "src/common/slurm_protocol_api.h" |
| #include "src/common/slurm_protocol_defs.h" |
| #include "src/common/slurm_resource_info.h" |
| #include "src/common/slurm_resolv.h" |
| #include "src/common/slurm_rlimits_info.h" |
| #include "src/common/strlcpy.h" |
| #include "src/common/uid.h" |
| #include "src/common/util-net.h" |
| #include "src/common/xassert.h" |
| #include "src/common/xmalloc.h" |
| #include "src/common/xstring.h" |
| |
| #include "src/interfaces/hash.h" |
| |
| /* |
| ** Define slurm-specific aliases for use by plugins, see slurm_xlator.h |
| ** for details. |
| */ |
| strong_alias(destroy_config_plugin_params, slurm_destroy_config_plugin_params); |
| 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(conf_get_opt_str, slurm_conf_get_opt_str); |
| strong_alias(add_key_pair, slurm_add_key_pair); |
| strong_alias(add_key_pair_bool, slurm_add_key_pair_bool); |
| strong_alias(add_key_pair_own, slurm_add_key_pair_own); |
| |
| /* |
| * Instantiation of the "extern slurm_conf_t slurm_conf" and |
| * "bool ignore_state_errors" found in slurmctld.h |
| */ |
| slurm_conf_t slurm_conf; |
| bool ignore_state_errors = false; |
| |
| static pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER; |
| static s_p_hashtbl_t *conf_hashtbl = NULL; |
| static buf_t *conf_buf = NULL; |
| static slurm_conf_t *conf_ptr = &slurm_conf; |
| static bool conf_initialized = false; |
| static s_p_hashtbl_t *default_nodename_tbl; |
| static s_p_hashtbl_t *default_partition_tbl; |
| static list_t *config_files = NULL; |
| |
| 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 */ |
| char *bcast_address; /* BcastAddress */ |
| uint16_t port; |
| slurm_addr_t addr; |
| slurm_addr_t bcast_addr; |
| bool addr_initialized; |
| bool bcast_addr_initialized; |
| bool is_cloud; |
| bool is_dynamic; |
| 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}; |
| |
| typedef struct slurm_conf_server { |
| char *hostname; |
| char *addr; |
| } slurm_conf_server_t; |
| |
| static slurm_conf_node_t *_create_conf_node(void); |
| static void _pack_node_conf_lite(void *n, buf_t *buffer); |
| static void *_unpack_node_conf_lite(buf_t *buffer); |
| static void _init_conf_node(slurm_conf_node_t *conf_node); |
| static void _destroy_nodename(void *ptr); |
| 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 slurm_conf_partition_t *_create_conf_part(void); |
| static void _init_conf_part(slurm_conf_partition_t *conf_part); |
| 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 _parse_nodeset(void **dest, slurm_parser_enum_t type, |
| const char *key, const char *value, |
| const char *line, char **leftover); |
| static void _destroy_nodeset(void *ptr); |
| |
| static int _load_slurmctld_host(slurm_conf_t *conf); |
| static int _parse_slurmctld_host(void **dest, slurm_parser_enum_t type, |
| const char *key, const char *value, |
| const char *line, char **leftover); |
| static void _destroy_slurmctld_host(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 void _internal_conf_remove_node(char *node_name); |
| static int _validate_and_set_defaults(slurm_conf_t *conf, |
| s_p_hashtbl_t *hashtbl); |
| static int _validate_bcast_exclude(slurm_conf_t *conf); |
| static uint16_t *_parse_srun_ports(const char *); |
| |
| static void _push_to_hashtbls(char *alias, char *hostname, char *address, |
| char *bcast_address, uint16_t port, |
| slurm_addr_t *addr, |
| bool initialized, bool dynamic, bool cloud); |
| |
| static s_p_options_t slurm_conf_stepd_options[] = { |
| {.key = "NodeName", |
| .type = S_P_ARRAY, |
| .handler = _parse_nodename, |
| .destroy = _destroy_nodename, |
| .pack = _pack_node_conf_lite, |
| .unpack = _unpack_node_conf_lite, |
| }, |
| {NULL} |
| }; |
| static int slurm_conf_stepd_options_cnt = 1; |
| |
| s_p_options_t slurm_conf_options[] = { |
| {"AccountingStorageBackupHost", S_P_STRING}, |
| {"AccountingStorageEnforce", S_P_STRING}, |
| {"AccountingStorageExternalHost", S_P_STRING}, |
| {"AccountingStorageHost", S_P_STRING}, |
| {"AccountingStorageParameters", S_P_STRING}, |
| {"AccountingStoragePass", S_P_STRING}, |
| {"AccountingStoragePort", S_P_UINT16}, |
| {"AccountingStorageTRES", S_P_STRING}, |
| {"AccountingStorageType", S_P_STRING}, |
| {"AccountingStorageUser", S_P_STRING, _defunct_option}, |
| {"AccountingStoreFlags", S_P_STRING}, |
| {"AccountingStoreJobComment", S_P_BOOLEAN}, |
| {"AcctGatherEnergyType", S_P_STRING}, |
| {"AcctGatherFilesystemType", S_P_STRING}, |
| {"AcctGatherInfinibandType", S_P_STRING}, |
| {"AcctGatherInterconnectType", S_P_STRING}, |
| {"AcctGatherNodeFreq", S_P_UINT16}, |
| {"AcctGatherProfileType", S_P_STRING}, |
| {"AllowSpecResourcesUsage", S_P_BOOLEAN}, |
| {"AuthAltParameters", S_P_STRING}, |
| {"AuthAltTypes", S_P_STRING}, |
| {"AuthInfo", S_P_STRING}, |
| {"AuthType", S_P_STRING}, |
| {"BackupAddr", S_P_STRING}, |
| {"BackupController", S_P_STRING}, |
| {"BatchStartTimeout", S_P_UINT16}, |
| {"BcastExclude", S_P_STRING}, |
| {"BcastParameters", S_P_STRING}, |
| {"BurstBufferParameters", S_P_STRING}, |
| {"BurstBufferType", S_P_STRING}, |
| {"CertgenType", S_P_STRING}, |
| {"CertgenParameters", S_P_STRING}, |
| {"CertmgrType", S_P_STRING}, |
| {"CertmgrParameters", S_P_STRING}, |
| {"CliFilterParameters", S_P_STRING}, |
| {"CliFilterPlugins", S_P_STRING}, |
| {"ClusterName", S_P_STRING}, |
| {"CommunicationParameters", S_P_STRING}, |
| {"CompleteWait", S_P_UINT16}, |
| {"ControlAddr", S_P_STRING}, |
| {"ControlMachine", S_P_STRING}, |
| {"CoreSpecPlugin", S_P_STRING, _defunct_option}, |
| {"CpuFreqDef", S_P_STRING}, |
| {"CpuFreqGovernors", S_P_STRING}, |
| {"CredType", S_P_STRING}, |
| {"CryptoType", S_P_STRING}, |
| {"DataParserParameters", S_P_STRING}, |
| {"DebugFlags", S_P_STRING}, |
| {"DefCPUPerGPU" , S_P_UINT64}, |
| {"DefMemPerCPU", S_P_UINT64}, |
| {"DefMemPerGPU" , S_P_UINT64}, |
| {"DefMemPerNode", S_P_UINT64}, |
| {"DependencyParameters", S_P_STRING}, |
| {"DisableRootJobs", S_P_BOOLEAN}, |
| {"EioTimeout", S_P_UINT16}, |
| {"EnforcePartLimits", S_P_STRING}, |
| {"Epilog", S_P_ARRAY}, |
| {"EpilogMsgTime", S_P_UINT32}, |
| {"EpilogSlurmctld", S_P_ARRAY}, |
| {"EpilogTimeout", S_P_UINT16}, |
| {"ExtSensorsFreq", S_P_UINT16, _defunct_option}, |
| {"ExtSensorsType", S_P_STRING, _defunct_option}, |
| {"FairShareDampeningFactor", S_P_UINT16}, |
| {"FastSchedule", S_P_UINT16}, |
| {"FederationParameters", S_P_STRING}, |
| {"FirstJobId", S_P_UINT32}, |
| {"GetEnvTimeout", S_P_UINT16, _defunct_option}, |
| {"GpuFreqDef", S_P_STRING}, |
| {"GresTypes", S_P_STRING}, |
| {"GroupUpdateForce", S_P_UINT16}, |
| {"GroupUpdateTime", S_P_UINT16}, |
| {"HashPlugin", S_P_STRING}, |
| {"HealthCheckInterval", S_P_UINT16}, |
| {"HealthCheckNodeState", S_P_STRING}, |
| {"HealthCheckProgram", S_P_STRING}, |
| {"HttpParserType", S_P_STRING}, |
| {"InactiveLimit", S_P_UINT16}, |
| {"InteractiveStepOptions", S_P_STRING}, |
| {"JobAcctGatherFrequency", S_P_STRING}, |
| {"JobAcctGatherParams", S_P_STRING}, |
| {"JobAcctGatherType", S_P_STRING}, |
| {"JobCompHost", S_P_STRING}, |
| {"JobCompLoc", S_P_STRING}, |
| {"JobCompParams", S_P_STRING}, |
| {"JobCompPass", S_P_STRING}, |
| {"JobCompPort", S_P_UINT32}, |
| {"JobCompType", S_P_STRING}, |
| {"JobCompUser", S_P_STRING}, |
| {"JobContainerType", S_P_STRING}, |
| {"JobCredentialPrivateKey", S_P_STRING, _defunct_option}, |
| {"JobCredentialPublicCertificate", S_P_STRING, _defunct_option}, |
| {"JobFileAppend", S_P_UINT16}, |
| {"JobRequeue", S_P_UINT16}, |
| {"JobSubmitPlugins", S_P_STRING}, |
| {"KeepAliveTime", S_P_UINT32}, |
| {"KillOnBadExit", S_P_UINT16}, |
| {"KillWait", S_P_UINT16}, |
| {"LaunchParameters", S_P_STRING}, |
| {"LaunchType", S_P_STRING}, |
| {"Licenses", S_P_STRING}, |
| {"LogTimeFormat", S_P_STRING}, |
| {"MailDomain", S_P_STRING}, |
| {"MailProg", S_P_STRING}, |
| {"MaxArraySize", S_P_UINT32}, |
| {"MaxBatchRequeue", S_P_UINT32}, |
| {"MaxDBDMsgs", S_P_UINT32}, |
| {"MaxJobCount", S_P_UINT32}, |
| {"MaxJobId", S_P_UINT32}, |
| {"MaxMemPerCPU", S_P_UINT64}, |
| {"MaxMemPerNode", S_P_UINT64}, |
| {"MaxNodeCount", S_P_UINT32}, |
| {"MaxStepCount", S_P_UINT32}, |
| {"MaxTasksPerNode", S_P_UINT16}, |
| {"MCSParameters", S_P_STRING}, |
| {"MCSPlugin", S_P_STRING}, |
| {"MessageTimeout", S_P_UINT16}, |
| {"MinJobAge", S_P_UINT32}, |
| {"MpiDefault", S_P_STRING}, |
| {"MpiParams", S_P_STRING}, |
| {"NodeFeaturesPlugins", S_P_STRING}, |
| {"OverTimeLimit", S_P_UINT16}, |
| {"PluginDir", S_P_STRING}, |
| {"PlugStackConfig", S_P_STRING}, |
| {"PowerParameters", S_P_STRING, _defunct_option}, |
| {"PowerPlugin", S_P_STRING, _defunct_option}, |
| {"PreemptExemptTime", S_P_STRING}, |
| {"PreemptMode", S_P_STRING}, |
| {"PreemptParameters", S_P_STRING}, |
| {"PreemptType", S_P_STRING}, |
| {"PrEpParameters", S_P_STRING}, |
| {"PrEpPlugins", S_P_STRING}, |
| {"PriorityCalcPeriod", S_P_STRING}, |
| {"PriorityDecayHalfLife", S_P_STRING}, |
| {"PriorityFavorSmall", S_P_BOOLEAN}, |
| {"PriorityFlags", S_P_STRING}, |
| {"PriorityMaxAge", S_P_STRING}, |
| {"PriorityParameters", S_P_STRING}, |
| {"PrioritySiteFactorParameters", S_P_STRING}, |
| {"PrioritySiteFactorPlugin", S_P_STRING}, |
| {"PriorityType", S_P_STRING}, |
| {"PriorityUsageResetPeriod", S_P_STRING}, |
| {"PriorityWeightAge", S_P_UINT32}, |
| {"PriorityWeightAssoc", S_P_UINT32}, |
| {"PriorityWeightFairshare", S_P_UINT32}, |
| {"PriorityWeightJobSize", S_P_UINT32}, |
| {"PriorityWeightPartition", S_P_UINT32}, |
| {"PriorityWeightQOS", S_P_UINT32}, |
| {"PriorityWeightTRES", S_P_STRING}, |
| {"PrivateData", S_P_STRING}, |
| {"ProctrackType", S_P_STRING}, |
| {"Prolog", S_P_ARRAY}, |
| {"PrologEpilogTimeout", S_P_UINT16}, |
| {"PrologFlags", S_P_STRING}, |
| {"PrologSlurmctld", S_P_ARRAY}, |
| {"PrologTimeout", S_P_UINT16}, |
| {"PropagatePrioProcess", S_P_UINT16}, |
| {"PropagateResourceLimits", S_P_STRING}, |
| {"PropagateResourceLimitsExcept", S_P_STRING}, |
| {"RebootProgram", S_P_STRING}, |
| {"ReconfigFlags", S_P_STRING}, |
| {"RequeueExit", S_P_STRING}, |
| {"RequeueExitHold", S_P_STRING}, |
| {"ResumeFailProgram", 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}, |
| {"RoutePlugin", S_P_STRING}, |
| {"SallocDefaultCommand", S_P_STRING}, |
| {"SbcastParameters", S_P_STRING}, |
| {"SchedulerParameters", S_P_STRING}, |
| {"SchedulerTimeSlice", S_P_UINT16}, |
| {"SchedulerType", S_P_STRING}, |
| {"ScronParameters", S_P_STRING}, |
| {"SelectType", S_P_STRING}, |
| {"SelectTypeParameters", S_P_STRING}, |
| {"SlurmctldAddr", S_P_STRING}, |
| {"SlurmctldDebug", S_P_STRING}, |
| {"SlurmctldLogFile", S_P_STRING}, |
| {"SlurmctldParameters", S_P_STRING}, |
| {"SlurmctldPidFile", S_P_STRING}, |
| {"SlurmctldPort", S_P_STRING}, |
| {"SlurmctldPrimaryOffProg", S_P_STRING}, |
| {"SlurmctldPrimaryOnProg", S_P_STRING}, |
| {"SlurmctldSyslogDebug", S_P_STRING}, |
| {"SlurmctldTimeout", S_P_UINT16}, |
| {"SlurmdDebug", S_P_STRING}, |
| {"SlurmdLogFile", S_P_STRING}, |
| {"SlurmdParameters", S_P_STRING}, |
| {"SlurmdPidFile", S_P_STRING}, |
| {"SlurmdPort", S_P_UINT32}, |
| {"SlurmdSpoolDir", S_P_STRING}, |
| {"SlurmdSyslogDebug", S_P_STRING}, |
| {"SlurmdTimeout", S_P_UINT16}, |
| {"SlurmdUser", S_P_STRING}, |
| {"SlurmSchedLogFile", S_P_STRING}, |
| {"SlurmSchedLogLevel", S_P_UINT16}, |
| {"SlurmUser", S_P_STRING}, |
| {"SrunEpilog", S_P_STRING}, |
| {"SrunPortRange", S_P_STRING}, |
| {"SrunProlog", S_P_STRING}, |
| {"StateSaveLocation", S_P_STRING}, |
| {"SuspendExcNodes", S_P_STRING}, |
| {"SuspendExcParts", S_P_STRING}, |
| {"SuspendExcStates", S_P_STRING}, |
| {"SuspendProgram", S_P_STRING}, |
| {"SuspendRate", S_P_UINT16}, |
| {"SuspendTime", S_P_STRING}, |
| {"SuspendTimeout", S_P_UINT16}, |
| {"SwitchParameters", S_P_STRING}, |
| {"SwitchType", S_P_STRING}, |
| {"TaskEpilog", S_P_STRING}, |
| {"TaskPlugin", S_P_STRING}, |
| {"TaskPluginParam", S_P_STRING}, |
| {"TaskProlog", S_P_STRING}, |
| {"TCPTimeout", S_P_UINT16}, |
| {"TLSParameters", S_P_STRING}, |
| {"TLSType", S_P_STRING}, |
| {"TmpFS", S_P_STRING}, |
| {"TopologyParam", S_P_STRING}, |
| {"TopologyPlugin", S_P_STRING}, |
| {"TrackWCKey", S_P_BOOLEAN}, |
| {"TreeWidth", S_P_UINT16}, |
| {"UnkillableStepProgram", S_P_STRING}, |
| {"UnkillableStepTimeout", S_P_UINT16}, |
| {"UrlParserType", S_P_STRING}, |
| {"UsePAM", S_P_BOOLEAN}, |
| {"VSizeFactor", S_P_UINT16}, |
| {"WaitTime", S_P_UINT16}, |
| {"X11Parameters", S_P_STRING}, |
| |
| {"DownNodes", S_P_ARRAY, _parse_downnodes, _destroy_downnodes}, |
| {"NodeName", S_P_ARRAY, _parse_nodename, _destroy_nodename}, |
| {"NodeSet", S_P_ARRAY, _parse_nodeset, _destroy_nodeset}, |
| {"PartitionName", S_P_ARRAY, _parse_partitionname, |
| _destroy_partitionname}, |
| {"SlurmctldHost", S_P_ARRAY, _parse_slurmctld_host, |
| _destroy_slurmctld_host}, |
| |
| {NULL} |
| }; |
| |
| static bool _is_valid_path(char *path, char *msg) |
| { |
| char *saveptr = NULL, *buf, *entry; |
| |
| if (path == NULL) { |
| error ("is_valid_path: path is NULL!"); |
| return false; |
| } |
| |
| buf = xstrdup(path); |
| entry = strtok_r(buf, ":", &saveptr); |
| while (entry) { |
| struct stat st; |
| |
| /* |
| * 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 = strtok_r(NULL, ":", &saveptr); |
| } |
| |
| 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_in_daemon("The option \"%s\" is defunct, please remove it from slurm.conf.", |
| key); |
| return 0; |
| } |
| |
| 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; |
| static s_p_options_t _nodename_options[] = { |
| {"BcastAddr", S_P_STRING}, |
| {"Boards", S_P_UINT16}, |
| {"CoreSpecCount", S_P_UINT16}, |
| {"CoresPerSocket", S_P_UINT16}, |
| {"CPUs", S_P_UINT16}, |
| {"CPUSpecList", S_P_STRING}, |
| {"CpuBind", S_P_STRING}, |
| {"Feature", S_P_STRING}, |
| {"Features", S_P_STRING}, |
| {"Gres", S_P_STRING}, |
| {"MemSpecLimit", S_P_UINT64}, |
| {"NodeAddr", S_P_STRING}, |
| {"NodeHostname", S_P_STRING}, |
| {"Port", S_P_STRING}, |
| {"Procs", S_P_UINT16}, |
| {"RealMemory", S_P_UINT64}, |
| {"Reason", S_P_STRING}, |
| {"RestrictedCoresPerGPU", S_P_UINT16}, |
| {"Sockets", S_P_UINT16}, |
| {"SocketsPerBoard", S_P_UINT16}, |
| {"State", S_P_STRING}, |
| {"ThreadsPerCore", S_P_UINT16}, |
| {"TmpDisk", S_P_UINT32}, |
| {"Topology", S_P_STRING}, |
| {"TRESWeights", S_P_STRING}, |
| {"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 (xstrcasecmp(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, "BcastAddr", tbl)) { |
| error("BcastAddr 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 if (!xstrcasecmp(value, "ALL")) { |
| fatal("'%s' is a reserved word disallowed for use with NodeName", |
| value); |
| } else { |
| bool no_cpus = false; |
| bool no_sockets = false; |
| bool no_sockets_per_board = false; |
| uint16_t sockets_per_board = 0; |
| char *cpu_bind = NULL; |
| |
| n = _create_conf_node(); |
| dflt = default_nodename_tbl; |
| |
| n->nodenames = xstrdup(value); |
| |
| 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); |
| s_p_get_string(&n->bcast_addresses, "BcastAddr", tbl); |
| |
| if (!s_p_get_uint16(&n->boards, "Boards", tbl)) |
| s_p_get_uint16(&n->boards, "Boards", dflt); |
| |
| if (s_p_get_string(&cpu_bind, "CpuBind", tbl) || |
| s_p_get_string(&cpu_bind, "CpuBind", dflt)) { |
| if (xlate_cpu_bind_str(cpu_bind, &n->cpu_bind) != |
| SLURM_SUCCESS) { |
| error_in_daemon("NodeNames=%s CpuBind=\'%s\' is invalid, ignored", |
| n->nodenames, cpu_bind); |
| n->cpu_bind = 0; |
| } |
| xfree(cpu_bind); |
| } |
| |
| if (!s_p_get_uint16(&n->core_spec_cnt, "CoreSpecCount", tbl)) |
| s_p_get_uint16(&n->core_spec_cnt, "CoreSpecCount", |
| dflt); |
| |
| if (!s_p_get_uint16(&n->cores, "CoresPerSocket", tbl)) |
| s_p_get_uint16(&n->cores, "CoresPerSocket", dflt); |
| |
| if (!s_p_get_string(&n->cpu_spec_list, "CPUSpecList", tbl)) |
| s_p_get_string(&n->cpu_spec_list, "CPUSpecList", dflt); |
| |
| if (!s_p_get_string(&n->feature, "Feature", tbl) && |
| !s_p_get_string(&n->feature, "Features", tbl) && |
| !s_p_get_string(&n->feature, "Feature", dflt)) |
| s_p_get_string(&n->feature, "Features", dflt); |
| |
| if (!s_p_get_string(&n->gres, "Gres", tbl)) |
| s_p_get_string(&n->gres, "Gres", dflt); |
| |
| if (!s_p_get_uint64(&n->mem_spec_limit, "MemSpecLimit", tbl)) |
| s_p_get_uint64(&n->mem_spec_limit, "MemSpecLimit", |
| 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_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)) { |
| no_cpus = true; |
| } |
| |
| if (!s_p_get_uint64(&n->real_memory, "RealMemory", tbl)) |
| s_p_get_uint64(&n->real_memory, "RealMemory", dflt); |
| |
| if (!s_p_get_string(&n->reason, "Reason", tbl)) |
| s_p_get_string(&n->reason, "Reason", dflt); |
| |
| if (!s_p_get_uint16(&n->res_cores_per_gpu, |
| "RestrictedCoresPerGPU", tbl)) |
| s_p_get_uint16(&n->res_cores_per_gpu, |
| "RestrictedCoresPerGPU", dflt); |
| |
| if (!s_p_get_uint16(&n->tot_sockets, "Sockets", tbl) && |
| !s_p_get_uint16(&n->tot_sockets, "Sockets", dflt)) { |
| 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); |
| |
| if (!s_p_get_uint16(&n->threads, "ThreadsPerCore", tbl)) |
| s_p_get_uint16(&n->threads, "ThreadsPerCore", dflt); |
| |
| if (!s_p_get_uint32(&n->tmp_disk, "TmpDisk", tbl)) |
| s_p_get_uint32(&n->tmp_disk, "TmpDisk", dflt); |
| |
| if (!s_p_get_string(&n->topology_str, "Topology", tbl)) |
| s_p_get_string(&n->topology_str, "Topology", dflt); |
| |
| if (!s_p_get_string(&n->tres_weights_str, "TRESWeights", tbl)) |
| s_p_get_string(&n->tres_weights_str, "TRESWeights", |
| dflt); |
| |
| if ((s_p_get_uint32(&n->weight, "Weight", tbl) || |
| s_p_get_uint32(&n->weight, "Weight", dflt)) && |
| (n->weight == INFINITE)) |
| n->weight -= 1; |
| |
| s_p_hashtbl_destroy(tbl); |
| |
| if (n->cores == 0) { /* make sure cores is non-zero */ |
| error_in_daemon("NodeNames=%s CoresPerSocket=0 is invalid, reset to 1", |
| n->nodenames); |
| n->cores = 1; |
| } |
| if (n->cpus == 0) { /* make sure cpus is non-zero */ |
| error_in_daemon("NodeNames=%s CPUs=0 is invalid, reset to 1", |
| n->nodenames); |
| n->cpus = 1; |
| } |
| if (n->threads == 0) { /* make sure threads is non-zero */ |
| error_in_daemon("NodeNames=%s ThreadsPerCore=0 is invalid, reset to 1", |
| n->nodenames); |
| n->threads = 1; |
| } |
| |
| if (sockets_per_board == 0) { |
| /* make sure sockets_per_boards is non-zero */ |
| error_in_daemon("NodeNames=%s SocketsPerBoards=0 is invalid, reset to 1", |
| n->nodenames); |
| sockets_per_board = 1; |
| } |
| |
| if (n->tot_sockets == 0) { |
| /* make sure tot_sockets is non-zero */ |
| error_in_daemon("NodeNames=%s Sockets=0 is invalid, reset to 1", |
| n->nodenames); |
| n->tot_sockets = 1; |
| } |
| |
| if (!no_sockets_per_board && !no_sockets) { |
| error_in_daemon("NodeNames=%s Sockets=# and SocketsPerBoard=# is invalid , using SocketsPerBoard", |
| n->nodenames); |
| no_sockets = true; |
| } |
| |
| if (n->boards == 0) { |
| /* make sure boards is non-zero */ |
| error_in_daemon("NodeNames=%s Boards=0 is invalid, reset to 1", |
| n->nodenames); |
| n->boards = 1; |
| } |
| |
| if (no_sockets) { |
| if (!no_sockets_per_board) { |
| n->tot_sockets = n->boards * sockets_per_board; |
| } else if (!no_cpus && |
| (n->cpus / (n->cores * n->threads)) && |
| !(n->cpus % (n->cores * n->threads))) { |
| /* infer missing Sockets= based on cpus */ |
| n->tot_sockets = n->cpus / (n->cores * |
| n->threads); |
| debug("NodeNames=%s setting Sockets=%d based on CPUs(%d)/(CoresPerSocket(%d)/ThreadsPerCore(%d))", |
| n->nodenames, |
| n->tot_sockets, |
| n->cpus, |
| n->cores, |
| n->threads); |
| } else { |
| /* default to one socket per board */ |
| n->tot_sockets = n->boards; |
| debug("NodeNames=%s setting Sockets=Boards(%d)", |
| n->nodenames, n->boards); |
| } |
| } |
| |
| if (no_cpus) { /* infer missing CPUs= */ |
| n->cpus = n->tot_sockets * n->cores * n->threads; |
| } |
| |
| if (n->tot_sockets < n->boards) { |
| error_in_daemon("NodeNames=%s Sockets(%d) < Boards(%d) resetting Boards=1", |
| n->nodenames, |
| n->tot_sockets, |
| n->boards); |
| n->boards = 1; |
| } |
| |
| /* Node boards are factored into sockets */ |
| if ((n->cpus != n->tot_sockets) && |
| (n->cpus != n->tot_sockets * n->cores) && |
| (n->cpus != n->tot_sockets * n->cores * n->threads)) { |
| error_in_daemon("NodeNames=%s CPUs=%d match no Sockets, Sockets*CoresPerSocket or Sockets*CoresPerSocket*ThreadsPerCore. Resetting CPUs.", |
| n->nodenames, n->cpus); |
| n->cpus = n->tot_sockets * n->cores * n->threads; |
| } |
| |
| if (n->core_spec_cnt >= (n->tot_sockets * n->cores)) { |
| error_in_daemon("NodeNames=%s CoreSpecCount=%u is invalid, reset to 1", |
| n->nodenames, n->core_spec_cnt); |
| n->core_spec_cnt = 1; |
| } |
| |
| if (n->cpu_spec_list) { |
| bitstr_t *cpu_spec_bitmap = bit_alloc(n->cpus); |
| if (bit_unfmt(cpu_spec_bitmap, n->cpu_spec_list)) { |
| error_in_daemon("NodeNames=%s CpuSpecList=%s - unable to convert it to bitmap of size CPUs=%d. Ignoring CpuSpecList.", |
| n->nodenames, n->cpu_spec_list, n->cpus); |
| xfree(n->cpu_spec_list); |
| } |
| FREE_NULL_BITMAP(cpu_spec_bitmap); |
| } |
| |
| if ((n->core_spec_cnt > 0) && n->cpu_spec_list) { |
| error_in_daemon("NodeNames=%s CoreSpecCount=%u is invalid with CPUSpecList, reset to 0", |
| n->nodenames, n->core_spec_cnt); |
| n->core_spec_cnt = 0; |
| } |
| |
| if (n->mem_spec_limit >= n->real_memory) { |
| error_in_daemon("NodeNames=%s MemSpecLimit=%"PRIu64" is invalid, reset to 0", |
| n->nodenames, n->mem_spec_limit); |
| n->mem_spec_limit = 0; |
| } |
| |
| *dest = (void *)n; |
| |
| return 1; |
| } |
| |
| /* should not get here */ |
| } |
| |
| /* This should only be going to the stepd, no protocol version needed */ |
| static void _pack_node_conf_lite(void *ptr, buf_t *buffer) |
| { |
| slurm_conf_node_t *n = ptr; |
| |
| xassert(n); |
| |
| packstr(n->nodenames, buffer); |
| packstr(n->addresses, buffer); |
| packstr(n->bcast_addresses, buffer); |
| packstr(n->hostnames, buffer); |
| packstr(n->port_str, buffer); |
| } |
| |
| static void *_unpack_node_conf_lite(buf_t *buffer) |
| { |
| slurm_conf_node_t *n = xmalloc(sizeof(*n)); |
| |
| safe_unpackstr(&n->nodenames, buffer); |
| safe_unpackstr(&n->addresses, buffer); |
| safe_unpackstr(&n->bcast_addresses, buffer); |
| safe_unpackstr(&n->hostnames, buffer); |
| safe_unpackstr(&n->port_str, buffer); |
| |
| return n; |
| |
| unpack_error: |
| _destroy_nodename(n); |
| return NULL; |
| } |
| |
| /* |
| * Sync _init_config_record(). |
| * |
| * _init_conf_node() initializes default values from slurm.conf parameters. |
| * After parsing slurm.conf, build_all_nodeline_info() copies slurm_conf_node_t |
| * to config_record_t. Defaults values between slurm_conf_node_t and |
| * config_record_t should stay in sync in case a config_record is created |
| * outside of slurm.conf parsing. |
| */ |
| static void _init_conf_node(slurm_conf_node_t *conf_node) |
| { |
| conf_node->boards = 1; |
| conf_node->cores = 1; |
| conf_node->cpus = 1; |
| conf_node->real_memory = 1; |
| conf_node->threads = 1; |
| conf_node->tot_sockets = 1; |
| conf_node->weight = 1; |
| } |
| |
| static slurm_conf_node_t *_create_conf_node(void) |
| { |
| slurm_conf_node_t *n = xmalloc(sizeof(slurm_conf_node_t)); |
| _init_conf_node(n); |
| |
| return n; |
| } |
| |
| static void _destroy_nodename(void *ptr) |
| { |
| slurm_conf_node_t *n = (slurm_conf_node_t *)ptr; |
| |
| xfree(n->addresses); |
| xfree(n->cpu_spec_list); |
| xfree(n->feature); |
| xfree(n->hostnames); |
| xfree(n->gres); |
| xfree(n->nodenames); |
| xfree(n->port_str); |
| xfree(n->reason); |
| xfree(n->state); |
| xfree(n->topology_str); |
| xfree(n->tres_weights_str); |
| xfree(ptr); |
| } |
| |
| /* _parse_srun_ports() |
| * |
| * Parse the srun port range specified like min-max. |
| * |
| */ |
| static uint16_t * |
| _parse_srun_ports(const char *str) |
| { |
| char *min; |
| char *max; |
| char *dash; |
| char *p; |
| uint16_t *v; |
| |
| p = xstrdup(str); |
| |
| min = p; |
| dash = strchr(p, '-'); |
| if (dash == NULL) { |
| xfree(p); |
| return NULL; |
| } |
| |
| *dash = 0; |
| max = dash + 1; |
| |
| v = xcalloc(2, sizeof(uint16_t)); |
| |
| if (parse_uint16(min, &v[0])) |
| goto hosed; |
| if (parse_uint16(max, &v[1])) |
| goto hosed; |
| if (v[1] <= v[0]) |
| goto hosed; |
| |
| xfree(p); |
| |
| return v; |
| hosed: |
| xfree(v); |
| xfree(p); |
| |
| return NULL; |
| } |
| |
| int slurm_conf_nodename_array(slurm_conf_node_t **ptr_array[]) |
| { |
| int count = 0; |
| 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; |
| } |
| } |
| |
| /* Copy list of job_defaults_t elements */ |
| extern list_t *job_defaults_copy(list_t *in_list) |
| { |
| list_t *out_list = NULL; |
| job_defaults_t *in_default, *out_default; |
| list_itr_t *iter; |
| |
| if (!in_list) |
| return out_list; |
| |
| out_list = list_create(xfree_ptr); |
| iter = list_iterator_create(in_list); |
| while ((in_default = list_next(iter))) { |
| out_default = xmalloc(sizeof(job_defaults_t)); |
| memcpy(out_default, in_default, sizeof(job_defaults_t)); |
| list_append(out_list, out_default); |
| } |
| list_iterator_destroy(iter); |
| |
| return out_list; |
| } |
| |
| static char *_job_def_name(uint16_t type) |
| { |
| static char name[32]; |
| |
| switch (type) { |
| case JOB_DEF_CPU_PER_GPU: |
| return "DefCpuPerGPU"; |
| case JOB_DEF_MEM_PER_GPU: |
| return "DefMemPerGPU"; |
| } |
| snprintf(name, sizeof(name), "Unknown(%u)", type); |
| return name; |
| } |
| |
| static uint16_t _job_def_type(char *type) |
| { |
| if (!xstrcasecmp(type, "DefCpuPerGPU")) |
| return JOB_DEF_CPU_PER_GPU; |
| if (!xstrcasecmp(type, "DefMemPerGPU")) |
| return JOB_DEF_MEM_PER_GPU; |
| return NO_VAL16; |
| } |
| |
| /* |
| * Translate string of job_defaults_t elements into a List. |
| * in_str IN - comma separated key=value pairs |
| * out_list OUT - equivalent list of key=value pairs |
| * Returns SLURM_SUCCESS or an error code |
| */ |
| extern int job_defaults_list(char *in_str, list_t **out_list) |
| { |
| int rc = SLURM_SUCCESS; |
| list_t *tmp_list; |
| char *end_ptr = NULL, *tmp_str, *save_ptr = NULL, *sep, *tok; |
| uint16_t type; |
| long long int value; |
| job_defaults_t *out_default; |
| |
| *out_list = NULL; |
| if (!in_str || (in_str[0] == '\0')) |
| return rc; |
| |
| tmp_list = list_create(xfree_ptr); |
| tmp_str = xstrdup(in_str); |
| tok = strtok_r(tmp_str, ",", &save_ptr); |
| while (tok) { |
| sep = strchr(tok, '='); |
| if (!sep) { |
| rc = EINVAL; |
| break; |
| } |
| sep[0] = '\0'; |
| sep++; |
| type = _job_def_type(tok); |
| if (type == NO_VAL16) { |
| rc = EINVAL; |
| break; |
| } |
| value = strtoll(sep, &end_ptr, 10); |
| if (!end_ptr || (end_ptr[0] != '\0') || |
| (value < 0) || (value == LLONG_MAX)) { |
| rc = EINVAL; |
| break; |
| } |
| out_default = xmalloc(sizeof(job_defaults_t)); |
| out_default->type = type; |
| out_default->value = (uint64_t) value; |
| list_append(tmp_list, out_default); |
| tok = strtok_r(NULL, ",", &save_ptr); |
| } |
| xfree(tmp_str); |
| if (rc != SLURM_SUCCESS) |
| FREE_NULL_LIST(tmp_list); |
| else |
| *out_list = tmp_list; |
| return rc; |
| } |
| |
| /* |
| * Translate list of job_defaults_t elements into a string. |
| * Return value must be released using xfree() |
| */ |
| extern char *job_defaults_str(list_t *in_list) |
| { |
| job_defaults_t *in_default; |
| list_itr_t *iter; |
| char *out_str = NULL, *sep = ""; |
| |
| if (!in_list) |
| return out_str; |
| |
| iter = list_iterator_create(in_list); |
| while ((in_default = list_next(iter))) { |
| xstrfmtcat(out_str, "%s%s=%"PRIu64, sep, |
| _job_def_name(in_default->type), in_default->value); |
| sep = ","; |
| } |
| list_iterator_destroy(iter); |
| |
| return out_str; |
| |
| } |
| |
| /* Pack a job_defaults_t element. Used by slurm_pack_list() */ |
| extern void job_defaults_pack(void *in, uint16_t protocol_version, |
| buf_t *buffer) |
| { |
| job_defaults_t *object = (job_defaults_t *)in; |
| |
| if (!object) { |
| pack16(0, buffer); |
| pack64(0, buffer); |
| return; |
| } |
| |
| pack16(object->type, buffer); |
| pack64(object->value, buffer); |
| } |
| |
| /* Unpack a job_defaults_t element. Used by slurm_unpack_list() */ |
| extern int job_defaults_unpack(void **out, uint16_t protocol_version, |
| buf_t *buffer) |
| { |
| job_defaults_t *object = xmalloc(sizeof(job_defaults_t)); |
| |
| safe_unpack16(&object->type, buffer); |
| safe_unpack64(&object->value, buffer); |
| *out = object; |
| return SLURM_SUCCESS; |
| |
| unpack_error: |
| xfree(object); |
| *out = NULL; |
| return SLURM_ERROR; |
| } |
| |
| 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; |
| uint64_t def_cpu_per_gpu = 0, def_mem_per_gpu = 0; |
| job_defaults_t *job_defaults; |
| char *cpu_bind = NULL, *tmp = NULL; |
| uint16_t tmp_16 = 0; |
| uint64_t tmp_64; |
| 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}, |
| {"CpuBind", S_P_STRING}, |
| {"DefCPUPerGPU" , S_P_UINT64}, |
| {"DefMemPerCPU", S_P_UINT64}, |
| {"DefMemPerGPU" , S_P_UINT64}, |
| {"DefMemPerNode", S_P_UINT64}, |
| {"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 */ |
| {"ExclusiveUser", S_P_BOOLEAN}, /* YES or NO */ |
| {"ExclusiveTopo", 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}, |
| {"MaxCPUsPerSocket", S_P_UINT32}, |
| {"MaxMemPerCPU", S_P_UINT64}, |
| {"MaxMemPerNode", S_P_UINT64}, |
| {"MaxTime", S_P_STRING}, |
| {"MaxNodes", S_P_UINT32}, /* INFINITE or a number */ |
| {"MinNodes", S_P_UINT32}, |
| {"Nodes", S_P_STRING}, |
| {"OverSubscribe", S_P_STRING}, /* YES, NO, or FORCE */ |
| {"OverTimeLimit", S_P_STRING}, |
| {"PowerDownOnIdle", S_P_BOOLEAN}, /* YES or NO */ |
| {"PreemptMode", S_P_STRING}, |
| {"Priority", S_P_UINT16}, |
| {"PriorityJobFactor", S_P_UINT16}, |
| {"PriorityTier", S_P_UINT16}, |
| {"QOS", S_P_STRING}, |
| {"RootOnly", S_P_BOOLEAN}, /* YES or NO */ |
| {"ReqResv", S_P_BOOLEAN}, /* YES or NO */ |
| {"ResumeTimeout", S_P_UINT16}, |
| {"SelectTypeParameters", S_P_STRING}, |
| {"Shared", S_P_STRING}, /* YES, NO, or FORCE */ |
| {"State", S_P_STRING}, /* UP, DOWN, INACTIVE or DRAIN */ |
| {"SuspendTime", S_P_STRING}, |
| {"SuspendTimeout", S_P_UINT16}, |
| {"Topology", S_P_STRING}, |
| {"TRESBillingWeights", S_P_STRING}, |
| {NULL} |
| }; |
| |
| tbl = s_p_hashtbl_create(_partition_options); |
| s_p_parse_line(tbl, *leftover, leftover); |
| /* s_p_dump_values(tbl, _partition_options); */ |
| |
| if (xstrcasecmp(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 { |
| slurm_conf_partition_t *p = _create_conf_part(); |
| 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); |
| /* lower case account names */ |
| if (p->allow_accounts) |
| xstrtolower(p->allow_accounts); |
| if (p->allow_accounts && |
| (xstrcasecmp(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 && |
| (xstrcasecmp(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); |
| /* lower case qos names */ |
| if (p->allow_qos) |
| xstrtolower(p->allow_qos); |
| if (p->allow_qos && (xstrcasecmp(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"); |
| } |
| /* lower case account names */ |
| else if(p->deny_accounts) |
| xstrtolower(p->deny_accounts); |
| |
| 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"); |
| } |
| /* lower case qos names */ |
| else if(p->deny_qos) |
| xstrtolower(p->deny_qos); |
| |
| 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 && |
| (xstrcasecmp(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_string(&cpu_bind, "CpuBind", tbl) || |
| s_p_get_string(&cpu_bind, "CpuBind", dflt)) { |
| if (xlate_cpu_bind_str(cpu_bind, &p->cpu_bind) != |
| SLURM_SUCCESS) { |
| error("Partition=%s CpuBind=\'%s\' is invalid, ignored", |
| p->name, cpu_bind); |
| p->cpu_bind = 0; |
| } |
| xfree(cpu_bind); |
| } |
| |
| if (!s_p_get_string(&p->billing_weights_str, |
| "TRESBillingWeights", tbl)) |
| s_p_get_string(&p->billing_weights_str, |
| "TRESBillingWeights", dflt); |
| |
| if (!s_p_get_boolean(&p->default_flag, "Default", tbl)) |
| s_p_get_boolean(&p->default_flag, "Default", dflt); |
| |
| if (!s_p_get_uint32(&p->max_cpus_per_node, "MaxCPUsPerNode", |
| tbl)) |
| s_p_get_uint32(&p->max_cpus_per_node, "MaxCPUsPerNode", |
| dflt); |
| |
| if (!s_p_get_uint32(&p->max_cpus_per_socket, "MaxCPUsPerSocket", |
| tbl)) |
| s_p_get_uint32(&p->max_cpus_per_socket, |
| "MaxCPUsPerSocket", dflt); |
| |
| if (s_p_get_uint64(&def_cpu_per_gpu, "DefCPUPerGPU", tbl) || |
| s_p_get_uint64(&def_cpu_per_gpu, "DefCPUPerGPU", dflt)) { |
| job_defaults = xmalloc(sizeof(job_defaults_t)); |
| job_defaults->type = JOB_DEF_CPU_PER_GPU; |
| job_defaults->value = def_cpu_per_gpu; |
| if (!p->job_defaults_list) { |
| p->job_defaults_list = list_create(xfree_ptr); |
| } |
| list_append(p->job_defaults_list, job_defaults); |
| } |
| if (s_p_get_uint64(&def_mem_per_gpu, "DefMemPerGPU", tbl) || |
| s_p_get_uint64(&def_mem_per_gpu, "DefMemPerGPU", dflt)) { |
| job_defaults = xmalloc(sizeof(job_defaults_t)); |
| job_defaults->type = JOB_DEF_MEM_PER_GPU; |
| job_defaults->value = def_mem_per_gpu; |
| if (!p->job_defaults_list) { |
| p->job_defaults_list = list_create(xfree_ptr); |
| } |
| list_append(p->job_defaults_list, job_defaults); |
| } |
| |
| if (!s_p_get_uint64(&p->def_mem_per_cpu, "DefMemPerNode", |
| tbl) && |
| !s_p_get_uint64(&p->def_mem_per_cpu, "DefMemPerNode", |
| dflt)) { |
| if (s_p_get_uint64(&p->def_mem_per_cpu, |
| "DefMemPerCPU", tbl) || |
| s_p_get_uint64(&p->def_mem_per_cpu, |
| "DefMemPerCPU", dflt)) { |
| p->def_mem_per_cpu |= MEM_PER_CPU; |
| } |
| } else if (s_p_get_uint64(&tmp_64, "DefMemPerCPU", tbl) || |
| s_p_get_uint64(&tmp_64, "DefMemPerCPU", dflt)) { |
| error("DefMemPerCPU ignored, since it's mutually exclusive with DefMemPerNode"); |
| } |
| |
| if (!s_p_get_uint64(&p->max_mem_per_cpu, "MaxMemPerNode", |
| tbl) && |
| !s_p_get_uint64(&p->max_mem_per_cpu, "MaxMemPerNode", |
| dflt)) { |
| if (s_p_get_uint64(&p->max_mem_per_cpu, |
| "MaxMemPerCPU", tbl) || |
| s_p_get_uint64(&p->max_mem_per_cpu, |
| "MaxMemPerCPU", dflt)) { |
| p->max_mem_per_cpu |= MEM_PER_CPU; |
| } |
| } else if (s_p_get_uint64(&tmp_64, "MaxMemPerCPU", tbl) || |
| s_p_get_uint64(&tmp_64, "MaxMemPerCPU", dflt)) { |
| error("MaxMemPerCPU ignored, since it's mutually exclusive with MaxMemPerNode"); |
| } |
| |
| s_p_get_boolean((bool *)&p->disable_root_jobs, |
| "DisableRootJobs", tbl); |
| |
| s_p_get_boolean((bool *)&p->exclusive_user, "ExclusiveUser", |
| tbl); |
| |
| s_p_get_boolean((bool *)&p->exclusive_topo, "ExclusiveTopo", |
| tbl); |
| |
| if (!s_p_get_boolean(&p->hidden_flag, "Hidden", tbl)) |
| s_p_get_boolean(&p->hidden_flag, "Hidden", dflt); |
| |
| if (s_p_get_string(&tmp, "MaxTime", tbl) || |
| s_p_get_string(&tmp, "MaxTime", dflt)) { |
| 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); |
| |
| if (s_p_get_string(&tmp, "DefaultTime", tbl) || |
| s_p_get_string(&tmp, "DefaultTime", dflt)) { |
| 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); |
| |
| if (!s_p_get_uint32(&p->min_nodes, "MinNodes", tbl)) |
| s_p_get_uint32(&p->min_nodes, "MinNodes", dflt); |
| |
| if (s_p_get_string(&p->nodes, "Nodes", tbl) || |
| s_p_get_string(&p->nodes, "Nodes", dflt)) { |
| 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); |
| |
| if (!s_p_get_boolean(&p->req_resv_flag, "ReqResv", tbl)) |
| s_p_get_boolean(&p->req_resv_flag, "ReqResv", dflt); |
| |
| if (!s_p_get_boolean(&p->lln_flag, "LLN", tbl)) |
| s_p_get_boolean(&p->lln_flag, "LLN", dflt); |
| |
| if (s_p_get_string(&tmp, "OverTimeLimit", tbl) || |
| s_p_get_string(&tmp, "OverTimeLimit", dflt)) { |
| if (!strcasecmp(tmp, "INFINITE") || |
| !strcasecmp(tmp, "UNLIMITED")) { |
| p->over_time_limit = INFINITE16; |
| } else { |
| int i = strtol(tmp, (char **) NULL, 10); |
| if (i < 0) |
| error("Ignoring bad OverTimeLimit value: %s", |
| tmp); |
| else if (i > 0xfffe) |
| p->over_time_limit = INFINITE16; |
| else |
| p->over_time_limit = i; |
| } |
| xfree(tmp); |
| } |
| |
| s_p_get_boolean(&p->power_down_on_idle, "PowerDownOnIdle", tbl); |
| |
| 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 & PREEMPT_MODE_GANG) { |
| error_in_daemon("PreemptMode=GANG is a cluster-wide option and cannot be set at partition level, option ignored."); |
| p->preempt_mode &= (~PREEMPT_MODE_GANG); |
| } |
| if (p->preempt_mode == NO_VAL16) { |
| error("Bad value \"%s\" for PreemptMode", tmp); |
| xfree(tmp); |
| return -1; |
| } |
| xfree(tmp); |
| } |
| |
| if (!s_p_get_uint16(&p->priority_job_factor, |
| "PriorityJobFactor", tbl)) |
| s_p_get_uint16(&p->priority_job_factor, |
| "PriorityJobFactor", dflt); |
| |
| if (!s_p_get_uint16(&p->priority_tier, "PriorityTier", tbl)) |
| s_p_get_uint16(&p->priority_tier, "PriorityTier", dflt); |
| if (s_p_get_uint16(&tmp_16, "Priority", tbl) || |
| s_p_get_uint16(&tmp_16, "Priority", dflt)) { |
| p->priority_job_factor = tmp_16; |
| p->priority_tier = tmp_16; |
| } |
| |
| if (!s_p_get_string(&p->qos_char, "QOS", tbl)) |
| s_p_get_string(&p->qos_char, "QOS", dflt); |
| |
| if (!s_p_get_uint16(&p->resume_timeout, "ResumeTimeout", tbl)) |
| s_p_get_uint16(&p->resume_timeout, "ResumeTimeout", |
| dflt); |
| |
| if (s_p_get_string(&tmp, "SelectTypeParameters", tbl)) { |
| if (xstrncasecmp(tmp, "CR_Core_Memory", 14) == 0) |
| p->cr_type = SELECT_CORE | SELECT_MEMORY; |
| else if (xstrncasecmp(tmp, "CR_Core", 7) == 0) |
| p->cr_type = SELECT_CORE; |
| else if (xstrncasecmp(tmp, "CR_Socket_Memory", 16) == 0) |
| p->cr_type = SELECT_SOCKET | SELECT_MEMORY; |
| else if (xstrncasecmp(tmp, "CR_Socket", 9) == 0) |
| p->cr_type = SELECT_SOCKET; |
| else { |
| error("Bad value for SelectTypeParameters: %s", |
| tmp); |
| _destroy_partitionname(p); |
| s_p_hashtbl_destroy(tbl); |
| xfree(tmp); |
| return -1; |
| } |
| xfree(tmp); |
| } |
| |
| if (s_p_get_string(&tmp, "OverSubscribe", tbl) || |
| s_p_get_string(&tmp, "OverSubscribe", dflt) || |
| s_p_get_string(&tmp, "Shared", tbl) || |
| s_p_get_string(&tmp, "Shared", dflt)) { |
| if (xstrcasecmp(tmp, "NO") == 0) |
| p->max_share = 1; |
| else if (xstrcasecmp(tmp, "EXCLUSIVE") == 0) |
| p->max_share = 0; |
| else if (xstrncasecmp(tmp, "YES:", 4) == 0) { |
| int i = strtol(&tmp[4], (char **) NULL, 10); |
| if (i <= 1) { |
| error("Ignoring bad OverSubscribe value: %s", |
| tmp); |
| p->max_share = 1; /* OverSubscribe=NO */ |
| } else |
| p->max_share = i; |
| } else if (xstrcasecmp(tmp, "YES") == 0) |
| p->max_share = 4; |
| else if (xstrncasecmp(tmp, "FORCE:", 6) == 0) { |
| int i = strtol(&tmp[6], (char **) NULL, 10); |
| if (i < 1) { |
| error("Ignoring bad OverSubscribe value: %s", |
| tmp); |
| p->max_share = 1; /* OverSubscribe=NO */ |
| } else |
| p->max_share = i | SHARED_FORCE; |
| } else if (xstrcasecmp(tmp, "FORCE") == 0) |
| p->max_share = 4 | SHARED_FORCE; |
| else { |
| error("Bad value \"%s\" for OverSubscribe", |
| tmp); |
| _destroy_partitionname(p); |
| s_p_hashtbl_destroy(tbl); |
| xfree(tmp); |
| return -1; |
| } |
| xfree(tmp); |
| } |
| |
| if (s_p_get_string(&tmp, "SuspendTime", tbl)) { |
| if (!xstrcasecmp(tmp, "INFINITE") || |
| !xstrcasecmp(tmp, "-1")) { |
| p->suspend_time = INFINITE; |
| } else { |
| tmp_64 = slurm_atoul(tmp); |
| if (tmp_64 > UINT32_MAX) { |
| error("Bad value \"%s\" for SuspendTime", |
| tmp); |
| xfree(tmp); |
| return -1; |
| } |
| p->suspend_time = (uint32_t) tmp_64; |
| } |
| xfree(tmp); |
| } |
| |
| if (!s_p_get_uint16(&p->suspend_timeout, "SuspendTimeout", tbl)) |
| s_p_get_uint16(&p->suspend_timeout, "SuspendTimeout", |
| dflt); |
| |
| if (s_p_get_string(&tmp, "State", tbl) || |
| s_p_get_string(&tmp, "State", dflt)) { |
| if (xstrncasecmp(tmp, "DOWN", 4) == 0) |
| p->state_up = PARTITION_DOWN; |
| else if (xstrncasecmp(tmp, "UP", 2) == 0) |
| p->state_up = PARTITION_UP; |
| else if (xstrncasecmp(tmp, "DRAIN", 5) == 0) |
| p->state_up = PARTITION_DRAIN; |
| else if (xstrncasecmp(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); |
| } |
| |
| if (!s_p_get_string(&p->topology_name, "Topology", tbl)) |
| s_p_get_string(&p->topology_name, "Topology", dflt); |
| |
| s_p_hashtbl_destroy(tbl); |
| |
| *dest = (void *)p; |
| |
| return 1; |
| } |
| |
| /* should not get here */ |
| } |
| |
| /* |
| * Sync with _init_part_record(). |
| * |
| * _init_conf_part() initializes default values from slurm.conf parameters. |
| * After parsing slurm.conf, _build_single_partitionline_info() copies |
| * slurm_conf_partition_t to part_record_t. Default values between |
| * slurm_conf_partition_t and part_record_t should stay in sync in case a |
| * part_record_t is created outside of slurm.conf parsing. |
| */ |
| static void _init_conf_part(slurm_conf_partition_t *conf_part) |
| { |
| conf_part->disable_root_jobs = NO_VAL8; |
| |
| /* sync with part_record_t */ |
| conf_part->default_time = NO_VAL; |
| conf_part->max_cpus_per_node = INFINITE; |
| conf_part->max_cpus_per_socket = INFINITE; |
| conf_part->max_nodes = INFINITE; |
| conf_part->max_share = 1; |
| conf_part->max_time = INFINITE; |
| conf_part->over_time_limit = NO_VAL16; |
| conf_part->preempt_mode = NO_VAL16; |
| conf_part->priority_job_factor = 1; |
| conf_part->priority_tier = 1; |
| conf_part->resume_timeout = NO_VAL16; |
| conf_part->state_up = PARTITION_UP; |
| conf_part->suspend_time = NO_VAL; |
| conf_part->suspend_timeout = NO_VAL16; |
| } |
| |
| static slurm_conf_partition_t *_create_conf_part(void) |
| { |
| slurm_conf_partition_t *p = xmalloc(sizeof(*p)); |
| _init_conf_part(p); |
| |
| return p; |
| } |
| |
| 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->alternate); |
| xfree(p->billing_weights_str); |
| xfree(p->deny_accounts); |
| xfree(p->deny_qos); |
| FREE_NULL_LIST(p->job_defaults_list); |
| xfree(p->name); |
| xfree(p->nodes); |
| xfree(p->qos_char); |
| xfree(p->topology_name); |
| xfree(ptr); |
| } |
| |
| static int _load_slurmctld_host(slurm_conf_t *conf) |
| { |
| int count = 0, i, j; |
| char *ignore; |
| slurm_conf_server_t **ptr = NULL; |
| |
| if (s_p_get_array((void ***)&ptr, &count, "SlurmctldHost", conf_hashtbl)) { |
| /* |
| * Using new-style SlurmctldHost entries. |
| */ |
| conf->control_machine = xcalloc(count + 1, sizeof(char *)); |
| conf->control_addr = xcalloc(count + 1, sizeof(char *)); |
| conf->control_cnt = count; |
| |
| for (i = 0; i < count; i++) { |
| conf->control_machine[i] = xstrdup(ptr[i]->hostname); |
| conf->control_addr[i] = xstrdup(ptr[i]->addr); |
| } |
| |
| /* |
| * Throw errors if old-style entries are still in the config, |
| * but continue on with the newer-style entries anyways. |
| */ |
| if (s_p_get_string(&ignore, "ControlMachine", conf_hashtbl)) { |
| error("Ignoring ControlMachine since SlurmctldHost is set."); |
| xfree(ignore); |
| } |
| if (s_p_get_string(&ignore, "ControlAddr", conf_hashtbl)) { |
| error("Ignoring ControlAddr since SlurmctldHost is set."); |
| xfree(ignore); |
| } |
| if (s_p_get_string(&ignore, "BackupController", conf_hashtbl)) { |
| error("Ignoring BackupController since SlurmctldHost is set."); |
| xfree(ignore); |
| } |
| if (s_p_get_string(&ignore, "BackupAddr", conf_hashtbl)) { |
| error("Ignoring BackupAddr since SlurmctldHost is set."); |
| xfree(ignore); |
| } |
| } else { |
| /* |
| * Using old-style ControlMachine/BackupController entries. |
| * |
| * Allocate two entries, one for primary and one for backup, |
| * plus space for NULL-termination. |
| */ |
| char *tmp = NULL; |
| conf->control_machine = xcalloc(3, sizeof(char *)); |
| conf->control_addr = xcalloc(3, sizeof(char *)); |
| conf->control_cnt = 1; |
| |
| if (!s_p_get_string(&conf->control_machine[0], |
| "ControlMachine", conf_hashtbl)) { |
| /* |
| * Missing SlurmctldHost and ControlMachine, so just |
| * warn about the newer config option. |
| */ |
| error("No SlurmctldHost defined."); |
| goto error; |
| } |
| if (!s_p_get_string(&conf->control_addr[0], |
| "ControlAddr", conf_hashtbl) && |
| conf->control_machine[0] && |
| strchr(conf->control_machine[0], ',')) { |
| error("ControlMachine has multiple host names, so ControlAddr must be specified."); |
| goto error; |
| } |
| |
| if (s_p_get_string(&tmp, "BackupController", conf_hashtbl)) { |
| conf->control_cnt = 2; |
| conf->control_machine[1] = tmp; |
| tmp = NULL; |
| } |
| if (s_p_get_string(&tmp, "BackupAddr", conf_hashtbl)) { |
| if (conf->control_cnt == 1) { |
| error("BackupAddr specified without BackupController"); |
| xfree(tmp); |
| goto error; |
| } |
| conf->control_addr[1] = tmp; |
| tmp = NULL; |
| } |
| } |
| |
| /* |
| * Fix up the control_addr array if they were not explicitly set above, |
| * replace "localhost" with the actual hostname, and verify there are |
| * no duplicate entries. |
| */ |
| for (i = 0; i < conf->control_cnt; i++) { |
| if (!conf->control_addr[i]) { |
| conf->control_addr[i] = |
| xstrdup(conf->control_machine[i]); |
| } |
| if (!xstrcasecmp("localhost", conf->control_machine[i])) { |
| xfree(conf->control_machine[i]); |
| conf->control_machine[i] = xmalloc(HOST_NAME_MAX); |
| if (gethostname_short(conf->control_machine[i], |
| HOST_NAME_MAX)) { |
| error("getnodename: %m"); |
| goto error; |
| } |
| } |
| for (j = 0; j < i; j++) { |
| if (!xstrcmp(conf->control_machine[i], |
| conf->control_machine[j])) { |
| error("Duplicate SlurmctldHost records: %s", |
| conf->control_machine[i]); |
| goto error; |
| } |
| } |
| } |
| return SLURM_SUCCESS; |
| |
| error: |
| if (conf->control_machine && conf->control_addr) { |
| for (i = 0; i < conf->control_cnt; i++) { |
| xfree(conf->control_machine[i]); |
| xfree(conf->control_addr[i]); |
| } |
| xfree(conf->control_machine); |
| xfree(conf->control_addr); |
| } |
| conf->control_cnt = 0; |
| return SLURM_ERROR; |
| } |
| |
| static void _load_script(char ***script, uint32_t *cnt, char *name) |
| { |
| int count = 0; |
| char **ptr = NULL; |
| |
| if (s_p_get_array((void ***) &ptr, &count, name, conf_hashtbl)) { |
| *script = xcalloc(count, sizeof(char *)); |
| *cnt = count; |
| |
| for (int i = 0; i < count; i++) |
| (*script)[i] = xstrdup(ptr[i]); |
| } |
| } |
| |
| static int _parse_slurmctld_host(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_server_t *p; |
| char *open_paren, *close_paren; |
| static s_p_options_t _slurmctld_host_options[] = { |
| {NULL} |
| }; |
| |
| tbl = s_p_hashtbl_create(_slurmctld_host_options); |
| s_p_parse_line(tbl, *leftover, leftover); |
| |
| open_paren = strchr(value, '('); |
| close_paren = strchr(value, ')'); |
| if ((open_paren && !close_paren) || |
| (!open_paren && close_paren) || |
| (close_paren && (close_paren[1] != '\0')) || |
| (close_paren && (close_paren != strrchr(value, ')')))) { |
| error("Bad value \"%s\" for SlurmctldHost", value); |
| return -1; |
| } |
| |
| p = xmalloc(sizeof(slurm_conf_server_t)); |
| if (open_paren && close_paren) { |
| p->hostname = xstrdup(value); |
| open_paren = strchr(p->hostname, '('); |
| if (open_paren) |
| open_paren[0] = '\0'; |
| p->addr = xstrdup(open_paren + 1); |
| close_paren = strchr(p->addr, ')'); |
| if (close_paren) |
| close_paren[0] = '\0'; |
| } else { |
| p->hostname = xstrdup(value); |
| p->addr = xstrdup(value); |
| } |
| |
| s_p_hashtbl_destroy(tbl); |
| *dest = (void *) p; |
| |
| return 1; |
| } |
| |
| /* May not be needed */ |
| static void _destroy_slurmctld_host(void *ptr) |
| { |
| slurm_conf_server_t *p = (slurm_conf_server_t *) ptr; |
| |
| xfree(p->hostname); |
| xfree(p->addr); |
| xfree(ptr); |
| } |
| |
| int slurm_conf_partition_array(slurm_conf_partition_t **ptr_array[]) |
| { |
| int count = 0; |
| 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 = 0; |
| 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 int _parse_nodeset(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_nodeset_t *n; |
| static s_p_options_t _nodeset_options[] = { |
| {"Feature", S_P_STRING}, |
| {"Nodes", S_P_STRING}, |
| {NULL} |
| }; |
| |
| tbl = s_p_hashtbl_create(_nodeset_options); |
| s_p_parse_line(tbl, *leftover, leftover); |
| /* s_p_dump_values(tbl, _nodeset_options); */ |
| |
| n = xmalloc(sizeof(slurm_conf_nodeset_t)); |
| n->name = xstrdup(value); |
| |
| s_p_get_string(&n->feature, "Feature", tbl); |
| s_p_get_string(&n->nodes, "Nodes", tbl); |
| |
| s_p_hashtbl_destroy(tbl); |
| |
| *dest = (void *)n; |
| |
| return 1; |
| } |
| |
| static void _destroy_nodeset(void *ptr) |
| { |
| slurm_conf_nodeset_t *n = (slurm_conf_nodeset_t *)ptr; |
| xfree(n->feature); |
| xfree(n->name); |
| xfree(n->nodes); |
| xfree(ptr); |
| } |
| |
| extern int slurm_conf_nodeset_array(slurm_conf_nodeset_t **ptr_array[]) |
| { |
| int count = 0; |
| slurm_conf_nodeset_t **ptr; |
| |
| if (s_p_get_array((void ***)&ptr, &count, "NodeSet", conf_hashtbl)) { |
| *ptr_array = ptr; |
| return count; |
| } else { |
| *ptr_array = NULL; |
| return 0; |
| } |
| } |
| |
| static void _free_single_names_ll_t(names_ll_t *p) |
| { |
| xfree(p->address); |
| xfree(p->alias); |
| xfree(p->hostname); |
| xfree(p); |
| } |
| |
| 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) { |
| q = p->next_alias; |
| _free_single_names_ll_t(p); |
| p = q; |
| } |
| node_to_host_hashtbl[i] = NULL; |
| host_to_node_hashtbl[i] = NULL; |
| } |
| nodehash_initialized = false; |
| } |
| |
| 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; |
| while (index < 0) /* Coverity thinks "index" could be negative with "if" */ |
| index += NAME_HASH_LEN; |
| |
| return index; |
| } |
| |
| static void _push_to_hashtbls(char *alias, char *hostname, char *address, |
| char *bcast_address, uint16_t port, |
| slurm_addr_t *addr, |
| bool initialized, bool dynamic, bool cloud) |
| { |
| int hostname_idx, alias_idx; |
| names_ll_t *p, *new; |
| |
| alias_idx = _get_hash_idx(alias); |
| hostname_idx = _get_hash_idx(hostname); |
| |
| #if !defined(MULTIPLE_SLURMD) |
| /* Ensure only one slurmd configured on each host */ |
| p = host_to_node_hashtbl[hostname_idx]; |
| while (p) { |
| if (xstrcmp(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 (xstrcmp(p->alias, alias) == 0) { |
| fatal("Duplicated NodeName %s in the config file", |
| p->alias); |
| } |
| p = p->next_alias; |
| } |
| |
| /* Create the new data structure and link it into the hash tables */ |
| new = xmalloc(sizeof(*new)); |
| new->alias = xstrdup(alias); |
| new->hostname = xstrdup(hostname); |
| new->address = xstrdup(address); |
| new->bcast_address = xstrdup(bcast_address); |
| new->port = port; |
| new->addr_initialized = initialized; |
| new->is_cloud = cloud; |
| new->is_dynamic = dynamic; |
| |
| if (addr) |
| memcpy(&new->addr, addr, sizeof(slurm_addr_t)); |
| |
| /* 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; |
| } |
| } |
| |
| static int _check_callback(char *alias, char *hostname, char *address, |
| char *bcast_address, uint16_t port, int state_val, |
| slurm_conf_node_t *node_ptr, |
| config_record_t *config_ptr) |
| { |
| bool dynamic_addr = false, cloud_node = false; |
| static bool cloud_dns = false; |
| static time_t last_update = 0; |
| |
| if (last_update != slurm_conf.last_update) { |
| if (xstrcasestr(slurm_conf.slurmctld_params, "cloud_dns")) |
| cloud_dns = true; |
| else |
| cloud_dns = false; |
| last_update = slurm_conf.last_update; |
| } |
| |
| if (!cloud_dns && |
| ((state_val & NODE_STATE_CLOUD) || |
| (state_val & NODE_STATE_FUTURE))) |
| dynamic_addr = true; |
| |
| if (!running_in_slurmctld() && |
| (state_val & NODE_STATE_CLOUD)) |
| cloud_node = true; |
| |
| _push_to_hashtbls(alias, hostname, address, bcast_address, port, |
| NULL, false, dynamic_addr, cloud_node); |
| return SLURM_SUCCESS; |
| } |
| |
| static void _init_slurmd_nodehash(void) |
| { |
| slurm_conf_node_t **ptr_array; |
| 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"); |
| } |
| |
| count = slurm_conf_nodename_array(&ptr_array); |
| for (i = 0; i < count; i++) { |
| expand_nodeline_info(ptr_array[i], NULL, NULL, _check_callback); |
| } |
| } |
| |
| /* |
| * 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 (xstrcmp(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; |
| |
| slurm_conf_lock(); |
| _init_slurmd_nodehash(); |
| idx = _get_hash_idx(node_hostname); |
| p = host_to_node_hashtbl[idx]; |
| while (p) { |
| if (xstrcmp(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 (useful 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 (xstrcmp(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 (!xstrcmp(p->hostname, node_hostname) || |
| !xstrcmp(p->alias, node_hostname)) { |
| 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; |
| } |
| |
| |
| /* |
| * This is a fallback function to search aliases if we can't |
| * determine the nodename using getaddrinfo()/getnameinfo(). |
| */ |
| static char *_get_aliased_nodename_fallback(char *hostname) |
| { |
| struct hostent *he = NULL; |
| char h_buf[4096]; |
| char *nodename = NULL; |
| int h_err; |
| |
| he = get_host_by_name(hostname, (void *) &h_buf, sizeof(h_buf), &h_err); |
| if (!he) |
| return NULL; |
| |
| /* hunt through the aliases list hoping for a match */ |
| for (int i = 0; he->h_aliases[i]; i++) { |
| if ((nodename = slurm_conf_get_nodename(he->h_aliases[i]))) |
| break; |
| } |
| |
| return nodename; |
| } |
| |
| /* |
| * 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(void) |
| { |
| struct addrinfo *addrs, *addr_ptr; |
| char hostname_full[NI_MAXHOST]; |
| char *nodename, *tmp_name = NULL; |
| |
| if (gethostname(hostname_full, sizeof(hostname_full))) |
| return NULL; |
| |
| nodename = slurm_conf_get_nodename(hostname_full); |
| /* hostname matched a nodename, so return now */ |
| if (nodename) |
| return nodename; |
| |
| /* |
| * We can't get a list of aliases anymore, do a lookup for every |
| * address we do get to try to avoid the old logic. |
| */ |
| addrs = xgetaddrinfo(hostname_full, NULL); |
| addr_ptr = addrs; |
| for(addr_ptr = addrs; addr_ptr; addr_ptr = addr_ptr->ai_next) { |
| if (addr_ptr->ai_canonname) { |
| nodename = |
| slurm_conf_get_nodename(addr_ptr->ai_canonname); |
| } else { |
| slurm_addr_t addr = {0}; |
| memcpy(&addr, &addr_ptr->ai_addr, addr_ptr->ai_addrlen); |
| tmp_name = xgetnameinfo(&addr); |
| nodename = slurm_conf_get_nodename(tmp_name); |
| xfree(tmp_name); |
| } |
| if (nodename) |
| break; |
| } |
| |
| if (addrs) |
| freeaddrinfo(addrs); |
| |
| if (!nodename) |
| nodename = _get_aliased_nodename_fallback(hostname_full); |
| |
| return nodename; |
| } |
| |
| /* |
| * Return NodeAddr (if set) for a given NodeName, or NULL. |
| */ |
| extern char *slurm_conf_get_address(const char *node_name) |
| { |
| int idx; |
| names_ll_t *p; |
| char *address; |
| |
| slurm_conf_lock(); |
| _init_slurmd_nodehash(); |
| |
| idx = _get_hash_idx(node_name); |
| p = node_to_host_hashtbl[idx]; |
| while (p && xstrcmp(p->alias, node_name)) |
| p = p->next_alias; |
| |
| if (!p) { |
| slurm_conf_unlock(); |
| return NULL; |
| } |
| |
| address = xstrdup(p->address); |
| slurm_conf_unlock(); |
| return address; |
| } |
| |
| /* |
| * Return BcastAddr (if set) for a given NodeName, or NULL. |
| */ |
| extern char *slurm_conf_get_bcast_address(const char *node_name) |
| { |
| int idx; |
| names_ll_t *p; |
| char *bcast_address; |
| |
| slurm_conf_lock(); |
| _init_slurmd_nodehash(); |
| |
| idx = _get_hash_idx(node_name); |
| p = node_to_host_hashtbl[idx]; |
| while (p && xstrcmp(p->alias, node_name)) |
| p = p->next_alias; |
| |
| if (!p) { |
| slurm_conf_unlock(); |
| return NULL; |
| } |
| |
| bcast_address = xstrdup(p->bcast_address); |
| slurm_conf_unlock(); |
| return bcast_address; |
| } |
| |
| /* |
| * Unlink names_ll_t from host_to_node_hashtbl without free'ing. |
| */ |
| static void _remove_host_to_node_link(names_ll_t *p) |
| { |
| int hostname_idx; |
| names_ll_t *p_curr, *p_prev = NULL; |
| |
| hostname_idx = _get_hash_idx(p->hostname); |
| |
| p_curr = host_to_node_hashtbl[hostname_idx]; |
| while (p_curr) { |
| if (p_curr == p) { |
| if (p_prev) |
| p_prev->next_hostname = p_curr->next_hostname; |
| else |
| host_to_node_hashtbl[hostname_idx] = |
| p_curr->next_hostname; |
| break; |
| } |
| p_prev = p_curr; |
| p_curr = p_curr->next_hostname; |
| } |
| } |
| |
| /* |
| * Update p's hostname and update host_to_node_hashtbl. |
| */ |
| static void _reset_hostname(names_ll_t *p, char *node_hostname) |
| { |
| int old_hostname_idx, new_hostname_idx; |
| names_ll_t *p_curr; |
| |
| old_hostname_idx = _get_hash_idx(p->hostname); |
| new_hostname_idx = _get_hash_idx(node_hostname); |
| |
| if (old_hostname_idx == new_hostname_idx) |
| goto end_it; |
| |
| /* remove old link */ |
| _remove_host_to_node_link(p); |
| |
| /* add new link */ |
| p->next_hostname = NULL; |
| if ((p_curr = host_to_node_hashtbl[new_hostname_idx])) { |
| while (p_curr->next_hostname) |
| p_curr = p_curr->next_hostname; |
| p_curr->next_hostname = p; |
| } else { |
| host_to_node_hashtbl[new_hostname_idx] = p; |
| } |
| |
| end_it: |
| /* reset hostname */ |
| xfree(p->hostname); |
| p->hostname = xstrdup(node_hostname); |
| } |
| |
| /* |
| * 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 (xstrcmp(p->alias, node_name) == 0) { |
| if (xstrcmp(p->address, node_addr)) { |
| xfree(p->address); |
| p->address = xstrdup(node_addr); |
| p->addr_initialized = false; |
| } |
| if (xstrcmp(p->hostname, node_hostname)) { |
| _reset_hostname(p, node_hostname); |
| } |
| break; |
| } |
| p = p->next_alias; |
| } |
| if (!p) { |
| _push_to_hashtbls(node_name, node_hostname, node_addr, |
| NULL, 0, NULL, false, false, false); |
| } |
| slurm_conf_unlock(); |
| |
| return; |
| } |
| |
| /* |
| * slurm_conf_get_addr - Return the slurm_addr_t for a given NodeName |
| * Returns SLURM_SUCCESS on success, SLURM_ERROR on failure. |
| */ |
| extern int slurm_conf_get_addr(const char *node_name, slurm_addr_t *address, |
| uint16_t flags) |
| { |
| 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 && xstrcmp(p->alias, node_name)) |
| p = p->next_alias; |
| |
| if (!p) { |
| slurm_conf_unlock(); |
| return SLURM_ERROR; |
| } |
| |
| if (!p->port) |
| p->port = (uint16_t) conf_ptr->slurmd_port; |
| |
| /* |
| * Only use BcastAddr if USE_BCAST_NETWORK flag set and BcastAddr |
| * exists. Otherwise fall through to using NodeAddr value below. |
| */ |
| if (p->bcast_address && (flags & USE_BCAST_NETWORK)) { |
| if (!p->bcast_addr_initialized) { |
| slurm_set_addr(&p->bcast_addr, p->port, |
| p->bcast_address); |
| if (slurm_addr_is_unspec(&p->bcast_addr)) { |
| slurm_conf_unlock(); |
| return SLURM_ERROR; |
| } |
| } |
| p->bcast_addr_initialized = true; |
| *address = p->bcast_addr; |
| slurm_conf_unlock(); |
| return SLURM_SUCCESS; |
| } |
| |
| if (!p->addr_initialized) { |
| slurm_set_addr(&p->addr, p->port, p->address); |
| if (slurm_addr_is_unspec(&p->addr)) { |
| slurm_conf_unlock(); |
| return SLURM_ERROR; |
| } |
| if (!p->is_cloud) |
| p->addr_initialized = true; |
| } |
| |
| *address = p->addr; |
| slurm_conf_unlock(); |
| return SLURM_SUCCESS; |
| } |
| |
| extern int slurm_conf_check_addr(const char *node_name, bool *dynamic) |
| { |
| 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 && xstrcmp(p->alias, node_name)) |
| p = p->next_alias; |
| |
| if (!p) { |
| slurm_conf_unlock(); |
| return SLURM_ERROR; |
| } |
| |
| if (dynamic) { |
| if (p->is_dynamic) |
| *dynamic = true; |
| else |
| *dynamic = false; |
| } |
| |
| slurm_conf_unlock(); |
| return SLURM_SUCCESS; |
| } |
| /* |
| * 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) |
| { |
| char *dot_ptr, path_name[1024]; |
| |
| if (gethostname(path_name, sizeof(path_name))) |
| return errno; |
| |
| if ((dot_ptr = strchr(path_name, '.'))) |
| *dot_ptr = '\0'; |
| |
| if (strlcpy(name, path_name, len) >= len) |
| return ENAMETOOLONG; |
| |
| return 0; |
| } |
| |
| /* |
| * free_slurm_conf - free all storage associated with a slurm_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_conf_t *ctl_conf_ptr, bool purge_node_hash) |
| { |
| xfree (ctl_conf_ptr->accounting_storage_backup_host); |
| xfree (ctl_conf_ptr->accounting_storage_ext_host); |
| xfree (ctl_conf_ptr->accounting_storage_host); |
| xfree (ctl_conf_ptr->accounting_storage_params); |
| xfree (ctl_conf_ptr->accounting_storage_pass); |
| xfree (ctl_conf_ptr->accounting_storage_tres); |
| xfree (ctl_conf_ptr->accounting_storage_type); |
| FREE_NULL_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_interconnect_type); |
| xfree (ctl_conf_ptr->acct_gather_filesystem_type); |
| xfree(ctl_conf_ptr->authalttypes); |
| xfree(ctl_conf_ptr->authalt_params); |
| xfree (ctl_conf_ptr->authinfo); |
| xfree (ctl_conf_ptr->authtype); |
| xfree (ctl_conf_ptr->bb_type); |
| xfree(ctl_conf_ptr->bcast_exclude); |
| xfree (ctl_conf_ptr->bcast_parameters); |
| xfree(ctl_conf_ptr->certgen_params); |
| xfree(ctl_conf_ptr->certgen_type); |
| xfree(ctl_conf_ptr->certmgr_params); |
| xfree(ctl_conf_ptr->certmgr_type); |
| FREE_NULL_LIST(ctl_conf_ptr->cgroup_conf); |
| xfree(ctl_conf_ptr->cli_filter_params); |
| xfree(ctl_conf_ptr->cli_filter_plugins); |
| xfree (ctl_conf_ptr->cluster_name); |
| xfree_array(ctl_conf_ptr->control_addr); |
| xfree_array(ctl_conf_ptr->control_machine); |
| ctl_conf_ptr->control_cnt = 0; |
| |
| xfree (ctl_conf_ptr->comm_params); |
| xfree (ctl_conf_ptr->control_addr); |
| xfree (ctl_conf_ptr->control_machine); |
| xfree (ctl_conf_ptr->cred_type); |
| xfree(ctl_conf_ptr->data_parser_parameters); |
| xfree (ctl_conf_ptr->dependency_params); |
| for (int i = 0; i < ctl_conf_ptr->epilog_cnt; i++) |
| xfree(ctl_conf_ptr->epilog[i]); |
| xfree (ctl_conf_ptr->epilog); |
| for (int i = 0; i < ctl_conf_ptr->epilog_slurmctld_cnt; i++) |
| xfree(ctl_conf_ptr->epilog_slurmctld[i]); |
| xfree (ctl_conf_ptr->epilog_slurmctld); |
| xfree (ctl_conf_ptr->fed_params); |
| xfree (ctl_conf_ptr->gres_plugins); |
| xfree (ctl_conf_ptr->gpu_freq_def); |
| xfree(ctl_conf_ptr->hash_plugin); |
| xfree (ctl_conf_ptr->health_check_program); |
| xfree(ctl_conf_ptr->http_parser_type); |
| xfree (ctl_conf_ptr->interactive_step_opts); |
| 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_comp_host); |
| xfree (ctl_conf_ptr->job_comp_loc); |
| xfree(ctl_conf_ptr->job_comp_params); |
| 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); |
| FREE_NULL_LIST(ctl_conf_ptr->job_defaults_list); |
| xfree (ctl_conf_ptr->job_submit_plugins); |
| xfree (ctl_conf_ptr->launch_params); |
| xfree (ctl_conf_ptr->licenses); |
| xfree (ctl_conf_ptr->mail_domain); |
| xfree (ctl_conf_ptr->mail_prog); |
| xfree (ctl_conf_ptr->mcs_plugin); |
| xfree (ctl_conf_ptr->mcs_plugin_params); |
| FREE_NULL_LIST(ctl_conf_ptr->mpi_conf); |
| xfree (ctl_conf_ptr->mpi_default); |
| xfree (ctl_conf_ptr->mpi_params); |
| FREE_NULL_LIST(ctl_conf_ptr->node_features_conf); |
| xfree (ctl_conf_ptr->node_features_plugins); |
| xfree (ctl_conf_ptr->plugindir); |
| xfree (ctl_conf_ptr->plugstack); |
| xfree(ctl_conf_ptr->preempt_params); |
| xfree (ctl_conf_ptr->preempt_type); |
| xfree(ctl_conf_ptr->prep_params); |
| xfree(ctl_conf_ptr->prep_plugins); |
| xfree (ctl_conf_ptr->priority_params); |
| xfree (ctl_conf_ptr->priority_type); |
| xfree (ctl_conf_ptr->priority_weight_tres); |
| xfree (ctl_conf_ptr->proctrack_type); |
| for (int i = 0; i < ctl_conf_ptr->prolog_cnt; i++) |
| xfree(ctl_conf_ptr->prolog[i]); |
| xfree (ctl_conf_ptr->prolog); |
| for (int i = 0; i < ctl_conf_ptr->prolog_slurmctld_cnt; i++) |
| xfree(ctl_conf_ptr->prolog_slurmctld[i]); |
| 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->requeue_exit); |
| xfree (ctl_conf_ptr->requeue_exit_hold); |
| xfree (ctl_conf_ptr->resume_fail_program); |
| xfree (ctl_conf_ptr->resume_program); |
| xfree (ctl_conf_ptr->resv_epilog); |
| xfree (ctl_conf_ptr->resv_prolog); |
| xfree (ctl_conf_ptr->sched_logfile); |
| xfree (ctl_conf_ptr->sched_params); |
| xfree (ctl_conf_ptr->schedtype); |
| xfree(ctl_conf_ptr->scron_params); |
| xfree (ctl_conf_ptr->select_type); |
| FREE_NULL_LIST(ctl_conf_ptr->select_conf_key_pairs); |
| xfree (ctl_conf_ptr->site_factor_params); |
| xfree (ctl_conf_ptr->site_factor_plugin); |
| xfree (ctl_conf_ptr->slurm_conf); |
| xfree (ctl_conf_ptr->slurm_user_name); |
| xfree (ctl_conf_ptr->slurmctld_addr); |
| xfree (ctl_conf_ptr->slurmctld_logfile); |
| xfree (ctl_conf_ptr->slurmctld_pidfile); |
| xfree (ctl_conf_ptr->slurmctld_primary_off_prog); |
| xfree (ctl_conf_ptr->slurmctld_primary_on_prog); |
| xfree (ctl_conf_ptr->slurmd_logfile); |
| xfree (ctl_conf_ptr->slurmctld_params); |
| xfree (ctl_conf_ptr->slurmd_params); |
| xfree (ctl_conf_ptr->slurmd_pidfile); |
| xfree (ctl_conf_ptr->slurmd_spooldir); |
| xfree (ctl_conf_ptr->slurmd_user_name); |
| xfree (ctl_conf_ptr->srun_epilog); |
| xfree (ctl_conf_ptr->srun_port_range); |
| 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_exc_states); |
| xfree (ctl_conf_ptr->suspend_program); |
| xfree (ctl_conf_ptr->switch_param); |
| 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->tls_params); |
| xfree(ctl_conf_ptr->tls_type); |
| xfree (ctl_conf_ptr->tmp_fs); |
| xfree (ctl_conf_ptr->topology_param); |
| xfree (ctl_conf_ptr->topology_plugin); |
| xfree (ctl_conf_ptr->unkillable_program); |
| xfree(ctl_conf_ptr->url_parser_type); |
| xfree (ctl_conf_ptr->version); |
| xfree (ctl_conf_ptr->x11_params); |
| |
| 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_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_ext_host); |
| xfree (ctl_conf_ptr->accounting_storage_host); |
| xfree (ctl_conf_ptr->accounting_storage_params); |
| xfree (ctl_conf_ptr->accounting_storage_pass); |
| ctl_conf_ptr->accounting_storage_port = 0; |
| xfree (ctl_conf_ptr->accounting_storage_tres); |
| xfree (ctl_conf_ptr->accounting_storage_type); |
| xfree(ctl_conf_ptr->authalttypes); |
| xfree(ctl_conf_ptr->authalt_params); |
| xfree (ctl_conf_ptr->authinfo); |
| xfree (ctl_conf_ptr->authtype); |
| ctl_conf_ptr->batch_start_timeout = 0; |
| xfree (ctl_conf_ptr->bb_type); |
| xfree(ctl_conf_ptr->bcast_exclude); |
| xfree(ctl_conf_ptr->bcast_parameters); |
| xfree(ctl_conf_ptr->certgen_params); |
| xfree(ctl_conf_ptr->certgen_type); |
| xfree(ctl_conf_ptr->certmgr_params); |
| xfree(ctl_conf_ptr->certmgr_type); |
| xfree(ctl_conf_ptr->cli_filter_params); |
| xfree(ctl_conf_ptr->cli_filter_plugins); |
| xfree (ctl_conf_ptr->cluster_name); |
| xfree (ctl_conf_ptr->comm_params); |
| ctl_conf_ptr->complete_wait = NO_VAL16; |
| ctl_conf_ptr->conf_flags = 0; |
| xfree_array(ctl_conf_ptr->control_addr); |
| xfree_array(ctl_conf_ptr->control_machine); |
| ctl_conf_ptr->control_cnt = 0; |
| xfree (ctl_conf_ptr->control_addr); |
| xfree (ctl_conf_ptr->control_machine); |
| xfree (ctl_conf_ptr->cred_type); |
| ctl_conf_ptr->def_mem_per_cpu = 0; |
| ctl_conf_ptr->debug_flags = 0; |
| xfree (ctl_conf_ptr->dependency_params); |
| 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_interconnect_type); |
| xfree (ctl_conf_ptr->acct_gather_filesystem_type); |
| ctl_conf_ptr->enforce_part_limits = 0; |
| xfree (ctl_conf_ptr->epilog); |
| ctl_conf_ptr->epilog_msg_time = NO_VAL; |
| xfree(ctl_conf_ptr->fed_params); |
| ctl_conf_ptr->first_job_id = NO_VAL; |
| xfree(ctl_conf_ptr->gres_plugins); |
| ctl_conf_ptr->group_time = 0; |
| ctl_conf_ptr->group_force = 0; |
| xfree(ctl_conf_ptr->hash_plugin); |
| ctl_conf_ptr->hash_val = NO_VAL; |
| ctl_conf_ptr->health_check_interval = 0; |
| xfree(ctl_conf_ptr->health_check_program); |
| xfree(ctl_conf_ptr->http_parser_type); |
| ctl_conf_ptr->inactive_limit = NO_VAL16; |
| xfree(ctl_conf_ptr->interactive_step_opts); |
| 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_comp_loc); |
| xfree(ctl_conf_ptr->job_comp_params); |
| 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); |
| FREE_NULL_LIST(ctl_conf_ptr->job_defaults_list); |
| ctl_conf_ptr->job_file_append = NO_VAL16; |
| ctl_conf_ptr->job_requeue = NO_VAL16; |
| xfree(ctl_conf_ptr->job_submit_plugins); |
| ctl_conf_ptr->keepalive_interval = NO_VAL; |
| ctl_conf_ptr->keepalive_probes = NO_VAL; |
| ctl_conf_ptr->keepalive_time = NO_VAL; |
| ctl_conf_ptr->kill_on_bad_exit = 0; |
| ctl_conf_ptr->kill_wait = NO_VAL16; |
| xfree (ctl_conf_ptr->launch_params); |
| xfree (ctl_conf_ptr->licenses); |
| xfree (ctl_conf_ptr->mail_domain); |
| xfree (ctl_conf_ptr->mail_prog); |
| ctl_conf_ptr->max_array_sz = NO_VAL; |
| ctl_conf_ptr->max_batch_requeue = NO_VAL; |
| ctl_conf_ptr->max_dbd_msgs = 0; |
| ctl_conf_ptr->max_job_cnt = NO_VAL; |
| ctl_conf_ptr->max_job_id = NO_VAL; |
| ctl_conf_ptr->max_mem_per_cpu = 0; |
| ctl_conf_ptr->max_step_cnt = NO_VAL; |
| xfree(ctl_conf_ptr->mcs_plugin); |
| xfree(ctl_conf_ptr->mcs_plugin_params); |
| ctl_conf_ptr->job_acct_oom_kill = false; |
| ctl_conf_ptr->min_job_age = NO_VAL; |
| FREE_NULL_LIST(ctl_conf_ptr->mpi_conf); |
| xfree (ctl_conf_ptr->mpi_default); |
| xfree (ctl_conf_ptr->mpi_params); |
| ctl_conf_ptr->msg_timeout = NO_VAL16; |
| ctl_conf_ptr->next_job_id = NO_VAL; |
| xfree(ctl_conf_ptr->node_features_plugins); |
| 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_params); |
| xfree (ctl_conf_ptr->preempt_type); |
| xfree (ctl_conf_ptr->priority_params); |
| xfree (ctl_conf_ptr->priority_type); |
| xfree (ctl_conf_ptr->priority_weight_tres); |
| 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 = NO_VAL16; |
| 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; |
| xfree(ctl_conf_ptr->requeue_exit); |
| xfree(ctl_conf_ptr->requeue_exit_hold); |
| ctl_conf_ptr->resume_timeout = 0; |
| xfree (ctl_conf_ptr->resume_fail_program); |
| xfree (ctl_conf_ptr->resume_program); |
| ctl_conf_ptr->resume_rate = NO_VAL16; |
| xfree (ctl_conf_ptr->resv_epilog); |
| ctl_conf_ptr->resv_over_run = 0; |
| xfree (ctl_conf_ptr->resv_prolog); |
| ctl_conf_ptr->ret2service = NO_VAL16; |
| xfree( ctl_conf_ptr->sched_params ); |
| ctl_conf_ptr->sched_time_slice = NO_VAL16; |
| xfree( ctl_conf_ptr->schedtype ); |
| xfree(ctl_conf_ptr->scron_params); |
| xfree( ctl_conf_ptr->select_type ); |
| ctl_conf_ptr->select_type_param = NO_VAL16; |
| ctl_conf_ptr->slurm_user_id = SLURM_AUTH_NOBODY; |
| xfree (ctl_conf_ptr->slurm_user_name); |
| ctl_conf_ptr->slurmd_user_id = SLURM_AUTH_NOBODY; |
| xfree (ctl_conf_ptr->slurmd_user_name); |
| ctl_conf_ptr->slurmctld_debug = NO_VAL16; |
| xfree (ctl_conf_ptr->slurmctld_logfile); |
| ctl_conf_ptr->slurmctld_syslog_debug = NO_VAL16; |
| xfree (ctl_conf_ptr->sched_logfile); |
| ctl_conf_ptr->sched_log_level = NO_VAL16; |
| xfree (ctl_conf_ptr->slurmctld_addr); |
| xfree (ctl_conf_ptr->slurmctld_pidfile); |
| ctl_conf_ptr->slurmctld_port = NO_VAL; |
| ctl_conf_ptr->slurmctld_port_count = 1; |
| xfree (ctl_conf_ptr->slurmctld_primary_off_prog); |
| xfree (ctl_conf_ptr->slurmctld_primary_on_prog); |
| ctl_conf_ptr->slurmctld_timeout = NO_VAL16; |
| xfree (ctl_conf_ptr->slurmctld_params); |
| ctl_conf_ptr->slurmd_debug = NO_VAL16; |
| xfree (ctl_conf_ptr->slurmd_logfile); |
| xfree (ctl_conf_ptr->slurmd_params); |
| ctl_conf_ptr->slurmd_syslog_debug = NO_VAL16; |
| xfree (ctl_conf_ptr->slurmd_pidfile); |
| ctl_conf_ptr->slurmd_port = NO_VAL; |
| xfree (ctl_conf_ptr->slurmd_spooldir); |
| ctl_conf_ptr->slurmd_timeout = NO_VAL16; |
| 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_exc_states); |
| xfree (ctl_conf_ptr->suspend_program); |
| ctl_conf_ptr->suspend_rate = NO_VAL16; |
| ctl_conf_ptr->suspend_time = NO_VAL16; |
| ctl_conf_ptr->suspend_timeout = 0; |
| xfree (ctl_conf_ptr->switch_type); |
| xfree(ctl_conf_ptr->switch_param); |
| 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); |
| ctl_conf_ptr->tcp_timeout = NO_VAL16; |
| xfree(ctl_conf_ptr->tls_params); |
| xfree(ctl_conf_ptr->tls_type); |
| xfree (ctl_conf_ptr->tmp_fs); |
| xfree (ctl_conf_ptr->topology_param); |
| xfree (ctl_conf_ptr->topology_plugin); |
| ctl_conf_ptr->tree_width = NO_VAL16; |
| xfree (ctl_conf_ptr->unkillable_program); |
| xfree(ctl_conf_ptr->url_parser_type); |
| ctl_conf_ptr->unkillable_timeout = NO_VAL16; |
| ctl_conf_ptr->vsize_factor = 0; |
| ctl_conf_ptr->wait_time = NO_VAL16; |
| xfree (ctl_conf_ptr->x11_params); |
| ctl_conf_ptr->prolog_timeout = NO_VAL16; |
| ctl_conf_ptr->epilog_timeout = NO_VAL16; |
| |
| _free_name_hashtbl(); |
| |
| return; |
| } |
| |
| extern slurm_conf_node_t *slurm_conf_parse_nodeline(const char *nodeline, |
| s_p_hashtbl_t **out_hashtbl) |
| { |
| int count = 0; |
| slurm_conf_node_t **ptr_array; |
| s_p_hashtbl_t *node_hashtbl = NULL; |
| char *leftover = NULL; |
| s_p_options_t node_options[] = { |
| {"NodeName", S_P_ARRAY, _parse_nodename, _destroy_nodename}, |
| {NULL} |
| }; |
| |
| xassert(out_hashtbl); |
| |
| node_hashtbl = s_p_hashtbl_create(node_options); |
| if (!s_p_parse_line(node_hashtbl, nodeline, &leftover)) { |
| s_p_hashtbl_destroy(node_hashtbl); |
| error("Failed to parse nodeline: '%s'", nodeline); |
| return NULL; |
| } |
| |
| if (!s_p_get_array((void ***)&ptr_array, &count, "NodeName", |
| node_hashtbl)) { |
| s_p_hashtbl_destroy(node_hashtbl); |
| error("Failed to find nodename in nodeline: '%s'", nodeline); |
| return NULL; |
| } |
| |
| if (count != 1) { |
| s_p_hashtbl_destroy(node_hashtbl); |
| error("Failed to find one NodeName in nodeline: '%s'", |
| nodeline); |
| return NULL; |
| } |
| |
| *out_hashtbl = node_hashtbl; |
| return ptr_array[0]; |
| } |
| |
| /* caller must lock conf_lock */ |
| static int _init_slurm_conf(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) |
| 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; |
| rc = s_p_parse_file(conf_hashtbl, &conf_ptr->hash_val, name, 0, NULL); |
| /* s_p_dump_values(conf_hashtbl, slurm_conf_options); */ |
| |
| if (_validate_and_set_defaults(conf_ptr, conf_hashtbl) == SLURM_ERROR) |
| rc = SLURM_ERROR; |
| conf_ptr->slurm_conf = xstrdup(name); |
| if (running_in_slurmd()) |
| conf_buf = s_p_pack_hashtbl(conf_hashtbl, |
| slurm_conf_stepd_options, |
| slurm_conf_stepd_options_cnt); |
| |
| conf_initialized = true; |
| |
| return rc; |
| } |
| |
| /* caller must lock conf_lock */ |
| static void |
| _destroy_slurm_conf(void) |
| { |
| FREE_NULL_LIST(config_files); |
| |
| s_p_hashtbl_destroy(conf_hashtbl); |
| FREE_NULL_BUFFER(conf_buf); |
| 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); |
| memset(conf_ptr, 0, sizeof(slurm_conf_t)); |
| conf_initialized = false; |
| |
| /* xfree(conf_ptr); */ |
| } |
| |
| /* |
| * Precedence order for user commands: |
| * |
| * 1. direct file |
| * a. argument if not NULL |
| * b. SLURM_CONF if not NULL |
| * c. default_slurm_config_file if it exists. |
| * d. /run/slurm/conf/slurm.conf if it exists. |
| * 2. SLURM_CONF_SERVER env var |
| * 3. DNS SRV record |
| */ |
| static int _establish_config_source(char **config_file, bool *memfd) |
| { |
| struct stat stat_buf; |
| config_file_t *config_tmp; |
| config_response_msg_t *config = NULL; |
| |
| /* |
| * If config_file was defined (e.g., through the -f option to slurmd) |
| * or the SLURM_CONF variable is set we will always respect those, |
| * and leave s_p_parse_file() to see if it can actually load the file. |
| */ |
| if (*config_file) { |
| debug2("%s: using config_file=%s (provided)", |
| __func__, *config_file); |
| return SLURM_SUCCESS; |
| } |
| if ((*config_file = xstrdup(getenv("SLURM_CONF")))) { |
| debug("%s: using config_file=%s (environment)", |
| __func__, *config_file); |
| return SLURM_SUCCESS; |
| } |
| |
| /* |
| * Use default_slurm_config_file iff the file exists. |
| * This is needed so the "configless" user commands do not get stuck |
| * attempting to load a non-existent config file for an entire |
| * minute in s_p_parse_file(), and we can fall back to our other |
| * options. |
| */ |
| if (!stat(default_slurm_config_file, &stat_buf)) { |
| *config_file = xstrdup(default_slurm_config_file); |
| debug2("%s: using config_file=%s (default)", |
| __func__, *config_file); |
| return SLURM_SUCCESS; |
| } |
| |
| /* |
| * Check /run for a usable symlink. This will only exist if slurmd |
| * is running in configless mode. |
| */ |
| if (!stat("/run/slurm/conf/slurm.conf", &stat_buf)) { |
| *config_file = xstrdup("/run/slurm/conf/slurm.conf"); |
| debug2("%s: using config_file=%s (cached)", |
| __func__, *config_file); |
| return SLURM_SUCCESS; |
| } |
| |
| /* |
| * One last shot - try the SLURM_CONF_SERVER envvar or DNS SRV |
| * entries to fetch the configs from the slurmctld. |
| */ |
| if (!(config = |
| fetch_config(NULL, CONFIG_REQUEST_SLURM_CONF, 0, NULL)) || |
| !config->config_files) { |
| error("%s: failed to fetch config", __func__); |
| return SLURM_ERROR; |
| } |
| |
| config_files = config->config_files; |
| config->config_files = NULL; |
| list_for_each(config_files, write_config_to_memfd, NULL); |
| |
| /* |
| * memfd is always created successfully as any failure causes the |
| * process to die with a fatal() error. |
| */ |
| if (!(config_tmp = list_find_first(config_files, find_conf_by_name, |
| "slurm.conf"))) { |
| error("%s: No slurm.conf found in configuration files received.", |
| __func__); |
| return SLURM_ERROR; |
| } |
| *config_file = xstrdup(config_tmp->memfd_path); |
| *memfd = true; |
| |
| slurm_free_config_response_msg(config); |
| debug2("%s: using config_file=%s (fetched)", __func__, *config_file); |
| |
| return SLURM_SUCCESS; |
| } |
| |
| extern int read_conf_send_stepd(int fd) |
| { |
| int len; |
| |
| xassert(running_in_slurmd()); |
| xassert(conf_buf); |
| |
| len = get_buf_offset(conf_buf); |
| safe_write(fd, &len, sizeof(int)); |
| safe_write(fd, get_buf_data(conf_buf), len); |
| |
| return SLURM_SUCCESS; |
| rwfail: |
| error("%s: failed", __func__); |
| return SLURM_ERROR; |
| } |
| |
| extern void read_conf_recv_stepd(int fd) |
| { |
| int len; |
| |
| xassert(running_in_slurmstepd()); |
| |
| safe_read(fd, &len, sizeof(int)); |
| |
| conf_buf = init_buf(len); |
| safe_read(fd, conf_buf->head, len); |
| conf_hashtbl = s_p_unpack_hashtbl_full(conf_buf, |
| slurm_conf_stepd_options); |
| rwfail: |
| FREE_NULL_BUFFER(conf_buf); |
| } |
| |
| extern void add_key_pair(list_t *key_pair_list, const char *key, |
| const char *fmt, ...) |
| { |
| va_list ap; |
| char *value = NULL; |
| config_key_pair_t *key_pair = NULL; |
| |
| va_start(ap, fmt); |
| _xstrdup_vprintf(&value, fmt, ap); |
| va_end(ap); |
| |
| key_pair = xmalloc(sizeof(*key_pair)); |
| key_pair->name = xstrdup(key); |
| key_pair->value = value; |
| list_append(key_pair_list, key_pair); |
| } |
| |
| extern void add_key_pair_bool(list_t *key_pair_list, const char *key, |
| bool value) |
| { |
| config_key_pair_t *key_pair = xmalloc(sizeof(*key_pair)); |
| |
| key_pair->name = xstrdup(key); |
| key_pair->value = xstrdup(value ? "yes" : "no"); |
| list_append(key_pair_list, key_pair); |
| } |
| |
| extern void add_key_pair_own(list_t *key_pair_list, const char *key, |
| char *value) |
| { |
| config_key_pair_t *key_pair = xmalloc(sizeof(*key_pair)); |
| |
| key_pair->name = xstrdup(key); |
| key_pair->value = value; |
| list_append(key_pair_list, key_pair); |
| } |
| |
| extern void slurm_conf_init_stepd(void) |
| { |
| if (slurm_conf.propagate_rlimits_except) { |
| if ((parse_rlimits(slurm_conf.propagate_rlimits_except, |
| NO_PROPAGATE_RLIMITS)) < 0) { |
| error("Bad PropagateResourceLimitsExcept: %s", |
| slurm_conf.propagate_rlimits_except); |
| return; |
| } |
| } else if ((parse_rlimits(slurm_conf.propagate_rlimits, |
| PROPAGATE_RLIMITS)) < 0) { |
| error("Bad PropagateResourceLimits: %s", |
| slurm_conf.propagate_rlimits); |
| return; |
| } |
| |
| conf_initialized = true; |
| } |
| |
| extern int slurm_conf_init(const char *file_name) |
| { |
| char *config_file; |
| bool memfd = false; |
| slurm_mutex_lock(&conf_lock); |
| |
| if (conf_initialized) { |
| slurm_mutex_unlock(&conf_lock); |
| return SLURM_ERROR; |
| } |
| |
| config_file = xstrdup(file_name); |
| if (_establish_config_source(&config_file, &memfd) != SLURM_SUCCESS) |
| fatal("Could not establish a configuration source"); |
| debug("%s: using config_file=%s", __func__, config_file); |
| |
| /* |
| * Ensure this determination is propagated throughout. A number of |
| * other internal functions will call getenv("SLURM_CONF") rather |
| * than use slurm_conf.slurm_conf, and we want to ensure they |
| * don't need to make similar decisions on where the configs live. |
| */ |
| setenv("SLURM_CONF", config_file, 1); |
| |
| init_slurm_conf(conf_ptr); |
| if (_init_slurm_conf(config_file) != SLURM_SUCCESS) |
| fatal("Unable to process configuration file"); |
| |
| if (memfd) |
| unsetenv("SLURM_CONF"); |
| |
| slurm_mutex_unlock(&conf_lock); |
| xfree(config_file); |
| |
| 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"); |
| |
| 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; |
| |
| slurm_mutex_lock(&conf_lock); |
| rc = _internal_reinit(file_name); |
| slurm_mutex_unlock(&conf_lock); |
| |
| return rc; |
| } |
| |
| extern void |
| slurm_conf_mutex_init(void) |
| { |
| slurm_mutex_init(&conf_lock); |
| } |
| |
| 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) |
| { |
| slurm_mutex_lock(&conf_lock); |
| |
| if (!conf_initialized) { |
| slurm_mutex_unlock(&conf_lock); |
| return SLURM_SUCCESS; |
| } |
| |
| _destroy_slurm_conf(); |
| |
| slurm_mutex_unlock(&conf_lock); |
| |
| return SLURM_SUCCESS; |
| } |
| |
| extern slurm_conf_t *slurm_conf_lock(void) |
| { |
| slurm_mutex_lock(&conf_lock); |
| if (!conf_initialized) { |
| if (_init_slurm_conf(NULL) != SLURM_SUCCESS) { |
| /* |
| * Clearing control_addr array entries 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. |
| */ |
| // FIXME: clear control_machine array as well? |
| xfree_array(conf_ptr->control_addr); |
| conf_ptr->control_cnt = 0; |
| } |
| } |
| |
| return conf_ptr; |
| } |
| |
| extern void |
| slurm_conf_unlock(void) |
| { |
| slurm_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; |
| bool state_set = false; |
| |
| token = strtok_r(tmp_str, ",", &last); |
| while (token) { |
| if (!xstrcasecmp(token, "ANY")) { |
| state_num |= HEALTH_CHECK_NODE_ANY; |
| state_set = true; |
| } else if (!xstrcasecmp(token, "ALLOC")) { |
| state_num |= HEALTH_CHECK_NODE_ALLOC; |
| state_set = true; |
| } else if (!xstrcasecmp(token, "CYCLE")) { |
| state_num |= HEALTH_CHECK_CYCLE; |
| } else if (!xstrcasecmp(token, "IDLE")) { |
| state_num |= HEALTH_CHECK_NODE_IDLE; |
| state_set = true; |
| } else if (!xstrcasecmp(token, "MIXED")) { |
| state_num |= HEALTH_CHECK_NODE_MIXED; |
| state_set = true; |
| } else if (!xstrcasecmp(token, "NONDRAINED_IDLE")) { |
| state_num |= HEALTH_CHECK_NODE_NONDRAINED_IDLE; |
| state_set = true; |
| } else if (!xstrcasecmp(token, "START_ONLY")) { |
| state_num |= HEALTH_CHECK_START_ONLY; |
| state_set = true; |
| } else { |
| error("Invalid HealthCheckNodeState value %s ignored", |
| token); |
| } |
| token = strtok_r(NULL, ",", &last); |
| } |
| if (!state_set) |
| state_num |= HEALTH_CHECK_NODE_ANY; |
| xfree(tmp_str); |
| |
| return state_num; |
| } |
| |
| /* Return TRUE if a comma-delimited token "hbm" is found */ |
| static bool _have_hbm_token(char *gres_plugins) |
| { |
| char *tmp, *tok, *save_ptr = NULL; |
| bool rc = false; |
| |
| if (!gres_plugins) |
| return false; |
| |
| tmp = xstrdup(gres_plugins); |
| tok = strtok_r(tmp, ",", &save_ptr); |
| while (tok) { |
| if (!xstrcasecmp(tok, "hbm")) { |
| rc = true; |
| break; |
| } |
| tok = strtok_r(NULL, ",", &save_ptr); |
| } |
| xfree(tmp); |
| |
| return rc; |
| } |
| |
| static int _validate_accounting_storage_enforce(char *acct_enforce_str, |
| slurm_conf_t *conf) |
| { |
| int rc = SLURM_SUCCESS; |
| char *tmp_str, *tok, *saveptr = NULL; |
| |
| tmp_str = xstrdup(acct_enforce_str); |
| tok = strtok_r(tmp_str, ",", &saveptr); |
| while (tok) { |
| if (!xstrcasecmp(tok, "1") |
| || !xstrcasecmp(tok, "associations")) { |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_ASSOCS; |
| } else if (!xstrcasecmp(tok, "2") |
| || !xstrcasecmp(tok, "limits")) { |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_ASSOCS; |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_LIMITS; |
| } else if (!xstrcasecmp(tok, "safe")) { |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_ASSOCS; |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_LIMITS; |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_SAFE; |
| } else if (!xstrcasecmp(tok, "wckeys")) { |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_ASSOCS; |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_WCKEYS; |
| conf->conf_flags |= CONF_FLAG_WCKEY; |
| } else if (!xstrcasecmp(tok, "qos")) { |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_ASSOCS; |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_QOS; |
| } else if (!xstrcasecmp(tok, "all")) { |
| conf->accounting_storage_enforce = 0xffff; |
| conf->conf_flags |= CONF_FLAG_WCKEY; |
| /* |
| * 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 |
| * below here. |
| */ |
| } else if (!xstrcasecmp(tok, "nojobs")) { |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_NO_JOBS; |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_NO_STEPS; |
| } else if (!xstrcasecmp(tok, "nosteps")) { |
| conf->accounting_storage_enforce |
| |= ACCOUNTING_ENFORCE_NO_STEPS; |
| } else { |
| error("Invalid parameter for AccountingStorageEnforce: %s", |
| tok); |
| conf->accounting_storage_enforce = 0; |
| conf->conf_flags &= ~CONF_FLAG_WCKEY; |
| rc = SLURM_ERROR; |
| break; |
| } |
| |
| tok = strtok_r(NULL, ",", &saveptr); |
| } |
| xfree(tmp_str); |
| |
| return rc; |
| } |
| |
| static int _validate_bcast_exclude(slurm_conf_t *conf) |
| { |
| int rc = SLURM_SUCCESS; |
| char *tmp_str = NULL, *tok = NULL, *saveptr = NULL; |
| |
| if (!xstrcasecmp(conf->bcast_exclude, "none")) |
| return rc; |
| |
| tmp_str = xstrdup(conf->bcast_exclude); |
| tok = strtok_r(tmp_str, ",", &saveptr); |
| while (tok) { |
| if (tok[0] != '/') { |
| error("Invalid path for BcastExclude: %s", |
| tok); |
| xfree(conf->bcast_exclude); |
| conf->bcast_exclude = xstrdup(DEFAULT_BCAST_EXCLUDE); |
| rc = SLURM_ERROR; |
| break; |
| } |
| tok = strtok_r(NULL, ",", &saveptr); |
| } |
| |
| xfree(tmp_str); |
| return rc; |
| } |
| |
| /* |
| * Parse a comma separated list of SelectType Parameters |
| * |
| * Return SLURM_SUCCESS on success, or SLURM_ERROR otherwise |
| */ |
| static int _parse_select_type_param( |
| char *select_type_parameters, uint16_t *param) |
| { |
| int rc = SLURM_SUCCESS; |
| char *str_parameters, *st_str = NULL; |
| int param_cnt = 0; |
| |
| *param = 0; |
| st_str = xstrdup(select_type_parameters); |
| str_parameters = strtok(st_str,","); |
| while (str_parameters) { |
| if (!xstrcasecmp(str_parameters, "CR_Socket")) { |
| *param |= SELECT_SOCKET; |
| param_cnt++; |
| } else if (!xstrcasecmp(str_parameters, "CR_Socket_Memory")) { |
| *param |= SELECT_SOCKET; |
| *param |= SELECT_MEMORY; |
| param_cnt++; |
| } else if (!xstrcasecmp(str_parameters, "CR_Core")) { |
| *param |= SELECT_CORE; |
| param_cnt++; |
| } else if (!xstrcasecmp(str_parameters, "CR_Core_Memory")) { |
| *param |= SELECT_CORE; |
| *param |= SELECT_MEMORY; |
| param_cnt++; |
| } else if (!xstrcasecmp(str_parameters, "CR_Memory")) { |
| *param |= SELECT_MEMORY; |
| param_cnt++; |
| } else if (!xstrcasecmp(str_parameters, "CR_CPU")) { |
| *param |= SELECT_CPU; |
| param_cnt++; |
| } else if (!xstrcasecmp(str_parameters, "CR_CPU_Memory")) { |
| *param |= SELECT_CPU; |
| *param |= SELECT_MEMORY; |
| param_cnt++; |
| } else if (!xstrcasecmp(str_parameters, |
| "CR_ONE_TASK_PER_CORE")) { |
| *param |= SELECT_ONE_TASK_PER_CORE; |
| } else if (!xstrcasecmp(str_parameters, |
| "CR_CORE_DEFAULT_DIST_BLOCK")) { |
| *param |= SELECT_CORE_DEFAULT_DIST_BLOCK; |
| } else if (!xstrcasecmp(str_parameters, "CR_LLN")) { |
| *param |= SELECT_LLN; |
| } else if (!xstrcasecmp(str_parameters, "CR_PACK_NODES")) { |
| *param |= SELECT_PACK_NODES; |
| } else if (!xstrcasecmp(str_parameters, "LL_SHARED_GRES")) { |
| *param |= SELECT_LL_SHARED_GRES; |
| } else if (!xstrcasecmp(str_parameters, |
| "MULTIPLE_SHARING_GRES_PJ")) { |
| *param |= SELECT_MULTIPLE_SHARING_GRES_PJ; |
| } else if (!xstrcasecmp(str_parameters, |
| "ENFORCE_BINDING_GRES")) { |
| *param |= SELECT_ENFORCE_BINDING_GRES; |
| } else if (!xstrcasecmp(str_parameters, |
| "ONE_TASK_PER_SHARING_GRES")) { |
| *param |= SELECT_ONE_TASK_PER_SHARING_GRES; |
| } else { |
| error("Bad SelectTypeParameter: %s", str_parameters); |
| rc = SLURM_ERROR; |
| xfree(st_str); |
| return rc; |
| } |
| |
| if ((*param & SELECT_CPU) && |
| (*param & SELECT_ONE_TASK_PER_CORE)) { |
| error("CR_ONE_TASK_PER_CORE is not compatible with CR_CPU*, please change to use CR_CORE* instead."); |
| rc = SLURM_ERROR; |
| xfree(st_str); |
| return rc; |
| } |
| |
| str_parameters = strtok(NULL,","); |
| } |
| xfree(st_str); |
| |
| if (param_cnt > 1) |
| rc = SLURM_ERROR; |
| |
| return rc; |
| } |
| |
| static int _add_to_str(void *x, void *arg) |
| { |
| char *elem = x; |
| char **sorted_str = arg; |
| |
| if (*sorted_str) |
| xstrcat(*sorted_str, ","); |
| xstrfmtcat(*sorted_str, "task/%s", elem); |
| |
| return SLURM_SUCCESS; |
| } |
| |
| /* reverse-alphabetical */ |
| static int _sort_plugins_by_name(void *x, void *y) |
| { |
| char *s1 = *(char **) x; |
| char *s2 = *(char **) y; |
| return xstrcmp(s2, s1); |
| } |
| |
| static int _validate_conf_nodeset_vs_nodenames() |
| { |
| slurm_conf_node_t **ptr_nname; |
| slurm_conf_nodeset_t **ptr_nset; |
| int count_nodename = slurm_conf_nodename_array(&ptr_nname); |
| int count_nodeset = slurm_conf_nodeset_array(&ptr_nset); |
| hostlist_t *nnames; |
| |
| for (int i = 0; i < count_nodeset; i++){ |
| for (int j = 0; j < count_nodename; j++) { |
| nnames = hostlist_create(ptr_nname[j]->nodenames); |
| if (!nnames) |
| continue; |
| if (hostlist_find(nnames, ptr_nset[i]->name) != -1) { |
| error("NodeSet with name %s overlaps with an existing NodeName", |
| ptr_nset[i]->name); |
| hostlist_destroy(nnames); |
| return SLURM_ERROR; |
| } |
| hostlist_destroy(nnames); |
| } |
| } |
| |
| return SLURM_SUCCESS; |
| } |
| |
| /* |
| * Sort the TaskPlugin= parameters in reverse alphabetical order. |
| * This provides a convenient shortcut to following these rules: |
| * a) task/cgroup must be listed before task/affinity. |
| * (This is due to a bug in kernels < 6.2 with cgroup/v2.) |
| */ |
| static void _sort_task_plugin(char **task_plugin) |
| { |
| char *str, *save_ptr = NULL, *sorted_list = NULL; |
| list_t *plugin_list; |
| |
| if (!*task_plugin || !*task_plugin[0]) |
| return; |
| |
| plugin_list = list_create(NULL); |
| str = *task_plugin; |
| while ((str = strtok_r(str, ",", &save_ptr))) { |
| if (!xstrncmp(str, "task/", 5)) |
| str += 5; |
| list_append(plugin_list, str); |
| str = NULL; |
| } |
| list_sort(plugin_list, _sort_plugins_by_name); |
| list_for_each(plugin_list, _add_to_str, &sorted_list); |
| list_destroy(plugin_list); |
| xfree(*task_plugin); |
| *task_plugin = sorted_list; |
| } |
| |
| /* |
| * |
| * 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 control_addr is NULL, it is over-written by control_machine |
| */ |
| static int _validate_and_set_defaults(slurm_conf_t *conf, |
| s_p_hashtbl_t *hashtbl) |
| { |
| char *temp_str = NULL; |
| bool truth; |
| uint16_t uint16_tmp; |
| uint64_t def_cpu_per_gpu = 0, def_mem_per_gpu = 0, tot_prio_weight; |
| uint64_t uint64_tmp; |
| uint32_t default_unkillable_timeout; |
| job_defaults_t *job_defaults; |
| int i; |
| |
| 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 && *conf->cluster_name) { |
| for (i = 0; conf->cluster_name[i] != '\0'; i++) |
| conf->cluster_name[i] = |
| (char)tolower((int)conf->cluster_name[i]); |
| } else { |
| error("ClusterName needs to be specified"); |
| return SLURM_ERROR; |
| } |
| |
| if (_validate_conf_nodeset_vs_nodenames() != SLURM_SUCCESS) |
| return SLURM_ERROR; |
| |
| if (!s_p_get_uint16(&conf->complete_wait, "CompleteWait", hashtbl)) |
| conf->complete_wait = DEFAULT_COMPLETE_WAIT; |
| |
| if (_load_slurmctld_host(conf) != SLURM_SUCCESS) |
| return SLURM_ERROR; |
| |
| if (!s_p_get_string(&conf->acct_gather_energy_type, |
| "AcctGatherEnergyType", hashtbl)) { |
| /* empty */ |
| } else if (xstrcasestr(conf->acct_gather_energy_type, "none")) |
| xfree(conf->acct_gather_energy_type); |
| else |
| xstrsubstituteall(conf->acct_gather_energy_type, |
| "rsmi", "gpu"); |
| |
| if (!s_p_get_string(&conf->acct_gather_profile_type, |
| "AcctGatherProfileType", hashtbl)) { |
| /* empty */ |
| } else if (xstrcasestr(conf->acct_gather_profile_type, "none")) |
| xfree(conf->acct_gather_profile_type); |
| |
| if (!s_p_get_string(&conf->acct_gather_interconnect_type, |
| "AcctGatherInterconnectType", hashtbl) && |
| !s_p_get_string(&conf->acct_gather_interconnect_type, |
| "AcctGatherInfinibandType", hashtbl)) { |
| /* empty */ |
| } else if (xstrcasestr(conf->acct_gather_interconnect_type, "none")) |
| xfree(conf->acct_gather_interconnect_type); |
| else |
| xstrsubstituteall(conf->acct_gather_interconnect_type, |
| "infiniband", "interconnect"); |
| |
| if (!s_p_get_string(&conf->acct_gather_filesystem_type, |
| "AcctGatherFilesystemType", hashtbl)) { |
| /* empty */ |
| } else if (xstrcasestr(conf->acct_gather_filesystem_type, "none")) |
| xfree(conf->acct_gather_filesystem_type); |
| |
| if (!s_p_get_uint16(&conf->acct_gather_node_freq, |
| "AcctGatherNodeFreq", hashtbl)) |
| conf->acct_gather_node_freq = 0; |
| |
| conf->conf_flags = 0; |
| if (s_p_get_boolean(&truth, "AllowSpecResourcesUsage", hashtbl)) { |
| if (truth) |
| conf->conf_flags |= CONF_FLAG_ASRU; |
| } else if (DEFAULT_ALLOW_SPEC_RESOURCE_USAGE) |
| conf->conf_flags |= CONF_FLAG_ASRU; |
| |
| if (!s_p_get_string(&conf->bcast_parameters, "BcastParameters", |
| hashtbl) && |
| s_p_get_string(&conf->bcast_parameters, "SbcastParameters", |
| hashtbl) && running_in_slurmctld()) |
| error("SbcastParameters has been renamed to BcastParameters. Please update your configuration."); |
| |
| (void) s_p_get_string(&conf->authalttypes, "AuthAltTypes", hashtbl); |
| (void) s_p_get_string(&conf->authalt_params, "AuthAltParameters", hashtbl); |
| |
| (void) 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_string(&conf->bcast_exclude, "BcastExclude", hashtbl)) { |
| if (_validate_bcast_exclude(conf) != SLURM_SUCCESS) |
| return SLURM_ERROR; |
| } else { |
| conf->bcast_exclude = xstrdup(DEFAULT_BCAST_EXCLUDE); |
| } |
| |
| (void) s_p_get_string(&conf->bb_type, "BurstBufferType", hashtbl); |
| |
| (void) s_p_get_string(&conf->certgen_params, "CertgenParameters", |
| hashtbl); |
| (void) s_p_get_string(&conf->certgen_type, "CertgenType", hashtbl); |
| |
| (void) s_p_get_string(&conf->certmgr_params, "CertmgrParameters", |
| hashtbl); |
| (void) s_p_get_string(&conf->certmgr_type, "CertmgrType", hashtbl); |
| |
| (void) s_p_get_string(&conf->comm_params, "CommunicationParameters", |
| hashtbl); |
| if (running_in_slurmctld() && |
| xstrcasestr(conf->comm_params, "NoAddrCache")) |
| error("The CommunicationParameters option \"NoAddrCache\" is defunct, please remove it from slurm.conf."); |
| |
| /* |
| * IPv4 on by default, can be disabled. |
| * IPv6 off by default, can be turned on. |
| */ |
| conf->conf_flags |= CONF_FLAG_IPV4_ENABLED; |
| if (xstrcasestr(slurm_conf.comm_params, "EnableIPv6")) |
| conf->conf_flags |= CONF_FLAG_IPV6_ENABLED; |
| if (xstrcasestr(slurm_conf.comm_params, "DisableIPv4")) |
| conf->conf_flags &= ~CONF_FLAG_IPV4_ENABLED; |
| |
| if (!(conf->conf_flags & CONF_FLAG_IPV4_ENABLED) && |
| !(conf->conf_flags & CONF_FLAG_IPV6_ENABLED)) |
| fatal("Both IPv4 and IPv6 support disabled, cannot communicate"); |
| |
| if ((temp_str = xstrcasestr(conf->comm_params, |
| "getnameinfo_cache_timeout="))) { |
| slurm_conf.getnameinfo_cache_timeout = atoi(temp_str + 26); |
| } else { |
| slurm_conf.getnameinfo_cache_timeout = |
| DEFAULT_GETNAMEINFO_CACHE_TIMEOUT; |
| } |
| |
| conf->host_unreach_retry_count = DEFAULT_HOST_UNREACH_RETRY_COUNT; |
| if ((temp_str = xstrcasestr(conf->comm_params, |
| "host_unreach_retry_count="))) { |
| long tmp_val = strtol(temp_str + 25, NULL, 10); |
| if ((tmp_val >= 0) && (tmp_val <= INT_MAX)) |
| conf->host_unreach_retry_count = tmp_val; |
| else |
| error("CommunicationParameters option host_unreach_retry_count=%ld is invalid, ignored", |
| tmp_val); |
| } |
| |
| (void) s_p_get_string(&conf->cli_filter_params, "CliFilterParameters", |
| hashtbl); |
| |
| if (!s_p_get_string(&conf->cli_filter_plugins, "CliFilterPlugins", |
| hashtbl)) { |
| /* empty */ |
| } else if (xstrcasestr(conf->cli_filter_plugins, "none")) { |
| if (xstrcasestr(conf->cli_filter_plugins, ",")) |
| error("Ignoring invalid CliFilterPlugins: '%s'. You can't have 'none' with another plugin.", |
| conf->cli_filter_plugins); |
| |
| xfree(conf->cli_filter_plugins); |
| } |
| |
| if (s_p_get_string(&temp_str, "CpuFreqDef", hashtbl)) { |
| if (cpu_freq_verify_def(temp_str, &conf->cpu_freq_def)) { |
| error("Ignoring invalid CpuFreqDef: %s", temp_str); |
| conf->cpu_freq_def = NO_VAL; |
| } |
| xfree(temp_str); |
| } else { |
| conf->cpu_freq_def = NO_VAL; |
| } |
| |
| if (s_p_get_string(&temp_str, "CpuFreqGovernors", hashtbl)) { |
| if (cpu_freq_verify_govlist(temp_str, &conf->cpu_freq_govs)) { |
| error("Ignoring invalid CpuFreqGovernors: %s", |
| temp_str); |
| conf->cpu_freq_govs = CPU_FREQ_ONDEMAND | |
| CPU_FREQ_PERFORMANCE | |
| CPU_FREQ_USERSPACE; |
| } |
| xfree(temp_str); |
| } else { |
| conf->cpu_freq_govs = CPU_FREQ_ONDEMAND | CPU_FREQ_PERFORMANCE | |
| CPU_FREQ_USERSPACE; |
| } |
| |
| if (!s_p_get_string(&conf->cred_type, "CredType", hashtbl)) { |
| if (s_p_get_string(&conf->cred_type, "CryptoType", hashtbl)) { |
| /* swap crypto/ for cred/ */ |
| xstrsubstitute(conf->cred_type, "crypto", "cred"); |
| } else |
| conf->cred_type = xstrdup(DEFAULT_CRED_TYPE); |
| } |
| |
| (void) s_p_get_string(&conf->data_parser_parameters, |
| "DataParserParameters", hashtbl); |
| |
| if (!s_p_get_uint64(&conf->def_mem_per_cpu, "DefMemPerNode", hashtbl)) { |
| if (s_p_get_uint64(&conf->def_mem_per_cpu, "DefMemPerCPU", |
| hashtbl)) { |
| conf->def_mem_per_cpu |= MEM_PER_CPU; |
| } else { |
| conf->def_mem_per_cpu = DEFAULT_MEM_PER_CPU; |
| } |
| } else if (s_p_get_uint64(&uint64_tmp, "DefMemPerCPU", hashtbl)) { |
| error("DefMemPerCPU ignored, since it's mutually exclusive with DefMemPerNode"); |
| } |
| |
| if (s_p_get_uint64(&def_cpu_per_gpu, "DefCPUPerGPU", hashtbl)) { |
| job_defaults = xmalloc(sizeof(job_defaults_t)); |
| job_defaults->type = JOB_DEF_CPU_PER_GPU; |
| job_defaults->value = def_cpu_per_gpu; |
| if (!conf->job_defaults_list) { |
| conf->job_defaults_list = list_create(xfree_ptr); |
| } |
| list_append(conf->job_defaults_list, job_defaults); |
| } |
| |
| if (s_p_get_uint64(&def_mem_per_gpu, "DefMemPerGPU", hashtbl)) { |
| job_defaults = xmalloc(sizeof(job_defaults_t)); |
| job_defaults->type = JOB_DEF_MEM_PER_GPU; |
| job_defaults->value = def_mem_per_gpu; |
| if (!conf->job_defaults_list) { |
| conf->job_defaults_list = list_create(xfree_ptr); |
| } |
| list_append(conf->job_defaults_list, job_defaults); |
| } |
| |
| if ((temp_str = xstrdup(getenv("SLURM_DEBUG_FLAGS"))) || |
| s_p_get_string(&temp_str, "DebugFlags", hashtbl)) { |
| if (debug_str2flags(temp_str, &conf->debug_flags) |
| != SLURM_SUCCESS) { |
| error("DebugFlags invalid: %s", temp_str); |
| return SLURM_ERROR; |
| } |
| xfree(temp_str); |
| } else /* Default: no DebugFlags */ |
| conf->debug_flags = 0; |
| |
| (void) s_p_get_string(&conf->dependency_params, |
| "DependencyParameters", hashtbl); |
| |
| if (s_p_get_boolean(&truth, "DisableRootJobs", hashtbl) && truth) |
| conf->conf_flags |= CONF_FLAG_DRJ; |
| |
| if (s_p_get_string(&temp_str, |
| "EnforcePartLimits", hashtbl)) { |
| uint16_t enforce_param; |
| if (parse_part_enforce_type(temp_str, &enforce_param) != |
| SLURM_SUCCESS) { |
| error("Bad EnforcePartLimits: %s", temp_str); |
| xfree(temp_str); |
| return SLURM_ERROR; |
| } |
| xfree(temp_str); |
| conf->enforce_part_limits = enforce_param; |
| } else { |
| conf->enforce_part_limits = DEFAULT_ENFORCE_PART_LIMITS; |
| } |
| |
| _load_script(&conf->epilog, &conf->epilog_cnt, "Epilog"); |
| |
| if (!s_p_get_uint32(&conf->epilog_msg_time, "EpilogMsgTime", hashtbl)) |
| conf->epilog_msg_time = DEFAULT_EPILOG_MSG_TIME; |
| |
| _load_script(&conf->epilog_slurmctld, &conf->epilog_slurmctld_cnt, |
| "EpilogSlurmctld"); |
| |
| if (!s_p_get_uint16(&conf->fs_dampening_factor, |
| "FairShareDampeningFactor", hashtbl)) |
| conf->fs_dampening_factor = 1; |
| |
| if (s_p_get_uint16(&uint16_tmp, "FastSchedule", hashtbl) && |
| running_in_slurmctld()) { |
| if (uint16_tmp == 1) |
| error("Ignoring obsolete FastSchedule=1 option. Please remove from your configuration."); |
| else if (uint16_tmp == 2) |
| fatal("The FastSchedule option has been removed. The FastSchedule=2 functionality is available through the SlurmdParameters=config_overrides option."); |
| else |
| fatal("The FastSchedule option has been removed. Please update your configuration."); |
| } |
| |
| (void) s_p_get_string(&conf->fed_params, "FederationParameters", |
| hashtbl); |
| |
| if (!s_p_get_uint32(&conf->first_job_id, "FirstJobId", hashtbl)) |
| conf->first_job_id = DEFAULT_FIRST_JOB_ID; |
| |
| if (!conf->first_job_id) |
| fatal("FirstJobId cannot be zero"); |
| |
| (void) s_p_get_string(&conf->gres_plugins, "GresTypes", hashtbl); |
| |
| if (!s_p_get_uint16(&conf->group_force, "GroupUpdateForce", hashtbl)) |
| conf->group_force = DEFAULT_GROUP_FORCE; |
| |
| if (!s_p_get_uint16(&conf->group_time, "GroupUpdateTime", hashtbl)) |
| conf->group_time = DEFAULT_GROUP_TIME; |
| |
| (void) s_p_get_string(&conf->gpu_freq_def, "GpuFreqDef", hashtbl); |
| |
| if (!s_p_get_string(&conf->hash_plugin, "HashPlugin", hashtbl)) |
| conf->hash_plugin = xstrdup(DEFAULT_HASH_PLUGIN); |
| |
| if (!s_p_get_uint16(&conf->inactive_limit, "InactiveLimit", hashtbl)) |
| conf->inactive_limit = DEFAULT_INACTIVE_LIMIT; |
| |
| if (!s_p_get_string(&conf->interactive_step_opts, |
| "InteractiveStepOptions", hashtbl)) |
| conf->interactive_step_opts = |
| xstrdup(DEFAULT_INTERACTIVE_STEP_OPTS); |
| |
| 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)) { |
| /* empty */ |
| } else if (xstrcasestr(conf->job_acct_gather_type, "none")) |
| xfree(conf->job_acct_gather_type); |
| |
| (void) s_p_get_string(&conf->job_acct_gather_params, |
| "JobAcctGatherParams", hashtbl); |
| |
| conf->job_acct_oom_kill = false; |
| if (conf->job_acct_gather_params) { |
| char *save_ptr = NULL; |
| char *tmp = xstrdup(conf->job_acct_gather_params); |
| char *tok = strtok_r(tmp, ",", &save_ptr); |
| |
| while (tok) { |
| if (xstrcasecmp(tok, "OverMemoryKill") == 0) { |
| conf->job_acct_oom_kill = true; |
| break; |
| } |
| tok = strtok_r(NULL, ",", &save_ptr); |
| } |
| xfree(tmp); |
| |
| if (xstrcasestr(conf->job_acct_gather_params, "UsePSS") && |
| xstrcasestr(conf->job_acct_gather_params, "NoShared")) |
| fatal("JobAcctGatherParams options UsePSS and NoShared are mutually exclusive."); |
| |
| if (!xstrcasestr(conf->job_acct_gather_type, "linux") && |
| (xstrcasestr(conf->job_acct_gather_params, "UsePSS") || |
| xstrcasestr(conf->job_acct_gather_params, "NoShared"))) |
| error_in_daemon("JobAcctGatherParams UsePSS and NoShared are only compatible with jobacct_gather/linux."); |
| } |
| |
| if (!s_p_get_string(&conf->job_comp_type, "JobCompType", hashtbl)) { |
| /* empty */ |
| } else if (xstrcasestr(conf->job_comp_type, "none")) |
| xfree(conf->job_comp_type); |
| |
| s_p_get_string(&conf->job_comp_loc, "JobCompLoc", hashtbl); |
| |
| if (!s_p_get_string(&conf->job_comp_host, "JobCompHost", |
| hashtbl)) |
| conf->job_comp_host = xstrdup(DEFAULT_STORAGE_HOST); |
| if (!s_p_get_string(&conf->job_comp_user, "JobCompUser", |
| hashtbl)) |
| conf->job_comp_user = xstrdup(DEFAULT_STORAGE_USER); |
| s_p_get_string(&conf->job_comp_params, "JobCompParams", hashtbl); |
| s_p_get_string(&conf->job_comp_pass, "JobCompPass", hashtbl); |
| if (!s_p_get_uint32(&conf->job_comp_port, "JobCompPort", |
| hashtbl)) { |
| if (!xstrcmp(conf->job_comp_type, "job_comp/mysql")) |
| conf->job_comp_port = DEFAULT_MYSQL_PORT; |
| else |
| conf->job_comp_port = DEFAULT_STORAGE_PORT; |
| } |
| |
| (void) s_p_get_string(&conf->job_container_plugin, "JobContainerType", |
| hashtbl); |
| if (xstrcasestr(conf->job_container_plugin, "none")) |
| xfree(conf->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; |
| |
| (void) s_p_get_string(&conf->job_submit_plugins, "JobSubmitPlugins", |
| hashtbl); |
| |
| (void) 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; |
| |
| (void) s_p_get_string(&conf->health_check_program, "HealthCheckProgram", |
| hashtbl); |
| |
| if (!s_p_get_string(&conf->http_parser_type, "HttpParserType", hashtbl)) |
| conf->http_parser_type = xstrdup(DEFAULT_HTTP_PARSER_TYPE); |
| |
| if (!s_p_get_uint32(&conf->keepalive_time, "KeepAliveTime", hashtbl)) { |
| conf->keepalive_time = DEFAULT_KEEPALIVE_TIME; |
| } else if (running_in_slurmctld()) |
| error("KeepAliveTime parameter has moved to CommunicationParameters. Please update your config."); |
| /* keepalive_time needs to eventually fit inside an int */ |
| if ((conf->keepalive_time != DEFAULT_KEEPALIVE_TIME) && |
| (conf->keepalive_time > INT_MAX)) { |
| error("KeepAliveTime %u invalid, ignoring it.", |
| conf->keepalive_time); |
| conf->keepalive_time = DEFAULT_KEEPALIVE_TIME; |
| } |
| |
| /* |
| * Parse keepalivetime option here so CommunicationParameters takes |
| * precedence over the deprecated KeepAliveTime standalone option. |
| */ |
| conf->keepalive_interval = DEFAULT_KEEPALIVE_INTERVAL; |
| if ((temp_str = xstrcasestr(slurm_conf.comm_params, |
| "keepaliveinterval="))) { |
| long tmp_val = strtol(temp_str + 18, NULL, 10); |
| if (tmp_val >= 0 && tmp_val <= INT_MAX) |
| conf->keepalive_interval = tmp_val; |
| else |
| error("CommunicationParameters option keepaliveinterval=%ld is invalid, ignored", |
| tmp_val); |
| } |
| conf->keepalive_probes = DEFAULT_KEEPALIVE_PROBES; |
| if ((temp_str = xstrcasestr(slurm_conf.comm_params, |
| "keepaliveprobes="))) { |
| long tmp_val = strtol(temp_str + 16, NULL, 10); |
| if (tmp_val >= 0 && tmp_val <= INT_MAX) |
| conf->keepalive_probes = tmp_val; |
| else |
| error("CommunicationParameters option keepaliveprobes=%ld is invalid, ignored", |
| tmp_val); |
| } |
| if ((temp_str = xstrcasestr(slurm_conf.comm_params, |
| "keepalivetime="))) { |
| long tmp_val = strtol(temp_str + 14, NULL, 10); |
| if ((tmp_val >= 0) && (tmp_val <= INT_MAX)) |
| conf->keepalive_time = tmp_val; |
| else |
| error("CommunicationParameters option keepalivetime=%ld is invalid, ignored", |
| tmp_val); |
| } |
| |
| 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; |
| |
| (void) s_p_get_string(&conf->launch_params, "LaunchParameters", |
| hashtbl); |
| |
| if (xstrcasestr(conf->launch_params, "enable_nss_slurm") && |
| xstrcasestr(conf->launch_params, "disable_send_gids")) |
| fatal("LaunchParameters options enable_nss_slurm and disable_send_gids are mutually exclusive."); |
| |
| (void) s_p_get_string(&conf->licenses, "Licenses", hashtbl); |
| |
| /* Default log format */ |
| conf->log_fmt = LOG_FMT_ISO8601_MS; |
| if (s_p_get_string(&temp_str, "LogTimeFormat", hashtbl)) { |
| /* |
| * If adding to this please update src/api/config_info.c to do |
| * the reverse translation. |
| */ |
| if (xstrcasestr(temp_str, "iso8601_ms")) |
| conf->log_fmt = LOG_FMT_ISO8601_MS; |
| else if (xstrcasestr(temp_str, "iso8601")) |
| conf->log_fmt = LOG_FMT_ISO8601; |
| else if (xstrcasestr(temp_str, "rfc5424_ms")) |
| conf->log_fmt = LOG_FMT_RFC5424_MS; |
| else if (xstrcasestr(temp_str, "rfc5424")) |
| conf->log_fmt = LOG_FMT_RFC5424; |
| else if (xstrcasestr(temp_str, "rfc3339")) |
| conf->log_fmt = LOG_FMT_RFC3339; |
| else if (xstrcasestr(temp_str, "clock")) |
| conf->log_fmt = LOG_FMT_CLOCK; |
| else if (xstrcasestr(temp_str, "short")) |
| conf->log_fmt = LOG_FMT_SHORT; |
| else if (xstrcasestr(temp_str, "thread_id")) |
| conf->log_fmt = LOG_FMT_THREAD_ID; |
| xfree(temp_str); |
| } |
| |
| (void) s_p_get_string(&conf->mail_domain, "MailDomain", hashtbl); |
| |
| if (!s_p_get_string(&conf->mail_prog, "MailProg", hashtbl)) { |
| struct stat stat_buf; |
| if ((stat(DEFAULT_MAIL_PROG, &stat_buf) == 0) || |
| (stat(DEFAULT_MAIL_PROG_ALT, &stat_buf) != 0)) |
| conf->mail_prog = xstrdup(DEFAULT_MAIL_PROG); |
| else |
| conf->mail_prog = xstrdup(DEFAULT_MAIL_PROG_ALT); |
| } |
| |
| 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 > 4000001) { |
| error("MaxArraySize value (%u) is greater than 4000001", |
| conf->max_array_sz); |
| } |
| |
| if (!s_p_get_uint32(&conf->max_batch_requeue, "MaxBatchRequeue", |
| hashtbl)) |
| conf->max_batch_requeue = DEFAULT_MAX_BATCH_REQUEUE; |
| |
| if (!s_p_get_uint32(&conf->max_dbd_msgs, "MaxDBDMsgs", hashtbl)) |
| conf->max_dbd_msgs = 0; |
| else if (conf->max_dbd_msgs < DEFAULT_MAX_DBD_MSGS) { |
| error("MaxDBDMsgs value (%u) needs to be greater than %d", |
| conf->max_dbd_msgs, DEFAULT_MAX_DBD_MSGS); |
| return SLURM_ERROR; |
| } |
| |
| 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->max_job_id > MAX_JOB_ID) { |
| error("MaxJobId can not exceed MAX_JOB_ID, resetting value"); |
| conf->max_job_id = 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 */ |
| if (running_in_slurmctld()) { |
| info("Resetting MaxJobCount from %u to %u (MaxJobId - FirstJobId + 1)", |
| conf->max_job_cnt, tmp32); |
| } |
| conf->max_job_cnt = tmp32; |
| } |
| } |
| |
| if (!s_p_get_uint64(&conf->max_mem_per_cpu, "MaxMemPerNode", hashtbl)) { |
| if (s_p_get_uint64(&conf->max_mem_per_cpu, "MaxMemPerCPU", |
| hashtbl)) { |
| conf->max_mem_per_cpu |= MEM_PER_CPU; |
| } else { |
| conf->max_mem_per_cpu = DEFAULT_MAX_MEM_PER_CPU; |
| } |
| } else if (s_p_get_uint64(&uint64_tmp, "MaxMemPerCPU", hashtbl)) { |
| error("MaxMemPerCPU ignored, since it's mutually exclusive with MaxMemPerNode"); |
| } |
| |
| if (!s_p_get_uint32(&conf->max_node_cnt, "MaxNodeCount", hashtbl)) |
| conf->max_node_cnt = NO_VAL; |
| else if (conf->max_node_cnt > MAX_SLURM_NODES) { |
| error("Specified MaxNodeCount in slurm.conf (%d) is higher than the maximum allowed (%d)", |
| conf->max_node_cnt, MAX_SLURM_NODES); |
| return SLURM_ERROR; |
| } |
| |
| 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; |
| } |
| |
| (void) s_p_get_string(&conf->mcs_plugin_params, "MCSParameters", |
| hashtbl); |
| |
| if (!s_p_get_string(&conf->mcs_plugin, "MCSPlugin", hashtbl)) { |
| if (conf->mcs_plugin_params) { |
| /* no plugin mcs and a mcs plugin param */ |
| error("MCSParameters=%s used and no MCSPlugin", |
| conf->mcs_plugin_params); |
| return SLURM_ERROR; |
| } |
| } else if (xstrcasestr(conf->mcs_plugin, "none")) |
| xfree(conf->mcs_plugin); |
| |
| if (conf->mcs_plugin_params && !conf->mcs_plugin) { |
| /* plugin mcs none and a mcs plugin param */ |
| warning("MCSParameters=%s can't be used with MCSPlugin=mcs/none", |
| conf->mcs_plugin_params); |
| } |
| if (!conf->mcs_plugin_params && |
| !xstrcmp(conf->mcs_plugin, "mcs/group")) { |
| /* plugin mcs/group and no mcs plugin param */ |
| error("MCSPlugin is mcs/group and no MCSParameters"); |
| return SLURM_ERROR; |
| } |
| |
| if (!s_p_get_uint16(&conf->msg_timeout, "MessageTimeout", hashtbl)) |
| conf->msg_timeout = DEFAULT_MSG_TIMEOUT; |
| else if (conf->msg_timeout > 100) |
| error_in_daemon("MessageTimeout is too high for effective fault-tolerance"); |
| |
| if (!s_p_get_uint32(&conf->min_job_age, "MinJobAge", hashtbl)) |
| conf->min_job_age = DEFAULT_MIN_JOB_AGE; |
| else if (conf->min_job_age < 2) { |
| error_in_daemon("MinJobAge must be at least 2"); |
| conf->min_job_age = 2; |
| } |
| |
| if (!s_p_get_string(&conf->mpi_default, "MpiDefault", hashtbl)) { |
| /* empty */ |
| } else if (xstrcasestr(conf->mpi_default, "none") || |
| xstrcasestr(conf->mpi_default, "openmpi")) { |
| xfree(conf->mpi_default); |
| } |
| |
| (void) s_p_get_string(&conf->mpi_params, "MpiParams", hashtbl); |
| |
| if (s_p_get_boolean((bool *)&truth, "TrackWCKey", hashtbl) && truth) |
| conf->conf_flags |= CONF_FLAG_WCKEY; |
| |
| if (!s_p_get_string(&conf->accounting_storage_type, |
| "AccountingStorageType", hashtbl)) { |
| /* empty */ |
| } else if (xstrcasestr(conf->accounting_storage_type, "none")) |
| xfree(conf->accounting_storage_type); |
| else if (xstrcasestr(conf->accounting_storage_type, "mysql")) |
| fatal("AccountingStorageType=accounting_storage/mysql only permitted in SlurmDBD."); |
| |
| (void) s_p_get_string(&conf->node_features_plugins, |
| "NodeFeaturesPlugins", hashtbl); |
| |
| if (xstrstr(conf->node_features_plugins, "knl_") && |
| !_have_hbm_token(conf->gres_plugins)) { |
| /* KNL nodes implicitly add GRES type of "hbm" */ |
| if (conf->gres_plugins && conf->gres_plugins[0]) |
| xstrcat(conf->gres_plugins, ",hbm"); |
| else |
| xstrcat(conf->gres_plugins, "hbm"); |
| } |
| |
| if (!s_p_get_string(&conf->accounting_storage_tres, |
| "AccountingStorageTRES", hashtbl)) { |
| /* Set to default accounting tres fields */ |
| conf->accounting_storage_tres = |
| xstrdup(DEFAULT_ACCOUNTING_TRES); |
| } else { |
| list_t *tres_list = list_create(xfree_ptr); |
| |
| slurm_addto_char_list(tres_list, DEFAULT_ACCOUNTING_TRES); |
| slurm_addto_char_list(tres_list, conf->accounting_storage_tres); |
| |
| /* |
| * If we are tracking gres/gpu, also add the usage tres to the |
| * mix. |
| */ |
| if (list_find_first(tres_list, slurm_find_char_in_list, |
| "gres/gpu")) { |
| slurm_addto_char_list(tres_list, |
| "gres/gpumem,gres/gpuutil"); |
| } |
| |
| xfree(conf->accounting_storage_tres); |
| conf->accounting_storage_tres = |
| slurm_char_list_to_xstr(tres_list); |
| FREE_NULL_LIST(tres_list); |
| } |
| |
| if (s_p_get_string(&temp_str, "AccountingStorageEnforce", hashtbl)) { |
| if (_validate_accounting_storage_enforce(temp_str, conf) != |
| SLURM_SUCCESS) { |
| error("AccountingStorageEnforce invalid: %s", |
| temp_str); |
| xfree(temp_str); |
| return SLURM_ERROR; |
| } |
| xfree(temp_str); |
| } else |
| conf->accounting_storage_enforce = 0; |
| |
| /* if no backup we don't care */ |
| (void) s_p_get_string(&conf->accounting_storage_backup_host, |
| "AccountingStorageBackupHost", hashtbl); |
| |
| s_p_get_string(&conf->accounting_storage_ext_host, |
| "AccountingStorageExternalHost", hashtbl); |
| |
| if (!s_p_get_string(&conf->accounting_storage_host, |
| "AccountingStorageHost", hashtbl)) |
| conf->accounting_storage_host = xstrdup(DEFAULT_STORAGE_HOST); |
| |
| s_p_get_string(&conf->accounting_storage_pass, "AccountingStoragePass", |
| hashtbl); |
| |
| if (s_p_get_string(&temp_str, "AccountingStoreFlags", hashtbl)) { |
| if (xstrcasestr(temp_str, "job_comment")) |
| conf->conf_flags |= CONF_FLAG_SJC; |
| if (xstrcasestr(temp_str, "job_env")) |
| conf->conf_flags |= CONF_FLAG_SJE; |
| if (xstrcasestr(temp_str, "job_extra")) |
| conf->conf_flags |= CONF_FLAG_SJX; |
| if (xstrcasestr(temp_str, "job_script")) |
| conf->conf_flags |= CONF_FLAG_SJS; |
| if (xstrcasestr(temp_str, "no_stdio")) |
| conf->conf_flags |= CONF_FLAG_NO_STDIO; |
| xfree(temp_str); |
| } |
| |
| if (s_p_get_boolean(&truth, "AccountingStoreJobComment", hashtbl)) |
| fatal("The AccountingStoreJobComment option has been removed, please use AccountingStoreFlags=job_comment option instead."); |
| |
| s_p_get_string(&conf->accounting_storage_params, |
| "AccountingStorageParameters", hashtbl); |
| |
| if (!s_p_get_uint16(&conf->accounting_storage_port, |
| "AccountingStoragePort", hashtbl)) { |
| if (!xstrcmp(conf->accounting_storage_type, |
| "accounting_storage/slurmdbd")) |
| conf->accounting_storage_port = SLURMDBD_PORT; |
| else if (!xstrcmp(conf->accounting_storage_type, |
| "accounting_storage/mysql")) |
| conf->accounting_storage_port = DEFAULT_MYSQL_PORT; |
| else |
| conf->accounting_storage_port = DEFAULT_STORAGE_PORT; |
| } |
| |
| if (!s_p_get_uint16(&conf->over_time_limit, "OverTimeLimit", hashtbl)) |
| conf->over_time_limit = 0; |
| |
| 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; |
| } |
| |
| s_p_get_string(&conf->plugstack, "PlugStackConfig", hashtbl); |
| |
| if (s_p_get_string(&temp_str, "PreemptExemptTime", hashtbl)) { |
| uint32_t exempt_time = time_str2secs(temp_str); |
| if (exempt_time == NO_VAL) { |
| error("PreemptExemptTime=%s invalid", temp_str); |
| xfree(temp_str); |
| return SLURM_ERROR; |
| } |
| conf->preempt_exempt_time = exempt_time; |
| xfree(temp_str); |
| } |
| |
| if (s_p_get_string(&temp_str, "PreemptMode", hashtbl)) { |
| conf->preempt_mode = preempt_mode_num(temp_str); |
| if (conf->preempt_mode == NO_VAL16) { |
| 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; |
| } |
| |
| (void) s_p_get_string(&conf->preempt_params, "PreemptParameters", |
| hashtbl); |
| |
| if (!s_p_get_string(&conf->preempt_type, "PreemptType", hashtbl) || |
| !xstrcmp(conf->preempt_type, "preempt/none")) { |
| int preempt_mode = conf->preempt_mode & (~PREEMPT_MODE_GANG); |
| /* empty */ |
| xfree(conf->preempt_type); |
| if (preempt_mode != PREEMPT_MODE_OFF) { |
| error("PreemptType and PreemptMode values incompatible"); |
| return SLURM_ERROR; |
| } |
| } else if (xstrcmp(conf->preempt_type, "preempt/qos") == 0) { |
| int preempt_mode = conf->preempt_mode & (~PREEMPT_MODE_GANG); |
| preempt_mode &= ~PREEMPT_MODE_WITHIN; |
| preempt_mode &= ~PREEMPT_MODE_PRIORITY; |
| if (preempt_mode == PREEMPT_MODE_OFF) { |
| error("PreemptType and PreemptMode values " |
| "incompatible"); |
| return SLURM_ERROR; |
| } |
| } else if (xstrcmp(conf->preempt_type, "preempt/partition_prio") == 0) { |
| int preempt_mode = conf->preempt_mode & (~PREEMPT_MODE_GANG); |
| preempt_mode &= ~PREEMPT_MODE_WITHIN; |
| preempt_mode &= ~PREEMPT_MODE_PRIORITY; |
| if (preempt_mode == PREEMPT_MODE_OFF) { |
| error("PreemptType and PreemptMode values " |
| "incompatible"); |
| return SLURM_ERROR; |
| } |
| } |
| |
| (void) s_p_get_string(&conf->prep_params, "PrEpParameters", hashtbl); |
| if (!s_p_get_string(&conf->prep_plugins, "PrEpPlugins", hashtbl)) |
| conf->prep_plugins = xstrdup(DEFAULT_PREP_PLUGINS); |
| |
| 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 = PRIORITY_FLAGS_FAIR_TREE; |
| if (s_p_get_string(&temp_str, "PriorityFlags", hashtbl)) { |
| if (xstrcasestr(temp_str, "ACCRUE_ALWAYS")) |
| conf->priority_flags |= PRIORITY_FLAGS_ACCRUE_ALWAYS; |
| if (xstrcasestr(temp_str, "SMALL_RELATIVE_TO_TIME")) |
| conf->priority_flags |= PRIORITY_FLAGS_SIZE_RELATIVE; |
| if (xstrcasestr(temp_str, "CALCULATE_RUNNING")) |
| conf->priority_flags |= PRIORITY_FLAGS_CALCULATE_RUNNING; |
| |
| if (xstrcasestr(temp_str, "DEPTH_OBLIVIOUS")) { |
| conf->priority_flags |= PRIORITY_FLAGS_DEPTH_OBLIVIOUS; |
| conf->priority_flags &= ~PRIORITY_FLAGS_FAIR_TREE; |
| } else if (xstrcasestr(temp_str, "NO_FAIR_TREE")) |
| conf->priority_flags &= ~PRIORITY_FLAGS_FAIR_TREE; |
| |
| if (xstrcasestr(temp_str, "INCR_ONLY")) |
| conf->priority_flags |= PRIORITY_FLAGS_INCR_ONLY; |
| |
| if (xstrcasestr(temp_str, "MAX_TRES_GRES")) |
| conf->priority_flags |= PRIORITY_FLAGS_MAX_TRES_GRES; |
| else if (xstrcasestr(temp_str, "MAX_TRES")) |
| conf->priority_flags |= PRIORITY_FLAGS_MAX_TRES; |
| |
| if (xstrcasestr(temp_str, "NO_NORMAL_ALL")) |
| conf->priority_flags |= |
| PRIORITY_FLAGS_NO_NORMAL_ASSOC | |
| PRIORITY_FLAGS_NO_NORMAL_PART | |
| PRIORITY_FLAGS_NO_NORMAL_QOS | |
| PRIORITY_FLAGS_NO_NORMAL_TRES; |
| if (xstrcasestr(temp_str, "NO_NORMAL_ASSOC")) |
| conf->priority_flags |= PRIORITY_FLAGS_NO_NORMAL_ASSOC; |
| if (xstrcasestr(temp_str, "NO_NORMAL_PART")) |
| conf->priority_flags |= PRIORITY_FLAGS_NO_NORMAL_PART; |
| if (xstrcasestr(temp_str, "NO_NORMAL_QOS")) |
| conf->priority_flags |= PRIORITY_FLAGS_NO_NORMAL_QOS; |
| if (xstrcasestr(temp_str, "NO_NORMAL_TRES")) |
| conf->priority_flags |= PRIORITY_FLAGS_NO_NORMAL_TRES; |
| |
| 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; |
| |
| (void) s_p_get_string(&conf->priority_params, "PriorityParameters", |
| hashtbl); |
| |
| |
| if (s_p_get_string(&temp_str, "PriorityUsageResetPeriod", hashtbl)) { |
| if (xstrcasecmp(temp_str, "none") == 0) |
| conf->priority_reset_period = PRIORITY_RESET_NONE; |
| else if (xstrcasecmp(temp_str, "now") == 0) |
| conf->priority_reset_period = PRIORITY_RESET_NOW; |
| else if (xstrcasecmp(temp_str, "daily") == 0) |
| conf->priority_reset_period = PRIORITY_RESET_DAILY; |
| else if (xstrcasecmp(temp_str, "weekly") == 0) |
| conf->priority_reset_period = PRIORITY_RESET_WEEKLY; |
| else if (xstrcasecmp(temp_str, "monthly") == 0) |
| conf->priority_reset_period = PRIORITY_RESET_MONTHLY; |
| else if (xstrcasecmp(temp_str, "quarterly") == 0) |
| conf->priority_reset_period = PRIORITY_RESET_QUARTERLY; |
| else if (xstrcasecmp(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; |
| } |
| } |
| |
| (void) s_p_get_string(&conf->site_factor_params, |
| "PrioritySiteFactorParameters", hashtbl); |
| |
| if (!s_p_get_string(&conf->site_factor_plugin, |
| "PrioritySiteFactorPlugin", hashtbl)) { |
| /* empty */ |
| } else if (xstrcasestr(conf->site_factor_plugin, "none")) |
| xfree(conf->site_factor_plugin); |
| |
| if (!s_p_get_string(&conf->priority_type, "PriorityType", hashtbl)) |
| conf->priority_type = xstrdup(DEFAULT_PRIORITY_TYPE); |
| |
| if (!s_p_get_uint32(&conf->priority_weight_age, |
| "PriorityWeightAge", hashtbl)) |
| conf->priority_weight_age = 0; |
| if (!s_p_get_uint32(&conf->priority_weight_assoc, |
| "PriorityWeightAssoc", hashtbl)) |
| conf->priority_weight_assoc = 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; |
| if (!s_p_get_string(&conf->priority_weight_tres, "PriorityWeightTRES", |
| hashtbl)) |
| conf->priority_weight_tres = NULL; |
| |
| /* Check for possible overflow of priority. |
| * We also check when doing the computation for each job. */ |
| tot_prio_weight = (uint64_t) conf->priority_weight_age + |
| (uint64_t) conf->priority_weight_assoc + |
| (uint64_t) conf->priority_weight_fs + |
| (uint64_t) conf->priority_weight_js + |
| (uint64_t) conf->priority_weight_part + |
| (uint64_t) conf->priority_weight_qos; |
| /* TODO include TRES weights */ |
| if (tot_prio_weight > 0xffffffff) |
| error("PriorityWeight values too high, job priority value may overflow"); |
| |
| if (!s_p_get_string(&conf->proctrack_type, "ProctrackType", hashtbl)) { |
| conf->proctrack_type = xstrdup(DEFAULT_PROCTRACK_TYPE); |
| } |
| |
| conf->private_data = 0; /* Set to default before parsing PrivateData */ |
| if (s_p_get_string(&temp_str, "PrivateData", hashtbl)) { |
| if (xstrcasestr(temp_str, "account")) |
| conf->private_data |= PRIVATE_DATA_ACCOUNTS; |
| if (xstrcasestr(temp_str, "event")) |
| conf->private_data |= PRIVATE_DATA_EVENTS; |
| if (xstrcasestr(temp_str, "job")) |
| conf->private_data |= PRIVATE_DATA_JOBS; |
| if (xstrcasestr(temp_str, "node")) |
| conf->private_data |= PRIVATE_DATA_NODES; |
| if (xstrcasestr(temp_str, "partition")) |
| conf->private_data |= PRIVATE_DATA_PARTITIONS; |
| if (xstrcasestr(temp_str, "reservation")) |
| conf->private_data |= PRIVATE_DATA_RESERVATIONS; |
| if (xstrcasestr(temp_str, "usage")) |
| conf->private_data |= PRIVATE_DATA_USAGE; |
| if (xstrcasestr(temp_str, "user")) |
| conf->private_data |= PRIVATE_DATA_USERS; |
| if (xstrcasestr(temp_str, "all")) |
| conf->private_data = 0xffff; |
| xfree(temp_str); |
| } |
| |
| _load_script(&conf->prolog, &conf->prolog_cnt, "Prolog"); |
| |
| _load_script(&conf->prolog_slurmctld, &conf->prolog_slurmctld_cnt, |
| "PrologSlurmctld"); |
| |
| if (s_p_get_string(&temp_str, "PrologFlags", hashtbl)) { |
| conf->prolog_flags = prolog_str2flags(temp_str); |
| if (conf->prolog_flags == NO_VAL16) { |
| fatal("PrologFlags invalid: %s", temp_str); |
| } |
| |
| if ((conf->prolog_flags & PROLOG_FLAG_NOHOLD) && |
| (conf->prolog_flags & PROLOG_FLAG_CONTAIN)) { |
| fatal("PrologFlags invalid combination: NoHold cannot be combined with Contain and/or X11"); |
| } |
| if ((conf->prolog_flags & PROLOG_FLAG_CONTAIN)) { |
| /* X11 is incompatible with proctrack/linuxproc */ |
| if (conf->prolog_flags & PROLOG_FLAG_X11 && |
| !xstrcmp(conf->proctrack_type, |
| "proctrack/linuxproc")) |
| fatal("Invalid combination: PrologFlags=X11 cannot be combined with proctrack/linuxproc"); |
| /* |
| * proctrack/cgroup is required for pam_slurm_adopt, |
| * but don't fatal if using a different plugin. |
| */ |
| if (running_in_slurmctld() && |
| xstrcmp(conf->proctrack_type, "proctrack/cgroup")) |
| error("If using PrologFlags=Contain for pam_slurm_adopt, proctrack/cgroup is required. If not using pam_slurm_adopt, please ignore error."); |
| } |
| if (conf->prolog_flags & PROLOG_FLAG_NOHOLD) { |
| conf->prolog_flags |= PROLOG_FLAG_ALLOC; |
| } |
| xfree(temp_str); |
| } else { /* Default: no Prolog Flags are set */ |
| conf->prolog_flags = 0; |
| } |
| |
| (void) s_p_get_string(&conf->tls_params, "TLSParameters", hashtbl); |
| |
| if (!s_p_get_string(&conf->tls_type, "TLSType", hashtbl)) |
| conf->tls_type = xstrdup(DEFAULT_TLS_TYPE); |
| |
| if (xstrstr(conf->job_container_plugin, "tmpfs") && |
| !(conf->prolog_flags & PROLOG_FLAG_CONTAIN)) |
| fatal("PrologFlags=Contain is required for use with job_container/tmpfs"); |
| |
| 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; |
| |
| (void) s_p_get_string(&conf->resv_epilog, "ResvEpilog", hashtbl); |
| (void) s_p_get_uint16(&conf->resv_over_run, "ResvOverRun", hashtbl); |
| (void)s_p_get_string(&conf->resv_prolog, "ResvProlog", hashtbl); |
| |
| (void)s_p_get_string(&conf->resume_fail_program, "ResumeFailProgram", |
| hashtbl); |
| (void)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; |
| |
| (void) s_p_get_string(&conf->reboot_program, "RebootProgram", hashtbl); |
| |
| if (s_p_get_string(&temp_str, "SallocDefaultCommand", hashtbl)) |
| fatal("SallocDefaultCommand has been removed. Please consider setting LaunchParameters=use_interactive_step instead."); |
| |
| (void) s_p_get_string(&conf->sched_params, "SchedulerParameters", |
| hashtbl); |
| if ((temp_str = xstrcasestr(conf->sched_params, "max_script_size="))) { |
| if (atoi(temp_str + 16) > MAX_BATCH_SCRIPT_SIZE) |
| fatal("SchedulerParameters option max_script_size cannot exceed %d", |
| MAX_BATCH_SCRIPT_SIZE); |
| } |
| temp_str = xstrcasestr(conf->sched_params, "max_submit_line_size="); |
| if (temp_str) { |
| if (atoi(temp_str + 21) > MAX_MAX_SUBMIT_LINE_SIZE) |
| fatal("SchedulerParameters option max_submit_line_size cannot exceed %d", |
| MAX_MAX_SUBMIT_LINE_SIZE); |
| } |
| if (xstrcasestr(conf->sched_params, "extra_constraints")) |
| extra_constraints_set_parsing(true); |
| else |
| extra_constraints_set_parsing(false); |
| |
| 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); |
| |
| s_p_get_string(&conf->scron_params, "ScronParameters", hashtbl); |
| |
| if (!s_p_get_string(&conf->select_type, "SelectType", hashtbl)) |
| conf->select_type = xstrdup(DEFAULT_SELECT_TYPE); |
| |
| if ((conf->max_node_cnt != NO_VAL) && |
| !xstrstr(conf->select_type, "cons_tres")) { |
| conf->max_node_cnt = NO_VAL; |
| error("MaxNodeCount only compatible with cons_tres"); |
| return SLURM_ERROR; |
| } |
| |
| if (s_p_get_string(&temp_str, |
| "SelectTypeParameters", hashtbl)) { |
| uint16_t type_param; |
| if ((_parse_select_type_param(temp_str, &type_param) != |
| SLURM_SUCCESS)) { |
| error("Bad SelectTypeParameter: %s", temp_str); |
| xfree(temp_str); |
| return SLURM_ERROR; |
| } |
| conf->select_type_param = type_param; |
| xfree(temp_str); |
| } else if (xstrstr(conf->select_type, "cons_tres")) { |
| slurm_conf.select_type_param = (SELECT_CORE | SELECT_MEMORY); |
| } else { |
| conf->select_type_param = 0; |
| } |
| |
| 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) != |
| SLURM_SUCCESS) { |
| 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; |
| } |
| } |
| |
| 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) != |
| SLURM_SUCCESS) { |
| 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; |
| } |
| } |
| |
| (void) s_p_get_string(&conf->slurmctld_addr, "SlurmctldAddr", |
| hashtbl); |
| |
| if (s_p_get_string(&temp_str, "SlurmctldDebug", hashtbl)) { |
| conf->slurmctld_debug = log_string2num(temp_str); |
| if (conf->slurmctld_debug == NO_VAL16) { |
| 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); |
| |
| (void )s_p_get_string(&conf->slurmctld_logfile, "SlurmctldLogFile", |
| hashtbl); |
| |
| if (s_p_get_string(&temp_str, "SlurmctldSyslogDebug", hashtbl)) { |
| conf->slurmctld_syslog_debug = log_string2num(temp_str); |
| if (conf->slurmctld_syslog_debug == NO_VAL16) { |
| error("Invalid SlurmctldSyslogDebug %s", temp_str); |
| return SLURM_ERROR; |
| } |
| xfree(temp_str); |
| _normalize_debug_level(&conf->slurmctld_syslog_debug); |
| } else |
| conf->slurmctld_syslog_debug = LOG_LEVEL_END; |
| |
| if (s_p_get_string(&temp_str, "SlurmctldPort", hashtbl)) { |
| char *end_ptr = NULL; |
| long port_long; |
| errno = 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; |
| } |
| |
| (void) s_p_get_string(&conf->slurmctld_primary_off_prog, |
| "SlurmctldPrimaryOffProg", hashtbl); |
| (void) s_p_get_string(&conf->slurmctld_primary_on_prog, |
| "SlurmctldPrimaryOnProg", hashtbl); |
| |
| if (!s_p_get_uint16(&conf->slurmctld_timeout, |
| "SlurmctldTimeout", hashtbl)) |
| conf->slurmctld_timeout = DEFAULT_SLURMCTLD_TIMEOUT; |
| |
| (void) s_p_get_string(&conf->slurmctld_params, |
| "SlurmctldParameters", hashtbl); |
| if (running_in_slurmctld() && |
| xstrcasestr(conf->slurmctld_params, "cloud_reg_addrs")) |
| error("The SlurmctldParameters option \"cloud_reg_addrs\" is defunct, please remove it from slurm.conf."); |
| |
| if (s_p_get_string(&temp_str, "SlurmdDebug", hashtbl)) { |
| conf->slurmd_debug = log_string2num(temp_str); |
| if (conf->slurmd_debug == NO_VAL16) { |
| 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; |
| |
| (void) s_p_get_string(&conf->slurmd_logfile, "SlurmdLogFile", hashtbl); |
| |
| (void) s_p_get_string(&conf->slurmd_params, "SlurmdParameters", hashtbl); |
| /* This also matches documented "config_overrides" */ |
| if (xstrcasestr(conf->slurmd_params, "config_override")) |
| conf->conf_flags |= CONF_FLAG_OR; |
| |
| if (xstrcasestr(conf->slurmd_params, "l3cache_as_socket")) |
| conf->conf_flags |= CONF_FLAG_L3CSOCK; |
| else if (xstrcasestr(conf->slurmd_params, "numa_node_as_socket")) |
| conf->conf_flags |= CONF_FLAG_NNSOCK; |
| |
| if (xstrcasestr(conf->slurmd_params, "l3cache_as_socket") && |
| xstrcasestr(conf->slurmd_params, "numa_node_as_socket")) |
| error_in_daemon("SlurmdParameters l3cache_as_socket and numa_node_as_socket are mutually exclusive. Ignoring numa_node_as_socket."); |
| |
| if (xstrcasestr(conf->slurmd_params, "allow_ecores")) |
| conf->conf_flags |= CONF_FLAG_ECORE; |
| |
| if (xstrcasestr(conf->slurmd_params, "shutdown_on_reboot")) |
| conf->conf_flags |= CONF_FLAG_SHR; |
| |
| if (xstrcasestr(conf->slurmd_params, "contain_spank")) |
| conf->conf_flags |= CONF_FLAG_CONTAIN_SPANK; |
| |
| 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; |
| |
| (void) 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_string(&temp_str, "SlurmdSyslogDebug", hashtbl)) { |
| conf->slurmd_syslog_debug = log_string2num(temp_str); |
| if (conf->slurmd_syslog_debug == NO_VAL16) { |
| error("Invalid SlurmdSyslogDebug %s", temp_str); |
| return SLURM_ERROR; |
| } |
| xfree(temp_str); |
| _normalize_debug_level(&conf->slurmd_syslog_debug); |
| } else |
| conf->slurmd_syslog_debug = LOG_LEVEL_END; |
| |
| if (!s_p_get_uint16(&conf->slurmd_timeout, "SlurmdTimeout", hashtbl)) |
| conf->slurmd_timeout = DEFAULT_SLURMD_TIMEOUT; |
| |
| (void) s_p_get_string(&conf->srun_prolog, "SrunProlog", hashtbl); |
| if (s_p_get_string(&temp_str, "SrunPortRange", hashtbl)) { |
| conf->srun_port_range = _parse_srun_ports(temp_str); |
| xfree(temp_str); |
| } |
| (void) 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); |
| |
| (void) s_p_get_string(&conf->suspend_exc_nodes, "SuspendExcNodes", |
| hashtbl); |
| (void) s_p_get_string(&conf->suspend_exc_parts, "SuspendExcParts", |
| hashtbl); |
| (void) s_p_get_string(&conf->suspend_exc_states, "SuspendExcStates", |
| hashtbl); |
| (void) 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_string(&temp_str, "SuspendTime", hashtbl)) { |
| if (!xstrcasecmp(temp_str, "NONE") || |
| !xstrcasecmp(temp_str, "INFINITE") || |
| !xstrcasecmp(temp_str, "-1")) { |
| conf->suspend_time = INFINITE; |
| } else { |
| uint64_tmp = slurm_atoul(temp_str); |
| if (uint64_tmp > UINT32_MAX) { |
| error("Bad value \"%s\" for SuspendTime", |
| temp_str); |
| xfree(temp_str); |
| return SLURM_ERROR; |
| } |
| conf->suspend_time = (uint32_t) uint64_tmp; |
| } |
| xfree(temp_str); |
| } else { |
| conf->suspend_time = INFINITE; |
| } |
| if (!s_p_get_uint16(&conf->suspend_timeout, "SuspendTimeout", hashtbl)) |
| conf->suspend_timeout = DEFAULT_SUSPEND_TIMEOUT; |
| |
| (void) s_p_get_string(&conf->switch_param, "SwitchParameters", |
| hashtbl); |
| |
| (void) s_p_get_string(&conf->switch_type, "SwitchType", hashtbl); |
| if (xstrcasestr(conf->switch_type, "none")) |
| xfree(conf->switch_type); |
| |
| if (!s_p_get_string(&conf->task_plugin, "TaskPlugin", hashtbl)) { |
| /* empty */ |
| } else if (xstrcasestr(conf->task_plugin, "none")) |
| xfree(conf->task_plugin); |
| |
| _sort_task_plugin(&conf->task_plugin); |
| |
| conf->task_plugin_param = 0; |
| if (s_p_get_string(&temp_str, "TaskPluginParam", hashtbl)) { |
| char *last = NULL, *tok; |
| bool set_unit = false, set_auto = false; |
| tok = strtok_r(temp_str, ",", &last); |
| while (tok) { |
| if (xstrcasecmp(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 (xstrcasecmp(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 (xstrcasecmp(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 (xstrcasecmp(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 (xstrcasecmp(tok, "verbose") == 0) { |
| conf->task_plugin_param |= CPU_BIND_VERBOSE; |
| } else if (xstrncasecmp(tok, "autobind=", |
| strlen("autobind=")) == 0) { |
| char *val_ptr = tok + strlen("autobind="); |
| |
| if (set_auto) { |
| error("Bad TaskPluginParam: " |
| "autobind already set"); |
| return SLURM_ERROR; |
| } |
| |
| if (xstrcasecmp(val_ptr, "none") == 0) { |
| set_auto = true; |
| } else if (xstrcasecmp(val_ptr, |
| "threads") == 0) { |
| set_auto = true; |
| conf->task_plugin_param |= |
| CPU_AUTO_BIND_TO_THREADS; |
| } else if (xstrcasecmp(val_ptr, |
| "cores") == 0) { |
| set_auto = true; |
| conf->task_plugin_param |= |
| CPU_AUTO_BIND_TO_CORES; |
| } else if (xstrcasecmp(val_ptr, |
| "sockets") == 0) { |
| set_auto = true; |
| conf->task_plugin_param |= |
| CPU_AUTO_BIND_TO_SOCKETS; |
| } else { |
| error("Bad TaskPluginParam autobind " |
| "value: %s",val_ptr); |
| return SLURM_ERROR; |
| } |
| } else if (xstrcasecmp(tok, "SlurmdOffSpec") == 0) { |
| conf->task_plugin_param |= SLURMD_OFF_SPEC; |
| } else if (!xstrcasecmp(tok, "OOMKillStep")) { |
| if (!xstrstr(conf->task_plugin, "task/cgroup")) { |
| error("TaskPluginParam=OOMKillStep must be used with task/cgroup"); |
| return SLURM_ERROR; |
| } |
| conf->task_plugin_param |= OOM_KILL_STEP; |
| } else if (!xstrcasecmp(tok, "SlurmdSpecOverride")) { |
| if (!xstrstr(conf->task_plugin, |
| "task/cgroup")) { |
| error("TaskPluginParam=SlurmdSpecOverride must be used with task/cgroup"); |
| return SLURM_ERROR; |
| } |
| if (!xstrstr(conf->select_type, "cons_tres")) { |
| error("TaskPluginParam=SlurmdSpecOverride must be used with cons/tres"); |
| return SLURM_ERROR; |
| } |
| conf->task_plugin_param |= SLURMD_SPEC_OVERRIDE; |
| } else { |
| error("Bad TaskPluginParam: %s", tok); |
| return SLURM_ERROR; |
| } |
| tok = strtok_r(NULL, ",", &last); |
| } |
| xfree(temp_str); |
| } |
| |
| if ((conf->task_plugin_param & SLURMD_OFF_SPEC) && |
| (conf->task_plugin_param & SLURMD_SPEC_OVERRIDE)) { |
| error("TaskPluginParams SlurmdOffSpec and SlurmdSpecOverride are mutually exclusive"); |
| return SLURM_ERROR; |
| } |
| |
| (void) s_p_get_string(&conf->task_epilog, "TaskEpilog", hashtbl); |
| (void) s_p_get_string(&conf->task_prolog, "TaskProlog", hashtbl); |
| |
| if (!s_p_get_uint16(&conf->tcp_timeout, "TCPTimeout", hashtbl)) |
| conf->tcp_timeout = DEFAULT_TCP_TIMEOUT; |
| |
| 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; |
| |
| (void) s_p_get_string(&conf->x11_params, "X11Parameters", hashtbl); |
| |
| (void) s_p_get_string(&conf->topology_param, "TopologyParam", hashtbl); |
| if (conf->topology_param) { |
| /* Move legacy settings over to new spot */ |
| char *legacy_var = "NoInAddrAny"; |
| if (xstrcasestr(conf->topology_param, legacy_var) && |
| !xstrcasestr(conf->comm_params, legacy_var)) |
| xstrfmtcat(conf->comm_params, "%s%s", |
| conf->comm_params ? "," : "", legacy_var); |
| |
| legacy_var = "NoCtldInAddrAny"; |
| if (xstrcasestr(conf->topology_param, legacy_var) && |
| !xstrcasestr(conf->comm_params, legacy_var)) |
| xstrfmtcat(conf->comm_params, "%s%s", |
| conf->comm_params ? "," : "", legacy_var); |
| } |
| |
| if (s_p_get_string(&temp_str, "RoutePlugin", hashtbl)) { |
| if (xstrcasestr(temp_str, "tree")) { |
| xstrfmtcat(conf->topology_param, "%sRouteTree", |
| conf->topology_param ? "," : ""); |
| } |
| xfree(temp_str); |
| } |
| |
| if (!s_p_get_string(&conf->topology_plugin, |
| "TopologyPlugin", hashtbl)) { |
| /* empty */ |
| } else if (!xstrcasecmp(conf->topology_plugin, "none") || |
| !xstrcasecmp(conf->topology_plugin, "default") || |
| !xstrcasecmp(conf->topology_plugin, "topology/none") || |
| !xstrcasecmp(conf->topology_plugin, "topology/default")) |
| xfree(conf->topology_plugin); |
| |
| if (!conf->topology_plugin) |
| conf->topology_plugin = xstrdup("topology/flat"); |
| |
| if (!xstrcasecmp(conf->select_type, "select/linear") && |
| !xstrcasecmp(conf->topology_plugin, "topology/tree")) |
| fatal("select/linear with topology/tree is not supported. Please switch to select/cons_tres or stop using topology/tree."); |
| |
| if (((conf->tree_width = (getenv("SLURM_TREE_WIDTH") ? |
| atoi(getenv("SLURM_TREE_WIDTH")) : 0)) > 0) || |
| (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->conf_flags |= CONF_FLAG_PAM; |
| |
| s_p_get_string(&conf->unkillable_program, |
| "UnkillableStepProgram", hashtbl); |
| default_unkillable_timeout = conf->msg_timeout * 5; |
| if (!s_p_get_uint16(&conf->unkillable_timeout, |
| "UnkillableStepTimeout", hashtbl)) { |
| if (default_unkillable_timeout > UINT16_MAX) { |
| error_in_daemon("The default value for UnkillableStepTimeout of MessageTimeout*5 (%u) is larger than the maximum allowed value for UnkillableStepTimeout (%u), setting UnkillableStepTimeout to the maximum value.", |
| default_unkillable_timeout, |
| UINT16_MAX); |
| conf->unkillable_timeout = UINT16_MAX; |
| } else |
| conf->unkillable_timeout = |
| MAX(DEFAULT_UNKILLABLE_TIMEOUT, |
| default_unkillable_timeout); |
| } else if (conf->unkillable_timeout < default_unkillable_timeout) |
| error_in_daemon("UnkillableStepTimeout must be at least 5 times greater than MessageTimeout, otherwise nodes may go down with the reason \"KillTaskFailed\". Current values: UnkillableStepTimeout=%u, MessageTimeout=%u", |
| conf->unkillable_timeout, conf->msg_timeout); |
| |
| if (!s_p_get_string(&conf->url_parser_type, "UrlParserType", hashtbl)) |
| conf->url_parser_type = xstrdup(DEFAULT_URL_PARSER_TYPE); |
| |
| (void) s_p_get_uint16(&conf->vsize_factor, "VSizeFactor", hashtbl); |
| |
| /* The default values for both of these variables are NULL. |
| */ |
| (void) s_p_get_string(&conf->requeue_exit, "RequeueExit", hashtbl); |
| (void) s_p_get_string(&conf->requeue_exit_hold, "RequeueExitHold", |
| hashtbl); |
| |
| /* srun eio network timeout with the slurmstepd |
| */ |
| if (!s_p_get_uint16(&conf->eio_timeout, "EioTimeout", hashtbl)) |
| conf->eio_timeout = DEFAULT_EIO_SHUTDOWN_WAIT; |
| |
| if (!s_p_get_uint16(&uint16_tmp, "PrologEpilogTimeout", hashtbl)) |
| uint16_tmp = NO_VAL16; /* default - wait forever */ |
| if (!s_p_get_uint16(&conf->prolog_timeout, "PrologTimeout", hashtbl)) |
| conf->prolog_timeout = uint16_tmp; /* PrologEpilogTimeout */ |
| if (!s_p_get_uint16(&conf->epilog_timeout, "EpilogTimeout", hashtbl)) |
| conf->epilog_timeout = uint16_tmp; /* PrologEpilogTimeout */ |
| |
| 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, |
| const char *host_name) |
| { |
| const char *hostname; |
| char *dir = NULL; |
| |
| #ifndef NDEBUG |
| if (xstrstr(path, "%n")) |
| xassert(node_name); |
| #endif |
| |
| dir = xstrdup(path); |
| if (!host_name) |
| hostname = _internal_get_hostname(node_name); |
| else |
| hostname = host_name; |
| xstrsubstitute(dir, "%h", hostname); |
| if (!host_name) |
| 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_CONTAIN) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Contain"); |
| } |
| |
| if (prolog_flags & PROLOG_FLAG_RUN_IN_JOB) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "RunInJob"); |
| } |
| |
| if (prolog_flags & PROLOG_FLAG_DEFER_BATCH) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DeferBatch"); |
| } |
| |
| if (prolog_flags & PROLOG_FLAG_NOHOLD) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "NoHold"); |
| } |
| |
| if (prolog_flags & PROLOG_FLAG_FORCE_REQUEUE_ON_FAIL) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "ForceRequeueOnFail"); |
| } |
| |
| if (prolog_flags & PROLOG_FLAG_SERIAL) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Serial"); |
| } |
| |
| if (prolog_flags & PROLOG_FLAG_X11) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "X11"); |
| } |
| |
| 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 (xstrcasecmp(tok, "Alloc") == 0) |
| rc |= PROLOG_FLAG_ALLOC; |
| else if (xstrcasecmp(tok, "Contain") == 0) |
| rc |= (PROLOG_FLAG_ALLOC | PROLOG_FLAG_CONTAIN); |
| else if (!xstrcasecmp(tok, "RunInJob")) |
| rc |= (PROLOG_FLAG_ALLOC | PROLOG_FLAG_CONTAIN | |
| PROLOG_FLAG_RUN_IN_JOB); |
| else if (xstrcasecmp(tok, "DeferBatch") == 0) |
| rc |= PROLOG_FLAG_DEFER_BATCH; |
| else if (xstrcasecmp(tok, "NoHold") == 0) |
| rc |= PROLOG_FLAG_NOHOLD; |
| else if (xstrcasecmp(tok, "ForceRequeueOnFail") == 0) |
| rc |= (PROLOG_FLAG_ALLOC | |
| PROLOG_FLAG_FORCE_REQUEUE_ON_FAIL); |
| else if (xstrcasecmp(tok, "Serial") == 0) |
| rc |= PROLOG_FLAG_SERIAL; |
| else if (xstrcasecmp(tok, "X11") == 0) { |
| #ifdef WITH_SLURM_X11 |
| rc |= (PROLOG_FLAG_ALLOC | PROLOG_FLAG_CONTAIN |
| | PROLOG_FLAG_X11); |
| #else |
| error("X11 forwarding not built in, cannot enable."); |
| rc = NO_VAL16; |
| break; |
| #endif |
| } else { |
| error("Invalid PrologFlag: %s", tok); |
| rc = NO_VAL16; |
| break; |
| } |
| tok = strtok_r(NULL, ",", &last); |
| } |
| xfree(tmp_str); |
| |
| if ((rc & PROLOG_FLAG_RUN_IN_JOB) && (rc & PROLOG_FLAG_SERIAL)) |
| error("PrologFlag Serial is incompatible with RunInJob"); |
| |
| return rc; |
| } |
| |
| /* |
| * debug_flags2str - convert a DebugFlags uint64_t to the equivalent string |
| * Keep in sync with debug_str2flags() below |
| */ |
| extern char * debug_flags2str(uint64_t debug_flags) |
| { |
| char *rc = NULL; |
| |
| /* When adding to this please attempt to keep flags in |
| * alphabetical order. |
| */ |
| |
| if (debug_flags & DEBUG_FLAG_ACCRUE) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Accrue"); |
| } |
| if (debug_flags & DEBUG_FLAG_JAG) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "JobAccountGather"); |
| } |
| if (debug_flags & DEBUG_FLAG_AGENT) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Agent"); |
| } |
| if (debug_flags & DEBUG_FLAG_AUDIT_RPCS) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "AuditRPCs"); |
| } |
| if (debug_flags & DEBUG_FLAG_AUDIT_TLS) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "AuditTLS"); |
| } |
| 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_BURST_BUF) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "BurstBuffer"); |
| } |
| if (debug_flags & DEBUG_FLAG_CGROUP) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Cgroup"); |
| } |
| if (debug_flags & DEBUG_FLAG_CPU_FREQ) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "CpuFrequency"); |
| } |
| if (debug_flags & DEBUG_FLAG_CPU_BIND) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "CPU_Bind"); |
| } |
| if (debug_flags & DEBUG_FLAG_DATA) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Data"); |
| } |
| if (debug_flags & DEBUG_FLAG_DBD_AGENT) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DBD_Agent"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_ARCHIVE) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_Archive"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_ASSOC) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_Assoc"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_TRES) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_TRES"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_EVENT) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_Event"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_JOB) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_Job"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_QOS) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_QOS"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_QUERY) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_Query"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_RESV) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_Reservation"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_RES) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_Resource"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_STEP) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_Step"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_USAGE) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_Usage"); |
| } |
| if (debug_flags & DEBUG_FLAG_DB_WCKEY) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "DB_WCKey"); |
| } |
| if (debug_flags & DEBUG_FLAG_DEPENDENCY) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Dependency"); |
| } |
| if (debug_flags & DEBUG_FLAG_ENERGY) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Energy"); |
| } |
| if (debug_flags & DEBUG_FLAG_FEDR) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Federation"); |
| } |
| if (debug_flags & DEBUG_FLAG_GANG) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Gang"); |
| } |
| if (debug_flags & DEBUG_FLAG_GLOB_SILENCE) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "GLOB_SILENCE"); |
| } |
| if (debug_flags & DEBUG_FLAG_GRES) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Gres"); |
| } |
| if (debug_flags & DEBUG_FLAG_HETJOB) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Hetjob"); |
| } |
| if (debug_flags & DEBUG_FLAG_INTERCONNECT) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Interconnect"); |
| } |
| if (debug_flags & DEBUG_FLAG_JOBCOMP) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "JobComp"); |
| } |
| if (debug_flags & DEBUG_FLAG_JOB_CONT) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "JobContainer"); |
| } |
| if (debug_flags & DEBUG_FLAG_NODE_FEATURES) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "NodeFeatures"); |
| } |
| if (debug_flags & DEBUG_FLAG_LICENSE) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "License"); |
| } |
| if (debug_flags & DEBUG_FLAG_MPI) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "MPI"); |
| } |
| if (debug_flags & DEBUG_FLAG_NET) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Network"); |
| } |
| if (debug_flags & DEBUG_FLAG_NET_RAW) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "NetworkRaw"); |
| } |
| if (debug_flags & DEBUG_FLAG_NO_CONF_HASH) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "NO_CONF_HASH"); |
| } |
| if (debug_flags & DEBUG_FLAG_POWER) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Power"); |
| } |
| 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_PROTOCOL) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Protocol"); |
| } |
| if (debug_flags & DEBUG_FLAG_RESERVATION) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Reservation"); |
| } |
| if (debug_flags & DEBUG_FLAG_ROUTE) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Route"); |
| } |
| if (debug_flags & DEBUG_FLAG_SACK) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Sack"); |
| } |
| if (debug_flags & DEBUG_FLAG_SCRIPT) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Script"); |
| } |
| 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_TLS) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "TLS"); |
| } |
| if (debug_flags & DEBUG_FLAG_TRACE_JOBS) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "TraceJobs"); |
| } |
| if (debug_flags & DEBUG_FLAG_TRIGGERS) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "Triggers"); |
| } |
| if (debug_flags & DEBUG_FLAG_CONMGR) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "ConMgr"); |
| } |
| |
| return rc; |
| } |
| |
| /* |
| * debug_str2flags - Convert a DebugFlags string to the equivalent uint64_t |
| * Keep in sync with debug_flags2str() above |
| * Returns SLURM_ERROR if invalid |
| */ |
| extern int debug_str2flags(const char *debug_flags, uint64_t *flags_out) |
| { |
| int rc = SLURM_SUCCESS; |
| char *tmp_str, *tok, *last = NULL; |
| |
| xassert(flags_out); |
| |
| (*flags_out) = 0; |
| |
| if (!debug_flags) |
| return rc; |
| |
| tmp_str = xstrdup(debug_flags); |
| tok = strtok_r(tmp_str, ",", &last); |
| while (tok) { |
| if (xstrcasecmp(tok, "Accrue") == 0) |
| (*flags_out) |= DEBUG_FLAG_ACCRUE; |
| else if (xstrcasecmp(tok, "Agent") == 0) |
| (*flags_out) |= DEBUG_FLAG_AGENT; |
| else if (!xstrcasecmp(tok, "AuditRPCs")) |
| (*flags_out) |= DEBUG_FLAG_AUDIT_RPCS; |
| else if (!xstrcasecmp(tok, "AuditTLS")) |
| (*flags_out) |= DEBUG_FLAG_AUDIT_TLS; |
| else if (xstrcasecmp(tok, "Backfill") == 0) |
| (*flags_out) |= DEBUG_FLAG_BACKFILL; |
| else if (xstrcasecmp(tok, "BackfillMap") == 0) |
| (*flags_out) |= DEBUG_FLAG_BACKFILL_MAP; |
| else if (xstrcasecmp(tok, "BurstBuffer") == 0) |
| (*flags_out) |= DEBUG_FLAG_BURST_BUF; |
| else if (xstrcasecmp(tok, "cgroup") == 0) |
| (*flags_out) |= DEBUG_FLAG_CGROUP; |
| else if (xstrcasecmp(tok, "CPU_Bind") == 0) |
| (*flags_out) |= DEBUG_FLAG_CPU_BIND; |
| else if (xstrcasecmp(tok, "Data") == 0) |
| (*flags_out) |= DEBUG_FLAG_DATA; |
| else if (xstrcasecmp(tok, "DBD_Agent") == 0) |
| (*flags_out) |= DEBUG_FLAG_DBD_AGENT; |
| else if (xstrcasecmp(tok, "DB_Archive") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_ARCHIVE; |
| else if (xstrcasecmp(tok, "DB_Assoc") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_ASSOC; |
| else if (xstrcasecmp(tok, "DB_TRES") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_TRES; |
| else if (xstrcasecmp(tok, "DB_Event") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_EVENT; |
| else if (xstrcasecmp(tok, "DB_Job") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_JOB; |
| else if (xstrcasecmp(tok, "DB_QOS") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_QOS; |
| else if (xstrcasecmp(tok, "DB_Query") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_QUERY; |
| else if (xstrcasecmp(tok, "DB_Reservation") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_RESV; |
| else if (xstrcasecmp(tok, "DB_Resource") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_RES; |
| else if (xstrcasecmp(tok, "DB_Step") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_STEP; |
| else if (xstrcasecmp(tok, "DB_Usage") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_USAGE; |
| else if (xstrcasecmp(tok, "DB_WCKey") == 0) |
| (*flags_out) |= DEBUG_FLAG_DB_WCKEY; |
| else if (xstrcasecmp(tok, "Dependency") == 0) |
| (*flags_out) |= DEBUG_FLAG_DEPENDENCY; |
| else if (xstrcasecmp(tok, "Energy") == 0) |
| (*flags_out) |= DEBUG_FLAG_ENERGY; |
| else if (xstrcasecmp(tok, "Federation") == 0) |
| (*flags_out) |= DEBUG_FLAG_FEDR; |
| else if (xstrcasecmp(tok, "Gang") == 0) |
| (*flags_out) |= DEBUG_FLAG_GANG; |
| else if (!xstrcasecmp(tok, "GLOB_SILENCE")) |
| (*flags_out) |= DEBUG_FLAG_GLOB_SILENCE; |
| else if (xstrcasecmp(tok, "Gres") == 0) |
| (*flags_out) |= DEBUG_FLAG_GRES; |
| else if (xstrcasecmp(tok, "Hetjob") == 0) |
| (*flags_out) |= DEBUG_FLAG_HETJOB; |
| else if (xstrcasecmp(tok, "Federation") == 0) |
| (*flags_out) |= DEBUG_FLAG_FEDR; |
| else if (xstrcasecmp(tok, "Interconnect") == 0) |
| (*flags_out) |= DEBUG_FLAG_INTERCONNECT; |
| else if (!xstrcasecmp(tok, "JobAccountGather") || |
| !xstrcasecmp(tok, "JAG")) |
| (*flags_out) |= DEBUG_FLAG_JAG; |
| else if (!xstrcasecmp(tok, "JobComp") || |
| !xstrcasecmp(tok, "Elasticsearch")) |
| (*flags_out) |= DEBUG_FLAG_JOBCOMP; |
| else if (xstrcasecmp(tok, "JobContainer") == 0) |
| (*flags_out) |= DEBUG_FLAG_JOB_CONT; |
| else if (xstrcasecmp(tok, "License") == 0) |
| (*flags_out) |= DEBUG_FLAG_LICENSE; |
| else if (xstrcasecmp(tok, "MPI") == 0) |
| (*flags_out) |= DEBUG_FLAG_MPI; |
| else if (xstrcasecmp(tok, "Network") == 0 || |
| xstrcasecmp(tok, "Net") == 0) |
| (*flags_out) |= DEBUG_FLAG_NET; |
| else if ((xstrcasecmp(tok, "NetworkRaw") == 0) || |
| (xstrcasecmp(tok, "NetRaw") == 0)) |
| (*flags_out) |= DEBUG_FLAG_NET_RAW; |
| else if (xstrcasecmp(tok, "NO_CONF_HASH") == 0) |
| (*flags_out) |= DEBUG_FLAG_NO_CONF_HASH; |
| else if (xstrcasecmp(tok, "NodeFeatures") == 0) |
| (*flags_out) |= DEBUG_FLAG_NODE_FEATURES; |
| else if (xstrcasecmp(tok, "Priority") == 0) |
| (*flags_out) |= DEBUG_FLAG_PRIO; |
| else if (xstrcasecmp(tok, "Profile") == 0) |
| (*flags_out) |= DEBUG_FLAG_PROFILE; |
| else if (xstrcasecmp(tok, "Protocol") == 0) |
| (*flags_out) |= DEBUG_FLAG_PROTOCOL; |
| else if (xstrcasecmp(tok, "Reservation") == 0) |
| (*flags_out) |= DEBUG_FLAG_RESERVATION; |
| else if (xstrcasecmp(tok, "Route") == 0) |
| (*flags_out) |= DEBUG_FLAG_ROUTE; |
| else if (xstrcasecmp(tok, "Sack") == 0) |
| (*flags_out) |= DEBUG_FLAG_SACK; |
| else if (xstrcasecmp(tok, "Script") == 0) |
| (*flags_out) |= DEBUG_FLAG_SCRIPT; |
| else if (xstrcasecmp(tok, "SelectType") == 0) |
| (*flags_out) |= DEBUG_FLAG_SELECT_TYPE; |
| else if (xstrcasecmp(tok, "Steps") == 0) |
| (*flags_out) |= DEBUG_FLAG_STEPS; |
| else if (xstrcasecmp(tok, "Switch") == 0) |
| (*flags_out) |= DEBUG_FLAG_SWITCH; |
| else if (xstrcasecmp(tok, "Task") == 0) |
| error("DebugFlag Task has been removed, please use CPU_Bind"); |
| else if (xstrcasecmp(tok, "TLS") == 0) |
| (*flags_out) |= DEBUG_FLAG_TLS | DEBUG_FLAG_AUDIT_TLS; |
| else if (xstrcasecmp(tok, "TraceJobs") == 0) |
| (*flags_out) |= DEBUG_FLAG_TRACE_JOBS; |
| else if (xstrcasecmp(tok, "Trigger") == 0) |
| (*flags_out) |= DEBUG_FLAG_TRIGGERS; |
| else if (xstrcasecmp(tok, "Triggers") == 0) |
| (*flags_out) |= DEBUG_FLAG_TRIGGERS; |
| else if (xstrcasecmp(tok, "CpuFrequency") == 0) |
| (*flags_out) |= DEBUG_FLAG_CPU_FREQ; |
| else if ((xstrcasecmp(tok, "Power") == 0) || |
| (xstrcasecmp(tok, "PowerSave") == 0)) |
| (*flags_out) |= DEBUG_FLAG_POWER; |
| else if (!xstrcasecmp(tok, "WorkQueue") || |
| !xstrcasecmp(tok, "WorkQ") || |
| !xstrcasecmp(tok, "ConMgr")) |
| (*flags_out) |= DEBUG_FLAG_CONMGR; |
| else { |
| error("Invalid DebugFlag: %s", tok); |
| (*flags_out) = 0; |
| rc = SLURM_ERROR; |
| 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"); |
| } |
| if (reconfig_flags & RECONFIG_KEEP_POWER_SAVE_SETTINGS) { |
| if (rc) |
| xstrcat(rc, ","); |
| xstrcat(rc, "KeepPowerSaveSettings"); |
| } |
| |
| 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 (xstrcasecmp(tok, "KeepPartInfo") == 0) |
| rc |= RECONFIG_KEEP_PART_INFO; |
| else if (xstrcasecmp(tok, "KeepPartState") == 0) |
| rc |= RECONFIG_KEEP_PART_STAT; |
| else if (xstrcasecmp(tok, "KeepPowerSaveSettings") == 0) |
| rc |= RECONFIG_KEEP_POWER_SAVE_SETTINGS; |
| else { |
| error("Invalid ReconfigFlag: %s", tok); |
| rc = NO_VAL16; |
| break; |
| } |
| tok = strtok_r(NULL, ",", &last); |
| } |
| xfree(tmp_str); |
| |
| return rc; |
| } |
| |
| extern void destroy_config_plugin_params(void *object) |
| { |
| config_plugin_params_t *plugin_ptr = (config_plugin_params_t *)object; |
| |
| if (plugin_ptr) { |
| xfree(plugin_ptr->name); |
| FREE_NULL_LIST(plugin_ptr->key_pairs); |
| xfree(object); |
| } |
| } |
| |
| extern void pack_config_plugin_params(void *in, uint16_t protocol_version, |
| buf_t *buff) |
| { |
| config_plugin_params_t *object = (config_plugin_params_t *)in; |
| |
| packstr(object->name, buff); |
| pack_key_pair_list((void *)object->key_pairs, protocol_version, buff); |
| } |
| |
| extern int unpack_config_plugin_params(void **object, uint16_t protocol_version, |
| buf_t *buff) |
| { |
| config_plugin_params_t *object_ptr = xmalloc(sizeof(*object_ptr)); |
| |
| *object = object_ptr; |
| safe_unpackstr(&object_ptr->name, buff); |
| |
| if (unpack_key_pair_list((void *) &object_ptr->key_pairs, |
| protocol_version, buff) != SLURM_SUCCESS) |
| goto unpack_error; |
| |
| return SLURM_SUCCESS; |
| |
| unpack_error: |
| destroy_config_plugin_params(object_ptr); |
| return SLURM_ERROR; |
| } |
| |
| extern void pack_config_plugin_params_list(void *in, uint16_t protocol_version, |
| buf_t *buff) |
| { |
| uint32_t count = NO_VAL; |
| |
| if (in) |
| count = list_count(in); |
| pack32(count, buff); |
| if (count && (count != NO_VAL)) { |
| list_itr_t *itr = list_iterator_create((list_t *) in); |
| config_plugin_params_t *obj = NULL; |
| while ((obj = list_next(itr))) { |
| pack_config_plugin_params(obj, protocol_version, buff); |
| } |
| list_iterator_destroy(itr); |
| } |
| } |
| |
| extern int unpack_config_plugin_params_list(void **plugin_params_l, |
| uint16_t protocol_version, |
| buf_t *buff) |
| { |
| uint32_t count = NO_VAL; |
| list_t *tmp_list = NULL; |
| |
| safe_unpack32(&count, buff); |
| if (count > NO_VAL) |
| goto unpack_error; |
| if (count != NO_VAL) { |
| tmp_list = list_create(destroy_config_plugin_params); |
| config_plugin_params_t *object = NULL; |
| int i; |
| for (i = 0; i < count; i++) { |
| if (unpack_config_plugin_params( |
| (void *)&object, protocol_version, buff) |
| == SLURM_ERROR) |
| goto unpack_error; |
| list_append(tmp_list, object); |
| } |
| *plugin_params_l = (void *)tmp_list; |
| } |
| return SLURM_SUCCESS; |
| |
| unpack_error: |
| FREE_NULL_LIST(tmp_list); |
| return SLURM_ERROR; |
| } |
| |
| extern void destroy_config_key_pair(void *object) |
| { |
| config_key_pair_t *key_pair_ptr = 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 protocol_version, |
| buf_t *buffer) |
| { |
| config_key_pair_t *object = in; |
| packstr(object->name, buffer); |
| packstr(object->value, buffer); |
| } |
| |
| extern int unpack_config_key_pair(void **object, uint16_t protocol_version, |
| buf_t *buffer) |
| { |
| config_key_pair_t *object_ptr = xmalloc(sizeof(*object_ptr)); |
| |
| *object = object_ptr; |
| safe_unpackstr(&object_ptr->name, buffer); |
| safe_unpackstr(&object_ptr->value, buffer); |
| |
| return SLURM_SUCCESS; |
| |
| unpack_error: |
| destroy_config_key_pair(object_ptr); |
| *object = NULL; |
| return SLURM_ERROR; |
| } |
| |
| extern void pack_key_pair_list(void *key_pairs, uint16_t protocol_version, |
| buf_t *buffer) |
| { |
| uint32_t count = NO_VAL; |
| |
| if (key_pairs) |
| count = list_count(key_pairs); |
| pack32(count, buffer); |
| if (count && (count != NO_VAL)) { |
| list_itr_t *itr = list_iterator_create((list_t *) key_pairs); |
| config_key_pair_t *key_pair = NULL; |
| while ((key_pair = list_next(itr))) { |
| pack_config_key_pair(key_pair, protocol_version, |
| buffer); |
| } |
| list_iterator_destroy(itr); |
| } |
| } |
| |
| extern int unpack_key_pair_list(void **key_pairs, uint16_t protocol_version, |
| buf_t *buffer) |
| { |
| uint32_t count = NO_VAL; |
| list_t *tmp_list = NULL; |
| |
| safe_unpack32(&count, buffer); |
| if (count > NO_VAL) |
| goto unpack_error; |
| if (count != NO_VAL) { |
| tmp_list = list_create(destroy_config_key_pair); |
| config_key_pair_t *object = NULL; |
| int i; |
| for (i = 0; i < count; i++) { |
| if (unpack_config_key_pair((void *)&object, |
| protocol_version, buffer) |
| == SLURM_ERROR) |
| goto unpack_error; |
| list_append(tmp_list, object); |
| } |
| } |
| |
| *key_pairs = (void *) tmp_list; |
| return SLURM_SUCCESS; |
| |
| unpack_error: |
| FREE_NULL_LIST(tmp_list); |
| 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 = xstrcmp(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"); |
| config_file_t *cached_config; |
| char *rc = NULL, *slash; |
| |
| if (!val) |
| val = default_slurm_config_file; |
| |
| /* |
| * Absolute paths are preserved as-is. |
| */ |
| if (conf_name && conf_name[0] == '/') |
| return xstrdup(conf_name); |
| |
| /* |
| * Config files such as plugstack.conf, topology.conf, and any |
| * non-absolute include files need special handling in "configless" |
| * operation as client commands. |
| */ |
| if (config_files && |
| (cached_config = list_find_first(config_files, find_conf_by_name, |
| conf_name)) && |
| cached_config->exists) |
| return xstrdup(cached_config->memfd_path); |
| |
| /* 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; |
| } |
| |
| /* |
| * Add nodes and corresponding pre-configured slurm_addr_t's to node conf hash |
| * tables. |
| * |
| * IN node_list - node_list allocated to job |
| * IN node_addrs - array of slurm_addr_t that corresponds to nodes built from |
| * host_list. See build_node_details(). |
| * RET return SLURM_SUCCESS on success, SLURM_ERROR otherwise. |
| */ |
| extern int add_remote_nodes_to_conf_tbls(char *node_list, |
| slurm_addr_t *node_addrs) |
| { |
| char *hostname = NULL; |
| hostlist_t *host_list = NULL; |
| int i = 0; |
| |
| xassert(node_list); |
| xassert(node_addrs); |
| |
| if ((host_list = hostlist_create(node_list)) == NULL) { |
| error("hostlist_create error for %s: %m", |
| node_list); |
| return SLURM_ERROR; |
| } |
| |
| slurm_conf_lock(); |
| _init_slurmd_nodehash(); |
| |
| while ((hostname = hostlist_shift(host_list))) { |
| _internal_conf_remove_node(hostname); |
| _push_to_hashtbls(hostname, hostname, NULL, NULL, 0, |
| &node_addrs[i++], true, true, false); |
| free(hostname); |
| } |
| slurm_conf_unlock(); |
| |
| hostlist_destroy(host_list); |
| |
| return SLURM_SUCCESS; |
| } |
| |
| extern void slurm_conf_add_node(node_record_t *node_ptr) |
| { |
| slurm_conf_lock(); |
| _init_slurmd_nodehash(); |
| |
| _push_to_hashtbls(node_ptr->name, node_ptr->node_hostname, |
| node_ptr->comm_name, node_ptr->bcast_address, |
| node_ptr->port, NULL, false, false, false); |
| slurm_conf_unlock(); |
| } |
| |
| static void _internal_conf_remove_node(char *node_name) |
| { |
| int alias_idx; |
| names_ll_t *p_prev = NULL, *p_curr; |
| |
| alias_idx = _get_hash_idx(node_name); |
| |
| p_curr = node_to_host_hashtbl[alias_idx]; |
| while (p_curr) { |
| if (!xstrcmp(p_curr->alias, node_name)) { |
| if (p_prev) |
| p_prev->next_alias = p_curr->next_alias; |
| else |
| node_to_host_hashtbl[alias_idx] = |
| p_curr->next_alias; |
| break; |
| } |
| |
| p_prev = p_curr; |
| p_curr = p_curr->next_alias; |
| } |
| |
| if (p_curr) { |
| _remove_host_to_node_link(p_curr); |
| |
| _free_single_names_ll_t(p_curr); |
| } |
| |
| } |
| |
| extern void slurm_conf_remove_node(char *node_name) |
| { |
| slurm_conf_lock(); |
| _init_slurmd_nodehash(); |
| _internal_conf_remove_node(node_name); |
| slurm_conf_unlock(); |
| } |
| |
| extern char *conf_get_opt_str(const char *opts, const char *arg) |
| { |
| char *str, *last = NULL, *ret = NULL, *tok; |
| int len; |
| |
| if (!opts || !opts[0]) |
| return NULL; |
| |
| len = strlen(arg); |
| str = xstrdup(opts); |
| |
| tok = strtok_r(str, ",", &last); |
| while (tok) { |
| if (!xstrncmp(tok, arg, len)) { |
| if (*(tok + len)) |
| ret = xstrdup(tok + len); |
| break; |
| } |
| tok = strtok_r(NULL, ",", &last); |
| } |
| |
| xfree(str); |
| |
| return ret; |
| } |