| /*****************************************************************************\ | |
| * user_report_functions.c - Interface to functions dealing with user reports. | |
| ****************************************************************************** | |
| * 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 "slurm/slurm.h" | |
| #include "slurm/slurm_errno.h" | |
| #include "slurm/slurmdb.h" | |
| #include "src/common/slurmdb_defs.h" | |
| #include "src/interfaces/accounting_storage.h" | |
| #include "src/common/xstring.h" | |
| extern list_t *slurmdb_report_user_top_usage(void *db_conn, | |
| slurmdb_user_cond_t *user_cond, | |
| bool group_accounts) | |
| { | |
| list_t *cluster_list = NULL; | |
| list_itr_t *itr = NULL, *itr2 = NULL, *itr3 = NULL; | |
| list_itr_t *cluster_itr = NULL; | |
| slurmdb_cluster_cond_t cluster_cond; | |
| list_t *user_list = NULL; | |
| list_t *usage_cluster_list = NULL; | |
| char *object = NULL; | |
| int exit_code = 0; | |
| slurmdb_user_rec_t *user = NULL; | |
| slurmdb_cluster_rec_t *cluster = NULL; | |
| slurmdb_assoc_rec_t *assoc = NULL; | |
| slurmdb_report_user_rec_t *slurmdb_report_user = NULL; | |
| slurmdb_report_cluster_rec_t *slurmdb_report_cluster = NULL; | |
| bool delete_user_cond = 0, delete_assoc_cond = 0, | |
| delete_cluster_list = 0; | |
| time_t start_time, end_time; | |
| if (!user_cond) { | |
| delete_user_cond = 1; | |
| user_cond = xmalloc(sizeof(slurmdb_user_cond_t)); | |
| } | |
| if (!user_cond->assoc_cond) { | |
| delete_assoc_cond = 1; | |
| user_cond->assoc_cond = | |
| xmalloc(sizeof(slurmdb_assoc_cond_t)); | |
| } | |
| if (!user_cond->assoc_cond->cluster_list) { | |
| delete_cluster_list = 1; | |
| user_cond->assoc_cond->cluster_list = list_create(xfree_ptr); | |
| } | |
| user_cond->with_deleted = 1; | |
| user_cond->with_assocs = 1; | |
| user_cond->assoc_cond->flags = ASSOC_COND_FLAG_WITH_NG_USAGE | | |
| ASSOC_COND_FLAG_WOPI; | |
| /* This needs to be done on some systems to make sure | |
| assoc_cond isn't messed up. This has happened on some 64 | |
| bit machines and this is here to be on the safe side. | |
| */ | |
| start_time = user_cond->assoc_cond->usage_start; | |
| end_time = user_cond->assoc_cond->usage_end; | |
| slurmdb_report_set_start_end_time(&start_time, &end_time); | |
| user_cond->assoc_cond->usage_start = start_time; | |
| user_cond->assoc_cond->usage_end = end_time; | |
| user_list = acct_storage_g_get_users(db_conn, user_cond); | |
| if (!user_list) { | |
| exit_code=1; | |
| fprintf(stderr, " Problem with user query.\n"); | |
| goto end_it; | |
| } | |
| /* We have to get the clusters here or we will be unable to | |
| get the correct total time for the cluster if associations | |
| are not enforced. | |
| */ | |
| slurmdb_init_cluster_cond(&cluster_cond, 0); | |
| cluster_cond.with_usage = 1; | |
| cluster_cond.with_deleted = 1; | |
| cluster_cond.usage_end = user_cond->assoc_cond->usage_end; | |
| cluster_cond.usage_start = user_cond->assoc_cond->usage_start; | |
| cluster_cond.cluster_list = user_cond->assoc_cond->cluster_list; | |
| usage_cluster_list = | |
| acct_storage_g_get_clusters(db_conn, &cluster_cond); | |
| if (!usage_cluster_list) { | |
| exit_code=1; | |
| fprintf(stderr, " Problem with cluster query.\n"); | |
| goto end_it; | |
| } | |
| cluster_list = list_create(slurmdb_destroy_report_cluster_rec); | |
| itr = list_iterator_create(usage_cluster_list); | |
| while((cluster = list_next(itr))) { | |
| /* check to see if this cluster is around during the | |
| time we are looking at */ | |
| if (!cluster->accounting_list | |
| || !list_count(cluster->accounting_list)) | |
| continue; | |
| slurmdb_report_cluster = slurmdb_cluster_rec_2_report(cluster); | |
| list_append(cluster_list, slurmdb_report_cluster); | |
| slurmdb_report_cluster->user_list = | |
| list_create(slurmdb_destroy_report_user_rec); | |
| } | |
| list_iterator_destroy(itr); | |
| FREE_NULL_LIST(usage_cluster_list); | |
| itr = list_iterator_create(user_list); | |
| cluster_itr = list_iterator_create(cluster_list); | |
| while((user = list_next(itr))) { | |
| struct passwd *passwd_ptr = NULL; | |
| if (!user->assoc_list || !list_count(user->assoc_list)) | |
| continue; | |
| passwd_ptr = getpwnam(user->name); | |
| if (passwd_ptr) | |
| user->uid = passwd_ptr->pw_uid; | |
| else | |
| user->uid = NO_VAL; | |
| itr2 = list_iterator_create(user->assoc_list); | |
| while((assoc = list_next(itr2))) { | |
| if (!assoc->accounting_list | |
| || !list_count(assoc->accounting_list)) | |
| continue; | |
| while((slurmdb_report_cluster = | |
| list_next(cluster_itr))) { | |
| if (!xstrcmp(slurmdb_report_cluster->name, | |
| assoc->cluster)) { | |
| list_itr_t *user_itr = NULL; | |
| if (!group_accounts) { | |
| slurmdb_report_user = NULL; | |
| goto new_user; | |
| } | |
| user_itr = list_iterator_create( | |
| slurmdb_report_cluster-> | |
| user_list); | |
| while((slurmdb_report_user | |
| = list_next(user_itr))) { | |
| if (slurmdb_report_user->uid | |
| != NO_VAL) { | |
| if (slurmdb_report_user-> | |
| uid | |
| == user->uid) | |
| break; | |
| } else if (slurmdb_report_user-> | |
| name | |
| && !xstrcasecmp( | |
| slurmdb_report_user-> | |
| name, | |
| user->name)) | |
| break; | |
| } | |
| list_iterator_destroy(user_itr); | |
| new_user: | |
| if (!slurmdb_report_user) { | |
| slurmdb_report_user = xmalloc( | |
| sizeof | |
| (slurmdb_report_user_rec_t)); | |
| slurmdb_report_user->name = | |
| xstrdup(assoc->user); | |
| slurmdb_report_user->uid = | |
| user->uid; | |
| slurmdb_report_user->acct_list = | |
| list_create(xfree_ptr); | |
| slurmdb_report_user->partition = | |
| xstrdup(assoc->partition); | |
| list_append(slurmdb_report_cluster-> | |
| user_list, | |
| slurmdb_report_user); | |
| /* | |
| * In order to know that | |
| * partition associations exist | |
| * for reporting we need to add | |
| * an empty partition list to | |
| * user_cond. | |
| */ | |
| if (slurmdb_report_user-> | |
| partition && | |
| !user_cond->assoc_cond-> | |
| partition_list) { | |
| user_cond->assoc_cond-> | |
| partition_list = | |
| list_create(NULL); | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| if (!slurmdb_report_cluster) { | |
| error("This cluster '%s' hasn't " | |
| "registered yet, but we have jobs " | |
| "that ran?", assoc->cluster); | |
| slurmdb_report_cluster = | |
| xmalloc(sizeof(slurmdb_report_cluster_rec_t)); | |
| list_append(cluster_list, slurmdb_report_cluster); | |
| slurmdb_report_cluster->name = xstrdup(assoc->cluster); | |
| slurmdb_report_cluster->user_list = | |
| list_create(slurmdb_destroy_report_user_rec); | |
| slurmdb_report_user = | |
| xmalloc(sizeof(slurmdb_report_user_rec_t)); | |
| slurmdb_report_user->name = xstrdup(assoc->user); | |
| slurmdb_report_user->uid = user->uid; | |
| slurmdb_report_user->acct_list = | |
| list_create(xfree_ptr); | |
| list_append(slurmdb_report_cluster->user_list, | |
| slurmdb_report_user); | |
| } | |
| list_iterator_reset(cluster_itr); | |
| itr3 = list_iterator_create( | |
| slurmdb_report_user->acct_list); | |
| while((object = list_next(itr3))) { | |
| if (!xstrcmp(object, assoc->acct)) | |
| break; | |
| } | |
| list_iterator_destroy(itr3); | |
| if (!object) | |
| list_append(slurmdb_report_user->acct_list, | |
| xstrdup(assoc->acct)); | |
| slurmdb_transfer_acct_list_2_tres( | |
| assoc->accounting_list, | |
| &slurmdb_report_user->tres_list); | |
| } | |
| list_iterator_destroy(itr2); | |
| } | |
| list_iterator_destroy(itr); | |
| list_iterator_destroy(cluster_itr); | |
| end_it: | |
| if (delete_cluster_list) { | |
| FREE_NULL_LIST(user_cond->assoc_cond->cluster_list); | |
| user_cond->assoc_cond->cluster_list = NULL; | |
| } | |
| if (delete_assoc_cond) { | |
| slurmdb_destroy_assoc_cond(user_cond->assoc_cond); | |
| user_cond->assoc_cond = NULL; | |
| } | |
| if (delete_user_cond) { | |
| slurmdb_destroy_user_cond(user_cond); | |
| user_cond = NULL; | |
| } | |
| FREE_NULL_LIST(user_list); | |
| if (exit_code) { | |
| FREE_NULL_LIST(cluster_list); | |
| } | |
| return cluster_list; | |
| } |