blob: 075a02471e9709bd171e778f337b511e2aae662c [file] [log] [blame]
/*****************************************************************************\
* slurmdb_defs.c - definitions used by slurmdb api
******************************************************************************
* Copyright (C) 2010 Lawrence Livermore National Security.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Danny Auble da@llnl.gov, et. al.
* 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 <stdlib.h>
#include "src/common/assoc_mgr.h"
#include "src/common/log.h"
#include "src/common/parse_time.h"
#include "src/interfaces/select.h"
#include "src/interfaces/auth.h"
#include "src/common/slurm_protocol_defs.h"
#include "src/interfaces/jobacct_gather.h"
#include "src/common/slurm_time.h"
#include "src/common/slurmdb_defs.h"
#include "src/common/xmalloc.h"
#include "src/common/xstring.h"
#include "src/slurmdbd/read_config.h"
#include "src/common/print_fields.h"
#define FORMAT_STRING_SIZE 34
slurmdb_cluster_rec_t *working_cluster_rec = NULL;
static void _free_res_cond_members(slurmdb_res_cond_t *res_cond);
static void _free_res_rec_members(slurmdb_res_rec_t *res);
strong_alias(get_qos_complete_str_bitstr, slurmdb_get_qos_complete_str_bitstr);
static void _free_clus_res_rec_members(slurmdb_clus_res_rec_t *clus_res)
{
if (clus_res) {
xfree(clus_res->cluster);
}
}
static void _free_cluster_rec_members(slurmdb_cluster_rec_t *cluster)
{
if (cluster) {
FREE_NULL_LIST(cluster->accounting_list);
xfree(cluster->control_host);
xfree(cluster->dim_size);
FREE_NULL_LIST(cluster->fed.feature_list);
xfree(cluster->fed.name);
slurm_persist_conn_destroy(cluster->fed.recv);
slurm_persist_conn_destroy(cluster->fed.send);
slurm_mutex_destroy(&cluster->lock);
xfree(cluster->name);
xfree(cluster->nodes);
slurmdb_destroy_assoc_rec(cluster->root_assoc);
FREE_NULL_LIST(cluster->send_rpc);
xfree(cluster->tres_str);
}
}
static void _free_federation_rec_members(slurmdb_federation_rec_t *federation)
{
if (federation) {
xfree(federation->name);
FREE_NULL_LIST(federation->cluster_list);
}
}
static void _free_wckey_rec_members(slurmdb_wckey_rec_t *wckey)
{
if (wckey) {
FREE_NULL_LIST(wckey->accounting_list);
xfree(wckey->cluster);
xfree(wckey->name);
xfree(wckey->user);
}
}
static void _free_cluster_cond_members(slurmdb_cluster_cond_t *cluster_cond)
{
if (cluster_cond) {
FREE_NULL_LIST(cluster_cond->cluster_list);
FREE_NULL_LIST(cluster_cond->federation_list);
FREE_NULL_LIST(cluster_cond->format_list);
FREE_NULL_LIST(cluster_cond->rpc_version_list);
}
}
static void _free_federation_cond_members(slurmdb_federation_cond_t *fed_cond)
{
if (fed_cond) {
FREE_NULL_LIST(fed_cond->cluster_list);
FREE_NULL_LIST(fed_cond->federation_list);
}
}
static void _free_tres_cond_members(slurmdb_tres_cond_t *tres_cond)
{
if (tres_cond) {
FREE_NULL_LIST(tres_cond->id_list);
FREE_NULL_LIST(tres_cond->name_list);
FREE_NULL_LIST(tres_cond->type_list);
}
}
static void _free_res_cond_members(slurmdb_res_cond_t *res_cond)
{
if (res_cond) {
FREE_NULL_LIST(res_cond->allowed_list);
FREE_NULL_LIST(res_cond->cluster_list);
FREE_NULL_LIST(res_cond->description_list);
FREE_NULL_LIST(res_cond->id_list);
FREE_NULL_LIST(res_cond->manager_list);
FREE_NULL_LIST(res_cond->name_list);
FREE_NULL_LIST(res_cond->server_list);
FREE_NULL_LIST(res_cond->type_list);
}
}
static void _free_res_rec_members(slurmdb_res_rec_t *res)
{
if (res) {
FREE_NULL_LIST(res->clus_res_list);
slurmdb_destroy_clus_res_rec(res->clus_res_rec);
xfree(res->description);
xfree(res->manager);
xfree(res->name);
xfree(res->server);
}
}
/*
* Comparator used for sorting immediate children of acct_hierarchical_recs
*
* returns: -1 assoc_a < assoc_b 0: assoc_a == assoc_b 1: assoc_a > assoc_b
*
*/
static int _sort_children_list(void *v1, void *v2)
{
int diff = 0;
slurmdb_hierarchical_rec_t *assoc_a;
slurmdb_hierarchical_rec_t *assoc_b;
assoc_a = *(slurmdb_hierarchical_rec_t **)v1;
assoc_b = *(slurmdb_hierarchical_rec_t **)v2;
/* Since all these associations are on the same level we don't
* have to check the lineage
*/
/* check to see if this is a user association or an account.
* We want the accounts at the bottom
*/
if (assoc_a->assoc->user && !assoc_b->assoc->user)
return -1;
else if (!assoc_a->assoc->user && assoc_b->assoc->user)
return 1;
/* Sort by alpha */
diff = xstrcmp(assoc_a->sort_name, assoc_b->sort_name);
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
return 0;
}
/*
* Comparator used for sorting immediate children of acct_hierarchical_recs by
* lineage
*
* returns: -1 assoc_a < assoc_b 0: assoc_a == assoc_b 1: assoc_a > assoc_b
*
*/
static int _sort_assoc_by_lineage_asc(void *v1, void *v2)
{
slurmdb_assoc_rec_t *assoc_a = *(slurmdb_assoc_rec_t **)v1;
slurmdb_assoc_rec_t *assoc_b = *(slurmdb_assoc_rec_t **)v2;
int diff = slurm_sort_char_list_asc(&assoc_a->cluster,
&assoc_b->cluster);
if (diff)
return diff;
return slurm_sort_char_list_asc(&assoc_a->lineage, &assoc_b->lineage);
}
static int _sort_slurmdb_hierarchical_rec_list(
list_t *slurmdb_hierarchical_rec_list)
{
slurmdb_hierarchical_rec_t *slurmdb_hierarchical_rec = NULL;
list_itr_t *itr;
if (!list_count(slurmdb_hierarchical_rec_list))
return SLURM_SUCCESS;
list_sort(slurmdb_hierarchical_rec_list, (ListCmpF)_sort_children_list);
itr = list_iterator_create(slurmdb_hierarchical_rec_list);
while((slurmdb_hierarchical_rec = list_next(itr))) {
if (list_count(slurmdb_hierarchical_rec->children))
_sort_slurmdb_hierarchical_rec_list(
slurmdb_hierarchical_rec->children);
}
list_iterator_destroy(itr);
return SLURM_SUCCESS;
}
static int _append_hierarchical_children_ret_list(
list_t *ret_list, list_t *slurmdb_hierarchical_rec_list)
{
slurmdb_hierarchical_rec_t *slurmdb_hierarchical_rec = NULL;
list_itr_t *itr;
if (!ret_list)
return SLURM_ERROR;
if (!list_count(slurmdb_hierarchical_rec_list))
return SLURM_SUCCESS;
itr = list_iterator_create(slurmdb_hierarchical_rec_list);
while((slurmdb_hierarchical_rec = list_next(itr))) {
list_append(ret_list, slurmdb_hierarchical_rec->assoc);
if (list_count(slurmdb_hierarchical_rec->children))
_append_hierarchical_children_ret_list(
ret_list, slurmdb_hierarchical_rec->children);
}
list_iterator_destroy(itr);
return SLURM_SUCCESS;
}
static char *_get_qos_list_str(list_t *qos_list)
{
char *qos_char = NULL;
list_itr_t *itr = NULL;
slurmdb_qos_rec_t *qos = NULL;
if (!qos_list)
return NULL;
itr = list_iterator_create(qos_list);
while((qos = list_next(itr))) {
if (qos_char)
xstrfmtcat(qos_char, ",%s", qos->name);
else
xstrcat(qos_char, qos->name);
}
list_iterator_destroy(itr);
return qos_char;
}
extern int slurmdb_setup_cluster_rec(slurmdb_cluster_rec_t *cluster_rec)
{
xassert(cluster_rec);
if (!cluster_rec->control_port) {
debug("Slurmctld on '%s' hasn't registered yet.",
cluster_rec->name);
return SLURM_ERROR;
}
slurm_set_addr(&cluster_rec->control_addr,
cluster_rec->control_port,
cluster_rec->control_host);
if (slurm_addr_is_unspec(&cluster_rec->control_addr)) {
error("Unable to establish control "
"machine address for '%s'(%s:%u)",
cluster_rec->name,
cluster_rec->control_host,
cluster_rec->control_port);
return SLURM_ERROR;
}
if (cluster_rec->dimensions > 1) {
int number, i, len;
char *nodes = cluster_rec->nodes;
cluster_rec->dim_size = xmalloc(sizeof(int) *
cluster_rec->dimensions);
len = strlen(nodes);
i = len - cluster_rec->dimensions;
if (nodes[len-1] == ']')
i--;
if (i > 0) {
number = xstrntol(nodes + i, NULL,
cluster_rec->dimensions, 36);
hostlist_parse_int_to_array(
number, cluster_rec->dim_size,
cluster_rec->dimensions, 36);
/* all calculations this is for should
* be expecting 0 not to count as a
* number so add 1 to it. */
for (i=0; i<cluster_rec->dimensions; i++)
cluster_rec->dim_size[i]++;
}
}
return SLURM_SUCCESS;
}
extern void slurmdb_job_cond_def_start_end(slurmdb_job_cond_t *job_cond)
{
time_t now = time(NULL);
if (!job_cond ||
(job_cond->flags & JOBCOND_FLAG_RUNAWAY) ||
(job_cond->flags & JOBCOND_FLAG_NO_DEFAULT_USAGE))
return;
/*
* Defaults for start (S) and end (E) times:
* - with -j and -s:
* -S defaults to Epoch 0
* -E defaults to -S (unless no -S then Now)
* - with only -j (NOT -s)
* -S defaults to Epoch 0
* -E defaults to Now
* - with only -s (NOT -j):
* -S defaults to Now
* -E defaults to -S
* - without either -j nor -s:
* -S defaults to Midnight
* -E defaults to Now
*/
if (job_cond->state_list && list_count(job_cond->state_list)) {
if (!job_cond->usage_start &&
(!job_cond->step_list || !list_count(job_cond->step_list)))
job_cond->usage_start = now;
if (job_cond->usage_start && !job_cond->usage_end)
job_cond->usage_end = job_cond->usage_start;
} else if (!job_cond->step_list || !list_count(job_cond->step_list)) {
if (!job_cond->usage_start) {
struct tm start_tm;
job_cond->usage_start = now;
if (!localtime_r(&job_cond->usage_start, &start_tm)) {
error("Couldn't get localtime from %ld",
(long)job_cond->usage_start);
} else {
start_tm.tm_sec = 0;
start_tm.tm_min = 0;
start_tm.tm_hour = 0;
job_cond->usage_start = slurm_mktime(&start_tm);
}
}
}
if (!job_cond->usage_end)
job_cond->usage_end = now;
/*
* The query will be exclusive of the end time, that is [S,E).
* We must adjust E when E==S to include S, and when E==Now to
* include the current second.
*/
if ((job_cond->usage_end == job_cond->usage_start) ||
(job_cond->usage_end == now))
job_cond->usage_end++;
}
#define T(flag, str) { flag, XSTRINGIFY(flag), str }
static const struct {
slurmdb_qos_flags_t flag;
char *flag_str;
char *str;
} slurmdb_qos_flags_map[] = {
T(QOS_FLAG_DELETED, "Deleted"),
T(QOS_FLAG_DENY_LIMIT, "DenyOnLimit"),
T(QOS_FLAG_ENFORCE_USAGE_THRES, "EnforceUsageThreshold"),
T(QOS_FLAG_PART_MIN_NODE, "PartitionMinNodes"),
T(QOS_FLAG_PART_MAX_NODE, "PartitionMaxNodes"),
T(QOS_FLAG_PART_TIME_LIMIT, "PartitionTimeLimit"),
T(QOS_FLAG_REQ_RESV, "RequiresReservation"),
T(QOS_FLAG_OVER_PART_QOS, "OverPartQOS"),
T(QOS_FLAG_PART_QOS, "PartQOS"),
T(QOS_FLAG_NO_RESERVE, "NoReserve"),
T(QOS_FLAG_NO_DECAY, "NoDecay"),
T(QOS_FLAG_RELATIVE, "Relative"),
T(QOS_FLAG_USAGE_FACTOR_SAFE, "UsageFactorSafe"),
};
#undef T
static int _str_2_qos_flags(char *flag_in, slurmdb_qos_flags_t *flags_ptr)
{
if (!flag_in || !flag_in[0])
return SLURM_SUCCESS;
for (int i = 0; i < ARRAY_SIZE(slurmdb_qos_flags_map); i++) {
if (!xstrncasecmp(flag_in, slurmdb_qos_flags_map[i].str,
strlen(flag_in))) {
*flags_ptr |= slurmdb_qos_flags_map[i].flag;
return SLURM_SUCCESS;
}
}
debug("%s: Unable to match %s to a slurmdbd_qos_flags_t flag",
__func__, flag_in);
return EINVAL;
}
static uint32_t _str_2_res_flags(char *flags)
{
if (xstrcasestr(flags, "Absolute"))
return SLURMDB_RES_FLAG_ABSOLUTE;
return 0;
}
static uint32_t _str_2_job_flags(char *flags)
{
if (xstrcasestr(flags, "None"))
return SLURMDB_JOB_FLAG_NONE;
if (xstrcasestr(flags, "SchedSubmit"))
return SLURMDB_JOB_FLAG_SUBMIT;
if (xstrcasestr(flags, "SchedMain"))
return SLURMDB_JOB_FLAG_SCHED;
if (xstrcasestr(flags, "SchedBackfill"))
return SLURMDB_JOB_FLAG_BACKFILL;
if (xstrcasestr(flags, "StartReceived"))
return SLURMDB_JOB_FLAG_START_R;
return SLURMDB_JOB_FLAG_NOTSET;
}
static will_run_response_msg_t *_job_will_run(job_desc_msg_t *req)
{
will_run_response_msg_t *will_run_resp = NULL;
int rc;
rc = slurm_job_will_run2(req, &will_run_resp);
if (rc >= 0) {
will_run_resp->cluster_name =
xstrdup(working_cluster_rec->name);
if (get_log_level() >= LOG_LEVEL_DEBUG) {
char buf[256];
slurm_make_time_str(&will_run_resp->start_time, buf,
sizeof(buf));
debug("Job %u to start at %s on cluster %s using %u processors on nodes %s in partition %s",
will_run_resp->job_id, buf,
working_cluster_rec->name,
will_run_resp->proc_cnt, will_run_resp->node_list,
will_run_resp->part_name);
if (will_run_resp->preemptee_job_id) {
list_itr_t *itr;
uint32_t *job_id_ptr;
char *job_list = NULL, *sep = "";
itr = list_iterator_create(
will_run_resp->preemptee_job_id);
while ((job_id_ptr = list_next(itr))) {
if (job_list)
sep = ",";
xstrfmtcat(job_list, "%s%u",
sep, *job_id_ptr);
}
list_iterator_destroy(itr);
debug(" Preempts: %s", job_list);
xfree(job_list);
}
}
}
return will_run_resp;
}
static int _set_qos_bit_from_string(bitstr_t *valid_qos, char *name)
{
void (*my_function) (bitstr_t *b, bitoff_t bit);
bitoff_t bit = 0;
xassert(valid_qos);
if (!name)
return SLURM_ERROR;
if (name[0] == '-') {
name++;
my_function = bit_clear;
} else if (name[0] == '+') {
name++;
my_function = bit_set;
} else
my_function = bit_set;
if ((bit = atoi(name)) >= bit_size(valid_qos))
return SLURM_ERROR;
(*(my_function))(valid_qos, bit);
return SLURM_SUCCESS;
}
static char *_create_hash_rec_id(slurmdb_assoc_rec_t *assoc, bool parent)
{
/*
* Add comma to key to distinguish between id and cluster name
* .e.g
* associd: 11 cluster: foo
* associd: 1 cluster: 1foo
*/
return xstrdup_printf("%u,%s",
parent ? assoc->parent_id : assoc->id,
assoc->cluster);
}
static void _arch_hash_rec_id(void *item, const char **key, uint32_t *key_len)
{
slurmdb_hierarchical_rec_t *arch_rec = item;
xfree(arch_rec->key);
arch_rec->key = _create_hash_rec_id(arch_rec->assoc, false);
*key = arch_rec->key;
*key_len = strlen(*key);
}
static int _list_copy_coord(void *x, void *key)
{
slurmdb_coord_rec_t *coord_in = x;
list_t **ret_list = key;
slurmdb_coord_rec_t *coord = xmalloc(sizeof(*coord));
if (!*ret_list)
*ret_list = list_create(slurmdb_destroy_coord_rec);
list_append(*ret_list, coord);
coord->name = xstrdup(coord_in->name);
coord->direct = coord_in->direct;
return 0;
}
extern slurmdb_job_rec_t *slurmdb_create_job_rec(void)
{
slurmdb_job_rec_t *job = xmalloc(sizeof(slurmdb_job_rec_t));
job->array_task_id = NO_VAL;
job->derived_ec = NO_VAL;
job->state = JOB_PENDING;
job->steps = list_create(slurmdb_destroy_step_rec);
job->requid = -1;
job->resvid = NO_VAL;
return job;
}
extern slurmdb_step_rec_t *slurmdb_create_step_rec(void)
{
slurmdb_step_rec_t *step = xmalloc(sizeof(slurmdb_step_rec_t));
memset(&step->stats, 0, sizeof(slurmdb_stats_t));
step->step_id.step_id = NO_VAL;
step->step_id.step_het_comp = NO_VAL;
step->state = NO_VAL;
step->exitcode = NO_VAL;
step->elapsed = NO_VAL;
step->tot_cpu_sec = NO_VAL;
step->tot_cpu_usec = NO_VAL;
step->requid = -1;
return step;
}
extern slurmdb_assoc_usage_t *slurmdb_create_assoc_usage(int tres_cnt)
{
slurmdb_assoc_usage_t *usage;
int alloc_size;
if (!tres_cnt)
fatal("%s: You need to give a tres_cnt to call this function",
__func__);
usage = xmalloc(sizeof(slurmdb_assoc_usage_t));
usage->level_shares = NO_VAL;
usage->shares_norm = (double)NO_VAL64;
usage->usage_efctv = 0;
usage->usage_norm = (long double)NO_VAL;
usage->usage_raw = 0;
usage->level_fs = 0;
usage->fs_factor = 0;
usage->tres_cnt = tres_cnt;
alloc_size = sizeof(uint64_t) * tres_cnt;
usage->grp_used_tres = xmalloc(alloc_size);
usage->grp_used_tres_run_secs = xmalloc(alloc_size);
usage->usage_tres_raw = xmalloc(sizeof(long double) * tres_cnt);
return usage;
}
extern slurmdb_qos_usage_t *slurmdb_create_qos_usage(int tres_cnt)
{
slurmdb_qos_usage_t *usage =
xmalloc(sizeof(slurmdb_qos_usage_t));
if (tres_cnt) {
int alloc_size = sizeof(uint64_t) * tres_cnt;
usage->tres_cnt = tres_cnt;
usage->grp_used_tres_run_secs = xmalloc(alloc_size);
usage->grp_used_tres = xmalloc(alloc_size);
usage->usage_tres_raw = xmalloc(sizeof(long double) * tres_cnt);
}
return usage;
}
extern void slurmdb_destroy_assoc_usage(void *object)
{
slurmdb_assoc_usage_t *usage =
(slurmdb_assoc_usage_t *)object;
if (usage) {
FREE_NULL_LIST(usage->children_list);
FREE_NULL_BITMAP(usage->grp_node_bitmap);
xfree(usage->grp_node_job_cnt);
xfree(usage->grp_used_tres_run_secs);
xfree(usage->grp_used_tres);
xfree(usage->usage_tres_raw);
FREE_NULL_BITMAP(usage->valid_qos);
xfree(usage);
}
}
extern void slurmdb_destroy_bf_usage(void *object)
{
slurmdb_destroy_bf_usage_members(object);
xfree(object);
}
extern void slurmdb_destroy_bf_usage_members(void *object)
{
return;
}
extern void slurmdb_destroy_qos_usage(void *object)
{
slurmdb_qos_usage_t *usage =
(slurmdb_qos_usage_t *)object;
if (usage) {
FREE_NULL_LIST(usage->acct_limit_list);
FREE_NULL_BITMAP(usage->grp_node_bitmap);
xfree(usage->grp_node_job_cnt);
xfree(usage->grp_used_tres_run_secs);
xfree(usage->grp_used_tres);
FREE_NULL_LIST(usage->job_list);
xfree(usage->usage_tres_raw);
FREE_NULL_LIST(usage->user_limit_list);
xfree(usage);
}
}
extern void slurmdb_free_user_rec_members(slurmdb_user_rec_t *slurmdb_user)
{
if (!slurmdb_user)
return;
FREE_NULL_LIST(slurmdb_user->assoc_list);
FREE_NULL_LIST(slurmdb_user->coord_accts);
xfree(slurmdb_user->default_acct);
xfree(slurmdb_user->default_wckey);
xfree(slurmdb_user->name);
xfree(slurmdb_user->old_name);
FREE_NULL_LIST(slurmdb_user->wckey_list);
slurmdb_destroy_bf_usage(slurmdb_user->bf_usage);
}
extern void slurmdb_destroy_user_rec(void *object)
{
slurmdb_user_rec_t *slurmdb_user = (slurmdb_user_rec_t *)object;
if (!slurmdb_user)
return;
slurmdb_free_user_rec_members(slurmdb_user);
xfree(slurmdb_user);
}
extern void slurmdb_destroy_account_rec(void *object)
{
slurmdb_account_rec_t *slurmdb_account =
(slurmdb_account_rec_t *)object;
if (slurmdb_account) {
FREE_NULL_LIST(slurmdb_account->assoc_list);
FREE_NULL_LIST(slurmdb_account->coordinators);
xfree(slurmdb_account->description);
xfree(slurmdb_account->name);
xfree(slurmdb_account->organization);
xfree(slurmdb_account);
}
}
extern void slurmdb_destroy_coord_rec(void *object)
{
slurmdb_coord_rec_t *slurmdb_coord =
(slurmdb_coord_rec_t *)object;
if (slurmdb_coord) {
xfree(slurmdb_coord->name);
xfree(slurmdb_coord);
}
}
extern void slurmdb_destroy_cluster_accounting_rec(void *object)
{
slurmdb_cluster_accounting_rec_t *clusteracct_rec =
(slurmdb_cluster_accounting_rec_t *)object;
if (clusteracct_rec) {
slurmdb_destroy_tres_rec_noalloc(
&clusteracct_rec->tres_rec);
xfree(clusteracct_rec);
}
}
extern void slurmdb_destroy_clus_res_rec(void *object)
{
slurmdb_clus_res_rec_t *slurmdb_clus_res =
(slurmdb_clus_res_rec_t *)object;
if (slurmdb_clus_res) {
_free_clus_res_rec_members(slurmdb_clus_res);
xfree(slurmdb_clus_res);
}
}
extern void slurmdb_destroy_cluster_rec(void *object)
{
slurmdb_cluster_rec_t *slurmdb_cluster =
(slurmdb_cluster_rec_t *)object;
if (slurmdb_cluster) {
_free_cluster_rec_members(slurmdb_cluster);
xfree(slurmdb_cluster);
}
}
extern void slurmdb_destroy_federation_rec(void *object)
{
slurmdb_federation_rec_t *slurmdb_federation =
(slurmdb_federation_rec_t *)object;
if (slurmdb_federation) {
_free_federation_rec_members(slurmdb_federation);
xfree(slurmdb_federation);
}
}
extern void slurmdb_destroy_accounting_rec(void *object)
{
slurmdb_accounting_rec_t *slurmdb_accounting =
(slurmdb_accounting_rec_t *)object;
if (slurmdb_accounting) {
slurmdb_destroy_tres_rec_noalloc(
&slurmdb_accounting->tres_rec);
xfree(slurmdb_accounting);
}
}
extern void slurmdb_free_assoc_rec_members(slurmdb_assoc_rec_t *assoc)
{
if (assoc) {
FREE_NULL_LIST(assoc->accounting_list);
xfree(assoc->acct);
xfree(assoc->cluster);
xfree(assoc->comment);
xfree(assoc->grp_tres);
xfree(assoc->grp_tres_ctld);
xfree(assoc->grp_tres_mins);
xfree(assoc->grp_tres_mins_ctld);
xfree(assoc->grp_tres_run_mins);
xfree(assoc->grp_tres_run_mins_ctld);
xfree(assoc->lineage);
xfree(assoc->max_tres_mins_pj);
xfree(assoc->max_tres_mins_ctld);
xfree(assoc->max_tres_run_mins);
xfree(assoc->max_tres_run_mins_ctld);
xfree(assoc->max_tres_pj);
xfree(assoc->max_tres_ctld);
xfree(assoc->max_tres_pn);
xfree(assoc->max_tres_pn_ctld);
xfree(assoc->parent_acct);
xfree(assoc->partition);
FREE_NULL_LIST(assoc->qos_list);
xfree(assoc->user);
/* Account with previously deleted users */
if (assoc->leaf_usage != assoc->usage)
slurmdb_destroy_assoc_usage(assoc->leaf_usage);
/*
* Be crazy safe and set this to NULL as it should never be used
* again!
*/
assoc->leaf_usage = NULL;
slurmdb_destroy_assoc_usage(assoc->usage);
/* NOTE assoc->user_rec is a soft reference, do not free here */
assoc->user_rec = NULL;
slurmdb_destroy_bf_usage(assoc->bf_usage);
}
}
extern void slurmdb_destroy_assoc_rec(void *object)
{
slurmdb_assoc_rec_t *slurmdb_assoc =
(slurmdb_assoc_rec_t *)object;
if (slurmdb_assoc) {
slurmdb_free_assoc_rec_members(slurmdb_assoc);
xfree(slurmdb_assoc);
}
}
extern void slurmdb_destroy_event_rec(void *object)
{
slurmdb_event_rec_t *slurmdb_event =
(slurmdb_event_rec_t *)object;
if (slurmdb_event) {
xfree(slurmdb_event->cluster);
xfree(slurmdb_event->cluster_nodes);
xfree(slurmdb_event->node_name);
xfree(slurmdb_event->reason);
xfree(slurmdb_event->tres_str);
xfree(slurmdb_event);
}
}
extern void slurmdb_destroy_instance_rec(void *object)
{
slurmdb_instance_rec_t *slurmdb_instance = object;
if (slurmdb_instance) {
xfree(slurmdb_instance->cluster);
xfree(slurmdb_instance->extra);
xfree(slurmdb_instance->instance_id);
xfree(slurmdb_instance->instance_type);
xfree(slurmdb_instance->node_name);
xfree(slurmdb_instance);
}
return;
}
extern void slurmdb_destroy_job_rec(void *object)
{
slurmdb_job_rec_t *job = (slurmdb_job_rec_t *)object;
if (job) {
xfree(job->account);
xfree(job->admin_comment);
xfree(job->array_task_str);
xfree(job->blockid);
xfree(job->cluster);
xfree(job->constraints);
xfree(job->container);
xfree(job->derived_es);
xfree(job->env);
xfree(job->extra);
xfree(job->failed_node);
xfree(job->jobname);
xfree(job->licenses);
xfree(job->lineage);
xfree(job->mcs_label);
xfree(job->partition);
xfree(job->qos_req);
xfree(job->nodes);
xfree(job->resv_name);
xfree(job->resv_req);
xfree(job->script);
FREE_NULL_LIST(job->steps);
xfree(job->std_err);
xfree(job->std_in);
xfree(job->std_out);
xfree(job->submit_line);
xfree(job->system_comment);
xfree(job->tres_alloc_str);
xfree(job->tres_req_str);
xfree(job->user);
xfree(job->wckey);
xfree(job->work_dir);
xfree(job);
}
}
extern void slurmdb_free_qos_rec_members(slurmdb_qos_rec_t *qos)
{
if (qos) {
xfree(qos->description);
xfree(qos->grp_tres);
xfree(qos->grp_tres_ctld);
xfree(qos->grp_tres_mins);
xfree(qos->grp_tres_mins_ctld);
xfree(qos->grp_tres_run_mins);
xfree(qos->grp_tres_run_mins_ctld);
xfree(qos->max_tres_mins_pj);
xfree(qos->max_tres_mins_pj_ctld);
xfree(qos->max_tres_run_mins_pa);
xfree(qos->max_tres_run_mins_pa_ctld);
xfree(qos->max_tres_run_mins_pu);
xfree(qos->max_tres_run_mins_pu_ctld);
xfree(qos->max_tres_pa);
xfree(qos->max_tres_pa_ctld);
xfree(qos->max_tres_pj);
xfree(qos->max_tres_pj_ctld);
xfree(qos->max_tres_pn);
xfree(qos->max_tres_pn_ctld);
xfree(qos->max_tres_pu);
xfree(qos->max_tres_pu_ctld);
xfree(qos->min_tres_pj);
xfree(qos->min_tres_pj_ctld);
xfree(qos->name);
FREE_NULL_BITMAP(qos->preempt_bitstr);
FREE_NULL_LIST(qos->preempt_list);
xfree(qos->relative_tres_cnt);
slurmdb_destroy_qos_usage(qos->usage);
}
}
extern void slurmdb_destroy_qos_rec(void *object)
{
slurmdb_qos_rec_t *slurmdb_qos = (slurmdb_qos_rec_t *)object;
if (slurmdb_qos) {
slurmdb_free_qos_rec_members(slurmdb_qos);
xfree(slurmdb_qos);
}
}
extern void slurmdb_destroy_reservation_rec(void *object)
{
slurmdb_reservation_rec_t *slurmdb_resv =
(slurmdb_reservation_rec_t *)object;
if (slurmdb_resv) {
xfree(slurmdb_resv->assocs);
xfree(slurmdb_resv->cluster);
xfree(slurmdb_resv->comment);
xfree(slurmdb_resv->name);
xfree(slurmdb_resv->nodes);
xfree(slurmdb_resv->node_inx);
xfree(slurmdb_resv->tres_str);
xfree(slurmdb_resv);
}
}
extern void slurmdb_destroy_step_rec(void *object)
{
slurmdb_step_rec_t *step = (slurmdb_step_rec_t *)object;
if (step) {
xfree(step->container);
xfree(step->nodes);
xfree(step->pid_str);
slurmdb_free_slurmdb_stats_members(&step->stats);
xfree(step->stepname);
xfree(step->cwd);
xfree(step->std_err);
xfree(step->std_in);
xfree(step->std_out);
xfree(step->submit_line);
xfree(step->tres_alloc_str);
xfree(step);
}
}
extern void slurmdb_destroy_res_rec(void *object)
{
slurmdb_res_rec_t *slurmdb_res =
(slurmdb_res_rec_t *)object;
if (slurmdb_res) {
_free_res_rec_members(slurmdb_res);
xfree(slurmdb_res);
}
}
extern void slurmdb_destroy_txn_rec(void *object)
{
slurmdb_txn_rec_t *slurmdb_txn = (slurmdb_txn_rec_t *)object;
if (slurmdb_txn) {
xfree(slurmdb_txn->accts);
xfree(slurmdb_txn->actor_name);
xfree(slurmdb_txn->clusters);
xfree(slurmdb_txn->set_info);
xfree(slurmdb_txn->users);
xfree(slurmdb_txn->where_query);
xfree(slurmdb_txn);
}
}
extern void slurmdb_destroy_wckey_rec(void *object)
{
slurmdb_wckey_rec_t *wckey = (slurmdb_wckey_rec_t *)object;
if (wckey) {
_free_wckey_rec_members(wckey);
xfree(wckey);
}
}
extern void slurmdb_destroy_archive_rec(void *object)
{
slurmdb_archive_rec_t *arch_rec = (slurmdb_archive_rec_t *)object;
if (arch_rec) {
xfree(arch_rec->archive_file);
xfree(arch_rec->insert);
xfree(arch_rec);
}
}
extern void slurmdb_destroy_tres_rec_noalloc(void *object)
{
slurmdb_tres_rec_t *tres_rec = (slurmdb_tres_rec_t *)object;
if (!tres_rec)
return;
xfree(tres_rec->name);
xfree(tres_rec->type);
}
extern void slurmdb_destroy_tres_rec(void *object)
{
slurmdb_tres_rec_t *tres_rec = (slurmdb_tres_rec_t *)object;
if (tres_rec) {
slurmdb_destroy_tres_rec_noalloc(tres_rec);
xfree(tres_rec);
}
}
extern void slurmdb_destroy_report_assoc_rec(void *object)
{
slurmdb_report_assoc_rec_t *slurmdb_report_assoc =
(slurmdb_report_assoc_rec_t *)object;
if (slurmdb_report_assoc) {
xfree(slurmdb_report_assoc->acct);
xfree(slurmdb_report_assoc->cluster);
xfree(slurmdb_report_assoc->parent_acct);
FREE_NULL_LIST(slurmdb_report_assoc->tres_list);
xfree(slurmdb_report_assoc->user);
xfree(slurmdb_report_assoc);
}
}
extern void slurmdb_destroy_report_user_rec(void *object)
{
slurmdb_report_user_rec_t *slurmdb_report_user =
(slurmdb_report_user_rec_t *)object;
if (slurmdb_report_user) {
xfree(slurmdb_report_user->acct);
FREE_NULL_LIST(slurmdb_report_user->acct_list);
FREE_NULL_LIST(slurmdb_report_user->assoc_list);
xfree(slurmdb_report_user->name);
FREE_NULL_LIST(slurmdb_report_user->tres_list);
xfree(slurmdb_report_user);
}
}
extern void slurmdb_destroy_report_cluster_rec(void *object)
{
slurmdb_report_cluster_rec_t *slurmdb_report_cluster =
(slurmdb_report_cluster_rec_t *)object;
if (slurmdb_report_cluster) {
FREE_NULL_LIST(slurmdb_report_cluster->assoc_list);
xfree(slurmdb_report_cluster->name);
FREE_NULL_LIST(slurmdb_report_cluster->tres_list);
FREE_NULL_LIST(slurmdb_report_cluster->user_list);
xfree(slurmdb_report_cluster);
}
}
extern void slurmdb_destroy_user_cond(void *object)
{
slurmdb_user_cond_t *slurmdb_user = (slurmdb_user_cond_t *)object;
if (slurmdb_user) {
slurmdb_destroy_assoc_cond(slurmdb_user->assoc_cond);
FREE_NULL_LIST(slurmdb_user->def_acct_list);
FREE_NULL_LIST(slurmdb_user->def_wckey_list);
xfree(slurmdb_user);
}
}
extern void slurmdb_destroy_account_cond(void *object)
{
slurmdb_account_cond_t *slurmdb_account =
(slurmdb_account_cond_t *)object;
if (slurmdb_account) {
slurmdb_destroy_assoc_cond(slurmdb_account->assoc_cond);
FREE_NULL_LIST(slurmdb_account->description_list);
FREE_NULL_LIST(slurmdb_account->organization_list);
xfree(slurmdb_account);
}
}
extern void slurmdb_destroy_cluster_cond(void *object)
{
slurmdb_cluster_cond_t *slurmdb_cluster =
(slurmdb_cluster_cond_t *)object;
if (slurmdb_cluster) {
_free_cluster_cond_members(slurmdb_cluster);
xfree(slurmdb_cluster);
}
}
extern void slurmdb_destroy_federation_cond(void *object)
{
slurmdb_federation_cond_t *slurmdb_federation =
(slurmdb_federation_cond_t *)object;
if (slurmdb_federation) {
_free_federation_cond_members(slurmdb_federation);
xfree(slurmdb_federation);
}
}
extern void slurmdb_destroy_tres_cond(void *object)
{
slurmdb_tres_cond_t *slurmdb_tres =
(slurmdb_tres_cond_t *)object;
if (slurmdb_tres) {
_free_tres_cond_members(slurmdb_tres);
xfree(slurmdb_tres);
}
}
extern void slurmdb_destroy_assoc_cond(void *object)
{
slurmdb_assoc_cond_t *slurmdb_assoc =
(slurmdb_assoc_cond_t *)object;
if (slurmdb_assoc) {
FREE_NULL_LIST(slurmdb_assoc->acct_list);
FREE_NULL_LIST(slurmdb_assoc->cluster_list);
FREE_NULL_LIST(slurmdb_assoc->def_qos_id_list);
FREE_NULL_LIST(slurmdb_assoc->id_list);
FREE_NULL_LIST(slurmdb_assoc->partition_list);
FREE_NULL_LIST(slurmdb_assoc->parent_acct_list);
FREE_NULL_LIST(slurmdb_assoc->qos_list);
FREE_NULL_LIST(slurmdb_assoc->user_list);
xfree(slurmdb_assoc);
}
}
extern void slurmdb_destroy_event_cond(void *object)
{
slurmdb_event_cond_t *slurmdb_event =
(slurmdb_event_cond_t *)object;
if (slurmdb_event) {
FREE_NULL_LIST(slurmdb_event->cluster_list);
FREE_NULL_LIST(slurmdb_event->format_list);
FREE_NULL_LIST(slurmdb_event->reason_list);
FREE_NULL_LIST(slurmdb_event->reason_uid_list);
FREE_NULL_LIST(slurmdb_event->state_list);
xfree(slurmdb_event->node_list);
xfree(slurmdb_event);
}
}
extern void slurmdb_destroy_instance_cond(void *object)
{
slurmdb_instance_cond_t *slurmdb_instance = object;
if (slurmdb_instance) {
FREE_NULL_LIST(slurmdb_instance->cluster_list);
FREE_NULL_LIST(slurmdb_instance->extra_list);
FREE_NULL_LIST(slurmdb_instance->format_list);
FREE_NULL_LIST(slurmdb_instance->instance_id_list);
FREE_NULL_LIST(slurmdb_instance->instance_type_list);
xfree(slurmdb_instance->node_list);
xfree(slurmdb_instance);
}
}
extern void slurmdb_destroy_job_cond_members(slurmdb_job_cond_t *job_cond)
{
if (!job_cond)
return;
FREE_NULL_LIST(job_cond->acct_list);
FREE_NULL_LIST(job_cond->associd_list);
FREE_NULL_LIST(job_cond->cluster_list);
FREE_NULL_LIST(job_cond->constraint_list);
FREE_NULL_LIST(job_cond->groupid_list);
FREE_NULL_LIST(job_cond->jobname_list);
FREE_NULL_LIST(job_cond->partition_list);
FREE_NULL_LIST(job_cond->qos_list);
FREE_NULL_LIST(job_cond->reason_list);
FREE_NULL_LIST(job_cond->resv_list);
FREE_NULL_LIST(job_cond->resvid_list);
FREE_NULL_LIST(job_cond->step_list);
FREE_NULL_LIST(job_cond->state_list);
xfree(job_cond->used_nodes);
FREE_NULL_LIST(job_cond->userid_list);
FREE_NULL_LIST(job_cond->wckey_list);
}
extern void slurmdb_destroy_job_cond(void *object)
{
slurmdb_job_cond_t *job_cond =
(slurmdb_job_cond_t *)object;
if (job_cond) {
slurmdb_destroy_job_cond_members(job_cond);
xfree(job_cond);
}
}
extern void slurmdb_destroy_qos_cond(void *object)
{
slurmdb_qos_cond_t *slurmdb_qos = (slurmdb_qos_cond_t *)object;
if (slurmdb_qos) {
FREE_NULL_LIST(slurmdb_qos->id_list);
FREE_NULL_LIST(slurmdb_qos->name_list);
xfree(slurmdb_qos);
}
}
extern void slurmdb_destroy_res_cond(void *object)
{
slurmdb_res_cond_t *slurmdb_res =
(slurmdb_res_cond_t *)object;
if (slurmdb_res) {
_free_res_cond_members(slurmdb_res);
xfree(slurmdb_res);
}
}
extern void slurmdb_destroy_reservation_cond(void *object)
{
slurmdb_reservation_cond_t *slurmdb_resv =
(slurmdb_reservation_cond_t *)object;
if (slurmdb_resv) {
FREE_NULL_LIST(slurmdb_resv->cluster_list);
FREE_NULL_LIST(slurmdb_resv->id_list);
FREE_NULL_LIST(slurmdb_resv->name_list);
xfree(slurmdb_resv->nodes);
xfree(slurmdb_resv);
}
}
extern void slurmdb_destroy_txn_cond(void *object)
{
slurmdb_txn_cond_t *slurmdb_txn = (slurmdb_txn_cond_t *)object;
if (slurmdb_txn) {
FREE_NULL_LIST(slurmdb_txn->acct_list);
FREE_NULL_LIST(slurmdb_txn->action_list);
FREE_NULL_LIST(slurmdb_txn->actor_list);
FREE_NULL_LIST(slurmdb_txn->cluster_list);
FREE_NULL_LIST(slurmdb_txn->id_list);
FREE_NULL_LIST(slurmdb_txn->info_list);
FREE_NULL_LIST(slurmdb_txn->name_list);
FREE_NULL_LIST(slurmdb_txn->user_list);
xfree(slurmdb_txn);
}
}
extern void slurmdb_destroy_wckey_cond(void *object)
{
slurmdb_wckey_cond_t *wckey = (slurmdb_wckey_cond_t *)object;
if (wckey) {
FREE_NULL_LIST(wckey->cluster_list);
FREE_NULL_LIST(wckey->id_list);
FREE_NULL_LIST(wckey->name_list);
FREE_NULL_LIST(wckey->user_list);
xfree(wckey);
}
}
extern void slurmdb_destroy_archive_cond(void *object)
{
slurmdb_archive_cond_t *arch_cond = (slurmdb_archive_cond_t *)object;
if (arch_cond) {
xfree(arch_cond->archive_dir);
xfree(arch_cond->archive_script);
slurmdb_destroy_job_cond(arch_cond->job_cond);
xfree(arch_cond);
}
}
extern void slurmdb_free_add_assoc_cond_members(
slurmdb_add_assoc_cond_t *add_assoc)
{
if (!add_assoc)
return;
FREE_NULL_LIST(add_assoc->acct_list);
slurmdb_free_assoc_rec_members(&add_assoc->assoc);
FREE_NULL_LIST(add_assoc->cluster_list);
xfree(add_assoc->default_acct);
FREE_NULL_LIST(add_assoc->partition_list);
FREE_NULL_LIST(add_assoc->user_list);
FREE_NULL_LIST(add_assoc->wckey_list);
}
extern void slurmdb_destroy_add_assoc_cond(void *object)
{
slurmdb_add_assoc_cond_t *add_assoc = object;
if (!add_assoc)
return;
slurmdb_free_add_assoc_cond_members(add_assoc);
xfree(add_assoc);
}
extern void slurmdb_destroy_update_object(void *object)
{
slurmdb_update_object_t *slurmdb_update =
(slurmdb_update_object_t *) object;
if (slurmdb_update) {
FREE_NULL_LIST(slurmdb_update->objects);
xfree(slurmdb_update);
}
}
extern void slurmdb_destroy_used_limits(void *object)
{
slurmdb_used_limits_t *slurmdb_used_limits =
(slurmdb_used_limits_t *)object;
if (slurmdb_used_limits) {
xfree(slurmdb_used_limits->acct);
FREE_NULL_BITMAP(slurmdb_used_limits->node_bitmap);
xfree(slurmdb_used_limits->node_job_cnt);
xfree(slurmdb_used_limits->tres);
xfree(slurmdb_used_limits->tres_run_secs);
xfree(slurmdb_used_limits);
}
}
extern void slurmdb_destroy_print_tree(void *object)
{
slurmdb_print_tree_t *slurmdb_print_tree =
(slurmdb_print_tree_t *)object;
if (slurmdb_print_tree) {
xfree(slurmdb_print_tree->name);
xfree(slurmdb_print_tree->print_name);
xfree(slurmdb_print_tree->spaces);
xfree(slurmdb_print_tree);
}
}
extern void slurmdb_destroy_hierarchical_rec(void *object)
{
/* Most of this is pointers to something else that will be
* destroyed elsewhere.
*/
slurmdb_hierarchical_rec_t *slurmdb_hierarchical_rec =
(slurmdb_hierarchical_rec_t *)object;
if (slurmdb_hierarchical_rec) {
xfree(slurmdb_hierarchical_rec->key);
FREE_NULL_LIST(slurmdb_hierarchical_rec->children);
xfree(slurmdb_hierarchical_rec);
}
}
extern void slurmdb_destroy_report_job_grouping(void *object)
{
slurmdb_report_job_grouping_t *job_grouping =
(slurmdb_report_job_grouping_t *)object;
if (job_grouping) {
FREE_NULL_LIST(job_grouping->jobs);
FREE_NULL_LIST(job_grouping->tres_list);
xfree(job_grouping);
}
}
extern void slurmdb_destroy_report_acct_grouping(void *object)
{
slurmdb_report_acct_grouping_t *acct_grouping =
(slurmdb_report_acct_grouping_t *)object;
if (acct_grouping) {
xfree(acct_grouping->acct);
FREE_NULL_LIST(acct_grouping->groups);
xfree(acct_grouping->lineage);
FREE_NULL_LIST(acct_grouping->tres_list);
xfree(acct_grouping);
}
}
extern void slurmdb_destroy_report_cluster_grouping(void *object)
{
slurmdb_report_cluster_grouping_t *cluster_grouping =
(slurmdb_report_cluster_grouping_t *)object;
if (cluster_grouping) {
xfree(cluster_grouping->cluster);
FREE_NULL_LIST(cluster_grouping->acct_list);
FREE_NULL_LIST(cluster_grouping->tres_list);
xfree(cluster_grouping);
}
}
extern list_t *slurmdb_get_info_cluster(char *cluster_names)
{
slurmdb_cluster_rec_t *cluster_rec = NULL;
slurmdb_cluster_cond_t cluster_cond;
list_t *temp_list = NULL;
char *cluster_name = NULL;
void *db_conn = NULL;
list_itr_t *itr, *itr2;
bool all_clusters = 0;
if (cluster_names && !xstrcasecmp(cluster_names, "all"))
all_clusters = 1;
db_conn = acct_storage_g_get_connection(0, NULL, 1,
slurm_conf.cluster_name);
slurmdb_init_cluster_cond(&cluster_cond, 0);
if (cluster_names && !all_clusters) {
cluster_cond.cluster_list = list_create(xfree_ptr);
slurm_addto_char_list(cluster_cond.cluster_list, cluster_names);
}
if (!(temp_list = acct_storage_g_get_clusters(db_conn, getuid(),
&cluster_cond))) {
error("Problem talking to database");
goto end_it;
}
itr = list_iterator_create(temp_list);
if (!cluster_names || all_clusters) {
while ((cluster_rec = list_next(itr))) {
if (slurmdb_setup_cluster_rec(cluster_rec) !=
SLURM_SUCCESS) {
list_delete_item(itr);
}
}
} else {
itr2 = list_iterator_create(cluster_cond.cluster_list);
while ((cluster_name = list_next(itr2))) {
while ((cluster_rec = list_next(itr))) {
if (!xstrcmp(cluster_name, cluster_rec->name))
break;
}
if (!cluster_rec) {
error("No cluster '%s' known by database.",
cluster_name);
goto next;
}
if (slurmdb_setup_cluster_rec(cluster_rec) !=
SLURM_SUCCESS) {
list_delete_item(itr);
}
next:
list_iterator_reset(itr);
}
list_iterator_destroy(itr2);
}
list_iterator_destroy(itr);
end_it:
FREE_NULL_LIST(cluster_cond.cluster_list);
acct_storage_g_close_connection(&db_conn);
if (temp_list && !list_count(temp_list)) {
FREE_NULL_LIST(temp_list);
}
return temp_list;
}
extern void slurmdb_init_assoc_rec(slurmdb_assoc_rec_t *assoc,
bool free_it)
{
if (!assoc)
return;
if (free_it)
slurmdb_free_assoc_rec_members(assoc);
memset(assoc, 0, sizeof(slurmdb_assoc_rec_t));
assoc->def_qos_id = NO_VAL;
assoc->is_def = NO_VAL16;
/* assoc->grp_tres_mins = NULL; */
/* assoc->grp_tres_run_mins = NULL; */
/* assoc->grp_tres = NULL; */
assoc->grp_jobs = NO_VAL;
assoc->grp_jobs_accrue = NO_VAL;
assoc->grp_submit_jobs = NO_VAL;
assoc->grp_wall = NO_VAL;
/* assoc->level_shares = NO_VAL; */
/* assoc->max_tres_mins_pj = NULL; */
/* assoc->max_tres_run_mins = NULL; */
/* assoc->max_tres_pj = NULL; */
assoc->max_jobs = NO_VAL;
assoc->max_jobs_accrue = NO_VAL;
assoc->min_prio_thresh = NO_VAL;
assoc->max_submit_jobs = NO_VAL;
assoc->max_wall_pj = NO_VAL;
assoc->priority = NO_VAL;
/* assoc->shares_norm = NO_VAL64; */
assoc->shares_raw = NO_VAL;
/* assoc->usage_efctv = 0; */
/* assoc->usage_norm = (long double)NO_VAL; */
/* assoc->usage_raw = 0; */
}
extern void slurmdb_init_clus_res_rec(slurmdb_clus_res_rec_t *clus_res,
bool free_it)
{
if (!clus_res)
return;
if (free_it)
_free_clus_res_rec_members(clus_res);
memset(clus_res, 0, sizeof(slurmdb_clus_res_rec_t));
clus_res->allowed = NO_VAL;
}
extern void slurmdb_init_cluster_rec(slurmdb_cluster_rec_t *cluster,
bool free_it)
{
if (!cluster)
return;
if (free_it)
_free_cluster_rec_members(cluster);
memset(cluster, 0, sizeof(slurmdb_cluster_rec_t));
cluster->flags = NO_VAL;
cluster->fed.state = NO_VAL;
slurm_mutex_init(&cluster->lock);
}
extern void slurmdb_init_federation_rec(slurmdb_federation_rec_t *federation,
bool free_it)
{
if (!federation)
return;
if (free_it)
_free_federation_rec_members(federation);
memset(federation, 0, sizeof(slurmdb_federation_rec_t));
federation->flags = FEDERATION_FLAG_NOTSET;
}
extern void slurmdb_init_instance_rec(slurmdb_instance_rec_t *instance)
{
if (!instance)
return;
memset(instance, 0, sizeof(slurmdb_instance_rec_t));
/* instance->cluster = NULL; */
/* instance->extra = NULL; */
/* instance->instance_id = NULL; */
/* instance->instance_type = NULL; */
/* instance->node_name = NULL; */
instance->time_end = NO_VAL;
instance->time_start = NO_VAL;
}
extern void slurmdb_init_qos_rec(slurmdb_qos_rec_t *qos, bool free_it,
uint32_t init_val)
{
if (!qos)
return;
if (free_it)
slurmdb_free_qos_rec_members(qos);
memset(qos, 0, sizeof(slurmdb_qos_rec_t));
qos->flags = QOS_FLAG_NOTSET;
qos->grace_time = init_val;
qos->preempt_mode = (uint16_t)init_val;
qos->preempt_exempt_time = init_val;
qos->priority = init_val;
/* qos->grp_tres_mins = NULL; */
/* qos->grp_tres_run_mins = NULL; */
/* qos->grp_tres = NULL; */
qos->grp_jobs = init_val;
qos->grp_jobs_accrue = init_val;
qos->grp_submit_jobs = init_val;
qos->grp_wall = init_val;
qos->limit_factor = (double)init_val;
/* qos->max_tres_mins_pj = NULL; */
/* qos->max_tres_run_mins_pa = NULL; */
/* qos->max_tres_run_mins_pu = NULL; */
/* qos->max_tres_pa = NULL; */
/* qos->max_tres_pj = NULL; */
/* qos->max_tres_pu = NULL; */
qos->max_jobs_pa = init_val;
qos->max_jobs_pu = init_val;
qos->max_jobs_accrue_pa = init_val;
qos->max_jobs_accrue_pu = init_val;
qos->min_prio_thresh = init_val;
qos->max_submit_jobs_pa = init_val;
qos->max_submit_jobs_pu = init_val;
qos->max_wall_pj = init_val;
/* qos->min_tres_pj = NULL; */
qos->usage_factor = (double)init_val;
qos->usage_thres = (double)init_val;
}
extern void slurmdb_init_res_rec(slurmdb_res_rec_t *res,
bool free_it)
{
if (!res)
return;
if (free_it)
_free_res_rec_members(res);
memset(res, 0, sizeof(slurmdb_res_rec_t));
res->count = NO_VAL;
res->flags = SLURMDB_RES_FLAG_NOTSET;
res->id = NO_VAL;
res->last_consumed = NO_VAL;
res->allocated = NO_VAL;
res->type = SLURMDB_RESOURCE_NOTSET;
}
extern void slurmdb_init_wckey_rec(slurmdb_wckey_rec_t *wckey, bool free_it)
{
if (!wckey)
return;
if (free_it)
_free_wckey_rec_members(wckey);
memset(wckey, 0, sizeof(slurmdb_wckey_rec_t));
wckey->is_def = NO_VAL16;
}
extern void slurmdb_init_add_assoc_cond(slurmdb_add_assoc_cond_t *add_assoc,
bool free_it)
{
if (!add_assoc)
return;
if (free_it)
slurmdb_free_add_assoc_cond_members(add_assoc);
memset(add_assoc, 0, sizeof(*add_assoc));
slurmdb_init_assoc_rec(&add_assoc->assoc, free_it);
}
extern void slurmdb_init_tres_cond(slurmdb_tres_cond_t *tres,
bool free_it)
{
if (!tres)
return;
if (free_it)
_free_tres_cond_members(tres);
memset(tres, 0, sizeof(slurmdb_tres_cond_t));
tres->count = NO_VAL;
}
extern void slurmdb_init_cluster_cond(slurmdb_cluster_cond_t *cluster,
bool free_it)
{
if (!cluster)
return;
if (free_it)
_free_cluster_cond_members(cluster);
memset(cluster, 0, sizeof(slurmdb_cluster_cond_t));
cluster->flags = NO_VAL;
}
extern void slurmdb_init_federation_cond(slurmdb_federation_cond_t *federation,
bool free_it)
{
if (!federation)
return;
if (free_it)
_free_federation_cond_members(federation);
memset(federation, 0, sizeof(slurmdb_federation_cond_t));
}
extern void slurmdb_init_res_cond(slurmdb_res_cond_t *res,
bool free_it)
{
if (!res)
return;
if (free_it)
_free_res_cond_members(res);
memset(res, 0, sizeof(slurmdb_res_cond_t));
res->flags = SLURMDB_RES_FLAG_NOTSET;
}
extern char *slurmdb_qos_str(list_t *qos_list, uint32_t level)
{
slurmdb_qos_rec_t *qos = NULL;
if (!qos_list) {
error("We need a qos list to translate");
return NULL;
} else if (!level) {
debug2("no level");
return "";
}
qos = list_find_first(qos_list, slurmdb_find_qos_in_list, &level);
if (qos)
return qos->name;
else
return NULL;
}
extern uint32_t str_2_slurmdb_qos(list_t *qos_list, char *level)
{
list_itr_t *itr = NULL;
slurmdb_qos_rec_t *qos = NULL;
char *working_level = NULL;
if (!qos_list) {
error("We need a qos list to translate");
return NO_VAL;
} else if (!level) {
debug2("no level");
return 0;
}
if (level[0] == '+' || level[0] == '-')
working_level = level+1;
else
working_level = level;
itr = list_iterator_create(qos_list);
while((qos = list_next(itr))) {
if (!xstrcasecmp(working_level, qos->name))
break;
}
list_iterator_destroy(itr);
if (qos)
return qos->id;
else
return NO_VAL;
}
extern char *slurmdb_federation_flags_str(uint32_t flags)
{
char *federation_flags = NULL;
if (flags & FEDERATION_FLAG_NOTSET)
return xstrdup("NotSet");
#if 0
/* Remove when there are actually flags since the flags will be
* comma-separated. */
if (federation_flags)
federation_flags[strlen(federation_flags)-1] = '\0';
#endif
return federation_flags;
}
#define T(flag, str) { flag, XSTRINGIFY(flag), str }
static const struct {
slurmdb_acct_flags_t flag;
char *flag_str;
char *str;
} slurmdb_acct_flags_map[] = {
T(SLURMDB_ACCT_FLAG_DELETED, "Deleted"),
T(SLURMDB_ACCT_FLAG_WASSOC, "WithAssociations"),
T(SLURMDB_ACCT_FLAG_WCOORD, "WithCoordinators"),
T(SLURMDB_ACCT_FLAG_USER_COORD_NO, "NoUsersAreCoords"),
T(SLURMDB_ACCT_FLAG_USER_COORD, "UsersAreCoords"),
};
#undef T
static int _str_2_acct_flag(const char *flag_in,
slurmdb_acct_flags_t *flags_ptr)
{
if (!flag_in || !flag_in[0])
return SLURM_SUCCESS;
for (int i = 0; i < ARRAY_SIZE(slurmdb_acct_flags_map); i++) {
if (!xstrncasecmp(flag_in, slurmdb_acct_flags_map[i].str,
strlen(flag_in))) {
*flags_ptr |= slurmdb_acct_flags_map[i].flag;
return SLURM_SUCCESS;
}
}
debug("%s: Unable to match %s to a slurmdbd_acct_flags_t flag",
__func__, flag_in);
return EINVAL;
}
extern int str_2_slurmdb_acct_flags(const char *str,
slurmdb_acct_flags_t *flags_ptr)
{
char *token, *my_flags, *last = NULL;
int rc = SLURM_SUCCESS;
/* Always reset flags */
*flags_ptr = SLURMDB_ACCT_FLAG_NONE;
my_flags = xstrdup(str);
token = strtok_r(my_flags, ",", &last);
while (token && !(rc = _str_2_acct_flag(token, flags_ptr)))
token = strtok_r(NULL, ",", &last);
xfree(my_flags);
return rc;
}
extern char *slurmdb_acct_flags_2_str(slurmdb_acct_flags_t flags)
{
char *acct_flags = NULL, *at = NULL;
if (flags == SLURMDB_ACCT_FLAG_NONE)
return xstrdup("None");
for (int i = 0; i < ARRAY_SIZE(slurmdb_acct_flags_map); i++) {
if ((slurmdb_acct_flags_map[i].flag & flags) ==
slurmdb_acct_flags_map[i].flag)
xstrfmtcatat(acct_flags, &at, "%s%s",
(acct_flags ? "," : ""),
slurmdb_acct_flags_map[i].str);
}
return acct_flags;
}
#define T(flag, str) { flag, XSTRINGIFY(flag), str }
static const struct {
slurmdb_assoc_flags_t flag;
char *flag_str;
char *str;
} slurmdb_assoc_flags_map[] = {
T(ASSOC_FLAG_DELETED, "Deleted"),
T(ASSOC_FLAG_NO_UPDATE, "NoUpdate"),
T(ASSOC_FLAG_EXACT, "Exact"),
T(ASSOC_FLAG_USER_COORD_NO, "NoUsersAreCoords"),
T(ASSOC_FLAG_USER_COORD, "UsersAreCoords"),
};
#undef T
static int _str_2_assoc_flag(const char *flag_in,
slurmdb_assoc_flags_t *flags_ptr)
{
if (!flag_in || !flag_in[0])
return SLURM_SUCCESS;
for (int i = 0; i < ARRAY_SIZE(slurmdb_assoc_flags_map); i++) {
if (!xstrncasecmp(flag_in, slurmdb_assoc_flags_map[i].str,
strlen(flag_in))) {
*flags_ptr |= slurmdb_assoc_flags_map[i].flag;
return slurmdb_assoc_flags_map[i].flag;
}
}
debug("%s: Unable to match %s to a slurmdbd_assoc_flags_t flag",
__func__, flag_in);
return EINVAL;
}
extern int str_2_slurmdb_assoc_flags(const char *str,
slurmdb_assoc_flags_t *flags_ptr)
{
char *token, *my_flags, *last = NULL;
int rc = SLURM_SUCCESS;
/* Always reset flags */
*flags_ptr = ASSOC_FLAG_NONE;
my_flags = xstrdup(str);
token = strtok_r(my_flags, ",", &last);
while (token && !(rc = _str_2_assoc_flag(token, flags_ptr)))
token = strtok_r(NULL, ",", &last);
xfree(my_flags);
return rc;
}
extern char *slurmdb_assoc_flags_2_str(slurmdb_assoc_flags_t flags)
{
char *assoc_flags = NULL, *at = NULL;
if (flags == ASSOC_FLAG_NONE)
return xstrdup("None");
for (int i = 0; i < ARRAY_SIZE(slurmdb_assoc_flags_map); i++) {
if ((slurmdb_assoc_flags_map[i].flag & flags) ==
slurmdb_assoc_flags_map[i].flag)
xstrfmtcatat(assoc_flags, &at, "%s%s",
(assoc_flags ? "," : ""),
slurmdb_assoc_flags_map[i].str);
}
return assoc_flags;
}
static uint32_t _str_2_federation_flags(char *flags)
{
return 0;
}
extern uint32_t str_2_federation_flags(char *flags, int option)
{
uint32_t federation_flags = 0;
char *token, *my_flags, *last = NULL;
if (!flags) {
error("We need a federation flags string to translate");
return FEDERATION_FLAG_NOTSET;
} else if (atoi(flags) == -1) {
/* clear them all */
federation_flags = INFINITE;
federation_flags &= (~FEDERATION_FLAG_NOTSET &
~FEDERATION_FLAG_ADD);
return federation_flags;
}
my_flags = xstrdup(flags);
token = strtok_r(my_flags, ",", &last);
while (token) {
federation_flags |= _str_2_federation_flags(token);
token = strtok_r(NULL, ",", &last);
}
xfree(my_flags);
if (!federation_flags)
federation_flags = FEDERATION_FLAG_NOTSET;
else if (option == '+')
federation_flags |= FEDERATION_FLAG_ADD;
else if (option == '-')
federation_flags |= FEDERATION_FLAG_REMOVE;
return federation_flags;
}
extern char *slurmdb_cluster_fed_states_str(uint32_t state)
{
int base = (state & CLUSTER_FED_STATE_BASE);
bool drain_flag = (state & CLUSTER_FED_STATE_DRAIN);
bool remove_flag = (state & CLUSTER_FED_STATE_REMOVE);
if (base == CLUSTER_FED_STATE_ACTIVE) {
if (remove_flag && drain_flag)
return "DRAIN+REMOVE";
else if (drain_flag)
return "DRAIN";
else
return "ACTIVE";
} else if (base == CLUSTER_FED_STATE_INACTIVE) {
if (remove_flag && drain_flag)
return "DRAINED+REMOVE";
else if (drain_flag)
return "DRAINED";
else
return "INACTIVE";
} else if (base == CLUSTER_FED_STATE_NA)
return "NA";
return "?";
}
extern uint32_t str_2_cluster_fed_states(char *state)
{
uint32_t fed_state = 0;
if (!state) {
error("We need a cluster federation state string to translate");
return SLURM_ERROR;
}
if (!xstrncasecmp(state, "Active", strlen(state)))
fed_state = CLUSTER_FED_STATE_ACTIVE;
else if (!xstrncasecmp(state, "Inactive", strlen(state)))
fed_state = CLUSTER_FED_STATE_INACTIVE;
else if (!xstrncasecmp(state, "DRAIN", strlen(state))) {
fed_state = CLUSTER_FED_STATE_ACTIVE;
fed_state |= CLUSTER_FED_STATE_DRAIN;
} else if (!xstrncasecmp(state, "DRAIN+REMOVE", strlen(state))) {
fed_state = CLUSTER_FED_STATE_ACTIVE;
fed_state |= (CLUSTER_FED_STATE_DRAIN |
CLUSTER_FED_STATE_REMOVE);
}
return fed_state;
}
extern char *slurmdb_job_flags_str(uint32_t flags)
{
char *job_flags = NULL;
if (flags == SLURMDB_JOB_FLAG_NONE)
return xstrdup("None");
if (flags & SLURMDB_JOB_FLAG_NOTSET)
xstrcat(job_flags, "SchedNotSet");
else if (flags & SLURMDB_JOB_FLAG_SUBMIT)
xstrcat(job_flags, "SchedSubmit");
else if (flags & SLURMDB_JOB_FLAG_SCHED)
xstrcat(job_flags, "SchedMain");
else if (flags & SLURMDB_JOB_FLAG_BACKFILL)
xstrcat(job_flags, "SchedBackfill");
if (flags & SLURMDB_JOB_FLAG_START_R)
xstrfmtcat(job_flags, "%sStartReceived", job_flags ? "," : "");
return job_flags;
}
extern uint32_t str_2_job_flags(char *flags)
{
uint32_t job_flags = 0;
char *token, *my_flags, *last = NULL;
if (!flags) {
error("We need a server job flags string to translate");
return SLURMDB_JOB_FLAG_NONE;
}
my_flags = xstrdup(flags);
token = strtok_r(my_flags, ",", &last);
while (token) {
job_flags |= _str_2_job_flags(token);
if (job_flags & SLURMDB_JOB_FLAG_NOTSET) {
error("%s: Invalid job flag %s", __func__, token);
xfree(my_flags);
return SLURMDB_JOB_FLAG_NOTSET;
}
token = strtok_r(NULL, ",", &last);
}
xfree(my_flags);
return job_flags;
}
extern char *slurmdb_qos_flags_str(slurmdb_qos_flags_t flags)
{
char *qos_flags = NULL, *at = NULL;
if (flags == QOS_FLAG_NOTSET)
return xstrdup("NotSet");
for (int i = 0; i < ARRAY_SIZE(slurmdb_qos_flags_map); i++) {
if ((slurmdb_qos_flags_map[i].flag & flags) ==
slurmdb_qos_flags_map[i].flag)
xstrfmtcatat(qos_flags, &at, "%s%s",
(qos_flags ? "," : ""),
slurmdb_qos_flags_map[i].str);
}
return qos_flags;
}
extern slurmdb_qos_flags_t str_2_qos_flags(char *flags, int option)
{
slurmdb_qos_flags_t qos_flags = 0;
char *token, *my_flags, *last = NULL;
int rc = SLURM_SUCCESS;
if (!flags) {
error("We need a qos flags string to translate");
return QOS_FLAG_NOTSET;
} else if (atoi(flags) == -1) {
/* clear them all */
qos_flags = INFINITE;
qos_flags &= (~QOS_FLAG_NOTSET &
~QOS_FLAG_ADD);
return qos_flags;
}
my_flags = xstrdup(flags);
token = strtok_r(my_flags, ",", &last);
while (token && !(rc = _str_2_qos_flags(token, &qos_flags)))
token = strtok_r(NULL, ",", &last);
xfree(my_flags);
if (rc || !qos_flags)
qos_flags = QOS_FLAG_NOTSET;
else if (option == '+')
qos_flags |= QOS_FLAG_ADD;
else if (option == '-')
qos_flags |= QOS_FLAG_REMOVE;
return qos_flags;
}
extern char *slurmdb_res_flags_str(uint32_t flags)
{
char *res_flags = NULL;
if (flags & SLURMDB_RES_FLAG_NOTSET)
return xstrdup("NotSet");
if (flags & SLURMDB_RES_FLAG_ADD)
xstrcat(res_flags, "Add,");
if (flags & SLURMDB_RES_FLAG_REMOVE)
xstrcat(res_flags, "Remove,");
if (flags & SLURMDB_RES_FLAG_ABSOLUTE)
xstrcat(res_flags, "Absolute,");
if (res_flags)
res_flags[strlen(res_flags)-1] = '\0';
return res_flags;
}
extern uint32_t str_2_res_flags(char *flags, int option)
{
uint32_t res_flags = 0;
char *token, *my_flags, *last = NULL;
if (!flags) {
error("We need a server resource flags string to translate");
return SLURMDB_RES_FLAG_NOTSET;
} else if (atoi(flags) == -1) {
/* clear them all */
res_flags = INFINITE;
res_flags &= (SLURMDB_RES_FLAG_NOTSET &
~SLURMDB_RES_FLAG_ADD);
return res_flags;
}
my_flags = xstrdup(flags);
token = strtok_r(my_flags, ",", &last);
while (token) {
res_flags |= _str_2_res_flags(token);
token = strtok_r(NULL, ",", &last);
}
xfree(my_flags);
if (!res_flags)
res_flags = SLURMDB_RES_FLAG_NOTSET;
else if (option == '+')
res_flags |= SLURMDB_RES_FLAG_ADD;
else if (option == '-')
res_flags |= SLURMDB_RES_FLAG_REMOVE;
return res_flags;
}
extern char *slurmdb_res_type_str(slurmdb_resource_type_t type)
{
switch (type) {
case SLURMDB_RESOURCE_NOTSET:
return "Not Set";
break;
case SLURMDB_RESOURCE_LICENSE:
return "License";
break;
}
return "Unknown";
}
extern char *slurmdb_admin_level_str(slurmdb_admin_level_t level)
{
switch(level) {
case SLURMDB_ADMIN_NOTSET:
return "Not Set";
break;
case SLURMDB_ADMIN_NONE:
return "None";
break;
case SLURMDB_ADMIN_OPERATOR:
return "Operator";
break;
case SLURMDB_ADMIN_SUPER_USER:
return "Administrator";
break;
}
return "Unknown";
}
extern slurmdb_admin_level_t str_2_slurmdb_admin_level(char *level)
{
if (!level) {
return SLURMDB_ADMIN_NOTSET;
} else if (!xstrncasecmp(level, "None", 1)) {
return SLURMDB_ADMIN_NONE;
} else if (!xstrncasecmp(level, "Operator", 1)) {
return SLURMDB_ADMIN_OPERATOR;
} else if (!xstrncasecmp(level, "SuperUser", 1)
|| !xstrncasecmp(level, "Admin", 1)) {
return SLURMDB_ADMIN_SUPER_USER;
} else {
return SLURMDB_ADMIN_NOTSET;
}
}
extern int slurmdb_ping(char *rem_host)
{
int rc;
persist_conn_t *persist_conn = xmalloc(sizeof(*persist_conn));
persist_conn->cluster_name = xstrdup(slurm_conf.cluster_name);
persist_conn->flags = PERSIST_FLAG_DBD | PERSIST_FLAG_SUPPRESS_ERR;
persist_conn->r_uid = SLURM_AUTH_UID_ANY;
persist_conn->rem_host = xstrdup(rem_host);
persist_conn->rem_port = slurm_conf.accounting_storage_port;
persist_conn->timeout = slurm_conf.msg_timeout * 1000;
persist_conn->version = SLURM_PROTOCOL_VERSION;
rc = slurm_persist_conn_open(persist_conn);
slurm_persist_conn_destroy(persist_conn);
return rc;
}
static void _ping_slurmdbd(slurmdbd_ping_t *ping, int offset)
{
DEF_TIMERS;
ping->offset = offset;
START_TIMER;
ping->pinged = !slurmdb_ping(ping->hostname);
END_TIMER;
ping->latency = DELTA_TIMER;
}
extern slurmdbd_ping_t *slurmdb_ping_all(void)
{
slurmdbd_ping_t *pings = NULL;
int slurmdbd_cnt = 0;
int i = 0;
if (slurm_conf.accounting_storage_host)
slurmdbd_cnt++;
else
return NULL;
if (slurm_conf.accounting_storage_backup_host)
slurmdbd_cnt++;
/* Allocate enough space for backup ping if needed */
pings = xcalloc(slurmdbd_cnt + 1, sizeof(*pings));
pings[i].hostname = slurm_conf.accounting_storage_host;
_ping_slurmdbd(&pings[i], i);
/*
* Don't ping backup if primary is good. slurmdbd in background mode
* doesn't handle RPCs currently so it would appear down anyways.
*/
if (pings[i].pinged)
return pings;
if (!slurm_conf.accounting_storage_backup_host)
return pings;
i++;
pings[i].hostname = slurm_conf.accounting_storage_backup_host;
_ping_slurmdbd(&pings[i], i);
return pings;
}
/* This reorders the list into a alphabetical hierarchy returned in a
* separate list. The original list is not affected. */
extern list_t *slurmdb_get_hierarchical_sorted_assoc_list(
list_t *assoc_list)
{
list_t *slurmdb_hierarchical_rec_list;
list_t *ret_list = list_create(NULL);
slurmdb_hierarchical_rec_list =
slurmdb_get_acct_hierarchical_rec_list(assoc_list);
_append_hierarchical_children_ret_list(ret_list,
slurmdb_hierarchical_rec_list);
FREE_NULL_LIST(slurmdb_hierarchical_rec_list);
return ret_list;
}
/* This reorders the list into a alphabetical hierarchy. */
extern void slurmdb_sort_hierarchical_assoc_list(list_t *assoc_list)
{
(void) list_sort(assoc_list, (ListCmpF)_sort_assoc_by_lineage_asc);
}
extern list_t *slurmdb_get_acct_hierarchical_rec_list(list_t *assoc_list)
{
slurmdb_hierarchical_rec_t *par_arch_rec = NULL;
slurmdb_hierarchical_rec_t *last_acct_parent = NULL;
slurmdb_hierarchical_rec_t *last_parent = NULL;
slurmdb_hierarchical_rec_t *arch_rec = NULL;
slurmdb_assoc_rec_t *assoc = NULL;
xhash_t *all_parents = xhash_init(_arch_hash_rec_id, NULL);
list_t *arch_rec_list =
list_create(slurmdb_destroy_hierarchical_rec);
list_itr_t *itr;
/*
* The list should already be sorted by lineage, do it anyway
* just to make sure it is correct.
*/
slurmdb_sort_hierarchical_assoc_list(assoc_list);
itr = list_iterator_create(assoc_list);
while((assoc = list_next(itr))) {
arch_rec = xmalloc(sizeof(slurmdb_hierarchical_rec_t));
arch_rec->children =
list_create(slurmdb_destroy_hierarchical_rec);
arch_rec->assoc = assoc;
/*
* To speed things up we are first looking if we have
* a parent_id to look for. If that doesn't work see
* if the last parent we had was what we are looking
* for. Then if that isn't panning out look at the
* last account parent. If still we don't have it we
* will look for it in the list. If it isn't there we
* will just add it to the parent and call it good
*/
if (!assoc->parent_id) {
arch_rec->sort_name = assoc->cluster;
list_append(arch_rec_list, arch_rec);
xhash_add(all_parents, arch_rec);
continue;
}
if (assoc->user)
arch_rec->sort_name = assoc->user;
else
arch_rec->sort_name = assoc->acct;
if (last_parent &&
(assoc->parent_id == last_parent->assoc->id) &&
!xstrcmp(assoc->cluster, last_parent->assoc->cluster)) {
par_arch_rec = last_parent;
} else if (last_acct_parent &&
(assoc->parent_id == last_acct_parent->assoc->id) &&
!xstrcmp(assoc->cluster,
last_acct_parent->assoc->cluster)) {
par_arch_rec = last_acct_parent;
} else {
char *key = _create_hash_rec_id(assoc, true);
par_arch_rec = xhash_get(all_parents, key, strlen(key));
xfree(key);
if (par_arch_rec) {
last_parent = par_arch_rec;
if (!assoc->user)
last_acct_parent = par_arch_rec;
}
}
if (!par_arch_rec) {
list_append(arch_rec_list, arch_rec);
last_parent = last_acct_parent = arch_rec;
} else
list_append(par_arch_rec->children, arch_rec);
if (!assoc->user) /* Users are never parent assocs */
xhash_add(all_parents, arch_rec);
}
list_iterator_destroy(itr);
xhash_free(all_parents);
/* info("got %d", list_count(arch_rec_list)); */
_sort_slurmdb_hierarchical_rec_list(arch_rec_list);
return arch_rec_list;
}
/* IN/OUT: tree_list a list of slurmdb_print_tree_t's */
extern char *slurmdb_tree_name_get(char *name, char *parent, list_t *tree_list)
{
list_itr_t *itr = NULL;
slurmdb_print_tree_t *slurmdb_print_tree = NULL;
slurmdb_print_tree_t *par_slurmdb_print_tree = NULL;
if (!tree_list)
return NULL;
itr = list_iterator_create(tree_list);
while((slurmdb_print_tree = list_next(itr))) {
/* we don't care about users in this list. They are
only there so we don't leak memory */
if (slurmdb_print_tree->user)
continue;
if (!xstrcmp(name, slurmdb_print_tree->name))
break;
else if (parent && !xstrcmp(parent, slurmdb_print_tree->name))
par_slurmdb_print_tree = slurmdb_print_tree;
}
list_iterator_destroy(itr);
if (parent && slurmdb_print_tree)
return slurmdb_print_tree->print_name;
slurmdb_print_tree = xmalloc(sizeof(slurmdb_print_tree_t));
slurmdb_print_tree->name = xstrdup(name);
if (par_slurmdb_print_tree)
slurmdb_print_tree->spaces =
xstrdup_printf(" %s", par_slurmdb_print_tree->spaces);
else
slurmdb_print_tree->spaces = xstrdup("");
/* user account */
if (name[0] == '|') {
slurmdb_print_tree->print_name = xstrdup_printf(
"%s%s", slurmdb_print_tree->spaces, parent);
slurmdb_print_tree->user = 1;
} else
slurmdb_print_tree->print_name = xstrdup_printf(
"%s%s", slurmdb_print_tree->spaces, name);
list_append(tree_list, slurmdb_print_tree);
return slurmdb_print_tree->print_name;
}
extern int set_qos_bitstr_from_list(bitstr_t *valid_qos, list_t *qos_list)
{
list_itr_t *itr = NULL;
int rc = SLURM_SUCCESS;
char *temp_char = NULL;
xassert(valid_qos);
if (!qos_list)
return SLURM_ERROR;
itr = list_iterator_create(qos_list);
while((temp_char = list_next(itr)))
_set_qos_bit_from_string(valid_qos, temp_char);
list_iterator_destroy(itr);
return rc;
}
extern const char *rollup_interval_to_string(int interval)
{
switch (interval) {
case DBD_ROLLUP_HOUR:
return "Hour";
case DBD_ROLLUP_DAY:
return "Day";
case DBD_ROLLUP_MONTH:
return "Month";
default:
return "Unknown";
}
}
extern int set_qos_bitstr_from_string(bitstr_t *valid_qos, char *names)
{
int rc = SLURM_SUCCESS;
int i=0, start=0;
char *name = NULL;
xassert(valid_qos);
if (!names)
return SLURM_ERROR;
/* skip the first comma if it is one */
if (names[i] == ',')
i++;
start = i;
while (names[i]) {
//info("got %d - %d = %d", i, start, i-start);
if (names[i] == ',') {
/* If there is a comma at the end just
ignore it */
if (!names[i+1])
break;
name = xstrndup(names+start, (i-start));
/* info("got %s %d", name, i-start); */
_set_qos_bit_from_string(valid_qos, name);
xfree(name);
i++;
start = i;
}
i++;
}
name = xstrndup(names+start, (i-start));
/* info("got %s %d", name, i-start); */
_set_qos_bit_from_string(valid_qos, name);
xfree(name);
return rc;
}
extern char *get_qos_complete_str_bitstr(list_t *qos_list, bitstr_t *valid_qos)
{
list_t *temp_list = NULL;
char *temp_char = NULL;
char *print_this = NULL;
int i = 0;
if (!qos_list || !list_count(qos_list)
|| !valid_qos || (bit_ffs(valid_qos) == -1))
return xstrdup("");
temp_list = list_create(NULL);
for(i=0; i<bit_size(valid_qos); i++) {
if (!bit_test(valid_qos, i))
continue;
if ((temp_char = slurmdb_qos_str(qos_list, i)))
list_append(temp_list, temp_char);
}
print_this = slurm_char_list_to_xstr(temp_list);
FREE_NULL_LIST(temp_list);
if (!print_this)
return xstrdup("");
return print_this;
}
extern list_t *get_qos_name_list(list_t *qos_list, list_t *num_qos_list)
{
list_t *temp_list;
char *temp_char;
list_itr_t *itr;
int option;
if (!qos_list || !list_count(qos_list)
|| !num_qos_list || !list_count(num_qos_list))
return NULL;
temp_list = list_create(xfree_ptr);
itr = list_iterator_create(num_qos_list);
while((temp_char = list_next(itr))) {
option = 0;
if (temp_char[0] == '+' || temp_char[0] == '-') {
option = temp_char[0];
temp_char++;
}
temp_char = slurmdb_qos_str(qos_list, atoi(temp_char));
if (temp_char) {
if (option)
list_append(temp_list, xstrdup_printf(
"%c%s", option, temp_char));
else
list_append(temp_list, xstrdup(temp_char));
}
}
list_iterator_destroy(itr);
return temp_list;
}
extern char *get_qos_complete_str(list_t *qos_list, list_t *num_qos_list)
{
list_t *temp_list;
char *print_this;
if (!qos_list || !list_count(qos_list) || !num_qos_list ||
!list_count(num_qos_list))
return xstrdup("");
temp_list = get_qos_name_list(qos_list, num_qos_list);
print_this = slurm_char_list_to_xstr(temp_list);
FREE_NULL_LIST(temp_list);
if (!print_this)
return xstrdup("");
return print_this;
}
extern char *get_classification_str(uint16_t class)
{
bool classified = class & SLURMDB_CLASSIFIED_FLAG;
slurmdb_classification_type_t type = class & SLURMDB_CLASS_BASE;
switch(type) {
case SLURMDB_CLASS_NONE:
return NULL;
break;
case SLURMDB_CLASS_CAPACITY:
if (classified)
return "*Capacity";
else
return "Capacity";
break;
case SLURMDB_CLASS_CAPABILITY:
if (classified)
return "*Capability";
else
return "Capability";
break;
case SLURMDB_CLASS_CAPAPACITY:
if (classified)
return "*Capapacity";
else
return "Capapacity";
break;
default:
if (classified)
return "*Unknown";
else
return "Unknown";
break;
}
}
extern uint16_t str_2_classification(char *class)
{
uint16_t type = 0;
if (!class)
return type;
if (xstrcasestr(class, "capac"))
type = SLURMDB_CLASS_CAPACITY;
else if (xstrcasestr(class, "capab"))
type = SLURMDB_CLASS_CAPABILITY;
else if (xstrcasestr(class, "capap"))
type = SLURMDB_CLASS_CAPAPACITY;
if (xstrcasestr(class, "*"))
type |= SLURMDB_CLASSIFIED_FLAG;
else if (xstrcasestr(class, "class"))
type |= SLURMDB_CLASSIFIED_FLAG;
return type;
}
extern char *slurmdb_problem_str_get(uint16_t problem)
{
slurmdb_problem_type_t type = problem;
switch(type) {
case SLURMDB_PROBLEM_NOT_SET:
return NULL;
break;
case SLURMDB_PROBLEM_ACCT_NO_ASSOC:
return "Account has no Associations";
break;
case SLURMDB_PROBLEM_ACCT_NO_USERS:
return "Account has no users";
break;
case SLURMDB_PROBLEM_USER_NO_ASSOC:
return "User has no Associations";
break;
case SLURMDB_PROBLEM_USER_NO_UID:
return "User does not have a uid";
break;
default:
return "Unknown";
break;
}
}
extern uint16_t str_2_slurmdb_problem(char *problem)
{
uint16_t type = 0;
if (!problem)
return type;
if (xstrcasestr(problem, "account no assocs"))
type = SLURMDB_PROBLEM_USER_NO_ASSOC;
else if (xstrcasestr(problem, "account no users"))
type = SLURMDB_PROBLEM_ACCT_NO_USERS;
else if (xstrcasestr(problem, "user no assocs"))
type = SLURMDB_PROBLEM_USER_NO_ASSOC;
else if (xstrcasestr(problem, "user no uid"))
type = SLURMDB_PROBLEM_USER_NO_UID;
return type;
}
extern void log_assoc_rec(slurmdb_assoc_rec_t *assoc_ptr,
list_t *qos_list)
{
char *tmp_char = NULL;
xassert(assoc_ptr);
if (get_log_level() < LOG_LEVEL_DEBUG2)
return;
debug2("association rec id : %u", assoc_ptr->id);
debug2(" acct : %s", assoc_ptr->acct);
debug2(" cluster : %s", assoc_ptr->cluster);
debug2(" comment : %s", assoc_ptr->comment);
if (assoc_ptr->shares_raw == INFINITE)
debug2(" RawShares : NONE");
else if (assoc_ptr->shares_raw != NO_VAL)
debug2(" RawShares : %u", assoc_ptr->shares_raw);
if (assoc_ptr->def_qos_id)
debug2(" Default QOS : %s",
slurmdb_qos_str(qos_list, assoc_ptr->def_qos_id));
else
debug2(" Default QOS : NONE");
debug2(" GrpTRESMins : %s",
assoc_ptr->grp_tres_mins ?
assoc_ptr->grp_tres_mins : "NONE");
debug2(" GrpTRESRunMins : %s",
assoc_ptr->grp_tres_run_mins ?
assoc_ptr->grp_tres_run_mins : "NONE");
debug2(" GrpTRES : %s",
assoc_ptr->grp_tres ?
assoc_ptr->grp_tres : "NONE");
if (assoc_ptr->grp_jobs == INFINITE)
debug2(" GrpJobs : NONE");
else if (assoc_ptr->grp_jobs != NO_VAL)
debug2(" GrpJobs : %u", assoc_ptr->grp_jobs);
if (assoc_ptr->grp_jobs_accrue == INFINITE)
debug2(" GrpJobsAccrue : NONE");
else if (assoc_ptr->grp_jobs_accrue != NO_VAL)
debug2(" GrpJobsAccrue : %u", assoc_ptr->grp_jobs_accrue);
if (assoc_ptr->grp_submit_jobs == INFINITE)
debug2(" GrpSubmitJobs : NONE");
else if (assoc_ptr->grp_submit_jobs != NO_VAL)
debug2(" GrpSubmitJobs : %u", assoc_ptr->grp_submit_jobs);
if (assoc_ptr->grp_wall == INFINITE)
debug2(" GrpWall : NONE");
else if (assoc_ptr->grp_wall != NO_VAL) {
char time_buf[32];
mins2time_str((time_t) assoc_ptr->grp_wall,
time_buf, sizeof(time_buf));
debug2(" GrpWall : %s", time_buf);
}
tmp_char = slurmdb_assoc_flags_2_str(assoc_ptr->flags);
debug2(" Flags : %s", tmp_char);
xfree(tmp_char);
debug2(" Lineage : %s", assoc_ptr->lineage);
debug2(" MaxTRESMins : %s",
assoc_ptr->max_tres_mins_pj ?
assoc_ptr->max_tres_mins_pj : "NONE");
debug2(" MaxTRESRunMins : %s",
assoc_ptr->max_tres_run_mins ?
assoc_ptr->max_tres_run_mins : "NONE");
debug2(" MaxTRESPerJob : %s",
assoc_ptr->max_tres_pj ?
assoc_ptr->max_tres_pj : "NONE");
debug2(" MaxTRESPerNode : %s",
assoc_ptr->max_tres_pn ?
assoc_ptr->max_tres_pn : "NONE");
if (assoc_ptr->max_jobs == INFINITE)
debug2(" MaxJobs : NONE");
else if (assoc_ptr->max_jobs != NO_VAL)
debug2(" MaxJobs : %u", assoc_ptr->max_jobs);
if (assoc_ptr->max_jobs_accrue == INFINITE)
debug2(" MaxJobsAccrue : NONE");
else if (assoc_ptr->max_jobs_accrue != NO_VAL)
debug2(" MaxJobsAccrue : %u", assoc_ptr->max_jobs_accrue);
if (assoc_ptr->min_prio_thresh == INFINITE)
debug2(" MinPrioThresh : NONE");
else if (assoc_ptr->min_prio_thresh != NO_VAL)
debug2(" MinPrioThresh : %u", assoc_ptr->min_prio_thresh);
if (assoc_ptr->max_submit_jobs == INFINITE)
debug2(" MaxSubmitJobs : NONE");
else if (assoc_ptr->max_submit_jobs != NO_VAL)
debug2(" MaxSubmitJobs : %u", assoc_ptr->max_submit_jobs);
if (assoc_ptr->max_wall_pj == INFINITE)
debug2(" MaxWall : NONE");
else if (assoc_ptr->max_wall_pj != NO_VAL) {
char time_buf[32];
mins2time_str((time_t) assoc_ptr->max_wall_pj,
time_buf, sizeof(time_buf));
debug2(" MaxWall : %s", time_buf);
}
if (assoc_ptr->qos_list) {
char *temp_char = get_qos_complete_str(qos_list,
assoc_ptr->qos_list);
if (temp_char) {
debug2(" Qos : %s", temp_char);
xfree(temp_char);
if (assoc_ptr->usage && assoc_ptr->usage->valid_qos) {
temp_char = get_qos_complete_str_bitstr(
qos_list, assoc_ptr->usage->valid_qos);
debug3(" Valid Qos : %s", temp_char);
xfree(temp_char);
}
}
} else {
debug2(" Qos : %s", "Normal");
}
if (assoc_ptr->parent_acct)
debug2(" ParentAccount : %s", assoc_ptr->parent_acct);
if (assoc_ptr->partition)
debug2(" Partition : %s", assoc_ptr->partition);
if (assoc_ptr->user)
debug2(" User : %s(%u)",
assoc_ptr->user, assoc_ptr->uid);
if (assoc_ptr->usage) {
if (!fuzzy_equal(assoc_ptr->usage->shares_norm, NO_VAL))
debug2(" NormalizedShares : %f",
assoc_ptr->usage->shares_norm);
if (assoc_ptr->usage->level_shares != NO_VAL)
debug2(" LevelShares : %u",
assoc_ptr->usage->level_shares);
debug2(" UsedJobs : %u", assoc_ptr->usage->used_jobs);
debug2(" RawUsage : %Lf", assoc_ptr->usage->usage_raw);
}
}
extern int slurmdb_report_set_start_end_time(time_t *start, time_t *end)
{
time_t my_time = time(NULL);
time_t temp_time;
struct tm start_tm;
struct tm end_tm;
int sent_start = (*start), sent_end = (*end);
// info("now got %d and %d sent", (*start), (*end));
/* Default is going to be the last day */
if (!sent_end) {
if (!localtime_r(&my_time, &end_tm)) {
error("Couldn't get localtime from end %ld",
(long)my_time);
return SLURM_ERROR;
}
end_tm.tm_hour = 0;
//(*end) = slurm_mktime(&end_tm);
} else {
temp_time = sent_end;
if (!localtime_r(&temp_time, &end_tm)) {
error("Couldn't get localtime from user end %ld",
(long)my_time);
return SLURM_ERROR;
}
}
if (end_tm.tm_sec != 0)
end_tm.tm_min++;
if (end_tm.tm_min != 0)
end_tm.tm_hour++;
end_tm.tm_sec = 0;
end_tm.tm_min = 0;
(*end) = slurm_mktime(&end_tm);
if (!sent_start) {
if (!localtime_r(&my_time, &start_tm)) {
error("Couldn't get localtime from start %ld",
(long)my_time);
return SLURM_ERROR;
}
start_tm.tm_hour = 0;
start_tm.tm_mday--;
//(*start) = slurm_mktime(&start_tm);
} else {
temp_time = sent_start;
if (!localtime_r(&temp_time, &start_tm)) {
error("Couldn't get localtime from user start %ld",
(long)my_time);
return SLURM_ERROR;
}
}
start_tm.tm_sec = 0;
start_tm.tm_min = 0;
(*start) = slurm_mktime(&start_tm);
if ((*end)-(*start) < 3600)
(*end) = (*start) + 3600;
/* info("now got %d and %d sent", (*start), (*end)); */
/* char start_char[20]; */
/* char end_char[20]; */
/* time_t my_start = (*start); */
/* time_t my_end = (*end); */
/* slurm_make_time_str(&my_start, */
/* start_char, sizeof(start_char)); */
/* slurm_make_time_str(&my_end, */
/* end_char, sizeof(end_char)); */
/* info("which is %s - %s", start_char, end_char); */
return SLURM_SUCCESS;
}
/* Convert a string to a duration in Months or Days
* input formats:
* <integer> defaults to Months
* <integer>Months
* <integer>Days
* <integer>Hours
*
* output:
* SLURMDB_PURGE_MONTHS | <integer> if input is in Months
* SLURMDB_PURGE_DAYS | <integer> if input is in Days
* SLURMDB_PURGE_HOURS | <integer> if input in in Hours
* 0 on error
*/
extern uint32_t slurmdb_parse_purge(char *string)
{
int i = 0;
uint32_t purge = NO_VAL;
xassert(string);
while(string[i]) {
if ((string[i] >= '0') && (string[i] <= '9')) {
if (purge == NO_VAL)
purge = 0;
purge = (purge * 10) + (string[i] - '0');
} else
break;
i++;
}
if (purge != NO_VAL) {
int len = strlen(string+i);
if (!len || !xstrncasecmp("months", string+i, MAX(len, 1))) {
purge |= SLURMDB_PURGE_MONTHS;
} else if (!xstrncasecmp("hours", string+i, MAX(len, 1))) {
purge |= SLURMDB_PURGE_HOURS;
} else if (!xstrncasecmp("days", string+i, MAX(len, 1))) {
purge |= SLURMDB_PURGE_DAYS;
} else {
error("Invalid purge unit '%s', valid options "
"are hours, days, or months", string+i);
purge = NO_VAL;
}
} else
error("Invalid purge string '%s'", string);
return purge;
}
extern char *slurmdb_purge_string(uint32_t purge, char *string, int len,
bool with_archive)
{
uint32_t units;
if (purge == NO_VAL) {
snprintf(string, len, "NONE");
return string;
}
units = SLURMDB_PURGE_GET_UNITS(purge);
if (SLURMDB_PURGE_IN_HOURS(purge)) {
if (with_archive && SLURMDB_PURGE_ARCHIVE_SET(purge))
snprintf(string, len, "%u hours*", units);
else
snprintf(string, len, "%u hours", units);
} else if (SLURMDB_PURGE_IN_DAYS(purge)) {
if (with_archive && SLURMDB_PURGE_ARCHIVE_SET(purge))
snprintf(string, len, "%u days*", units);
else
snprintf(string, len, "%u days", units);
} else {
if (with_archive && SLURMDB_PURGE_ARCHIVE_SET(purge))
snprintf(string, len, "%u months*", units);
else
snprintf(string, len, "%u months", units);
}
return string;
}
typedef struct {
bool add_set;
bool equal_set;
int option;
list_t *qos_list;
} qos_char_list_args_t;
static int _slurmdb_addto_qos_char_list_internal(list_t *char_list, char *name,
void *args_in)
{
char *tmp_name;
uint32_t id;
qos_char_list_args_t *args = args_in;
int tmp_option = args->option;
if ((name[0] == '+') || (name[0] == '-')) {
tmp_option = name[0];
name++;
}
id = str_2_slurmdb_qos(args->qos_list, name);
if (id == NO_VAL) {
char *tmp = _get_qos_list_str(args->qos_list);
error("You gave a bad qos '%s'. Valid QOS's are %s", name, tmp);
xfree(tmp);
list_flush(char_list);
return SLURM_ERROR;
}
if (tmp_option) {
if (args->equal_set) {
error("You can't set qos equal to something and then add or subtract from it in the same line");
list_flush(char_list);
return SLURM_ERROR;
}
args->add_set = 1;
tmp_name = xstrdup_printf("%c%u", tmp_option, id);
} else {
if (args->add_set) {
error("You can't set qos equal to something and then add or subtract from it in the same line");
list_flush(char_list);
return SLURM_ERROR;
}
args->equal_set = 1;
tmp_name = xstrdup_printf("%u", id);
}
if (!list_find_first(char_list, slurm_find_char_in_list, tmp_name)) {
list_append(char_list, tmp_name);
return 1;
} else {
xfree(tmp_name);
return 0;
}
}
extern int slurmdb_addto_qos_char_list(list_t *char_list, list_t *qos_list,
char *names, int option)
{
int count;
qos_char_list_args_t args = {0};
if (!char_list) {
error("No list was given to fill in");
return 0;
}
if (!xstrcmp(names, "")) {
list_append(char_list, xstrdup(""));
return 1;
}
args.option = option;
args.qos_list = qos_list;
count = slurm_parse_char_list(char_list, names, &args,
_slurmdb_addto_qos_char_list_internal);
if (!count) {
error("You gave me an empty qos list");
}
return count;
}
extern int slurmdb_send_accounting_update_persist(list_t *update_list,
persist_conn_t *persist_conn)
{
slurm_msg_t req;
slurm_msg_t resp;
accounting_update_msg_t msg = {0};
int rc;
xassert(persist_conn);
if (!persist_conn->tls_conn) {
if (slurm_persist_conn_open(persist_conn) !=
SLURM_SUCCESS) {
error("slurmdb_send_accounting_update_persist: Unable to open connection to registered cluster %s.",
persist_conn->cluster_name);
persist_conn->tls_conn = NULL;
rc = SLURM_ERROR;
goto end;
}
}
msg.update_list = update_list;
msg.rpc_version = req.protocol_version = persist_conn->version;
slurm_msg_t_init(&req);
req.msg_type = ACCOUNTING_UPDATE_MSG;
req.conn = persist_conn;
req.data = &msg;
/* resp is inited in slurm_send_recv_msg */
rc = slurm_send_recv_msg(persist_conn->tls_conn, &req, &resp, 0);
end:
if (rc != SLURM_SUCCESS) {
error("update cluster: %s at %s(%hu): %m",
persist_conn->cluster_name,
persist_conn->rem_host,
persist_conn->rem_port);
} else {
rc = slurm_get_return_code(resp.msg_type, resp.data);
slurm_free_return_code_msg(resp.data);
}
//info("got rc of %d", rc);
return rc;
}
/*
* send_accounting_update - send update to controller of cluster
* IN update_list: updates to send
* IN cluster: name of cluster
* IN host: control host of cluster
* IN port: control port of cluster
* IN rpc_version: rpc version of cluster
* RET: error code
*/
extern int slurmdb_send_accounting_update(list_t *update_list, char *cluster,
char *host, uint16_t port,
uint16_t rpc_version)
{
accounting_update_msg_t msg;
slurm_msg_t req;
slurm_msg_t resp;
int i, rc;
// Set highest version that we can use
if (rpc_version > SLURM_PROTOCOL_VERSION) {
rpc_version = SLURM_PROTOCOL_VERSION;
}
memset(&msg, 0, sizeof(accounting_update_msg_t));
msg.rpc_version = rpc_version;
msg.update_list = update_list;
debug("sending updates to %s at %s(%hu) ver %hu",
cluster, host, port, rpc_version);
slurm_msg_t_init(&req);
slurm_set_addr(&req.address, port, host);
req.protocol_version = rpc_version;
slurm_msg_set_r_uid(&req, SLURM_AUTH_UID_ANY);
req.msg_type = ACCOUNTING_UPDATE_MSG;
if (slurmdbd_conf)
req.flags = SLURM_GLOBAL_AUTH_KEY;
req.data = &msg;
slurm_msg_t_init(&resp);
for (i = 0; i < 4; i++) {
/* Retry if the slurmctld can connect, but is not responding */
rc = slurm_send_recv_node_msg(&req, &resp, 0);
if ((rc == SLURM_SUCCESS) ||
(errno != SLURM_PROTOCOL_SOCKET_IMPL_TIMEOUT))
break;
}
if (rc != SLURM_SUCCESS) {
error("update cluster: %m to %s at %s(%hu)",
cluster, host, port);
rc = SLURM_ERROR;
} else
rc = slurm_get_return_code(resp.msg_type, resp.data);
if (resp.auth_cred)
auth_g_destroy(resp.auth_cred);
slurm_free_return_code_msg(resp.data);
//info("got rc of %d", rc);
return rc;
}
extern slurmdb_report_cluster_rec_t *slurmdb_cluster_rec_2_report(
slurmdb_cluster_rec_t *cluster)
{
slurmdb_report_cluster_rec_t *slurmdb_report_cluster;
slurmdb_cluster_accounting_rec_t *accting = NULL;
slurmdb_tres_rec_t *tres_rec;
list_itr_t *itr = NULL;
int count;
xassert(cluster);
slurmdb_report_cluster = xmalloc(sizeof(slurmdb_report_cluster_rec_t));
slurmdb_report_cluster->name = xstrdup(cluster->name);
if (!(count = list_count(cluster->accounting_list)))
return slurmdb_report_cluster;
/* get the amount of time and the average count
during the time we are looking at */
itr = list_iterator_create(cluster->accounting_list);
while ((accting = list_next(itr)))
slurmdb_add_cluster_accounting_to_tres_list(
accting, &slurmdb_report_cluster->tres_list);
list_iterator_destroy(itr);
itr = list_iterator_create(slurmdb_report_cluster->tres_list);
while ((tres_rec = list_next(itr)))
tres_rec->count /= tres_rec->rec_count;
list_iterator_destroy(itr);
return slurmdb_report_cluster;
}
/*
* get the first cluster that will run a job
* IN: req - description of resource allocation request
* IN: cluster_names - comma separated string of cluster names
* OUT: cluster_rec - record of selected cluster or NULL if none found or
* cluster_names is NULL
* RET: SLURM_SUCCESS on success SLURM_ERROR else
*
* Note: Cluster_rec needs to be freed with slurmdb_destroy_cluster_rec() when
* called
* Note: The will_runs are not threaded. Currently it relies on the
* working_cluster_rec to pack the job_desc's jobinfo. See previous commit for
* an example of how to thread this.
*/
extern int slurmdb_get_first_avail_cluster(job_desc_msg_t *req,
char *cluster_names, slurmdb_cluster_rec_t **cluster_rec)
{
will_run_response_msg_t *will_run_resp;
int rc = SLURM_SUCCESS;
char local_hostname[HOST_NAME_MAX];
list_itr_t *itr;
list_t *cluster_list = NULL;
list_t *ret_list = NULL;
*cluster_rec = NULL;
if (slurm_get_cluster_info(&(cluster_list), cluster_names, 0)) {
return SLURM_ERROR;
}
/* return if we only have 1 or less clusters here */
if (!cluster_list || !list_count(cluster_list)) {
rc = SLURM_ERROR;
goto end_it;
} else if (list_count(cluster_list) == 1) {
*cluster_rec = list_pop(cluster_list);
goto end_it;
}
if ((req->alloc_node == NULL) &&
(gethostname_short(local_hostname, sizeof(local_hostname)) == 0)) {
req->alloc_node = local_hostname;
}
if (working_cluster_rec)
*cluster_rec = working_cluster_rec;
ret_list = list_create(slurm_free_will_run_response_msg);
itr = list_iterator_create(cluster_list);
while ((working_cluster_rec = list_next(itr))) {
if ((will_run_resp = _job_will_run(req))) {
list_append(ret_list, will_run_resp);
} else {
error("Problem with submit to cluster %s: %m",
working_cluster_rec->name);
}
}
list_iterator_destroy(itr);
/* restore working_cluster_rec in case it was already set */
if (*cluster_rec) {
working_cluster_rec = *cluster_rec;
*cluster_rec = NULL;
}
if (req->alloc_node == local_hostname)
req->alloc_node = NULL;
if (!list_count(ret_list)) {
error("Can't run on any of the specified clusters");
rc = SLURM_ERROR;
goto end_it;
}
/* sort the list so the first spot is on top */
list_sort(ret_list, slurm_sort_will_run_resp);
will_run_resp = list_peek(ret_list);
/* prevent cluster_rec from being freed when cluster_list is destroyed */
working_cluster_rec = list_remove_first(cluster_list,
slurmdb_find_cluster_in_list,
will_run_resp->cluster_name);
end_it:
FREE_NULL_LIST(ret_list);
FREE_NULL_LIST(cluster_list);
return rc;
}
/* Report the latest start time for any hetjob component on this cluster.
* Return NULL if any component can not run here */
static will_run_response_msg_t *_het_job_will_run(list_t *job_req_list)
{
will_run_response_msg_t *ret_resp = NULL, *tmp_resp;
job_desc_msg_t *req;
list_itr_t *iter;
iter = list_iterator_create(job_req_list);
while ((req = (job_desc_msg_t *) list_next(iter))) {
tmp_resp = _job_will_run(req);
if (!tmp_resp) { /* Some het component can't run here */
slurm_free_will_run_response_msg(ret_resp);
ret_resp = NULL;
break;
}
if (!ret_resp) {
ret_resp = tmp_resp;
ret_resp = NULL;
} else if (ret_resp->start_time < tmp_resp->start_time)
ret_resp->start_time = tmp_resp->start_time;
xfree(ret_resp);
}
list_iterator_destroy(iter);
return ret_resp;
}
/*
* get the first cluster that will run a heterogeneous job
* IN: req - description of resource allocation request
* IN: cluster_names - comma separated string of cluster names
* OUT: cluster_rec - record of selected cluster or NULL if none found or
* cluster_names is NULL
* RET: SLURM_SUCCESS on success SLURM_ERROR else
*
* Note: Cluster_rec needs to be freed with slurmdb_destroy_cluster_rec() when
* called
* Note: The will_runs are not threaded. Currently it relies on the
* working_cluster_rec to pack the job_desc's jobinfo. See previous commit for
* an example of how to thread this.
*/
extern int slurmdb_get_first_het_job_cluster(list_t *job_req_list,
char *cluster_names, slurmdb_cluster_rec_t **cluster_rec)
{
job_desc_msg_t *req;
will_run_response_msg_t *will_run_resp = NULL;
int rc = SLURM_SUCCESS;
char local_hostname[HOST_NAME_MAX] = "";
list_itr_t *itr;
list_t *cluster_list = NULL;
list_t *ret_list = NULL;
*cluster_rec = NULL;
if (slurm_get_cluster_info(&(cluster_list), cluster_names, 0)) {
return SLURM_ERROR;
}
/* return if we only have 1 or less clusters here */
if (!cluster_list || !list_count(cluster_list)) {
rc = SLURM_ERROR;
goto end_it;
} else if (list_count(cluster_list) == 1) {
*cluster_rec = list_pop(cluster_list);
goto end_it;
}
(void) gethostname_short(local_hostname, sizeof(local_hostname));
itr = list_iterator_create(job_req_list);
while ((req = (job_desc_msg_t *) list_next(itr))) {
if ((req->alloc_node == NULL) && local_hostname[0])
req->alloc_node = local_hostname;
}
list_iterator_destroy(itr);
if (working_cluster_rec)
*cluster_rec = working_cluster_rec;
ret_list = list_create(xfree_ptr);
itr = list_iterator_create(cluster_list);
while ((working_cluster_rec = list_next(itr))) {
if ((will_run_resp = _het_job_will_run(job_req_list))) {
list_append(ret_list, will_run_resp);
} else {
error("Problem with submit to cluster %s: %m",
working_cluster_rec->name);
}
}
list_iterator_destroy(itr);
/* restore working_cluster_rec in case it was already set */
if (*cluster_rec) {
working_cluster_rec = *cluster_rec;
*cluster_rec = NULL;
}
itr = list_iterator_create(job_req_list);
while ((req = (job_desc_msg_t *) list_next(itr))) {
if (req->alloc_node == local_hostname)
req->alloc_node = NULL;
}
list_iterator_destroy(itr);
if (!list_count(ret_list)) {
error("Can't run on any of the specified clusters");
rc = SLURM_ERROR;
goto end_it;
}
/* sort the list so the first spot is on top */
list_sort(ret_list, slurm_sort_will_run_resp);
will_run_resp = list_peek(ret_list);
/* prevent cluster_rec from being freed when cluster_list is destroyed */
working_cluster_rec = list_remove_first(cluster_list,
slurmdb_find_cluster_in_list,
will_run_resp->cluster_name);
end_it:
FREE_NULL_LIST(ret_list);
FREE_NULL_LIST(cluster_list);
return rc;
}
extern void slurmdb_copy_assoc_rec_limits(slurmdb_assoc_rec_t *out,
slurmdb_assoc_rec_t *in)
{
out->grp_jobs = in->grp_jobs;
out->grp_jobs_accrue = in->grp_jobs_accrue;
out->grp_submit_jobs = in->grp_submit_jobs;
xfree(out->grp_tres);
out->grp_tres = xstrdup(in->grp_tres);
xfree(out->grp_tres_mins);
out->grp_tres_mins = xstrdup(in->grp_tres_mins);
xfree(out->grp_tres_run_mins);
out->grp_tres_run_mins = xstrdup(in->grp_tres_run_mins);
out->grp_wall = in->grp_wall;
out->max_jobs = in->max_jobs;
out->max_jobs_accrue = in->max_jobs_accrue;
out->min_prio_thresh = in->min_prio_thresh;
out->max_submit_jobs = in->max_submit_jobs;
xfree(out->max_tres_pj);
out->max_tres_pj = xstrdup(in->max_tres_pj);
xfree(out->max_tres_pn);
out->max_tres_pn = xstrdup(in->max_tres_pn);
xfree(out->max_tres_mins_pj);
out->max_tres_mins_pj = xstrdup(in->max_tres_mins_pj);
xfree(out->max_tres_run_mins);
out->max_tres_run_mins = xstrdup(in->max_tres_run_mins);
out->max_wall_pj = in->max_wall_pj;
out->priority = in->priority;
out->comment = xstrdup(in->comment);
FREE_NULL_LIST(out->qos_list);
out->qos_list = slurm_copy_char_list(in->qos_list);
}
extern void slurmdb_copy_cluster_rec(slurmdb_cluster_rec_t *out,
slurmdb_cluster_rec_t *in)
{
out->classification = in->classification;
xfree(out->control_host);
out->control_host = xstrdup(in->control_host);
out->control_port = in->control_port;
out->dimensions = in->dimensions;
xfree(out->fed.name);
out->fed.name = xstrdup(in->fed.name);
out->fed.id = in->fed.id;
out->fed.state = in->fed.state;
out->flags = in->flags;
xfree(out->name);
out->name = xstrdup(in->name);
xfree(out->nodes);
out->nodes = xstrdup(in->nodes);
out->rpc_version = in->rpc_version;
xfree(out->tres_str);
out->tres_str = xstrdup(in->tres_str);
slurmdb_destroy_assoc_rec(out->root_assoc);
if (in->root_assoc) {
out->root_assoc = xmalloc(sizeof(slurmdb_assoc_rec_t));
slurmdb_init_assoc_rec(out->root_assoc, 0);
slurmdb_copy_assoc_rec_limits( out->root_assoc, in->root_assoc);
}
FREE_NULL_LIST(out->fed.feature_list);
if (in->fed.feature_list) {
out->fed.feature_list = list_create(xfree_ptr);
slurm_char_list_copy(out->fed.feature_list,
in->fed.feature_list);
}
/* Not copied currently:
* accounting_list
* control_addr
* dim_size
* fed.recv
* fed.send
*/
}
extern void slurmdb_copy_federation_rec(slurmdb_federation_rec_t *out,
slurmdb_federation_rec_t *in)
{
xfree(out->name);
out->name = xstrdup(in->name);
out->flags = in->flags;
FREE_NULL_LIST(out->cluster_list);
if (in->cluster_list) {
slurmdb_cluster_rec_t *cluster_in = NULL;
list_itr_t *itr = list_iterator_create(in->cluster_list);
out->cluster_list = list_create(slurmdb_destroy_cluster_rec);
while ((cluster_in = list_next(itr))) {
slurmdb_cluster_rec_t *cluster_out =
xmalloc(sizeof(slurmdb_cluster_rec_t));
slurmdb_init_cluster_rec(cluster_out, 0);
slurmdb_copy_cluster_rec(cluster_out, cluster_in);
list_append(out->cluster_list, cluster_out);
}
list_iterator_destroy(itr);
}
}
extern void slurmdb_copy_qos_rec_limits(slurmdb_qos_rec_t *out,
slurmdb_qos_rec_t *in)
{
out->flags = in->flags;
out->grace_time = in->grace_time;
out->grp_jobs = in->grp_jobs;
out->grp_jobs_accrue = in->grp_jobs_accrue;
out->grp_submit_jobs = in->grp_submit_jobs;
xfree(out->grp_tres);
out->grp_tres = xstrdup(in->grp_tres);
xfree(out->grp_tres_mins);
out->grp_tres_mins = xstrdup(in->grp_tres_mins);
xfree(out->grp_tres_run_mins);
out->grp_tres_run_mins = xstrdup(in->grp_tres_run_mins);
out->grp_wall = in->grp_wall;
out->limit_factor = in->limit_factor;
out->max_jobs_pa = in->max_jobs_pa;
out->max_jobs_pu = in->max_jobs_pu;
out->max_jobs_accrue_pa = in->max_jobs_accrue_pa;
out->max_jobs_accrue_pu = in->max_jobs_accrue_pu;
out->max_submit_jobs_pa = in->max_submit_jobs_pa;
out->max_submit_jobs_pu = in->max_submit_jobs_pu;
xfree(out->max_tres_mins_pj);
out->max_tres_mins_pj = xstrdup(in->max_tres_mins_pj);
xfree(out->max_tres_pa);
out->max_tres_pa = xstrdup(in->max_tres_pa);
xfree(out->max_tres_pj);
out->max_tres_pj = xstrdup(in->max_tres_pj);
xfree(out->max_tres_pn);
out->max_tres_pn = xstrdup(in->max_tres_pn);
xfree(out->max_tres_pu);
out->max_tres_pu = xstrdup(in->max_tres_pu);
xfree(out->max_tres_run_mins_pa);
out->max_tres_run_mins_pa = xstrdup(in->max_tres_run_mins_pa);
xfree(out->max_tres_run_mins_pu);
out->max_tres_run_mins_pu = xstrdup(in->max_tres_run_mins_pu);
out->max_wall_pj = in->max_wall_pj;
out->min_prio_thresh = in->min_prio_thresh;
xfree(out->min_tres_pj);
out->min_tres_pj = xstrdup(in->min_tres_pj);
FREE_NULL_LIST(out->preempt_list);
out->preempt_list = slurm_copy_char_list(in->preempt_list);
out->preempt_mode = in->preempt_mode;
out->preempt_exempt_time = in->preempt_exempt_time;
out->priority = in->priority;
out->usage_factor = in->usage_factor;
out->usage_thres = in->usage_thres;
}
extern slurmdb_tres_rec_t *slurmdb_copy_tres_rec(slurmdb_tres_rec_t *tres)
{
slurmdb_tres_rec_t *tres_out = NULL;
if (!tres)
return tres_out;
tres_out = xmalloc_nz(sizeof(slurmdb_tres_rec_t));
memcpy(tres_out, tres, sizeof(slurmdb_tres_rec_t));
tres_out->name = xstrdup(tres->name);
tres_out->type = xstrdup(tres->type);
return tres_out;
}
extern list_t *slurmdb_copy_tres_list(list_t *tres)
{
slurmdb_tres_rec_t *tres_rec = NULL;
list_itr_t *itr;
list_t *tres_out;
if (!tres)
return NULL;
tres_out = list_create(slurmdb_destroy_tres_rec);
itr = list_iterator_create(tres);
while ((tres_rec = list_next(itr)))
list_append(tres_out, slurmdb_copy_tres_rec(tres_rec));
list_iterator_destroy(itr);
return tres_out;
}
extern list_t *slurmdb_list_copy_coord(list_t *coord_accts)
{
list_t *ret_list = NULL;
if (!coord_accts || !list_count(coord_accts))
return NULL;
list_for_each(coord_accts, _list_copy_coord, &ret_list);
return ret_list;
}
extern list_t *slurmdb_diff_tres_list(list_t *tres_list_old,
list_t *tres_list_new)
{
slurmdb_tres_rec_t *tres_rec = NULL, *tres_rec_old;
list_itr_t *itr;
list_t *tres_out;
if (!tres_list_new || !list_count(tres_list_new))
return NULL;
tres_out = slurmdb_copy_tres_list(tres_list_new);
itr = list_iterator_create(tres_out);
while ((tres_rec = list_next(itr))) {
if (!(tres_rec_old = list_find_first(tres_list_old,
slurmdb_find_tres_in_list,
&tres_rec->id)))
continue;
if (tres_rec_old->count == tres_rec->count)
list_delete_item(itr);
}
list_iterator_destroy(itr);
return tres_out;
}
extern char *slurmdb_tres_string_combine_lists(
list_t *tres_list_old, list_t *tres_list_new)
{
slurmdb_tres_rec_t *tres_rec = NULL, *tres_rec_old;
list_itr_t *itr;
char *tres_str = NULL;
if (!tres_list_new || !list_count(tres_list_new))
return NULL;
itr = list_iterator_create(tres_list_new);
while ((tres_rec = list_next(itr))) {
if (!(tres_rec_old = list_find_first(tres_list_old,
slurmdb_find_tres_in_list,
&tres_rec->id))
|| (tres_rec_old->count == INFINITE64))
continue;
if (tres_str)
xstrcat(tres_str, ",");
xstrfmtcat(tres_str, "%u=%"PRIu64,
tres_rec->id, tres_rec->count);
}
list_iterator_destroy(itr);
return tres_str;
}
/* caller must xfree this char * returned */
extern char *slurmdb_make_tres_string(list_t *tres, uint32_t flags)
{
char *tres_str = NULL;
list_itr_t *itr;
slurmdb_tres_rec_t *tres_rec;
if (!tres)
return tres_str;
itr = list_iterator_create(tres);
while ((tres_rec = list_next(itr))) {
if ((flags & TRES_STR_FLAG_REMOVE) &&
(tres_rec->count == INFINITE64))
continue;
if ((flags & TRES_STR_FLAG_SIMPLE) || !tres_rec->type)
xstrfmtcat(tres_str, "%s%u=%"PRIu64,
(tres_str ||
(flags & TRES_STR_FLAG_COMMA1)) ? "," : "",
tres_rec->id, tres_rec->count);
else
xstrfmtcat(tres_str, "%s%s%s%s=%"PRIu64,
(tres_str ||
(flags & TRES_STR_FLAG_COMMA1)) ? "," : "",
tres_rec->type,
tres_rec->name ? "/" : "",
tres_rec->name ? tres_rec->name : "",
tres_rec->count);
}
list_iterator_destroy(itr);
return tres_str;
}
extern char *slurmdb_make_tres_string_from_arrays(char **tres_names,
uint64_t *tres_cnts,
uint32_t tres_cnt,
uint32_t flags)
{
char *tres_str = NULL;
int i;
if (!tres_names || !tres_cnts)
return tres_str;
for (i=0; i<tres_cnt; i++) {
if ((tres_cnts[i] == INFINITE64) &&
(flags & TRES_STR_FLAG_REMOVE))
continue;
xstrfmtcat(tres_str, "%s%s=%"PRIu64,
tres_str ? "," : "", tres_names[i], tres_cnts[i]);
}
return tres_str;
}
extern char *slurmdb_make_tres_string_from_simple(
char *tres_in, list_t *full_tres_list, int spec_unit,
uint32_t convert_flags, uint32_t tres_str_flags, char *nodes)
{
char *tres_str = NULL;
char *tmp_str = tres_in;
int id;
uint64_t count;
slurmdb_tres_rec_t *tres_rec;
char *node_name = NULL;
list_t *char_list = NULL;
if (!full_tres_list || !tmp_str || !tmp_str[0]
|| tmp_str[0] < '0' || tmp_str[0] > '9')
return tres_str;
while (tmp_str) {
id = atoi(tmp_str);
if (id <= 0) {
error("slurmdb_make_tres_string_from_simple: no id "
"found at %s instead", tmp_str);
goto get_next;
}
if (!(tres_rec = list_find_first(
full_tres_list, slurmdb_find_tres_in_list,
&id))) {
debug("No tres known by id %d", id);
goto get_next;
}
if (!(tmp_str = strchr(tmp_str, '='))) {
error("slurmdb_make_tres_string_from_simple: "
"no value found");
break;
}
count = slurm_atoull(++tmp_str);
if (count == NO_VAL64)
goto get_next;
if (tres_str)
xstrcat(tres_str, ",");
if (!tres_rec->type)
xstrfmtcat(tres_str, "%u=", tres_rec->id);
else
xstrfmtcat(tres_str, "%s%s%s=",
tres_rec->type,
tres_rec->name ? "/" : "",
tres_rec->name ? tres_rec->name : "");
if (count != INFINITE64) {
if (nodes) {
node_name = find_hostname(count, nodes);
xstrfmtcat(tres_str, "%s", node_name);
xfree(node_name);
} else if (tres_str_flags & TRES_STR_FLAG_BYTES) {
/* This mean usage */
char outbuf[FORMAT_STRING_SIZE];
if (tres_rec->id == TRES_CPU) {
count /= CPU_TIME_ADJ;
secs2time_str((time_t)count, outbuf,
FORMAT_STRING_SIZE);
} else if (!xstrcasecmp(tres_rec->name,
"gpuutil")) {
snprintf(outbuf, sizeof(outbuf),
"%"PRIu64, count);
} else
convert_num_unit((double)count, outbuf,
sizeof(outbuf),
UNIT_NONE,
spec_unit,
convert_flags);
xstrfmtcat(tres_str, "%s", outbuf);
} else if ((tres_rec->id == TRES_MEM) ||
!xstrcasecmp(tres_rec->name, "gpumem") ||
!xstrcasecmp(tres_rec->type, "bb")) {
char outbuf[FORMAT_STRING_SIZE];
convert_num_unit((double)count, outbuf,
sizeof(outbuf), UNIT_MEGA,
spec_unit, convert_flags);
xstrfmtcat(tres_str, "%s", outbuf);
} else {
xstrfmtcat(tres_str, "%"PRIu64, count);
}
} else
xstrfmtcat(tres_str, "NONE");
if (!(tres_str_flags & TRES_STR_FLAG_SORT_ID)) {
if (!char_list)
char_list = list_create(xfree_ptr);
list_append(char_list, tres_str);
tres_str = NULL;
}
get_next:
if (!(tmp_str = strchr(tmp_str, ',')))
break;
tmp_str++;
}
if (char_list) {
tres_str = slurm_char_list_to_xstr(char_list);
FREE_NULL_LIST(char_list);
}
return tres_str;
}
extern char *slurmdb_format_tres_str(
char *tres_in, list_t *full_tres_list, bool simple)
{
char *tres_str = NULL;
char *val_unit = NULL;
char *tmp_str = tres_in;
uint64_t count;
slurmdb_tres_rec_t *tres_rec;
if (!full_tres_list || !tmp_str || !tmp_str[0])
return tres_str;
if (tmp_str[0] == ',')
tmp_str++;
while (tmp_str) {
if (tmp_str[0] >= '0' && tmp_str[0] <= '9') {
int id = atoi(tmp_str);
if (id <= 0) {
error("%s: cannot convert %s to ID.",
__func__, tmp_str);
return NULL;
}
if (!(tres_rec = list_find_first(
full_tres_list, slurmdb_find_tres_in_list,
&id))) {
error("%s: no TRES known by id %d",
__func__, id);
return NULL;
}
} else {
int end = 0;
char *tres_name;
while (tmp_str[end]) {
if (tmp_str[end] == '=')
break;
end++;
}
if (!tmp_str[end]) {
error("%s: no TRES id found for %s",
__func__, tmp_str);
return NULL;
}
tres_name = xstrndup(tmp_str, end);
if (!(tres_rec = list_find_first(
full_tres_list,
slurmdb_find_tres_in_list_by_type,
tres_name))) {
error("%s: no TRES known by type %s",
__func__, tres_name);
xfree(tres_name);
return NULL;
}
xfree(tres_name);
}
if (!(tmp_str = strchr(tmp_str, '='))) {
error("%s: no value given as TRES type/id.", __func__);
return NULL;
}
count = strtoull(++tmp_str, &val_unit, 10);
if (val_unit && *val_unit != ',' && *val_unit != '\0' &&
tres_rec->type) {
int base_unit =
slurmdb_get_tres_base_unit(tres_rec->type);
int convert_val =
get_convert_unit_val(base_unit, *val_unit);
if (convert_val > 0)
count *= convert_val;
}
if (tres_str)
xstrcat(tres_str, ",");
if (simple || !tres_rec->type)
xstrfmtcat(tres_str, "%u=%"PRIu64"",
tres_rec->id, count);
else
xstrfmtcat(tres_str, "%s%s%s=%"PRIu64"",
tres_rec->type,
tres_rec->name ? "/" : "",
tres_rec->name ? tres_rec->name : "",
count);
if (!(tmp_str = strchr(tmp_str, ',')))
break;
tmp_str++;
}
return tres_str;
}
/*
* Comparator used for sorting tres by id
*
* returns: -1 tres_a < tres_b 0: tres_a == tres_b 1: tres_a > tres_b
*
*/
extern int slurmdb_sort_tres_by_id_asc(void *v1, void *v2)
{
slurmdb_tres_rec_t *tres_a = *(slurmdb_tres_rec_t **)v1;
slurmdb_tres_rec_t *tres_b = *(slurmdb_tres_rec_t **)v2;
if ((tres_a->id > TRES_STATIC_CNT) &&
(tres_b->id > TRES_STATIC_CNT)) {
int diff = xstrcmp(tres_a->type, tres_b->type);
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
diff = xstrcmp(tres_a->name, tres_b->name);
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
}
if (tres_a->id < tres_b->id)
return -1;
else if (tres_a->id > tres_b->id)
return 1;
return 0;
}
extern void slurmdb_tres_list_from_string(list_t **tres_list, const char *tres,
uint32_t flags, list_t *sub_tres_list)
{
const char *tmp_str = tres;
int id;
uint64_t count;
slurmdb_tres_rec_t *tres_rec;
int remove_found = 0;
list_t *mgr_tres_list =
sub_tres_list ? sub_tres_list : assoc_mgr_tres_list;
xassert(tres_list);
if (!tres || !tres[0])
return;
if (tmp_str[0] == ',')
tmp_str++;
while (tmp_str) {
if (tmp_str[0] >= '0' && tmp_str[0] <= '9') {
id = atoi(tmp_str);
} else {
int end = 0;
char *tres_name;
assoc_mgr_lock_t locks = { .tres = READ_LOCK };
while (tmp_str[end]) {
if (tmp_str[end] == '=')
break;
end++;
}
if (!tmp_str[end]) {
error("%s: no TRES id found for %s",
__func__, tmp_str);
break;
}
tres_name = xstrndup(tmp_str, end);
if (!sub_tres_list)
assoc_mgr_lock(&locks);
if (!mgr_tres_list) {
error("%s: No assoc_mgr_tres_list, this function can't be used here with a formatted tres list.", __func__);
break;
}
tres_rec = list_find_first(
mgr_tres_list,
slurmdb_find_tres_in_list_by_type, tres_name);
if (!sub_tres_list)
assoc_mgr_unlock(&locks);
if (!tres_rec) {
error("%s: no TRES known by type %s",
__func__, tres_name);
xfree(tres_name);
break;
}
id = tres_rec->id;
xfree(tres_name);
}
/* 0 isn't a valid tres id */
if (id <= 0) {
error("slurmdb_tres_list_from_string: no id "
"found at %s instead", tmp_str);
break;
}
if (!(tmp_str = strchr(tmp_str, '='))) {
error("slurmdb_tres_list_from_string: "
"no value found %s", tres);
break;
}
count = slurm_atoull(++tmp_str);
if (!*tres_list)
*tres_list = list_create(slurmdb_destroy_tres_rec);
if (!(tres_rec = list_find_first(
*tres_list, slurmdb_find_tres_in_list, &id))) {
tres_rec = xmalloc(sizeof(slurmdb_tres_rec_t));
tres_rec->id = id;
tres_rec->count = count;
list_append(*tres_list, tres_rec);
if (count == INFINITE64)
remove_found++;
} else if (flags & TRES_STR_FLAG_REPLACE) {
debug2("TRES %u was already here with count %"PRIu64", "
"replacing with %"PRIu64,
tres_rec->id, tres_rec->count, count);
tres_rec->count = count;
} else if (flags & TRES_STR_FLAG_SUM) {
if (count != INFINITE64) {
if (tres_rec->count == INFINITE64)
tres_rec->count = count;
else
tres_rec->count += count;
}
} else if (flags & TRES_STR_FLAG_MAX) {
if (count != INFINITE64) {
if (tres_rec->count == INFINITE64)
tres_rec->count = count;
else
tres_rec->count =
MAX(tres_rec->count, count);
}
} else if (flags & TRES_STR_FLAG_MIN) {
if (count != INFINITE64) {
if (tres_rec->count == INFINITE64)
tres_rec->count = count;
else
tres_rec->count =
MIN(tres_rec->count, count);
}
}
if (!(tmp_str = strchr(tmp_str, ',')))
break;
tmp_str++;
}
if (remove_found && (flags & TRES_STR_FLAG_REMOVE)) {
/* here we will remove the tres we don't want in the
string */
uint64_t inf64 = INFINITE64;
int removed;
if ((removed = list_delete_all(
*tres_list,
slurmdb_find_tres_in_list_by_count,
&inf64)) != remove_found)
debug("slurmdb_tres_list_from_string: "
"was expecting to remove %d, but removed %d",
remove_found, removed);
}
if (*tres_list && (flags & TRES_STR_FLAG_SORT_ID))
list_sort(*tres_list, (ListCmpF)slurmdb_sort_tres_by_id_asc);
return;
}
extern char *slurmdb_combine_tres_strings(
char **tres_str_old, char *tres_str_new, uint32_t flags)
{
list_t *tres_list = NULL;
xassert(tres_str_old);
/* If a new string is being added concat it onto the old
* string, then send it to slurmdb_tres_list_from_string which
* will make it a unique list if flags doesn't contain
* TRES_STR_FLAG_ONLY_CONCAT.
*/
if (tres_str_new && tres_str_new[0])
xstrfmtcat(*tres_str_old, "%s%s%s",
(flags & (TRES_STR_FLAG_COMMA1 |
TRES_STR_FLAG_ONLY_CONCAT)) ? "," : "",
(*tres_str_old && tres_str_new[0] != ',') ? "," : "",
tres_str_new);
if (flags & TRES_STR_FLAG_ONLY_CONCAT)
goto endit;
slurmdb_tres_list_from_string(&tres_list, *tres_str_old, flags, NULL);
xfree(*tres_str_old);
/* Always make it a simple string */
flags |= TRES_STR_FLAG_SIMPLE;
/* Make a new string from the combined */
*tres_str_old = slurmdb_make_tres_string(tres_list, flags);
FREE_NULL_LIST(tres_list);
endit:
/* Send back a blank string instead of NULL. */
if (!*tres_str_old && (flags & TRES_STR_FLAG_NO_NULL))
*tres_str_old = xstrdup("");
return *tres_str_old;
}
extern slurmdb_tres_rec_t *slurmdb_find_tres_in_string(
char *tres_str_in, int id)
{
slurmdb_tres_rec_t *tres_rec = NULL;
char *tmp_str = tres_str_in;
if (!tmp_str || !tmp_str[0])
return tres_rec;
while (tmp_str) {
if (id == atoi(tmp_str)) {
if (!(tmp_str = strchr(tmp_str, '='))) {
error("%s: no value found", __func__);
break;
}
tres_rec = xmalloc(sizeof(slurmdb_tres_rec_t));
tres_rec->id = id;
tres_rec->count = slurm_atoull(++tmp_str);
return tres_rec;
}
if (!(tmp_str = strchr(tmp_str, ',')))
break;
tmp_str++;
}
return tres_rec;
}
extern uint64_t slurmdb_find_tres_count_in_string(char *tres_str_in, int id)
{
char *tmp_str = tres_str_in;
if (!tmp_str || !tmp_str[0])
return INFINITE64;
while (tmp_str) {
if (id == atoi(tmp_str)) {
if (!(tmp_str = strchr(tmp_str, '='))) {
error("slurmdb_find_tres_count_in_string: "
"no value found");
break;
}
return slurm_atoull(++tmp_str);
}
if (!(tmp_str = strchr(tmp_str, ',')))
break;
tmp_str++;
}
return INFINITE64;
}
extern int slurmdb_find_qos_in_list_by_name(void *x, void *key)
{
slurmdb_qos_rec_t *qos_rec = (slurmdb_qos_rec_t *)x;
char *name = (char *)key;
if (!xstrcmp(qos_rec->name, name))
return 1;
return 0;
}
extern int slurmdb_find_qos_in_list(void *x, void *key)
{
slurmdb_qos_rec_t *qos_rec = (slurmdb_qos_rec_t *)x;
uint32_t qos_id = *(uint32_t *)key;
if (qos_rec->id == qos_id)
return 1;
return 0;
}
extern int slurmdb_find_selected_step_in_list(void *x, void *key)
{
slurm_selected_step_t *selected_step = (slurm_selected_step_t *)x;
slurm_selected_step_t *query_step = (slurm_selected_step_t *)key;
if (!memcmp(&query_step->step_id, &selected_step->step_id,
sizeof(query_step->step_id)) &&
(query_step->array_task_id == selected_step->array_task_id) &&
(query_step->het_job_offset == selected_step->het_job_offset))
return 1;
return 0;
}
extern int slurmdb_find_assoc_in_list(void *x, void *key)
{
slurmdb_assoc_rec_t *assoc_rec = (slurmdb_assoc_rec_t *)x;
uint32_t assoc_id = *(uint32_t *)key;
if (assoc_rec->id == assoc_id)
return 1;
return 0;
}
extern int slurmdb_find_update_object_in_list(void *x, void *key)
{
slurmdb_update_object_t *update_object = (slurmdb_update_object_t *)x;
slurmdb_update_type_t type = *(slurmdb_update_type_t *)key;
if (update_object->type == type)
return 1;
return 0;
}
extern int slurmdb_find_tres_in_list(void *x, void *key)
{
slurmdb_tres_rec_t *tres_rec = (slurmdb_tres_rec_t *)x;
uint32_t tres_id = *(uint32_t *)key;
if (tres_rec->id == tres_id)
return 1;
return 0;
}
extern int slurmdb_find_tres_in_list_by_count(void *x, void *key)
{
slurmdb_tres_rec_t *tres_rec = (slurmdb_tres_rec_t *)x;
uint64_t count = *(uint64_t *)key;
if (tres_rec->count == count)
return 1;
return 0;
}
extern int slurmdb_find_tres_in_list_by_type(void *x, void *key)
{
slurmdb_tres_rec_t *tres_rec = (slurmdb_tres_rec_t *)x;
char *type = (char *)key;
int end = 0;
bool found = false;
while (type[end]) {
if (type[end] == '/') {
found = true;
break;
}
end++;
}
if (!xstrncasecmp(tres_rec->type, type, end)) {
if ((!found && !tres_rec->name) ||
(found && !xstrcasecmp(tres_rec->name, type + end + 1))) {
return 1;
}
}
return 0;
}
extern int slurmdb_find_cluster_in_list(void *x, void *key)
{
slurmdb_cluster_rec_t *object = (slurmdb_cluster_rec_t *)x;
char *name = (char *)key;
if (!xstrcmp(object->name, name))
return 1;
return 0;
}
extern int slurmdb_find_cluster_accting_tres_in_list(void *x, void *key)
{
slurmdb_cluster_accounting_rec_t *object =
(slurmdb_cluster_accounting_rec_t *)x;
uint32_t tres_id = *(uint32_t *)key;
if (object->tres_rec.id == tres_id)
return 1;
return 0;
}
extern int slurmdb_add_cluster_accounting_to_tres_list(
slurmdb_cluster_accounting_rec_t *accting,
list_t **tres)
{
slurmdb_tres_rec_t *tres_rec = NULL;
if (!*tres)
*tres = list_create(slurmdb_destroy_tres_rec);
else
tres_rec = list_find_first(*tres,
slurmdb_find_tres_in_list,
&accting->tres_rec.id);
if (!tres_rec) {
tres_rec = slurmdb_copy_tres_rec(&accting->tres_rec);
if (!tres_rec) {
error("slurmdb_copy_tres_rec returned NULL");
return SLURM_ERROR;
}
list_push(*tres, tres_rec);
}
tres_rec->alloc_secs += accting->alloc_secs
+ accting->down_secs + accting->idle_secs
+ accting->plan_secs + accting->pdown_secs;
tres_rec->count += accting->tres_rec.count;
tres_rec->rec_count++;
return SLURM_SUCCESS;
}
extern int slurmdb_add_accounting_to_tres_list(
slurmdb_accounting_rec_t *accting,
list_t **tres)
{
slurmdb_tres_rec_t *tres_rec = NULL;
if (!*tres)
*tres = list_create(slurmdb_destroy_tres_rec);
else
tres_rec = list_find_first(*tres,
slurmdb_find_tres_in_list,
&accting->tres_rec.id);
if (!tres_rec) {
tres_rec = slurmdb_copy_tres_rec(&accting->tres_rec);
if (!tres_rec) {
error("slurmdb_copy_tres_rec returned NULL");
return SLURM_ERROR;
}
list_push(*tres, tres_rec);
}
tres_rec->alloc_secs += accting->alloc_secs;
return SLURM_SUCCESS;
}
extern int slurmdb_add_time_from_count_to_tres_list(
slurmdb_tres_rec_t *tres_in, list_t **tres, time_t elapsed)
{
slurmdb_tres_rec_t *tres_rec = NULL;
if (!elapsed)
return SLURM_SUCCESS;
if (!*tres)
*tres = list_create(slurmdb_destroy_tres_rec);
else
tres_rec = list_find_first(*tres,
slurmdb_find_tres_in_list,
&tres_in->id);
if (!tres_rec) {
tres_rec = slurmdb_copy_tres_rec(tres_in);
if (!tres_rec) {
error("slurmdb_copy_tres_rec returned NULL");
return SLURM_ERROR;
}
list_push(*tres, tres_rec);
}
tres_rec->alloc_secs +=
((uint64_t)tres_in->count * (uint64_t)elapsed);
return SLURM_SUCCESS;
}
extern int slurmdb_sum_accounting_list(
slurmdb_cluster_accounting_rec_t *accting,
list_t **total_tres_acct)
{
slurmdb_cluster_accounting_rec_t *total_acct = NULL;
if (!*total_tres_acct)
*total_tres_acct = list_create(
slurmdb_destroy_cluster_accounting_rec);
else
total_acct = list_find_first(
*total_tres_acct,
slurmdb_find_cluster_accting_tres_in_list,
&accting->tres_rec.id);
if (!total_acct) {
total_acct = xmalloc(sizeof(slurmdb_cluster_accounting_rec_t));
total_acct->tres_rec.id = accting->tres_rec.id;
list_push(*total_tres_acct, total_acct);
}
total_acct->alloc_secs += accting->alloc_secs;
total_acct->down_secs += accting->down_secs;
total_acct->idle_secs += accting->idle_secs;
total_acct->plan_secs += accting->plan_secs;
total_acct->over_secs += accting->over_secs;
total_acct->pdown_secs += accting->pdown_secs;
total_acct->tres_rec.count += accting->tres_rec.count;
total_acct->tres_rec.rec_count++;
return SLURM_SUCCESS;
}
extern void slurmdb_transfer_acct_list_2_tres(
list_t *accounting_list, list_t **tres)
{
list_itr_t *itr;
slurmdb_accounting_rec_t *accting = NULL;
xassert(accounting_list);
xassert(tres);
/* get the amount of time this assoc used
during the time we are looking at */
itr = list_iterator_create(accounting_list);
while ((accting = list_next(itr)))
slurmdb_add_accounting_to_tres_list(accting, tres);
list_iterator_destroy(itr);
}
extern void slurmdb_transfer_tres_time(
list_t **tres_list_out, char *tres_str, int elapsed)
{
list_itr_t *itr;
slurmdb_tres_rec_t *tres_rec = NULL;
list_t *job_tres_list = NULL;
xassert(tres_list_out);
slurmdb_tres_list_from_string(&job_tres_list, tres_str,
TRES_STR_FLAG_NONE, NULL);
if (!job_tres_list)
return;
/* get the amount of time this assoc used
during the time we are looking at */
itr = list_iterator_create(job_tres_list);
while ((tres_rec = list_next(itr)))
slurmdb_add_time_from_count_to_tres_list(
tres_rec, tres_list_out, elapsed);
list_iterator_destroy(itr);
FREE_NULL_LIST(job_tres_list);
}
extern int slurmdb_get_tres_base_unit(char *tres_type)
{
int ret_unit = UNIT_NONE;
if ((!xstrcasecmp(tres_type, "mem")) ||
(!xstrcasecmp(tres_type, "bb"))) {
ret_unit = UNIT_MEGA;
}
return ret_unit;
}
extern char *slurmdb_ave_tres_usage(char *tres_string, int tasks)
{
list_t *tres_list = NULL;
list_itr_t *itr;
slurmdb_tres_rec_t *tres_rec = NULL;
uint32_t flags = TRES_STR_FLAG_SIMPLE + TRES_STR_FLAG_REPLACE;
char *ret_tres_str = NULL;
if (!tres_string || (tres_string[0] == '\0'))
return NULL;
slurmdb_tres_list_from_string(&tres_list, tres_string, flags, NULL);
if (!tres_list) {
error("%s: couldn't make tres_list from \'%s\'", __func__,
tres_string);
return ret_tres_str;
}
itr = list_iterator_create(tres_list);
while ((tres_rec = list_next(itr)))
tres_rec->count /= (uint64_t)tasks;
list_iterator_destroy(itr);
ret_tres_str = slurmdb_make_tres_string(tres_list, flags);
FREE_NULL_LIST(tres_list);
return ret_tres_str;
}
extern void slurmdb_destroy_rpc_obj(void *object)
{
slurmdb_rpc_obj_t *rpc_obj = (slurmdb_rpc_obj_t *)object;
if (!rpc_obj)
return;
xfree(rpc_obj);
}
extern void slurmdb_destroy_rollup_stats(void *object)
{
slurmdb_rollup_stats_t *rollup_stats = (slurmdb_rollup_stats_t *)object;
if (!rollup_stats)
return;
xfree(rollup_stats->cluster_name);
xfree(rollup_stats);
}
extern void slurmdb_free_stats_rec_members(void *object)
{
slurmdb_stats_rec_t *rpc_stats = (slurmdb_stats_rec_t *)object;
if (!rpc_stats)
return;
slurmdb_destroy_rollup_stats(rpc_stats->dbd_rollup_stats);
rpc_stats->dbd_rollup_stats = NULL;
FREE_NULL_LIST(rpc_stats->rollup_stats);
FREE_NULL_LIST(rpc_stats->rpc_list);
FREE_NULL_LIST(rpc_stats->user_list);
}
extern void slurmdb_destroy_stats_rec(void *object)
{
if (!object)
return;
slurmdb_free_stats_rec_members(object);
xfree(object);
}
extern void slurmdb_free_slurmdb_stats_members(slurmdb_stats_t *stats)
{
if (stats) {
xfree(stats->tres_usage_in_ave);
xfree(stats->tres_usage_in_max);
xfree(stats->tres_usage_in_max_nodeid);
xfree(stats->tres_usage_in_max_taskid);
xfree(stats->tres_usage_in_min);
xfree(stats->tres_usage_in_min_nodeid);
xfree(stats->tres_usage_in_min_taskid);
xfree(stats->tres_usage_in_tot);
xfree(stats->tres_usage_out_ave);
xfree(stats->tres_usage_out_max);
xfree(stats->tres_usage_out_max_nodeid);
xfree(stats->tres_usage_out_max_taskid);
xfree(stats->tres_usage_out_min);
xfree(stats->tres_usage_out_min_nodeid);
xfree(stats->tres_usage_out_min_taskid);
xfree(stats->tres_usage_out_tot);
}
}
extern void slurmdb_destroy_slurmdb_stats(slurmdb_stats_t *stats)
{
slurmdb_free_slurmdb_stats_members(stats);
xfree(stats);
}
/*
* Comparator for sorting jobs by submit time. 0 (unknown) submit time
* is mapped to INFINITE
*/
extern int slurmdb_job_sort_by_submit_time(void *v1, void *v2)
{
time_t time1 = (*(slurmdb_job_rec_t **)v1)->submit;
time_t time2 = (*(slurmdb_job_rec_t **)v2)->submit;
/*
* Sanity check submits should never be 0, but if somehow that does
* happen treat it as the highest number.
*/
time1 = time1 ? time1 : INFINITE;
time2 = time2 ? time2 : INFINITE;
if (time1 < time2)
return -1;
else if (time1 > time2)
return 1;
return 0;
}
extern void slurmdb_merge_grp_node_usage(bitstr_t **grp_node_bitmap1,
uint16_t **grp_node_job_cnt1,
bitstr_t *grp_node_bitmap2,
uint16_t *grp_node_job_cnt2)
{
if (!grp_node_bitmap2)
return;
if (!grp_node_bitmap1) {
error("%s: grp_node_bitmap1 is NULL", __func__);
return;
}
if (!grp_node_job_cnt1) {
error("%s: grp_node_job_cnt1 is NULL", __func__);
return;
}
if (*grp_node_bitmap1)
bit_or(*grp_node_bitmap1, grp_node_bitmap2);
else
*grp_node_bitmap1 = bit_copy(grp_node_bitmap2);
if (!*grp_node_job_cnt1)
*grp_node_job_cnt1 =
xcalloc(bit_size(*grp_node_bitmap1), sizeof(uint16_t));
for (int i = 0; next_node_bitmap(grp_node_bitmap2, &i); i++) {
(*grp_node_job_cnt1)[i] +=
grp_node_job_cnt2 ? grp_node_job_cnt2[i] : 1;
}
}
extern char *slurmdb_get_job_id_str(slurmdb_job_rec_t *job)
{
char *id = NULL;
if (job->array_task_str) {
xlate_array_task_str(
&job->array_task_str,
job->array_max_tasks, NULL);
id = xstrdup_printf("%u_[%s]",
job->array_job_id,
job->array_task_str);
} else if (job->array_task_id != NO_VAL)
id = xstrdup_printf("%u_%u",
job->array_job_id,
job->array_task_id);
else if (job->het_job_id)
id = xstrdup_printf("%u+%u",
job->het_job_id,
job->het_job_offset);
else
id = xstrdup_printf("%u", job->jobid);
return id;
}
/* This always refers to the batch step. */
extern char *slurmdb_expand_job_stdio_fields(char *path, slurmdb_job_rec_t *job)
{
job_std_pattern_t job_stp = { 0 };
hostlist_t *nodes = NULL;
char *ret;
if (job->nodes) {
nodes = hostlist_create(job->nodes);
job_stp.first_step_node = hostlist_shift(nodes);
} else {
/* Can be NULL if job was never allocated. */
job_stp.first_step_node = NULL;
}
job_stp.array_job_id = job->array_job_id;
job_stp.array_task_id = job->array_task_id;
job_stp.first_step_id = SLURM_BATCH_SCRIPT;
job_stp.jobid = job->jobid;
job_stp.jobname = job->jobname;
job_stp.user = job->user;
job_stp.work_dir = job->work_dir;
ret = expand_stdio_fields(path, &job_stp);
if (nodes) {
hostlist_destroy(nodes);
if (job_stp.first_step_node)
free(job_stp.first_step_node);
}
return ret;
}
extern char *slurmdb_expand_step_stdio_fields(char *path,
slurmdb_step_rec_t *step)
{
job_std_pattern_t job_stp = { 0 };
slurmdb_job_rec_t *job = step->job_ptr;
hostlist_t *nodes = hostlist_create(step->nodes);
char *ret;
job_stp.array_job_id = job->array_job_id;
job_stp.array_task_id = job->array_task_id;
job_stp.first_step_id = step->step_id.step_id;
job_stp.first_step_node = hostlist_shift(nodes);
job_stp.jobid = step->step_id.job_id;
job_stp.jobname = job->jobname;
job_stp.user = job->user;
job_stp.work_dir = step->cwd;
ret = expand_stdio_fields(path, &job_stp);
hostlist_destroy(nodes);
if (job_stp.first_step_node)
free(job_stp.first_step_node);
return ret;
}
extern int slurmdb_add_coord_to_user(slurmdb_user_rec_t *user, char *acct_name,
uint16_t direct)
{
slurmdb_coord_rec_t *coord = NULL;
xassert(user);
xassert(user->coord_accts);
if (assoc_mgr_is_user_acct_coord_user_rec(user, acct_name))
return 0;
coord = xmalloc(sizeof(*coord));
coord->name = xstrdup(acct_name);
coord->direct = direct;
list_append(user->coord_accts, coord);
debug2("adding %s to coord_accts for user %s %s",
coord->name, user->name,
coord->direct ? "directly" : "indirectly");
return 1;
}