| /*****************************************************************************\ |
| * 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; |
| } |