diff --git a/src/common/assoc_mgr.c b/src/common/assoc_mgr.c index a2a437a15a592e60ea9cfe3c713bc1ed7aadee97..f2e7a0a26dd75d35853691b2399b5ae80cb06173 100644 --- a/src/common/assoc_mgr.c +++ b/src/common/assoc_mgr.c @@ -824,6 +824,53 @@ extern int assoc_mgr_fini(char *state_save_location) return SLURM_SUCCESS; } +extern int assoc_mgr_get_user_assocs(void *db_conn, + acct_association_rec_t *assoc, + int enforce, + List assoc_list) +{ + ListIterator itr = NULL; + acct_association_rec_t *found_assoc = NULL; + int set = 1; + + xassert(assoc); + xassert(assoc->uid != (uint32_t)NO_VAL); + xassert(assoc_list); + + if(!assoc_mgr_association_list) { + if(_get_assoc_mgr_association_list(db_conn, enforce) + == SLURM_ERROR) + return SLURM_ERROR; + } + + if((!assoc_mgr_association_list + || !list_count(assoc_mgr_association_list)) + && !(enforce & ACCOUNTING_ENFORCE_ASSOCS)) + return SLURM_SUCCESS; + + slurm_mutex_lock(&assoc_mgr_association_lock); + itr = list_iterator_create(assoc_mgr_association_list); + while((found_assoc = list_next(itr))) { + if(assoc->uid != found_assoc->uid) { + debug4("not the right user %u != %u", + assoc->uid, found_assoc->uid); + continue; + } + + list_append(assoc_list, found_assoc); + set = 1; + } + list_iterator_destroy(itr); + slurm_mutex_unlock(&assoc_mgr_association_lock); + + if(set) + return SLURM_SUCCESS; + else { + debug("user %u does not have any associations", assoc->uid); + return SLURM_ERROR; + } +} + extern int assoc_mgr_fill_in_assoc(void *db_conn, acct_association_rec_t *assoc, int enforce, acct_association_rec_t **assoc_pptr) diff --git a/src/common/assoc_mgr.h b/src/common/assoc_mgr.h index fc86956716fd645f5c89471d45aded384bf982e1..d81d78dc6a7ea18c58552c9eaf2b6e2ec435d8cb 100644 --- a/src/common/assoc_mgr.h +++ b/src/common/assoc_mgr.h @@ -76,17 +76,21 @@ extern pthread_mutex_t assoc_mgr_wckey_lock; /* * get info from the storage - * IN/OUT: user - acct_user_rec_t with the name set of the user. - * "default_account" will be filled in on - * successful return DO NOT FREE. - * IN/OUT: user_pptr - if non-NULL then return a pointer to the - * acct_user record in cache on success - * DO NOT FREE. - * RET: SLURM_SUCCESS on success SLURM_ERROR else + * IN: assoc - acct_association_rec_t with at least cluster and + * account set for account association. To get user + * association set user, and optional partition. + * Sets "id" field with the association ID. + * IN: enforce - return an error if no such association exists + * IN/OUT: assoc_list - contains a list of assoc_rec ptrs to + * associations this user has in the list. This + * list should be created with list_create(NULL) + * since we are putting pointers to memory used elsewhere. + * RET: SLURM_SUCCESS on success, else SLURM_ERROR */ -extern int assoc_mgr_fill_in_user(void *db_conn, acct_user_rec_t *user, - int enforce, - acct_user_rec_t **user_pptr); +extern int assoc_mgr_get_user_assocs(void *db_conn, + acct_association_rec_t *assoc, + int enforce, + List assoc_list); /* * get info from the storage @@ -105,6 +109,19 @@ extern int assoc_mgr_fill_in_assoc(void *db_conn, int enforce, acct_association_rec_t **assoc_pptr); +/* + * get info from the storage + * IN/OUT: user - acct_user_rec_t with the name set of the user. + * "default_account" will be filled in on + * successful return DO NOT FREE. + * IN/OUT: user_pptr - if non-NULL then return a pointer to the + * acct_user record in cache on success + * DO NOT FREE. + * RET: SLURM_SUCCESS on success SLURM_ERROR else + */ +extern int assoc_mgr_fill_in_user(void *db_conn, acct_user_rec_t *user, + int enforce, + acct_user_rec_t **user_pptr); /* * get info from the storage diff --git a/src/common/slurm_accounting_storage.c b/src/common/slurm_accounting_storage.c index 27f9c64056e3220cb63574276ded68775e902a00..499641588daea397312b503bbe0b38d4172fa09f 100644 --- a/src/common/slurm_accounting_storage.c +++ b/src/common/slurm_accounting_storage.c @@ -757,6 +757,7 @@ extern void destroy_acct_reservation_rec(void *object) { acct_reservation_rec_t *acct_resv = (acct_reservation_rec_t *)object; if(acct_resv) { + xfree(acct_resv->assocs); xfree(acct_resv->cluster); xfree(acct_resv->nodes); xfree(acct_resv); @@ -5665,6 +5666,7 @@ extern void pack_acct_reservation_rec(void *in, uint16_t rpc_version, acct_reservation_rec_t *object = (acct_reservation_rec_t *)in; if(!object) { + packnull(buffer); packnull(buffer); pack32((uint32_t)NO_VAL, buffer); pack16((uint16_t)NO_VAL, buffer); @@ -5676,6 +5678,7 @@ extern void pack_acct_reservation_rec(void *in, uint16_t rpc_version, return; } + packstr(object->assocs, buffer); packstr(object->cluster, buffer); pack32(object->cpus, buffer); pack16(object->flags, buffer); @@ -5695,6 +5698,7 @@ extern int unpack_acct_reservation_rec(void **object, uint16_t rpc_version, *object = object_ptr; + safe_unpackstr_xmalloc(&object_ptr->assocs, &uint32_tmp, buffer); safe_unpackstr_xmalloc(&object_ptr->cluster, &uint32_tmp, buffer); safe_unpack32(&object_ptr->cpus, buffer); safe_unpack16(&object_ptr->flags, buffer); diff --git a/src/common/slurm_accounting_storage.h b/src/common/slurm_accounting_storage.h index ce73450580a57edd9a3966f2781a3ab3e8b532fe..970b33562eafb549c550874a2e16dec99c6fa8e5 100644 --- a/src/common/slurm_accounting_storage.h +++ b/src/common/slurm_accounting_storage.h @@ -349,6 +349,7 @@ typedef struct { } acct_qos_cond_t; typedef struct { + char *assocs; /* comma seperated list of associations */ char *cluster; /* cluster reservation is for */ uint32_t cpus; /* how many cpus are in reservation */ uint16_t flags; /* flags for reservation. */ diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c index f800efbc18c321168f3182178ff02fd5ca19aa4c..692e1cef6c905bf084fc6cbd0975535eafbce7e5 100644 --- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c +++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c @@ -878,6 +878,12 @@ static int _setup_resv_limits(acct_reservation_rec_t *resv, { /* strip off the action item from the flags */ + if(resv->assocs) { + xstrcat(*cols, ", assoclist"); + xstrfmtcat(*vals, ", \"%s\"", resv->assocs); + xstrfmtcat(*extra, ", assoclist=\"%s\"", resv->assocs); + } + if(resv->cpus != (uint32_t)NO_VAL) { xstrcat(*cols, ", cpus"); xstrfmtcat(*vals, ", %u", resv->cpus); @@ -2667,8 +2673,9 @@ static int _mysql_acct_check_tables(MYSQL *db_conn) { "cluster", "text not null" }, { "deleted", "tinyint default 0" }, { "cpus", "mediumint unsigned not null" }, + { "assoclist", "text not null default ''" }, { "nodelist", "text not null default ''" }, - { "start", "int unsigned default 0 not null" }, + { "start", "int unsigned default 0 not null"}, { "end", "int unsigned default 0 not null" }, { "flags", "smallint default 0 not null" }, { NULL, NULL} @@ -4553,7 +4560,6 @@ extern int acct_storage_p_add_reservation(mysql_conn_t *mysql_conn, if((rc = mysql_db_query(mysql_conn->db_conn, query) == SLURM_SUCCESS)) rc = mysql_clear_results(mysql_conn->db_conn); - xfree(query); xfree(cols); @@ -5850,6 +5856,7 @@ extern int acct_storage_p_modify_reservation(mysql_conn_t *mysql_conn, int i; int set = 0; char *resv_req_inx[] = { + "assoclist", "start", "end", "cpus", @@ -5857,6 +5864,7 @@ extern int acct_storage_p_modify_reservation(mysql_conn_t *mysql_conn, "flags" }; enum { + RESV_ASSOCS, RESV_START, RESV_END, RESV_CPU, @@ -5944,20 +5952,30 @@ try_again: /* check differences here */ - if(resv->cpus == (uint32_t)NO_VAL) { - resv->cpus = atoi(row[RESV_CPU]); + if(!resv->assocs + && row[RESV_ASSOCS] && row[RESV_ASSOCS][0]) + // if this changes we just update the + // record, no need to create a new one since + // this doesn't really effect the + // reservation accounting wise + resv->assocs = xstrdup(row[RESV_ASSOCS]); + + if(resv->cpus != (uint32_t)NO_VAL) set = 1; - } + else + resv->cpus = atoi(row[RESV_CPU]); + - if(resv->flags == (uint16_t)NO_VAL) { - resv->flags = atoi(row[RESV_FLAGS]); + if(resv->flags == (uint16_t)NO_VAL) set = 1; - } + else + resv->flags = atoi(row[RESV_FLAGS]); + - if(!resv->nodes) { - resv->nodes = xstrdup(row[RESV_NODES]); + if(resv->nodes) set = 1; - } + else if(row[RESV_NODES] && row[RESV_NODES][0]) + resv->nodes = xstrdup(row[RESV_NODES]); if(!resv->time_end) resv->time_end = atoi(row[RESV_END]); @@ -5991,9 +6009,9 @@ try_again: resv->id, start, resv->cluster); xstrfmtcat(query, - "insert into %s (id, cluster, %s) " - "values (%u, '%s', %s) " - "on duplicate key update deleted=0, %s;", + "insert into %s (id, cluster%s) " + "values (%u, '%s'%s) " + "on duplicate key update deleted=0%s;", resv_table, cols, resv->id, resv->cluster, vals, extra); } diff --git a/src/plugins/accounting_storage/mysql/mysql_jobacct_process.h b/src/plugins/accounting_storage/mysql/mysql_jobacct_process.h index 12d7a4c4529233d3a39d5d64ff076bf85a4af0bd..2e1b55edc4cf1cc0d186950aafd62b8efae0f250 100644 --- a/src/plugins/accounting_storage/mysql/mysql_jobacct_process.h +++ b/src/plugins/accounting_storage/mysql/mysql_jobacct_process.h @@ -56,11 +56,29 @@ #ifdef HAVE_MYSQL //extern int acct_db_init; - +extern char *acct_coord_table; +extern char *acct_table; +extern char *assoc_day_table; +extern char *assoc_hour_table; +extern char *assoc_month_table; extern char *assoc_table; +extern char *cluster_day_table; +extern char *cluster_hour_table; +extern char *cluster_month_table; +extern char *cluster_table; +extern char *event_table; extern char *job_table; +extern char *last_ran_table; +extern char *qos_table; +extern char *resv_table; extern char *step_table; +extern char *txn_table; +extern char *user_table; extern char *suspend_table; +extern char *wckey_day_table; +extern char *wckey_hour_table; +extern char *wckey_month_table; +extern char *wckey_table; extern int setup_job_cond_limits(acct_job_cond_t *job_cond, char **extra); diff --git a/src/plugins/accounting_storage/mysql/mysql_rollup.c b/src/plugins/accounting_storage/mysql/mysql_rollup.c index 0e5d1f1d5e6c82592389506edf88cafb2856268d..4a3ca46bd552a88d04db4c4adec29a6f4ddd032c 100644 --- a/src/plugins/accounting_storage/mysql/mysql_rollup.c +++ b/src/plugins/accounting_storage/mysql/mysql_rollup.c @@ -51,6 +51,7 @@ typedef struct { typedef struct { char *name; + int id; /*only needed for reservations */ uint64_t total_time; uint64_t a_cpu; int cpu_count; @@ -62,7 +63,18 @@ typedef struct { time_t end; } local_cluster_usage_t; -extern void _destroy_local_id_usage(void *object) +typedef struct { + uint64_t a_cpu; + char *cluster; + int id; + List local_assocs; /* list of assocs to spread unused time + over of type local_id_usage_t */ + uint64_t total_time; + time_t start; + time_t end; +} local_resv_usage_t; + +static void _destroy_local_id_usage(void *object) { local_id_usage_t *a_usage = (local_id_usage_t *)object; if(a_usage) { @@ -70,7 +82,7 @@ extern void _destroy_local_id_usage(void *object) } } -extern void _destroy_local_cluster_usage(void *object) +static void _destroy_local_cluster_usage(void *object) { local_cluster_usage_t *c_usage = (local_cluster_usage_t *)object; if(c_usage) { @@ -79,6 +91,17 @@ extern void _destroy_local_cluster_usage(void *object) } } +static void _destroy_local_resv_usage(void *object) +{ + local_resv_usage_t *r_usage = (local_resv_usage_t *)object; + if(r_usage) { + xfree(r_usage->cluster); + if(r_usage->local_assocs) + list_destroy(r_usage->local_assocs); + xfree(r_usage); + } +} + extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, time_t start, time_t end) { @@ -94,11 +117,12 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, ListIterator a_itr = NULL; ListIterator c_itr = NULL; ListIterator w_itr = NULL; + ListIterator r_itr = NULL; List assoc_usage_list = list_create(_destroy_local_id_usage); List cluster_usage_list = list_create(_destroy_local_cluster_usage); List wckey_usage_list = list_create(_destroy_local_id_usage); + List resv_usage_list = list_create(_destroy_local_resv_usage); uint16_t track_wckey = slurm_get_track_wckey(); - local_cluster_usage_t *last_c_usage = NULL; char *event_req_inx[] = { "node_name", @@ -116,6 +140,7 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, EVENT_REQ_END, EVENT_REQ_COUNT }; + char *job_req_inx[] = { "id", "jobid", @@ -127,7 +152,9 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, "end", "suspended", "alloc_cpus", - "req_cpus" + "req_cpus", + "resvid" + }; char *job_str = NULL; enum { @@ -142,8 +169,10 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, JOB_REQ_SUSPENDED, JOB_REQ_ACPU, JOB_REQ_RCPU, + JOB_REQ_RESVID, JOB_REQ_COUNT }; + char *suspend_req_inx[] = { "start", "end" @@ -155,6 +184,25 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, SUSPEND_REQ_COUNT }; + char *resv_req_inx[] = { + "id", + "cluster", + "assoclist", + "cpus", + "start", + "end" + }; + char *resv_str = NULL; + enum { + RESV_REQ_ID, + RESV_REQ_CLUSTER, + RESV_REQ_ASSOCS, + RESV_REQ_CPU, + RESV_REQ_START, + RESV_REQ_END, + RESV_REQ_COUNT + }; + i=0; xstrfmtcat(event_str, "%s", event_req_inx[i]); for(i=1; i<EVENT_REQ_COUNT; i++) { @@ -173,21 +221,28 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, xstrfmtcat(suspend_str, ", %s", suspend_req_inx[i]); } + i=0; + xstrfmtcat(resv_str, "%s", resv_req_inx[i]); + for(i=1; i<RESV_REQ_COUNT; i++) { + xstrfmtcat(resv_str, ", %s", resv_req_inx[i]); + } + /* info("begin start %s", ctime(&curr_start)); */ /* info("begin end %s", ctime(&curr_end)); */ a_itr = list_iterator_create(assoc_usage_list); c_itr = list_iterator_create(cluster_usage_list); w_itr = list_iterator_create(wckey_usage_list); + r_itr = list_iterator_create(resv_usage_list); while(curr_start < end) { + local_cluster_usage_t *last_c_usage = NULL; int last_id = -1; int last_wckeyid = -1; int seconds = 0; local_cluster_usage_t *c_usage = NULL; + local_resv_usage_t *r_usage = NULL; local_id_usage_t *a_usage = NULL; local_id_usage_t *w_usage = NULL; - last_c_usage = NULL; - debug3("curr hour is now %d-%d", curr_start, curr_end); /* info("start %s", ctime(&curr_start)); */ /* info("end %s", ctime(&curr_end)); */ @@ -301,6 +356,54 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, } mysql_free_result(result); + // now get the reservations during this time + query = xstrdup_printf("select %s from %s where " + "(start < %d && end >= %d) " + "order by cluster, start", + resv_str, resv_table, + curr_end, curr_start); + + debug3("%d(%d) query\n%s", mysql_conn->conn, __LINE__, query); + if(!(result = mysql_db_query_ret( + mysql_conn->db_conn, query, 0))) { + xfree(query); + return SLURM_ERROR; + } + xfree(query); + + while((row = mysql_fetch_row(result))) { + int row_start = atoi(row[RESV_REQ_START]); + int row_end = atoi(row[RESV_REQ_END]); + int row_cpu = atoi(row[RESV_REQ_CPU]); + + if(row_start < curr_start) + row_start = curr_start; + + if(!row_end || row_end > curr_end) + row_end = curr_end; + + /* Don't worry about it if the time is less + * than 1 second. + */ + if((row_end - row_start) < 1) + continue; + + r_usage = xmalloc(sizeof(local_resv_usage_t)); + r_usage->id = atoi(row[RESV_REQ_ID]); + + r_usage->local_assocs = list_create(slurm_destroy_char); + slurm_addto_char_list(r_usage->local_assocs, + row[RESV_REQ_ASSOCS]); + + r_usage->cluster = xstrdup(row[RESV_REQ_CLUSTER]); + r_usage->total_time = (row_end - row_start) * row_cpu; + r_usage->start = row_start; + r_usage->end = row_end; + list_append(resv_usage_list, r_usage); + } + mysql_free_result(result); + + /* now get the jobs during this time */ query = xstrdup_printf("select %s from %s where " "(eligible < %d && (end >= %d " "|| end = 0)) " @@ -320,6 +423,7 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, int job_id = atoi(row[JOB_REQ_JOBID]); int assoc_id = atoi(row[JOB_REQ_ASSOCID]); int wckey_id = atoi(row[JOB_REQ_WCKEYID]); + int resv_id = atoi(row[JOB_REQ_RESVID]); int row_eligible = atoi(row[JOB_REQ_ELG]); int row_start = atoi(row[JOB_REQ_START]); int row_end = atoi(row[JOB_REQ_END]); @@ -338,7 +442,7 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, if(!row_start || ((row_end - row_start) < 1)) goto calc_cluster; - + seconds = (row_end - row_start); if(row[JOB_REQ_SUSPENDED]) { @@ -379,7 +483,7 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, if((local_end - local_start) < 1) continue; - + seconds -= (local_end - local_start); } mysql_free_result(result2); @@ -388,14 +492,14 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, debug4("This job (%u) was suspended " "the entire hour", job_id); continue; - } + } if(last_id != assoc_id) { a_usage = xmalloc(sizeof(local_id_usage_t)); a_usage->id = assoc_id; list_append(assoc_usage_list, a_usage); last_id = assoc_id; - } + } a_usage->a_cpu += seconds * row_acpu; @@ -425,6 +529,32 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, if(!row[JOB_REQ_CLUSTER] || !row[JOB_REQ_CLUSTER][0]) continue; + /* first figure out the reservation */ + if(resv_id) { + list_iterator_reset(r_itr); + while((r_usage = list_next(r_itr))) { + if((r_usage->id == resv_id) + && !strcmp(r_usage->cluster, + row[JOB_REQ_CLUSTER])) { + int temp_end = row_end; + int temp_start = row_start; + if(r_usage->start > temp_start) + temp_start = + r_usage->start; + if(r_usage->end < temp_end) + temp_end = r_usage->end; + + if((temp_end - temp_start) + > 0) { + r_usage->a_cpu += + (temp_end + - temp_start) + * row_acpu; + } + } + } + } + if(last_c_usage && !strcmp(last_c_usage->name, row[JOB_REQ_CLUSTER])) { c_usage = last_c_usage; @@ -471,7 +601,8 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, row_end = c_usage->end; if((row_end - row_start) > 0) { - seconds = (row_end - row_start); + seconds = (row_end - row_start) + * row_rcpu; /* info("%d assoc %d reserved " */ /* "(%d)(%d-%d) * %d = %d " */ @@ -483,12 +614,76 @@ extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, /* row_rcpu, */ /* seconds * row_rcpu, */ /* row_rcpu); */ - c_usage->r_cpu += seconds * row_rcpu; + c_usage->r_cpu += seconds; } } } mysql_free_result(result); + /* now figure out how much more to add to the cluster + from the reservations + */ + list_iterator_reset(r_itr); + while((r_usage = list_next(r_itr))) { + int64_t idle = r_usage->total_time - r_usage->a_cpu; + char *assoc = NULL; + ListIterator tmp_itr = NULL; + + if(idle <= 0) + continue; + /* Since this reservation was added to the + cluster and only certain people could run + there we will use this as allocated time on + the system. + */ + if(last_c_usage && !strcmp(last_c_usage->name, + r_usage->cluster)) { + c_usage = last_c_usage; + } else { + list_iterator_reset(c_itr); + while((c_usage = list_next(c_itr))) { + if(!strcmp(c_usage->name, + r_usage->cluster)) { + last_c_usage = c_usage; + break; + } + } + } + c_usage->a_cpu += idle; + info("adding this much %ll to cluster %s", + idle, c_usage->name); + /* now divide that time by the number of + associations in the reservation and add + them to each association */ + seconds = idle / list_count(r_usage->local_assocs); + info("got %d for seconds for %d assocs", seconds, + list_count(r_usage->local_assocs)); + tmp_itr = list_iterator_create(r_usage->local_assocs); + while((assoc = list_next(tmp_itr))) { + int associd = atoi(assoc); + if(last_id != associd) { + list_iterator_reset(a_itr); + while((a_usage = list_next(a_itr))) { + if(!a_usage->id == associd) { + last_id = a_usage->id; + break; + } + } + } + + if(!a_usage) { + a_usage = xmalloc( + sizeof(local_id_usage_t)); + a_usage->id = associd; + list_append(assoc_usage_list, a_usage); + last_id = associd; + } + + a_usage->a_cpu += seconds; + } + list_iterator_destroy(tmp_itr); + } + /* Now put the lists into the usage tables */ list_iterator_reset(c_itr); while((c_usage = list_next(c_itr))) { @@ -673,13 +868,17 @@ end_it: xfree(suspend_str); xfree(event_str); xfree(job_str); + xfree(resv_str); list_iterator_destroy(a_itr); list_iterator_destroy(c_itr); list_iterator_destroy(w_itr); + list_iterator_destroy(r_itr); list_destroy(assoc_usage_list); list_destroy(cluster_usage_list); list_destroy(wckey_usage_list); + list_destroy(resv_usage_list); + /* info("stop start %s", ctime(&curr_start)); */ /* info("stop end %s", ctime(&curr_end)); */ return rc; diff --git a/src/plugins/accounting_storage/mysql/mysql_rollup.h b/src/plugins/accounting_storage/mysql/mysql_rollup.h index c10e1fcfd02af1a24def8a19340493ab5f35dd7e..25ac36fd05b61317148a992c884d3550389eadb7 100644 --- a/src/plugins/accounting_storage/mysql/mysql_rollup.h +++ b/src/plugins/accounting_storage/mysql/mysql_rollup.h @@ -44,25 +44,14 @@ #include "mysql_jobacct_process.h" #ifdef HAVE_MYSQL -extern char *assoc_table; -extern char *assoc_day_table; -extern char *assoc_hour_table; -extern char *assoc_month_table; -extern char *cluster_day_table; -extern char *cluster_hour_table; -extern char *cluster_month_table; -extern char *event_table; -extern char *suspend_table; -extern char *wckey_day_table; -extern char *wckey_hour_table; -extern char *wckey_month_table; extern int mysql_hourly_rollup(mysql_conn_t *mysql_conn, time_t start, time_t end); extern int mysql_daily_rollup(mysql_conn_t *mysql_conn, time_t start, time_t end, uint16_t archive_data); extern int mysql_monthly_rollup(mysql_conn_t *mysql_conn, - time_t start, time_t end, uint16_t archive_data); + time_t start, time_t end, + uint16_t archive_data); #endif diff --git a/src/slurmctld/reservation.c b/src/slurmctld/reservation.c index 85fa71d72ad2bf8dada747d46ab32a39313c2fce..a409fcb926ebf70886b29d332a7ec2878d1c1e0c 100644 --- a/src/slurmctld/reservation.c +++ b/src/slurmctld/reservation.c @@ -97,25 +97,27 @@ static void _generate_resv_id(void); static void _generate_resv_name(reserve_request_msg_t *resv_ptr); static bool _is_account_valid(char *account); static bool _is_resv_used(slurmctld_resv_t *resv_ptr); -static void _pack_resv(struct slurmctld_resv *resv_ptr, Buf buffer, +static void _pack_resv(slurmctld_resv_t *resv_ptr, Buf buffer, bool internal); static int _resize_resv(slurmctld_resv_t *resv_ptr, uint32_t node_cnt); static bool _resv_overlap(time_t start_time, time_t end_time, uint16_t flags, bitstr_t *node_bitmap, - struct slurmctld_resv *this_resv_ptr); + slurmctld_resv_t *this_resv_ptr); static int _select_nodes(reserve_request_msg_t *resv_desc_ptr, struct part_record **part_ptr, bitstr_t **resv_bitmap); -static void _set_cpu_cnt(struct slurmctld_resv *resv_ptr); +static int _set_assoc_list(slurmctld_resv_t *resv_ptr); +static void _set_cpu_cnt(slurmctld_resv_t *resv_ptr); static void _swap_resv(slurmctld_resv_t *resv_backup, slurmctld_resv_t *resv_ptr); -static int _post_resv_create(struct slurmctld_resv *resv_ptr); -static int _post_resv_delete(struct slurmctld_resv *resv_ptr); -static int _post_resv_update(struct slurmctld_resv *resv_ptr); +static int _post_resv_create(slurmctld_resv_t *resv_ptr); +static int _post_resv_delete(slurmctld_resv_t *resv_ptr); +static int _post_resv_update(slurmctld_resv_t *resv_ptr, + slurmctld_resv_t *old_resv_ptr); -static int _update_account_list(struct slurmctld_resv *resv_ptr, +static int _update_account_list(slurmctld_resv_t *resv_ptr, char *accounts); -static int _update_uid_list(struct slurmctld_resv *resv_ptr, char *users); +static int _update_uid_list(slurmctld_resv_t *resv_ptr, char *users); static void _validate_all_reservations(void); static int _valid_job_access_resv(struct job_record *job_ptr, slurmctld_resv_t *resv_ptr); @@ -189,6 +191,7 @@ static void _del_resv_rec(void *x) for (i=0; i<resv_ptr->account_cnt; i++) xfree(resv_ptr->account_list[i]); xfree(resv_ptr->account_list); + xfree(resv_ptr->assoc_list); xfree(resv_ptr->features); xfree(resv_ptr->name); if (resv_ptr->node_bitmap) @@ -311,13 +314,112 @@ static bool _is_account_valid(char *account) return true; } +static int _append_assoc_list(List assoc_list, acct_association_rec_t *assoc) +{ + int rc = ESLURM_INVALID_BANK_ACCOUNT; + acct_association_rec_t *assoc_ptr = NULL; + if (assoc_mgr_fill_in_assoc( + acct_db_conn, assoc, + accounting_enforce, + &assoc_ptr)) { + if(accounting_enforce & ACCOUNTING_ENFORCE_ASSOCS) { + error("No association for user %u and account %s", + assoc->uid, assoc->acct); + } else { + verbose("No association for user %u and account %s", + assoc->uid, assoc->acct); + rc = SLURM_SUCCESS; + } + + } + if(assoc_ptr) { + info("got here"); + list_append(assoc_list, assoc_ptr); + rc = SLURM_SUCCESS; + } + + return rc; +} +/* Set a association list based upon accounts and users */ +static int _set_assoc_list(slurmctld_resv_t *resv_ptr) +{ + int rc = SLURM_SUCCESS, i = 0, j = 0; + List assoc_list = NULL; + acct_association_rec_t assoc, *assoc_ptr = NULL; + + /* no need to do this if we can't ;) */ + if(!association_based_accounting) + return rc; + + assoc_list = list_create(NULL); + + memset(&assoc, 0, sizeof(acct_association_rec_t)); + + if(resv_ptr->user_cnt) { + for(i=0; i < resv_ptr->user_cnt; i++) { + assoc.uid = (uint32_t)resv_ptr->user_list[i]; + + if(resv_ptr->account_cnt) { + for(j=0; j < resv_ptr->account_cnt; j++) { + assoc.acct = resv_ptr->account_list[j]; + if((rc = _append_assoc_list( + assoc_list, &assoc)) + != SLURM_SUCCESS) { + goto end_it; + } + } + } else { + if((rc = assoc_mgr_get_user_assocs( + acct_db_conn, &assoc, + accounting_enforce, assoc_list)) + != SLURM_SUCCESS) { + rc = ESLURM_INVALID_BANK_ACCOUNT; + goto end_it; + } + } + } + } else if(resv_ptr->account_cnt) { + assoc.uid = (uint32_t)NO_VAL; + for(i=0; i < resv_ptr->account_cnt; i++) { + assoc.acct = resv_ptr->account_list[j]; + if((rc = _append_assoc_list(assoc_list, &assoc)) + != SLURM_SUCCESS) { + goto end_it; + } + } + } else if(accounting_enforce & ACCOUNTING_ENFORCE_ASSOCS) { + error("We need at least 1 user or 1 account to " + "create a reservtion."); + rc = SLURM_ERROR; + } + + if(list_count(assoc_list)) { + ListIterator itr = list_iterator_create(assoc_list); + xfree(resv_ptr->assoc_list); /* clear for modify */ + while((assoc_ptr = list_next(itr))) { + if(resv_ptr->assoc_list) + xstrfmtcat(resv_ptr->assoc_list, ",%u", + assoc_ptr->id); + else + xstrfmtcat(resv_ptr->assoc_list, "%u", + assoc_ptr->id); + } + list_iterator_destroy(itr); + } + +end_it: + list_destroy(assoc_list); + return rc; +} + /* Post reservation create */ -static int _post_resv_create(struct slurmctld_resv *resv_ptr) +static int _post_resv_create(slurmctld_resv_t *resv_ptr) { int rc = SLURM_SUCCESS; acct_reservation_rec_t resv; memset(&resv, 0, sizeof(acct_reservation_rec_t)); + resv.assocs = resv_ptr->assoc_list; resv.cluster = slurmctld_cluster_name; resv.cpus = resv_ptr->cpu_cnt; resv.flags = resv_ptr->flags; @@ -332,7 +434,7 @@ static int _post_resv_create(struct slurmctld_resv *resv_ptr) } /* Note that a reservation has been deleted */ -static int _post_resv_delete(struct slurmctld_resv *resv_ptr) +static int _post_resv_delete(slurmctld_resv_t *resv_ptr) { int rc = SLURM_SUCCESS; acct_reservation_rec_t resv; @@ -351,21 +453,50 @@ static int _post_resv_delete(struct slurmctld_resv *resv_ptr) } /* Note that a reservation has been updated */ -static int _post_resv_update(struct slurmctld_resv *resv_ptr) +static int _post_resv_update(slurmctld_resv_t *resv_ptr, + slurmctld_resv_t *old_resv_ptr) { int rc = SLURM_SUCCESS; acct_reservation_rec_t resv; memset(&resv, 0, sizeof(acct_reservation_rec_t)); - + resv.cluster = slurmctld_cluster_name; - resv.cpus = resv_ptr->cpu_cnt; - resv.flags = resv_ptr->flags; resv.id = resv_ptr->resv_id; - resv.nodes = resv_ptr->node_list; resv.time_end = resv_ptr->end_time; resv.time_start = resv_ptr->start_time; resv.time_start_prev = resv_ptr->start_time_prev; + + if(!old_resv_ptr) { + resv.assocs = resv_ptr->assoc_list; + resv.cpus = resv_ptr->cpu_cnt; + resv.flags = resv_ptr->flags; + resv.nodes = resv_ptr->node_list; + } else { + if(old_resv_ptr->assoc_list && resv_ptr->assoc_list) { + if(strcmp(old_resv_ptr->assoc_list, + resv_ptr->assoc_list)) + resv.assocs = resv_ptr->assoc_list; + } else if(resv_ptr->assoc_list) + resv.assocs = resv_ptr->assoc_list; + + if(old_resv_ptr->cpu_cnt != resv_ptr->cpu_cnt) + resv.cpus = resv_ptr->cpu_cnt; + else + resv.cpus = (uint32_t)NO_VAL; + + if(old_resv_ptr->flags != resv_ptr->flags) + resv.flags = resv_ptr->flags; + else + resv.flags = (uint16_t)NO_VAL; + + if(old_resv_ptr->node_list && resv_ptr->node_list) { + if(strcmp(old_resv_ptr->node_list, + resv_ptr->node_list)) + resv.nodes = resv_ptr->node_list; + } else if(resv_ptr->node_list) + resv.nodes = resv_ptr->node_list; + } rc = acct_storage_g_modify_reservation(acct_db_conn, &resv); return rc; @@ -426,7 +557,7 @@ static int _build_account_list(char *accounts, int *account_cnt, * IN accounts - a list of account names, to set, add, or remove * RETURN 0 on success */ -static int _update_account_list(struct slurmctld_resv *resv_ptr, +static int _update_account_list(slurmctld_resv_t *resv_ptr, char *accounts) { char *last = NULL, *ac_cpy, *tok; @@ -618,7 +749,7 @@ static int _build_uid_list(char *users, int *user_cnt, uid_t **user_list) * IN users - a list of user names, to set, add, or remove * RETURN 0 on success */ -static int _update_uid_list(struct slurmctld_resv *resv_ptr, char *users) +static int _update_uid_list(slurmctld_resv_t *resv_ptr, char *users) { char *last = NULL, *u_cpy = NULL, *tmp = NULL, *tok; int u_cnt = 0, i, j, k; @@ -766,7 +897,7 @@ static int _update_uid_list(struct slurmctld_resv *resv_ptr, char *users) * to _unpack_reserve_info_members() in common/slurm_protocol_pack.c * plus load_all_resv_state() below. */ -static void _pack_resv(struct slurmctld_resv *resv_ptr, Buf buffer, +static void _pack_resv(slurmctld_resv_t *resv_ptr, Buf buffer, bool internal) { packstr(resv_ptr->accounts, buffer); @@ -781,9 +912,10 @@ static void _pack_resv(struct slurmctld_resv *resv_ptr, Buf buffer, packstr(resv_ptr->users, buffer); if (internal) { - pack32(resv_ptr->cpu_cnt, buffer); + packstr(resv_ptr->assoc_list, buffer); + pack32(resv_ptr->cpu_cnt, buffer); + pack32(resv_ptr->resv_id, buffer); pack_time(resv_ptr->start_time_prev, buffer); - pack32(resv_ptr->resv_id, buffer); } } @@ -794,7 +926,7 @@ static void _pack_resv(struct slurmctld_resv *resv_ptr, Buf buffer, */ static bool _resv_overlap(time_t start_time, time_t end_time, uint16_t flags, bitstr_t *node_bitmap, - struct slurmctld_resv *this_resv_ptr) + slurmctld_resv_t *this_resv_ptr) { ListIterator iter; slurmctld_resv_t *resv_ptr; @@ -846,7 +978,7 @@ static bool _resv_overlap(time_t start_time, time_t end_time, /* Set a reservation's CPU count. Requires that the reservation's * node_bitmap be set. */ -static void _set_cpu_cnt(struct slurmctld_resv *resv_ptr) +static void _set_cpu_cnt(slurmctld_resv_t *resv_ptr) { int i; uint32_t cpu_cnt = 0; @@ -1018,6 +1150,8 @@ extern int create_resv(reserve_request_msg_t *resv_desc_ptr) resv_ptr->user_list = user_list; resv_desc_ptr->users = NULL; /* Nothing left to free */ _set_cpu_cnt(resv_ptr); + if((rc = _set_assoc_list(resv_ptr)) != SLURM_SUCCESS) + goto bad_parse; /* This needs to be done after all other setup is done. */ _post_resv_create(resv_ptr); @@ -1201,6 +1335,8 @@ extern int update_resv(reserve_request_msg_t *resv_desc_ptr) goto update_failure; } _set_cpu_cnt(resv_ptr); + if((error_code = _set_assoc_list(resv_ptr)) != SLURM_SUCCESS) + goto update_failure; slurm_make_time_str(&resv_ptr->start_time, start_time, sizeof(start_time)); @@ -1210,8 +1346,8 @@ extern int update_resv(reserve_request_msg_t *resv_desc_ptr) resv_ptr->name, resv_ptr->accounts, resv_ptr->users, resv_ptr->node_list, start_time, end_time); + _post_resv_update(resv_ptr, resv_backup); _del_resv_rec(resv_backup); - _post_resv_update(resv_ptr); last_resv_update = now; schedule_resv_save(); return error_code; @@ -1518,6 +1654,7 @@ static void _validate_all_reservations(void) _clear_job_resv(resv_ptr); list_delete_item(iter); } else { + _set_assoc_list(resv_ptr); tmp = strrchr(resv_ptr->name, '_'); if (tmp) { res_num = atoi(tmp + 1); @@ -1651,9 +1788,11 @@ extern int load_all_resv_state(int recover) safe_unpackstr_xmalloc(&resv_ptr->users,&uint32_tmp, buffer); /* Fields saved for internal use only (save state) */ + safe_unpackstr_xmalloc(&resv_ptr->assoc_list, + &uint32_tmp, buffer); safe_unpack32(&resv_ptr->cpu_cnt, buffer); safe_unpack32(&resv_ptr->resv_id, buffer); - safe_unpack_time(&resv_ptr->start_time_prev, buffer); + safe_unpack_time(&resv_ptr->start_time_prev, buffer); list_append(resv_list, resv_ptr); info("Recovered state of reservation %s", resv_ptr->name); @@ -2119,7 +2258,7 @@ extern void fini_job_resv_check(void) resv_ptr->start_time_prev = resv_ptr->start_time; resv_ptr->start_time += 24 * 60 * 60; resv_ptr->end_time += 24 * 60 * 60; - _post_resv_update(resv_ptr); + _post_resv_update(resv_ptr, NULL); last_resv_update = now; schedule_resv_save(); continue; @@ -2131,7 +2270,7 @@ extern void fini_job_resv_check(void) resv_ptr->start_time_prev = resv_ptr->start_time; resv_ptr->start_time += 7 * 24 * 60 * 60; resv_ptr->end_time += 7 * 24 * 60 * 60; - _post_resv_update(resv_ptr); + _post_resv_update(resv_ptr, NULL); last_resv_update = now; schedule_resv_save(); continue; diff --git a/src/slurmctld/slurmctld.h b/src/slurmctld/slurmctld.h index 68a4296d47358cdcb8a61b971886b78fd8a15f12..d518d5d32a50fcbf16762f8744a95ca2fecc4e1b 100644 --- a/src/slurmctld/slurmctld.h +++ b/src/slurmctld/slurmctld.h @@ -310,6 +310,7 @@ typedef struct slurmctld_resv { char *accounts; /* names of accounts permitted to use */ int account_cnt; /* count of accounts permitted to use */ char **account_list; /* list of accounts permitted to use */ + char *assoc_list; /* list of associations */ uint32_t cpu_cnt; /* number of reserved CPUs */ time_t end_time; /* end time of reservation */ char *features; /* required node features */