/*****************************************************************************\ * info_assoc_mgr.c - Association Manager information from the * slurmctld functions for scontrol. ***************************************************************************** * Copyright (C) 2004 CSCS * Copyright (C) 2015 SchedMD LLC * Written by Stephen Trofinoff and Danny Auble * * This file is part of Slurm, a resource management program. * For details, see . * 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 "scontrol.h" #include "src/common/xstring.h" static uint32_t tres_cnt = 0; static char **tres_names = NULL; static uint32_t req_flags = 0; static void _print_tres_line(const char *name, uint64_t *limits, uint64_t *used, uint64_t divider) { int i; bool comma = 0; xassert(tres_cnt); xassert(tres_names); printf("%s=", name); if (!limits) return; for (i=0; iacct, one_liner ? "={" : new_line_char); printf("MaxJobsPA="); if (qos_rec->max_jobs_pa != INFINITE) printf("%u", qos_rec->max_jobs_pa); else printf("N"); printf("(%u) ", used_limit->jobs); printf("MaxJobsAccruePA="); if (qos_rec->max_jobs_accrue_pa != INFINITE) printf("%u", qos_rec->max_jobs_accrue_pa); else printf("N"); printf("(%u) ", used_limit->accrue_cnt); printf("MaxSubmitJobsPA="); if (qos_rec->max_submit_jobs_pa != INFINITE) printf("%u", qos_rec->max_submit_jobs_pa); else printf("N"); printf("(%u)%s", used_limit->submit_jobs, new_line_char); _print_tres_line("MaxTRESPA", qos_rec->max_tres_pa_ctld, used_limit->tres, 0); if (one_liner) printf("}"); /* MaxTRESRunMinsPA doesn't do anything yet, if/when it does * change the last param in the print_tres_line to 0. */ /* printf("%s", one_liner ? "" : " "); */ /* _print_tres_line("MaxTRESRunMinsPA", */ /* qos_rec->max_tres_run_mins_pa_ctld, */ /* used_limit->tres_run_mins, 60, 1); */ return SLURM_SUCCESS; } static int _print_used_user_limit(slurmdb_used_limits_t *used_limit, slurmdb_qos_rec_t *qos_rec) { char *new_line_char = one_liner ? " " : "\n "; printf("%s%d%s", one_liner ? " " : "\n ", used_limit->uid, one_liner ? "={" : new_line_char); printf("MaxJobsPU="); if (qos_rec->max_jobs_pu != INFINITE) printf("%u", qos_rec->max_jobs_pu); else printf("N"); printf("(%u) ", used_limit->jobs); printf("MaxJobsAccruePU="); if (qos_rec->max_jobs_accrue_pu != INFINITE) printf("%u", qos_rec->max_jobs_accrue_pu); else printf("N"); printf("(%u) ", used_limit->accrue_cnt); printf("MaxSubmitJobsPU="); if (qos_rec->max_submit_jobs_pu != INFINITE) printf("%u", qos_rec->max_submit_jobs_pu); else printf("N"); printf("(%u)%s", used_limit->submit_jobs, new_line_char); _print_tres_line("MaxTRESPU", qos_rec->max_tres_pu_ctld, used_limit->tres, 0); if (one_liner) printf("}"); /* MaxTRESRunMinsPU doesn't do anything yet, if/when it does * change the last param in the print_tres_line to 0. */ /* printf("%s", one_liner ? "" : " "); */ /* _print_tres_line("MaxTRESRunMinsPU", */ /* qos_rec->max_tres_run_mins_pu_ctld, */ /* used_limit->tres_run_mins, 60, 1); */ return SLURM_SUCCESS; } static void _print_assoc_mgr_info(assoc_mgr_info_msg_t *msg) { ListIterator itr; slurmdb_user_rec_t *user_rec; slurmdb_assoc_rec_t *assoc_rec; slurmdb_qos_rec_t *qos_rec; uint64_t tmp64_array[msg->tres_cnt]; char *new_line_char = one_liner ? " " : "\n "; int i; printf("Current Association Manager state\n"); tres_cnt = msg->tres_cnt; tres_names = msg->tres_names; if (!msg->user_list || !list_count(msg->user_list)) { if (req_flags & ASSOC_MGR_INFO_FLAG_USERS) printf("%sNo users currently cached in Slurm.%s\n", one_liner ? "" : "\n", one_liner ? "" : "\n"); } else { printf("%sUser Records%s\n", one_liner ? "" : "\n", one_liner ? "" : "\n"); itr = list_iterator_create(msg->user_list); while ((user_rec = list_next(itr))) { printf("UserName=%s(%u) DefAccount=%s " "DefWckey=%s AdminLevel=%s\n", user_rec->name, user_rec->uid, user_rec->default_acct, user_rec->default_wckey, slurmdb_admin_level_str(user_rec->admin_level)); } list_iterator_destroy(itr); } if (!msg->assoc_list || !list_count(msg->assoc_list)) { if (req_flags & ASSOC_MGR_INFO_FLAG_ASSOC) printf("%sNo associations currently " "cached in Slurm.%s\n", one_liner ? "" : "\n", one_liner ? "" : "\n"); } else { printf("%sAssociation Records%s\n", one_liner ? "" : "\n", one_liner ? "" : "\n"); itr = list_iterator_create(msg->assoc_list); while ((assoc_rec = list_next(itr))) { if (!assoc_rec->usage) continue; printf("ClusterName=%s Account=%s ", assoc_rec->cluster, assoc_rec->acct); if (assoc_rec->user) printf("UserName=%s(%u) ", assoc_rec->user, assoc_rec->uid); else printf("UserName= "); printf("Partition=%s Priority=%u ID=%u%s", assoc_rec->partition ? assoc_rec->partition : "", assoc_rec->priority, assoc_rec->id, new_line_char); printf("SharesRaw/Norm/Level/Factor=" "%u/%.2f/%u/%.2f%s", assoc_rec->shares_raw, assoc_rec->usage->shares_norm, (assoc_rec->usage->level_shares == NO_VAL) ? 1 : assoc_rec->usage->level_shares, assoc_rec->usage->fs_factor, new_line_char); printf("UsageRaw/Norm/Efctv=%.2Lf/%.2Lf/%.2Lf%s", assoc_rec->usage->usage_raw, (assoc_rec->usage->usage_norm == (long double)NO_VAL) ? 1 : assoc_rec->usage->usage_norm, (assoc_rec->usage->usage_efctv == (long double)NO_VAL) ? 1 : assoc_rec->usage->usage_efctv, new_line_char); if (assoc_rec->parent_acct) printf("ParentAccount=%s(%u) ", assoc_rec->parent_acct, assoc_rec->parent_id); else printf("ParentAccount= "); /* rgt isn't always valid coming from the * association manager (so don't print it). */ printf("Lft=%u DefAssoc=%s%s", assoc_rec->lft, assoc_rec->is_def ? "Yes" : "No", new_line_char); if (assoc_rec->grp_jobs != INFINITE) printf("GrpJobs=%u(%u) ", assoc_rec->grp_jobs, assoc_rec->usage->used_jobs); else printf("GrpJobs=N(%u) ", assoc_rec->usage->used_jobs); if (assoc_rec->grp_jobs_accrue != INFINITE) printf("GrpJobsAccrue=%u(%u)", assoc_rec->grp_jobs_accrue, assoc_rec->usage->accrue_cnt); else printf("GrpJobsAccrue=N(%u)", assoc_rec->usage->accrue_cnt); /* NEW LINE */ printf("%s", new_line_char); if (assoc_rec->grp_submit_jobs != INFINITE) printf("GrpSubmitJobs=%u(%u) ", assoc_rec->grp_submit_jobs, assoc_rec->usage->used_submit_jobs); else printf("GrpSubmitJobs=N(%u) ", assoc_rec->usage->used_submit_jobs); if (assoc_rec->grp_wall != INFINITE) printf("GrpWall=%u(%.2f)", assoc_rec->grp_wall, assoc_rec->usage->grp_used_wall/60); else printf("GrpWall=N(%.2f)", assoc_rec->usage->grp_used_wall/60); /* NEW LINE */ printf("%s", new_line_char); _print_tres_line("GrpTRES", assoc_rec->grp_tres_ctld, assoc_rec->usage->grp_used_tres, 0); /* NEW LINE */ printf("%s", new_line_char); memset(tmp64_array, 0, sizeof(tmp64_array)); if (assoc_rec->usage->usage_tres_raw) for (i=0; iusage-> usage_tres_raw[i]; _print_tres_line("GrpTRESMins", assoc_rec->grp_tres_mins_ctld, tmp64_array, 60); /* NEW LINE */ printf("%s", new_line_char); _print_tres_line("GrpTRESRunMins", assoc_rec->grp_tres_run_mins_ctld, assoc_rec->usage-> grp_used_tres_run_secs, 60); /* NEW LINE */ printf("%s", new_line_char); if (assoc_rec->max_jobs != INFINITE) printf("MaxJobs=%u(%u) ", assoc_rec->max_jobs, assoc_rec->usage->used_jobs); else printf("MaxJobs= "); if (assoc_rec->max_jobs_accrue != INFINITE) printf("MaxJobsAccrue=%u(%u) ", assoc_rec->max_jobs_accrue, assoc_rec->usage->accrue_cnt); else printf("MaxJobsAccrue= "); if (assoc_rec->max_submit_jobs != INFINITE) printf("MaxSubmitJobs=%u(%u) ", assoc_rec->max_submit_jobs, assoc_rec->usage->used_submit_jobs); else printf("MaxSubmitJobs= "); if (assoc_rec->max_wall_pj != INFINITE) printf("MaxWallPJ=%u", assoc_rec->max_wall_pj); else printf("MaxWallPJ="); /* NEW LINE */ printf("%s", new_line_char); _print_tres_line("MaxTRESPJ", assoc_rec->max_tres_ctld, NULL, 0); /* NEW LINE */ printf("%s", new_line_char); _print_tres_line("MaxTRESPN", assoc_rec->max_tres_pn_ctld, NULL, 0); /* NEW LINE */ printf("%s", new_line_char); _print_tres_line("MaxTRESMinsPJ", assoc_rec->max_tres_mins_ctld, NULL, 0); /* NEW LINE */ printf("%s", new_line_char); if (assoc_rec->min_prio_thresh != INFINITE) printf("MinPrioThresh=%u", assoc_rec->min_prio_thresh); else printf("MinPrioThresh="); /* NEW LINE */ printf("\n"); /* Doesn't do anything yet */ /* _print_tres_line("MaxTRESRunMins", */ /* assoc_rec->max_tres_mins_ctld, */ /* NULL, 0); */ /* NEW LINE */ /* printf("%s", new_line_char); */ } } if (!msg->qos_list || !list_count(msg->qos_list)) { if (req_flags & ASSOC_MGR_INFO_FLAG_QOS) printf("%sNo QOS currently cached in Slurm.%s\n", one_liner ? "" : "\n", one_liner ? "" : "\n"); } else { printf("%sQOS Records%s\n", one_liner ? "" : "\n", one_liner ? "" : "\n"); itr = list_iterator_create(msg->qos_list); while ((qos_rec = list_next(itr))) { if (!qos_rec->usage) continue; printf("QOS=%s(%u)%s", qos_rec->name, qos_rec->id, new_line_char); printf("UsageRaw=%Lf%s", qos_rec->usage->usage_raw, new_line_char); if (qos_rec->grp_jobs != INFINITE) printf("GrpJobs=%u(%u) ", qos_rec->grp_jobs, qos_rec->usage->grp_used_jobs); else printf("GrpJobs=N(%u) ", qos_rec->usage->grp_used_jobs); if (qos_rec->grp_jobs_accrue != INFINITE) printf("GrpJobsAccrue=%u(%u) ", qos_rec->grp_jobs_accrue, qos_rec->usage->accrue_cnt); else printf("GrpJobsAccrue=N(%u) ", qos_rec->usage->accrue_cnt); if (qos_rec->grp_submit_jobs != INFINITE) printf("GrpSubmitJobs=%u(%u) ", qos_rec->grp_submit_jobs, qos_rec->usage->grp_used_submit_jobs); else printf("GrpSubmitJobs=N(%u) ", qos_rec->usage->grp_used_submit_jobs); if (qos_rec->grp_wall != INFINITE) printf("GrpWall=%u(%.2f)", qos_rec->grp_wall, qos_rec->usage->grp_used_wall/60); else printf("GrpWall=N(%.2f)", qos_rec->usage->grp_used_wall/60); /* NEW LINE */ printf("%s", new_line_char); _print_tres_line("GrpTRES", qos_rec->grp_tres_ctld, qos_rec->usage->grp_used_tres, 0); /* NEW LINE */ printf("%s", new_line_char); memset(tmp64_array, 0, sizeof(tmp64_array)); if (qos_rec->usage->usage_tres_raw) for (i=0; iusage-> usage_tres_raw[i]; _print_tres_line("GrpTRESMins", qos_rec->grp_tres_mins_ctld, tmp64_array, 60); /* NEW LINE */ printf("%s", new_line_char); _print_tres_line("GrpTRESRunMins", qos_rec->grp_tres_run_mins_ctld, qos_rec->usage-> grp_used_tres_run_secs, 60); /* NEW LINE */ printf("%s", new_line_char); if (qos_rec->max_wall_pj != INFINITE) printf("MaxWallPJ=%u", qos_rec->max_wall_pj); else printf("MaxWallPJ="); /* NEW LINE */ printf("%s", new_line_char); _print_tres_line("MaxTRESPJ", qos_rec->max_tres_pj_ctld, NULL, 0); /* NEW LINE */ printf("%s", new_line_char); _print_tres_line("MaxTRESPN", qos_rec->max_tres_pn_ctld, NULL, 0); /* NEW LINE */ printf("%s", new_line_char); _print_tres_line("MaxTRESMinsPJ", qos_rec->max_tres_mins_pj_ctld, NULL, 0); /* NEW LINE */ printf("%s", new_line_char); /* Doesn't do anything yet */ /* _print_tres_line("MaxTRESRunMinsPA", */ /* qos_rec->max_tres_mins_pa_ctld, */ /* NULL, 0); */ /* NEW LINE */ /* printf("%s", new_line_char); */ /* _print_tres_line("MaxTRESRunMinsPU", */ /* qos_rec->max_tres_mins_pu_ctld, */ /* NULL, 0); */ /* NEW LINE */ /* printf("%s", new_line_char); */ if (qos_rec->min_prio_thresh != INFINITE) printf("MinPrioThresh=%u ", qos_rec->min_prio_thresh); else printf("MinPrioThresh= "); /* NEW LINE */ printf("%s", new_line_char); _print_tres_line("MinTRESPJ", qos_rec->min_tres_pj_ctld, NULL, 0); /* NEW LINE */ printf("%s", new_line_char); printf("PreemptMode=%s%s", preempt_mode_string(qos_rec->preempt_mode), one_liner ? " " : "\n "); if (qos_rec->priority == INFINITE || qos_rec->priority == NO_VAL) printf("Priority=NONE"); else printf("Priority=%u", qos_rec->priority); /* NEW LINE */ printf("%s", new_line_char); printf("Account Limits%s", one_liner ? "=" : ""); if (qos_rec->usage->acct_limit_list) { list_for_each(qos_rec->usage->acct_limit_list, (ListForF)_print_used_acct_limit, qos_rec); } else printf("%sNo Accounts", one_liner ? "" : "\n "); /* NEW LINE */ printf("%s", new_line_char); printf("User Limits%s", one_liner ? "=" : ""); if (qos_rec->usage->user_limit_list) { list_for_each(qos_rec->usage->user_limit_list, (ListForF)_print_used_user_limit, qos_rec); } else printf("%sNo Users", one_liner ? "" : "\n "); /* NEW LINE */ printf("\n"); } } } /* scontrol_print_assoc_mgr_info() * * Retrieve and display the association manager information * from the controller * */ extern void scontrol_print_assoc_mgr_info(int argc, char **argv) { char *tag = NULL, *val = NULL; int cc, tag_len, i; assoc_mgr_info_request_msg_t req; assoc_mgr_info_msg_t *msg = NULL; memset(&req, 0, sizeof(assoc_mgr_info_request_msg_t)); for (i = 0; i < argc; ++i) { tag = argv[i]; tag_len = strlen(tag); val = strchr(argv[i], '='); if (val) { tag_len = val - argv[i]; val++; } /* We free every list before creating it. This way we ensure * we are just appending the last value if user repeats entity. */ if (!val || !val[0]) { fprintf(stderr, "No value given for option %s\n", tag); goto endit; } else if (!xstrncasecmp(tag, "accounts", MAX(tag_len, 1))) { if (!req.acct_list) req.acct_list = list_create(xfree_ptr); slurm_addto_char_list(req.acct_list, val); } else if (!xstrncasecmp(tag, "flags", MAX(tag_len, 1))) { if (xstrcasestr(val, "users")) req.flags |= ASSOC_MGR_INFO_FLAG_USERS; if (xstrcasestr(val, "assoc")) req.flags |= ASSOC_MGR_INFO_FLAG_ASSOC; if (xstrcasestr(val, "qos")) req.flags |= ASSOC_MGR_INFO_FLAG_QOS; if (!req.flags) { fprintf(stderr, "invalid flag '%s', " "valid options are " "'Assoc, QOS, and/or Users'\n", val); goto endit; } } else if (!xstrncasecmp(tag, "qos", MAX(tag_len, 1))) { if (!req.qos_list) req.qos_list = list_create(xfree_ptr); slurm_addto_char_list(req.qos_list, val); } else if (!xstrncasecmp(tag, "users", MAX(tag_len, 1))) { if (!req.user_list) req.user_list = list_create(xfree_ptr); /* * Since we don't have a real connection to the dbd to * know if case is enforced or not so we will assume * it is. */ slurm_addto_char_list_with_case(req.user_list, val, 0); } else { exit_code = 1; if (quiet_flag != 1) fprintf(stderr, "invalid entity: %s for keyword" ":show assoc_mgr\n", tag); goto endit; } } if (!req.flags) req.flags = ASSOC_MGR_INFO_FLAG_ASSOC | ASSOC_MGR_INFO_FLAG_USERS | ASSOC_MGR_INFO_FLAG_QOS; req_flags = req.flags; /* call the controller to get the meat */ cc = slurm_load_assoc_mgr_info(&req, &msg); if (cc == SLURM_SUCCESS) { /* print the info */ _print_assoc_mgr_info(msg); } else { /* Hosed, crap out. */ exit_code = 1; if (quiet_flag != 1) slurm_perror("slurm_load_assoc_mgr_info error"); } slurm_free_assoc_mgr_info_msg(msg); endit: slurm_free_assoc_mgr_info_request_members(&req); return; }