From eda39975a92bc95652c7116a7f0fda61a9df7fe4 Mon Sep 17 00:00:00 2001 From: Danny Auble <da@llnl.gov> Date: Wed, 10 Feb 2010 20:33:25 +0000 Subject: [PATCH] ok got (hopefully) up to association mod --- .../mysql/accounting_storage_mysql.c | 31 +- .../mysql/accounting_storage_mysql.h | 3 +- .../accounting_storage/mysql/mysql_acct.c | 40 +- .../accounting_storage/mysql/mysql_archive.c | 152 +- .../accounting_storage/mysql/mysql_assoc.c | 1354 +++++++++-------- .../accounting_storage/mysql/mysql_cluster.c | 3 +- .../accounting_storage/mysql/mysql_qos.c | 2 +- .../accounting_storage/mysql/mysql_user.c | 2 +- 8 files changed, 823 insertions(+), 764 deletions(-) diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c index abc2b328e35..5996a8e6123 100644 --- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c +++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c @@ -627,8 +627,8 @@ static int _mysql_acct_check_tables(MYSQL *db_conn) "@delta_qos := CONCAT(delta_qos, @delta_qos), '); " "end if; " "set @s = concat(@s, ' @my_acct := parent_acct from ', " - "my_table, ' where acct = \"', @my_acct, '\" && " - "cluster = \"', cluster, '\" && user=\"\"'); " + "cluster, '_', my_table, ' where " + "acct = \"', @my_acct, '\" && user=\"\"'); " "prepare query from @s; " "execute query; " "deallocate prepare query; " @@ -1208,21 +1208,34 @@ extern int modify_common(mysql_conn_t *mysql_conn, char *user_name, char *table, char *cond_char, - char *vals) + char *vals, + char *cluster_name) { char *query = NULL; int rc = SLURM_SUCCESS; char *tmp_cond_char = fix_double_quotes(cond_char); char *tmp_vals = NULL; + bool cluster_centric = true; + + /* figure out which tables we need to append the cluster name to */ + if((table == cluster_table) || (table == acct_coord_table) + || (table == acct_table) || (table == qos_table) + || (table == txn_table) || (table == user_table)) + cluster_centric = false; if(vals[1]) tmp_vals = fix_double_quotes(vals+2); - - xstrfmtcat(query, - "update %s set mod_time=%d%s " - "where deleted=0 && %s;", - table, now, vals, - cond_char); + if(cluster_centric) { + xassert(cluster_name); + xstrfmtcat(query, + "update %s_%s set mod_time=%d%s " + "where deleted=0 && %s;", + cluster_name, table, now, vals, cond_char); + } else + xstrfmtcat(query, + "update %s set mod_time=%d%s " + "where deleted=0 && %s;", + table, now, vals, cond_char); xstrfmtcat(query, "insert into %s " "(timestamp, action, name, actor, info) " diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.h b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.h index 0debd71eb74..4db9f5769d4 100644 --- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.h +++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.h @@ -106,7 +106,8 @@ extern int modify_common(mysql_conn_t *mysql_conn, char *user_name, char *table, char *cond_char, - char *vals); + char *vals, + char *cluster_name); extern int remove_common(mysql_conn_t *mysql_conn, uint16_t type, time_t now, diff --git a/src/plugins/accounting_storage/mysql/mysql_acct.c b/src/plugins/accounting_storage/mysql/mysql_acct.c index 01fafa9a2fc..2b8a1e4ab94 100644 --- a/src/plugins/accounting_storage/mysql/mysql_acct.c +++ b/src/plugins/accounting_storage/mysql/mysql_acct.c @@ -47,10 +47,11 @@ static int _get_account_coords(mysql_conn_t *mysql_conn, acct_account_rec_t *acct) { - char *query = NULL; + char *query = NULL, *cluster_name = NULL; acct_coord_rec_t *coord = NULL; MYSQL_RES *result = NULL; MYSQL_ROW row; + ListIterator itr; if(!acct) { error("We need a account to fill in."); @@ -78,15 +79,32 @@ static int _get_account_coords(mysql_conn_t *mysql_conn, } mysql_free_result(result); - query = xstrdup_printf("select distinct t0.user from %s as t0, " - "%s as t1, %s as t2 where t0.acct=t1.acct && " - "t1.lft<t2.lft && t1.rgt>t2.lft && " - "t1.user='' && t2.acct=\"%s\" " - "&& t1.acct!=\"%s\" && !t0.deleted;", - acct_coord_table, assoc_table, assoc_table, - acct->name, acct->name); - if(!(result = - mysql_db_query_ret(mysql_conn->db_conn, query, 0))) { + slurm_mutex_lock(&mysql_cluster_list_lock); + itr = list_iterator_create(mysql_cluster_list); + while((cluster_name = list_next(itr))) { + if(query) + xstrcat(query, " union "); + xstrfmtcat(query, + "select distinct t0.user from %s as t0, " + "%s_%s as t1, %s_%s as t2 " + "where t0.acct=t1.acct && " + "t1.lft<t2.lft && t1.rgt>t2.lft && " + "t1.user='' && t2.acct=\"%s\" " + "&& t1.acct!=\"%s\" && !t0.deleted", + acct_coord_table, cluster_name, assoc_table, + cluster_name, assoc_table, + acct->name, acct->name); + } + list_iterator_destroy(itr); + slurm_mutex_unlock(&mysql_cluster_list_lock); + + if(!query) { + error("No clusters defined? How could there be accts?"); + return SLURM_SUCCESS; + } + xstrcat(query, ";"); + + if(!(result = mysql_db_query_ret(mysql_conn->db_conn, query, 0))) { xfree(query); return SLURM_ERROR; } @@ -335,7 +353,7 @@ extern List mysql_modify_accts(mysql_conn_t *mysql_conn, uint32_t uid, user_name = uid_to_string((uid_t) uid); rc = modify_common(mysql_conn, DBD_MODIFY_ACCOUNTS, now, - user_name, acct_table, name_char, vals); + user_name, acct_table, name_char, vals, NULL); xfree(user_name); if (rc == SLURM_ERROR) { error("Couldn't modify accounts"); diff --git a/src/plugins/accounting_storage/mysql/mysql_archive.c b/src/plugins/accounting_storage/mysql/mysql_archive.c index c284487899e..cf8d41e5d43 100644 --- a/src/plugins/accounting_storage/mysql/mysql_archive.c +++ b/src/plugins/accounting_storage/mysql/mysql_archive.c @@ -135,26 +135,26 @@ typedef struct { /* if this changes you will need to edit the corresponding * enum below */ -static char *event_req_inx[] = { +char *event_req_inx[] = { + "time_start", + "time_end", "node_name", + "cluster_nodes", "cpu_count", - "state", - "period_start", - "period_end", "reason", "reason_uid", - "cluster_nodes", + "state", }; enum { - EVENT_REQ_NODE, - EVENT_REQ_CPU, - EVENT_REQ_STATE, EVENT_REQ_START, EVENT_REQ_END, + EVENT_REQ_NODE, + EVENT_REQ_CNODES, + EVENT_REQ_CPU, EVENT_REQ_REASON, EVENT_REQ_REASON_UID, - EVENT_REQ_CNODES, + EVENT_REQ_STATE, EVENT_REQ_COUNT }; @@ -162,33 +162,33 @@ enum { * enum below */ static char *job_req_inx[] = { "account", - "alloc_cpus", - "alloc_nodes", - "associd", - "blockid", - "comp_code", - "eligible", - "end", - "gid", - "id", - "jobid", + "cpus_alloc", + "nodes_alloc", + "id_assoc", + "id_block", + "exit_code", + "time_eligible", + "time_end", + "id_group", + "job_db_inx", + "id_job", "kill_requid", - "name", + "job_name", "nodelist", "node_inx", "partition", "priority", "qos", - "req_cpus", - "resvid", - "start", + "cpus_req", + "id_resv", + "time_start", "state", - "submit", - "suspended", + "time_submit", + "time_suspended", "track_steps", - "uid", + "id_user", "wckey", - "wckeyid", + "id_wckey", }; enum { @@ -226,20 +226,20 @@ enum { /* if this changes you will need to edit the corresponding * enum below */ static char *step_req_inx[] = { - "id", - "stepid", - "start", - "end", - "suspended", - "name", + "job_db_inx", + "id_step", + "time_start", + "time_end", + "time_suspended", + "step_name", "nodelist", "node_inx", "state", "kill_requid", - "comp_code", - "nodes", - "cpus", - "tasks", + "exit_code", + "nodes_alloc", + "cpus_alloc", + "task_cnt", "task_dist", "user_sec", "user_usec", @@ -306,10 +306,10 @@ enum { /* if this changes you will need to edit the corresponding * enum below */ static char *suspend_req_inx[] = { - "id", - "associd", - "start", - "end", + "job_db_inx", + "id_assoc", + "time_start", + "time_end", }; enum { @@ -653,31 +653,6 @@ static uint32_t _archive_events(mysql_conn_t *mysql_conn, char *cluster_name, Buf buffer; int error_code = 0, i = 0; - /* if this changes you will need to edit the corresponding - * enum below */ - char *event_req_inx[] = { - "node_name", - "cpu_count", - "state", - "period_start", - "period_end", - "reason", - "reason_uid", - "cluster_nodes", - }; - - enum { - EVENT_REQ_NODE, - EVENT_REQ_CPU, - EVENT_REQ_STATE, - EVENT_REQ_START, - EVENT_REQ_END, - EVENT_REQ_REASON, - EVENT_REQ_REASON_UID, - EVENT_REQ_CNODES, - EVENT_REQ_COUNT - }; - xfree(tmp); xstrfmtcat(tmp, "%s", event_req_inx[0]); for(i=1; i<EVENT_REQ_COUNT; i++) { @@ -685,9 +660,9 @@ static uint32_t _archive_events(mysql_conn_t *mysql_conn, char *cluster_name, } /* get all the events started before this time listed */ - query = xstrdup_printf("select %s from %s where period_start <= %d " + query = xstrdup_printf("select %s from %s_%s where period_start <= %d " "&& period_end != 0 order by period_start asc", - tmp, event_table, period_end); + tmp, cluster_name, event_table, period_end); xfree(tmp); // START_TIMER; @@ -752,7 +727,8 @@ static char *_load_events(uint16_t rpc_version, Buf buffer, local_event_t object; int i = 0; - xstrfmtcat(insert, "insert into %s (%s", event_table, event_req_inx[0]); + xstrfmtcat(insert, "insert into %s_%s (%s", + cluster_name, event_table, event_req_inx[0]); xstrcat(format, "('%s'"); for(i=1; i<EVENT_REQ_COUNT; i++) { xstrfmtcat(insert, ", %s", event_req_inx[i]); @@ -810,10 +786,10 @@ static uint32_t _archive_jobs(mysql_conn_t *mysql_conn, char *cluster_name, } /* get all the events started before this time listed */ - query = xstrdup_printf("select %s from %s where " + query = xstrdup_printf("select %s from %s_%s where " "submit < %d && end != 0 && !deleted " "order by submit asc", - tmp, job_table, period_end); + tmp, cluster_name, job_table, period_end); xfree(tmp); // START_TIMER; @@ -898,7 +874,8 @@ static char *_load_jobs(uint16_t rpc_version, Buf buffer, local_job_t object; int i = 0; - xstrfmtcat(insert, "insert into %s (%s", job_table, job_req_inx[0]); + xstrfmtcat(insert, "insert into %s_%s (%s", + cluster_name, job_table, job_req_inx[0]); xstrcat(format, "('%s'"); for(i=1; i<JOB_REQ_COUNT; i++) { xstrfmtcat(insert, ", %s", job_req_inx[i]); @@ -976,10 +953,10 @@ static uint32_t _archive_steps(mysql_conn_t *mysql_conn, char *cluster_name, } /* get all the events started before this time listed */ - query = xstrdup_printf("select %s from %s where " + query = xstrdup_printf("select %s from %s_%s where " "start <= %d && end != 0 " "&& !deleted order by start asc", - tmp, step_table, period_end); + tmp, cluster_name, step_table, period_end); xfree(tmp); // START_TIMER; @@ -1071,7 +1048,8 @@ static char *_load_steps(uint16_t rpc_version, Buf buffer, local_step_t object; int i = 0; - xstrfmtcat(insert, "insert into %s (%s", step_table, step_req_inx[0]); + xstrfmtcat(insert, "insert into %s_%s (%s", + cluster_name, step_table, step_req_inx[0]); xstrcat(format, "('%s'"); for(i=1; i<STEP_REQ_COUNT; i++) { xstrfmtcat(insert, ", %s", step_req_inx[i]); @@ -1156,10 +1134,10 @@ static uint32_t _archive_suspend(mysql_conn_t *mysql_conn, char *cluster_name, } /* get all the events started before this time listed */ - query = xstrdup_printf("select %s from %s where " + query = xstrdup_printf("select %s from %s_%s where " "start <= %d && end != 0 " "order by start asc", - tmp, suspend_table, period_end); + tmp, cluster_name, suspend_table, period_end); xfree(tmp); // START_TIMER; @@ -1220,8 +1198,8 @@ static char *_load_suspend(uint16_t rpc_version, Buf buffer, local_suspend_t object; int i = 0; - xstrfmtcat(insert, "insert into %s (%s", - suspend_table, suspend_req_inx[0]); + xstrfmtcat(insert, "insert into %s_%s (%s", + cluster_name, suspend_table, suspend_req_inx[0]); xstrcat(format, "('%s'"); for(i=1; i<SUSPEND_REQ_COUNT; i++) { xstrfmtcat(insert, ", %s", suspend_req_inx[i]); @@ -1420,9 +1398,9 @@ static int _execute_archive(mysql_conn_t *mysql_conn, time_t last_submit, else if(rc == SLURM_ERROR) return rc; } - query = xstrdup_printf("delete from %s where " + query = xstrdup_printf("delete from %s_%s where " "period_start <= %d && period_end != 0", - event_table, curr_end); + cluster_name, event_table, curr_end); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, __FILE__, __LINE__, query); rc = mysql_db_query(mysql_conn->db_conn, query); @@ -1465,9 +1443,9 @@ exit_events: else if(rc == SLURM_ERROR) return rc; } - query = xstrdup_printf("delete from %s where start <= %d " + query = xstrdup_printf("delete from %s_%s where start <= %d " "&& end != 0", - suspend_table, curr_end); + cluster_name, suspend_table, curr_end); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, __FILE__, __LINE__, query); rc = mysql_db_query(mysql_conn->db_conn, query); @@ -1511,9 +1489,9 @@ exit_suspend: return rc; } - query = xstrdup_printf("delete from %s where start <= %d " + query = xstrdup_printf("delete from %s_%s where start <= %d " "&& end != 0", - step_table, curr_end); + cluster_name, step_table, curr_end); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, __FILE__, __LINE__, query); rc = mysql_db_query(mysql_conn->db_conn, query); @@ -1556,9 +1534,9 @@ exit_steps: return rc; } - query = xstrdup_printf("delete from %s where submit <= %d " + query = xstrdup_printf("delete from %s_%s where submit <= %d " "&& end != 0", - job_table, curr_end); + cluster_name, job_table, curr_end); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, __FILE__, __LINE__, query); rc = mysql_db_query(mysql_conn->db_conn, query); diff --git a/src/plugins/accounting_storage/mysql/mysql_assoc.c b/src/plugins/accounting_storage/mysql/mysql_assoc.c index e53b862a25a..319af24084b 100644 --- a/src/plugins/accounting_storage/mysql/mysql_assoc.c +++ b/src/plugins/accounting_storage/mysql/mysql_assoc.c @@ -40,6 +40,67 @@ #include "mysql_assoc.h" #include "mysql_usage.h" +static char *aassoc_req_inx[] = { + "id_assoc", + "parent_acct", + "lft", + "rgt", + "deleted" +}; + +enum { + AASSOC_ID, + AASSOC_PACCT, + AASSOC_LFT, + AASSOC_RGT, + AASSOC_DELETED, + AASSOC_COUNT +}; + +static char *massoc_req_inx[] = { + "id_assoc", + "acct", + "parent_acct", + "user", + "partition", + "lft", + "rgt", + "qos", +}; + +enum { + MASSOC_ID, + MASSOC_ACCT, + MASSOC_PACCT, + MASSOC_USER, + MASSOC_PART, + MASSOC_LFT, + MASSOC_RGT, + MASSOC_QOS, + MASSOC_COUNT +}; + +/* if this changes you will need to edit the corresponding + * enum below also t1 is step_table */ +static char *rassoc_req_inx[] = { + "id_assoc", + "acct", + "parent_acct", + "cluster", + "user", + "partition" +}; + +enum { + RASSOC_ID, + RASSOC_ACCT, + RASSOC_PACCT, + RASSOC_CLUSTER, + RASSOC_USER, + RASSOC_PART, + RASSOC_COUNT +}; + /* This should take care of all the lft and rgts when you move an * account. This handles deleted associations also. */ @@ -53,10 +114,8 @@ static int _move_account(mysql_conn_t *mysql_conn, uint32_t *lft, uint32_t *rgt, int diff = 0; int width = 0; char *query = xstrdup_printf( - "SELECT lft from %s " - "where cluster=\"%s\" && acct=\"%s\" && user='';", - assoc_table, - cluster, parent); + "SELECT lft from %s_%s where acct=\"%s\" && user='';", + cluster, assoc_table, parent); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, __FILE__, __LINE__, query); if(!(result = mysql_db_query_ret( @@ -86,47 +145,47 @@ static int _move_account(mysql_conn_t *mysql_conn, uint32_t *lft, uint32_t *rgt, /* every thing below needs to be a %d not a %u because we are looking for -1 */ xstrfmtcat(query, - "update %s set mod_time=%d, deleted = deleted + 2, " + "update %s_%s set mod_time=%d, deleted = deleted + 2, " "lft = lft + %d, rgt = rgt + %d " "WHERE lft BETWEEN %d AND %d;", - assoc_table, now, diff, diff, *lft, *rgt); + cluster, assoc_table, now, diff, diff, *lft, *rgt); xstrfmtcat(query, - "UPDATE %s SET mod_time=%d, rgt = rgt + %d WHERE " + "UPDATE %s_%s SET mod_time=%d, rgt = rgt + %d WHERE " "rgt > %d && deleted < 2;" - "UPDATE %s SET mod_time=%d, lft = lft + %d WHERE " + "UPDATE %s_%s SET mod_time=%d, lft = lft + %d WHERE " "lft > %d && deleted < 2;", - assoc_table, now, width, + cluster, assoc_table, now, width, par_left, - assoc_table, now, width, + cluster, assoc_table, now, width, par_left); xstrfmtcat(query, - "UPDATE %s SET mod_time=%d, rgt = rgt - %d WHERE " + "UPDATE %s_%s SET mod_time=%d, rgt = rgt - %d WHERE " "(%d < 0 && rgt > %d && deleted < 2) " "|| (%d > 0 && rgt > %d);" - "UPDATE %s SET mod_time=%d, lft = lft - %d WHERE " + "UPDATE %s_%s SET mod_time=%d, lft = lft - %d WHERE " "(%d < 0 && lft > %d && deleted < 2) " "|| (%d > 0 && lft > %d);", - assoc_table, now, width, + cluster, assoc_table, now, width, diff, *rgt, diff, *lft, - assoc_table, now, width, + cluster, assoc_table, now, width, diff, *rgt, diff, *lft); xstrfmtcat(query, - "update %s set mod_time=%d, " + "update %s_%s set mod_time=%d, " "deleted = deleted - 2 WHERE deleted > 1;", - assoc_table, now); + cluster, assoc_table, now); xstrfmtcat(query, - "update %s set mod_time=%d, " - "parent_acct=\"%s\" where id = %s;", - assoc_table, now, parent, id); + "update %s_%s set mod_time=%d, " + "parent_acct=\"%s\" where id_assoc = %s;", + cluster, assoc_table, now, parent, id); /* get the new lft and rgt if changed */ xstrfmtcat(query, - "select lft, rgt from %s where id = %s", - assoc_table, id); + "select lft, rgt from %s_%s where id_assoc = %s", + cluster, assoc_table, id); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, __FILE__, __LINE__, query); if(!(result = mysql_db_query_ret(mysql_conn->db_conn, query, 1))) { @@ -166,9 +225,10 @@ static int _move_parent(mysql_conn_t *mysql_conn, uid_t uid, * accounts parent and then do the move. */ query = xstrdup_printf( - "select id, lft, rgt from %s where lft between %d and %d " + "select id_assoc, lft, rgt from %s_%s " + "where lft between %d and %d " "&& acct=\"%s\" && user='' order by lft;", - assoc_table, *lft, *rgt, + cluster, assoc_table, *lft, *rgt, new_parent); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, __FILE__, __LINE__, query); @@ -198,8 +258,8 @@ static int _move_parent(mysql_conn_t *mysql_conn, uid_t uid, * have changed. */ query = xstrdup_printf( - "select lft, rgt from %s where id=%s;", - assoc_table, id); + "select lft, rgt from %s_%s where id_assoc=%s;", + cluster, assoc_table, id); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, __FILE__, __LINE__, query); if(!(result = @@ -234,10 +294,9 @@ static uint32_t _get_parent_id( xassert(parent); xassert(cluster); - query = xstrdup_printf("select id from %s where user='' " - "and deleted = 0 and acct=\"%s\" " - "and cluster=\"%s\";", - assoc_table, parent, cluster); + query = xstrdup_printf("select id_assoc from %s_%s where user='' " + "and deleted = 0 and acct=\"%s\";", + cluster, assoc_table, parent); debug4("%d(%s:%d) query\n%s", mysql_conn->conn, __FILE__, __LINE__, query); @@ -266,10 +325,11 @@ static int _set_assoc_lft_rgt( char *query = NULL; int rc = SLURM_ERROR; + xassert(assoc->cluster); xassert(assoc->id); - query = xstrdup_printf("select lft, rgt from %s where id=%u;", - assoc_table, assoc->id); + query = xstrdup_printf("select lft, rgt from %s_%s where id_assoc=%u;", + assoc->cluster, assoc_table, assoc->id); debug4("%d(%s:%d) query\n%s", mysql_conn->conn, __FILE__, __LINE__, query); @@ -411,10 +471,9 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn, int i; char *assoc_req_inx[] = { - "id", + "id_assoc", "user", "acct", - "cluster", "partition", "max_jobs", "max_submit_jobs", @@ -432,7 +491,6 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn, ASSOC_ID, ASSOC_USER, ASSOC_ACCT, - ASSOC_CLUSTER, ASSOC_PART, ASSOC_MJ, ASSOC_MSJ, @@ -447,6 +505,9 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn, ASSOC_COUNT }; + xassert(assoc); + xassert(assoc->cluster); + if(!ret_list || !acct) return SLURM_ERROR; @@ -457,12 +518,13 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn, } /* We want all the sub accounts and user accounts */ - query = xstrdup_printf("select distinct %s from %s where deleted=0 " + query = xstrdup_printf("select distinct %s from %s_%s where deleted=0 " "&& lft between %d and %d && " "((user = '' && parent_acct = \"%s\") || " "(user != '' && acct = \"%s\")) " "order by lft;", - object, assoc_table, lft, rgt, acct, acct); + object, assoc->cluster, assoc_table, + lft, rgt, acct, acct); xfree(object); debug3("%d(%s:%d) query\n%s", mysql_conn->conn, __FILE__, __LINE__, query); @@ -480,6 +542,7 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn, mod_assoc = xmalloc(sizeof(acct_association_rec_t)); init_acct_association_rec(mod_assoc); mod_assoc->id = atoi(row[ASSOC_ID]); + mod_assoc->cluster = xstrdup(assoc->cluster); if(!row[ASSOC_MJ] && assoc->max_jobs != NO_VAL) { mod_assoc->max_jobs = assoc->max_jobs; @@ -585,12 +648,12 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn, // see if there is a partition name object = xstrdup_printf( "C = %-10s A = %-20s U = %-9s P = %s", - row[ASSOC_CLUSTER], row[ASSOC_ACCT], + assoc->cluster, row[ASSOC_ACCT], row[ASSOC_USER], row[ASSOC_PART]); } else { object = xstrdup_printf( "C = %-10s A = %-20s U = %-9s", - row[ASSOC_CLUSTER], + assoc->cluster, row[ASSOC_ACCT], row[ASSOC_USER]); } @@ -601,8 +664,8 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn, destroy_acct_association_rec(mod_assoc); else if(addto_update_list(mysql_conn->update_list, - ACCT_MODIFY_ASSOC, - mod_assoc) + ACCT_MODIFY_ASSOC, + mod_assoc) != SLURM_SUCCESS) error("couldn't add to " "the update list"); @@ -616,17 +679,18 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn, } /* when doing a select on this all the select should have a prefix of - * t1. */ -static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond, - char **extra) + * t1. Returns "where" clause which needs to be xfreed. */ +static char *_setup_association_cond_qos(acct_association_cond_t *assoc_cond, + char *cluster_name) { int set = 0; ListIterator itr = NULL; char *object = NULL; char *prefix = "t1"; + char *extra = NULL; if(!assoc_cond) - return 0; + return NULL; /* we need to check this first so we can update the with_sub_accts if needed since this the qos_list is a @@ -638,15 +702,15 @@ static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond, really most likely a parent thing */ assoc_cond->with_sub_accts = 1; prefix = "t2"; - xstrfmtcat(*extra, ", %s as t2 where " + xstrfmtcat(extra, ", %s_%s as t2 where " "(t1.lft between t2.lft and t2.rgt) && (", - assoc_table); + cluster_name, assoc_table); set = 0; itr = list_iterator_create(assoc_cond->qos_list); while((object = list_next(itr))) { if(set) - xstrcat(*extra, " || "); - xstrfmtcat(*extra, + xstrcat(extra, " || "); + xstrfmtcat(extra, "(%s.qos like '%%,%s' " "|| %s.qos like '%%,%s,%%' " "|| %s.delta_qos like '%%,+%s' " @@ -656,14 +720,27 @@ static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond, set = 1; } list_iterator_destroy(itr); - xstrcat(*extra, ") &&"); + xstrcat(extra, ") &&"); } else if(assoc_cond->with_sub_accts) { prefix = "t2"; - xstrfmtcat(*extra, ", %s as t2 where " + xstrfmtcat(extra, ", %s as t2 where " "(t1.lft between t2.lft and t2.rgt) &&", assoc_table); } else - xstrcat(*extra, " where"); + xstrcat(extra, " where"); + return extra; +} + +/* When doing a select on this all the select should have a prefix of t1. */ +static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond, + const char *prefix, char **extra) +{ + int set = 0; + ListIterator itr = NULL; + char *object = NULL; + + if(!assoc_cond) + return 0; if(assoc_cond->with_deleted) xstrfmtcat(*extra, " (%s.deleted=0 || %s.deleted=1)", @@ -685,20 +762,6 @@ static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond, xstrcat(*extra, ")"); } - if(assoc_cond->cluster_list && list_count(assoc_cond->cluster_list)) { - set = 0; - xstrcat(*extra, " && ("); - itr = list_iterator_create(assoc_cond->cluster_list); - while((object = list_next(itr))) { - if(set) - xstrcat(*extra, " || "); - xstrfmtcat(*extra, "%s.cluster=\"%s\"", prefix, object); - set = 1; - } - list_iterator_destroy(itr); - xstrcat(*extra, ")"); - } - if(assoc_cond->fairshare_list && list_count(assoc_cond->fairshare_list)) { set = 0; @@ -974,161 +1037,467 @@ static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond, return set; } -extern int mysql_add_assocs(mysql_conn_t *mysql_conn, uint32_t uid, - List association_list) +static int _process_modify_assoc_results(mysql_conn_t *mysql_conn, + MYSQL_RES *result, + acct_association_rec_t *assoc, + acct_user_rec_t *user, + char *cluster_name, + bool is_admin, List ret_list) { ListIterator itr = NULL; + MYSQL_ROW row; + int added = 0; int rc = SLURM_SUCCESS; - int i=0; - acct_association_rec_t *object = NULL; - char *cols = NULL, *vals = NULL, *txn_query = NULL, - *extra = NULL, *query = NULL, *update = NULL, *tmp_extra = NULL; - char *parent = NULL; - time_t now = time(NULL); - char *user_name = NULL; - char *tmp_char = NULL; - int assoc_id = 0; - int incr = 0, my_left = 0, my_par_id = 0; - int affect_rows = 0; + int set_qos_vals = 0; int moved_parent = 0; - MYSQL_RES *result = NULL; - MYSQL_ROW row; - char *old_parent = NULL, *old_cluster = NULL; - char *last_parent = NULL, *last_cluster = NULL; - char *massoc_req_inx[] = { - "id", - "parent_acct", - "lft", - "rgt", - "deleted" - }; + char *vals = NULL, *object = NULL, *name_char = NULL; + time_t now = time(NULL); - enum { - MASSOC_ID, - MASSOC_PACCT, - MASSOC_LFT, - MASSOC_RGT, - MASSOC_DELETED, - MASSOC_COUNT - }; + xassert(result); - if(!association_list) { - error("No association list given"); - return SLURM_ERROR; - } + if(!mysql_num_rows(result)) + return SLURM_SUCCESS; - if(check_connection(mysql_conn) != SLURM_SUCCESS) - return ESLURM_DB_CONNECTION; + while((row = mysql_fetch_row(result))) { + acct_association_rec_t *mod_assoc = NULL; + int account_type=0; + /* If parent changes these also could change + so we need to keep track of the latest + ones. + */ + uint32_t lft = atoi(row[MASSOC_LFT]); + uint32_t rgt = atoi(row[MASSOC_RGT]); - user_name = uid_to_string((uid_t) uid); - itr = list_iterator_create(association_list); - while((object = list_next(itr))) { - if(!object->cluster || !object->cluster[0] - || !object->acct || !object->acct[0]) { - error("We need a association cluster and " - "acct to add one."); - rc = SLURM_ERROR; - continue; - } + if(!is_admin) { + acct_coord_rec_t *coord = NULL; + char *account = row[MASSOC_ACCT]; - if(object->parent_acct) { - parent = object->parent_acct; - } else if(object->user) { - parent = object->acct; - } else { - parent = "root"; - } + /* Here we want to see if the person + * is a coord of the parent account + * since we don't want him to be able + * to alter the limits of the account + * he is directly coord of. They + * should be able to alter the + * sub-accounts though. If no parent account + * that means we are talking about a user + * association so account is really the parent + * of the user a coord can change that all day long. + */ + if(row[MASSOC_PACCT][0]) + account = row[MASSOC_PACCT]; - xstrcat(cols, "creation_time, mod_time, cluster, acct"); - xstrfmtcat(vals, "%d, %d, \"%s\", \"%s\"", - now, now, object->cluster, object->acct); - xstrfmtcat(update, - "where cluster=\"%s\" && acct=\"%s\"", - object->cluster, object->acct); + if(!user->coord_accts) { // This should never + // happen + error("We are here with no coord accts."); + rc = ESLURM_ACCESS_DENIED; + goto end_it; + } + itr = list_iterator_create(user->coord_accts); + while((coord = list_next(itr))) { + if(!strcasecmp(coord->name, account)) + break; + } + list_iterator_destroy(itr); - xstrfmtcat(extra, ", mod_time=%d, cluster=\"%s\", " - "acct=\"%s\"", now, object->cluster, object->acct); - if(!object->user) { - xstrcat(cols, ", parent_acct"); - xstrfmtcat(vals, ", \"%s\"", parent); - xstrfmtcat(extra, ", parent_acct=\"%s\", user=\"\"", - parent); - xstrfmtcat(update, " && user=\"\""); - } else { - char *part = object->partition; - xstrcat(cols, ", user"); - xstrfmtcat(vals, ", \"%s\"", object->user); - xstrfmtcat(update, " && user=\"%s\"", object->user); - xstrfmtcat(extra, ", user=\"%s\"", object->user); + if(!coord) { + if(row[MASSOC_PACCT][0]) + error("User %s(%d) can not modify " + "account (%s) because they " + "are not coordinators of " + "parent account \"%s\".", + user->name, user->uid, + row[MASSOC_ACCT], + row[MASSOC_PACCT]); + else + error("User %s(%d) does not have the " + "ability to modify the account " + "(%s).", + user->name, user->uid, + row[MASSOC_ACCT]); - /* We need to give a partition whether it be - * '' or the actual partition name given - */ - if(!part) - part = ""; - xstrcat(cols, ", partition"); - xstrfmtcat(vals, ", \"%s\"", part); - xstrfmtcat(update, " && partition=\"%s\"", part); - xstrfmtcat(extra, ", partition=\"%s\"", part); + rc = ESLURM_ACCESS_DENIED; + goto end_it; + } } - setup_association_limits(object, &cols, &vals, &extra, - QOS_LEVEL_NONE, 1); + if(row[MASSOC_PART][0]) { + // see if there is a partition name + object = xstrdup_printf( + "C = %-10s A = %-20s U = %-9s P = %s", + row[MASSOC_COUNT], row[MASSOC_ACCT], + row[MASSOC_USER], row[MASSOC_PART]); + } else if(row[MASSOC_USER][0]){ + object = xstrdup_printf( + "C = %-10s A = %-20s U = %-9s", + row[MASSOC_COUNT], row[MASSOC_ACCT], + row[MASSOC_USER]); + } else { + if(assoc->parent_acct) { + if(!strcasecmp(row[MASSOC_ACCT], + assoc->parent_acct)) { + error("You can't make an account be a " + "child of it's self"); + xfree(object); + continue; + } + rc = _move_parent(mysql_conn, user->uid, + &lft, &rgt, + row[MASSOC_COUNT], + row[MASSOC_ID], + row[MASSOC_PACCT], + assoc->parent_acct, + now); + if((rc == ESLURM_INVALID_PARENT_ACCOUNT) + || (rc == ESLURM_SAME_PARENT_ACCOUNT)) { + continue; + } else if(rc != SLURM_SUCCESS) + break; - for(i=0; i<MASSOC_COUNT; i++) { - if(i) - xstrcat(tmp_char, ", "); - xstrcat(tmp_char, massoc_req_inx[i]); + moved_parent = 1; + } + if(row[MASSOC_PACCT][0]) { + object = xstrdup_printf( + "C = %-10s A = %s of %s", + row[MASSOC_COUNT], row[MASSOC_ACCT], + row[MASSOC_PACCT]); + } else { + object = xstrdup_printf( + "C = %-10s A = %s", + row[MASSOC_COUNT], row[MASSOC_ACCT]); + } + account_type = 1; } + list_append(ret_list, object); + added++; - xstrfmtcat(query, - "select distinct %s from %s %s order by lft " - "FOR UPDATE;", - tmp_char, assoc_table, update); - xfree(tmp_char); - debug3("%d(%s:%d) query\n%s", - mysql_conn->conn, __FILE__, __LINE__, query); - if(!(result = mysql_db_query_ret( - mysql_conn->db_conn, query, 0))) { - xfree(query); - xfree(cols); - xfree(vals); - xfree(extra); - xfree(update); - error("couldn't query the database"); - rc = SLURM_ERROR; - break; - } - xfree(query); + if(name_char) + xstrfmtcat(name_char, " || id_assoc=%s", + row[MASSOC_ID]); + else + xstrfmtcat(name_char, "(id_assoc=%s", row[MASSOC_ID]); - assoc_id = 0; - if(!(row = mysql_fetch_row(result))) { - /* This code speeds up the add process quite a bit - * here we are only doing an update when we are done - * adding to a specific group (cluster/account) other - * than that we are adding right behind what we were - * so just total them up and then do one update - * instead of the slow ones that require an update - * every time. There is a incr check outside of the - * loop to catch everything on the last spin of the - * while. - */ - if(!old_parent || !old_cluster - || strcasecmp(parent, old_parent) - || strcasecmp(object->cluster, old_cluster)) { - char *sel_query = xstrdup_printf( - "SELECT lft FROM %s WHERE " - "acct = \"%s\" and cluster = \"%s\" " - "and user = '' order by lft;", - assoc_table, - parent, object->cluster); - MYSQL_RES *sel_result = NULL; + mod_assoc = xmalloc(sizeof(acct_association_rec_t)); + init_acct_association_rec(mod_assoc); + mod_assoc->id = atoi(row[MASSOC_ID]); + mod_assoc->cluster = xstrdup(cluster_name); - if(incr) { - char *up_query = xstrdup_printf( - "UPDATE %s SET rgt = rgt+%d " - "WHERE rgt > %d && deleted < 2;" - "UPDATE %s SET lft = lft+%d " + mod_assoc->shares_raw = assoc->shares_raw; + + mod_assoc->grp_cpus = assoc->grp_cpus; + mod_assoc->grp_cpu_mins = assoc->grp_cpu_mins; + mod_assoc->grp_jobs = assoc->grp_jobs; + mod_assoc->grp_nodes = assoc->grp_nodes; + mod_assoc->grp_submit_jobs = assoc->grp_submit_jobs; + mod_assoc->grp_wall = assoc->grp_wall; + + mod_assoc->max_cpus_pj = assoc->max_cpus_pj; + mod_assoc->max_cpu_mins_pj = assoc->max_cpu_mins_pj; + mod_assoc->max_jobs = assoc->max_jobs; + mod_assoc->max_nodes_pj = assoc->max_nodes_pj; + mod_assoc->max_submit_jobs = assoc->max_submit_jobs; + mod_assoc->max_wall_pj = assoc->max_wall_pj; + + /* no need to get the parent id since if we moved + * parent id's we will get it when we send the total list */ + + if(!row[MASSOC_USER][0]) + mod_assoc->parent_acct = xstrdup(assoc->parent_acct); + if(assoc->qos_list && list_count(assoc->qos_list)) { + ListIterator new_qos_itr = + list_iterator_create(assoc->qos_list); + char *new_qos = NULL, *tmp_qos = NULL; + + mod_assoc->qos_list = list_create(slurm_destroy_char); + + while((new_qos = list_next(new_qos_itr))) { + if(new_qos[0] == '-' || new_qos[0] == '+') { + list_append(mod_assoc->qos_list, + xstrdup(new_qos)); + } else if(new_qos[0]) { + list_append(mod_assoc->qos_list, + xstrdup_printf("=%s", + new_qos)); + } + + if(set_qos_vals) + continue; + /* Now we can set up the values and + make sure we aren't over writing + things that are really from the + parent + */ + if(new_qos[0] == '-') { + xstrfmtcat(vals, + ", qos=if(qos='', '', " + "replace(qos, ',%s', ''))" + ", delta_qos=if(qos='', " + "concat(replace(replace(" + "delta_qos, ',+%s', ''), " + "',-%s', ''), ',%s'), '')", + new_qos+1, new_qos+1, + new_qos+1, new_qos); + } else if(new_qos[0] == '+') { + xstrfmtcat(vals, + ", qos=if(qos='', '', " + "concat_ws(',', " + "replace(qos, ',%s', ''), " + "\"%s\")), delta_qos=if(" + "qos='', concat(" + "replace(replace(" + "delta_qos, ',+%s', ''), " + "',-%s', ''), ',%s'), '')", + new_qos+1, new_qos+1, + new_qos+1, new_qos+1, + new_qos); + } else if(new_qos[0]) + xstrfmtcat(tmp_qos, ",%s", new_qos); + else + xstrcat(tmp_qos, ""); + + } + list_iterator_destroy(new_qos_itr); + + if(!set_qos_vals && tmp_qos) + xstrfmtcat(vals, ", qos='%s', delta_qos=''", + tmp_qos); + xfree(tmp_qos); + + set_qos_vals=1; + } + + if(addto_update_list(mysql_conn->update_list, + ACCT_MODIFY_ASSOC, + mod_assoc) != SLURM_SUCCESS) + error("couldn't add to the update list"); + if(account_type) { + _modify_unset_users(mysql_conn, + mod_assoc, + row[MASSOC_ACCT], + lft, rgt, + ret_list, + moved_parent); + } + } + + xstrcat(name_char, ")"); + + if(assoc->parent_acct) { + if(((rc == ESLURM_INVALID_PARENT_ACCOUNT) + || (rc == ESLURM_SAME_PARENT_ACCOUNT)) + && added) + rc = SLURM_SUCCESS; + } + + if(rc != SLURM_SUCCESS) + goto end_it; + + if(vals) { + char *user_name = uid_to_string((uid_t) user->uid); + rc = modify_common(mysql_conn, DBD_MODIFY_ASSOCS, now, + user_name, assoc_table, name_char, vals, + cluster_name); + xfree(user_name); + if (rc == SLURM_ERROR) { + if(mysql_conn->rollback) { + mysql_db_rollback(mysql_conn->db_conn); + } + list_flush(mysql_conn->update_list); + error("Couldn't modify associations"); + list_destroy(ret_list); + ret_list = NULL; + goto end_it; + } + } + + if(moved_parent) { + List local_assoc_list = NULL; + ListIterator local_itr = NULL; + acct_association_rec_t *local_assoc = NULL; + acct_association_cond_t local_assoc_cond; + /* now we need to send the update of the new parents and + * limits, so just to be safe, send the whole + * tree because we could have some limits that + * were affected but not noticed. + */ + /* we can probably just look at the mod time now but + * we will have to wait for the next revision number + * since you can't query on mod time here and I don't + * want to rewrite code to make it happen + */ + + memset(&local_assoc_cond, 0, sizeof(acct_association_cond_t)); + local_assoc_cond.cluster_list = list_create(NULL); + list_append(local_assoc_cond.cluster_list, cluster_name); + local_assoc_list = mysql_get_assocs( + mysql_conn, user->uid, &local_assoc_cond); + list_destroy(local_assoc_cond.cluster_list); + if(!local_assoc_list) + goto end_it; + /* NOTE: you can not use list_pop, or list_push + anywhere either, since mysql is + exporting something of the same type as a macro, + which messes everything up (my_list.h is + the bad boy). + So we are just going to delete each item as it + comes out since we are moving it to the update_list. + */ + local_itr = list_iterator_create(local_assoc_list); + while((local_assoc = list_next(local_itr))) { + if(addto_update_list(mysql_conn->update_list, + ACCT_MODIFY_ASSOC, + local_assoc) == SLURM_SUCCESS) + list_remove(local_itr); + } + list_iterator_destroy(local_itr); + list_destroy(local_assoc_list); + } + +end_it: + xfree(name_char); + xfree(vals); + + return rc; +} + +extern int mysql_add_assocs(mysql_conn_t *mysql_conn, uint32_t uid, + List association_list) +{ + ListIterator itr = NULL; + int rc = SLURM_SUCCESS; + int i=0; + acct_association_rec_t *object = NULL; + char *cols = NULL, *vals = NULL, *txn_query = NULL, + *extra = NULL, *query = NULL, *update = NULL, *tmp_extra = NULL; + char *parent = NULL; + time_t now = time(NULL); + char *user_name = NULL; + char *tmp_char = NULL; + int assoc_id = 0; + int incr = 0, my_left = 0, my_par_id = 0; + int affect_rows = 0; + int moved_parent = 0; + MYSQL_RES *result = NULL; + MYSQL_ROW row; + char *old_parent = NULL, *old_cluster = NULL; + char *last_parent = NULL, *last_cluster = NULL; + + if(!association_list) { + error("No association list given"); + return SLURM_ERROR; + } + + if(check_connection(mysql_conn) != SLURM_SUCCESS) + return ESLURM_DB_CONNECTION; + + user_name = uid_to_string((uid_t) uid); + itr = list_iterator_create(association_list); + while((object = list_next(itr))) { + if(!object->cluster || !object->cluster[0] + || !object->acct || !object->acct[0]) { + error("We need a association cluster and " + "acct to add one."); + rc = SLURM_ERROR; + continue; + } + + if(object->parent_acct) { + parent = object->parent_acct; + } else if(object->user) { + parent = object->acct; + } else { + parent = "root"; + } + + xstrcat(cols, "creation_time, mod_time, cluster, acct"); + xstrfmtcat(vals, "%d, %d, \"%s\", \"%s\"", + now, now, object->cluster, object->acct); + xstrfmtcat(update, + "where cluster=\"%s\" && acct=\"%s\"", + object->cluster, object->acct); + + xstrfmtcat(extra, ", mod_time=%d, cluster=\"%s\", " + "acct=\"%s\"", now, object->cluster, object->acct); + if(!object->user) { + xstrcat(cols, ", parent_acct"); + xstrfmtcat(vals, ", \"%s\"", parent); + xstrfmtcat(extra, ", parent_acct=\"%s\", user=\"\"", + parent); + xstrfmtcat(update, " && user=\"\""); + } else { + char *part = object->partition; + xstrcat(cols, ", user"); + xstrfmtcat(vals, ", \"%s\"", object->user); + xstrfmtcat(update, " && user=\"%s\"", object->user); + xstrfmtcat(extra, ", user=\"%s\"", object->user); + + /* We need to give a partition whether it be + * '' or the actual partition name given + */ + if(!part) + part = ""; + xstrcat(cols, ", partition"); + xstrfmtcat(vals, ", \"%s\"", part); + xstrfmtcat(update, " && partition=\"%s\"", part); + xstrfmtcat(extra, ", partition=\"%s\"", part); + } + + setup_association_limits(object, &cols, &vals, &extra, + QOS_LEVEL_NONE, 1); + + for(i=0; i<AASSOC_COUNT; i++) { + if(i) + xstrcat(tmp_char, ", "); + xstrcat(tmp_char, aassoc_req_inx[i]); + } + + xstrfmtcat(query, + "select distinct %s from %s %s order by lft " + "FOR UPDATE;", + tmp_char, assoc_table, update); + xfree(tmp_char); + debug3("%d(%s:%d) query\n%s", + mysql_conn->conn, __FILE__, __LINE__, query); + if(!(result = mysql_db_query_ret( + mysql_conn->db_conn, query, 0))) { + xfree(query); + xfree(cols); + xfree(vals); + xfree(extra); + xfree(update); + error("couldn't query the database"); + rc = SLURM_ERROR; + break; + } + xfree(query); + + assoc_id = 0; + if(!(row = mysql_fetch_row(result))) { + /* This code speeds up the add process quite a bit + * here we are only doing an update when we are done + * adding to a specific group (cluster/account) other + * than that we are adding right behind what we were + * so just total them up and then do one update + * instead of the slow ones that require an update + * every time. There is a incr check outside of the + * loop to catch everything on the last spin of the + * while. + */ + if(!old_parent || !old_cluster + || strcasecmp(parent, old_parent) + || strcasecmp(object->cluster, old_cluster)) { + char *sel_query = xstrdup_printf( + "SELECT lft FROM %s WHERE " + "acct = \"%s\" and cluster = \"%s\" " + "and user = '' order by lft;", + assoc_table, + parent, object->cluster); + MYSQL_RES *sel_result = NULL; + + if(incr) { + char *up_query = xstrdup_printf( + "UPDATE %s SET rgt = rgt+%d " + "WHERE rgt > %d && deleted < 2;" + "UPDATE %s SET lft = lft+%d " "WHERE lft > %d " "&& deleted < 2;" "UPDATE %s SET deleted = 0 " @@ -1218,7 +1587,7 @@ extern int mysql_add_assocs(mysql_conn_t *mysql_conn, uint32_t uid, /* "values (%s, @myLeft+1, @myLeft+2);", */ /* assoc_table, cols, */ /* vals); */ - } else if(!atoi(row[MASSOC_DELETED])) { + } else if(!atoi(row[AASSOC_DELETED])) { /* We don't need to do anything here */ debug("This account was added already"); xfree(cols); @@ -1228,25 +1597,25 @@ extern int mysql_add_assocs(mysql_conn_t *mysql_conn, uint32_t uid, xfree(extra); continue; } else { - uint32_t lft = atoi(row[MASSOC_LFT]); - uint32_t rgt = atoi(row[MASSOC_RGT]); + uint32_t lft = atoi(row[AASSOC_LFT]); + uint32_t rgt = atoi(row[AASSOC_RGT]); /* If it was once deleted we have kept the lft * and rgt's consant while it was deleted and * so we can just unset the deleted flag, * check for the parent and move if needed. */ - assoc_id = atoi(row[MASSOC_ID]); + assoc_id = atoi(row[AASSOC_ID]); if(object->parent_acct && strcasecmp(object->parent_acct, - row[MASSOC_PACCT])) { + row[AASSOC_PACCT])) { /* We need to move the parent! */ if(_move_parent(mysql_conn, uid, &lft, &rgt, object->cluster, - row[MASSOC_ID], - row[MASSOC_PACCT], + row[AASSOC_ID], + row[AASSOC_PACCT], object->parent_acct, now) == SLURM_ERROR) continue; @@ -1419,456 +1788,146 @@ end_it: list_iterator_destroy(itr); list_destroy(assoc_list); } - } else { - xfree(txn_query); - if(mysql_conn->rollback) { - mysql_db_rollback(mysql_conn->db_conn); - } - list_flush(mysql_conn->update_list); - } - - return rc; -} - -extern List mysql_modify_assocs(mysql_conn_t *mysql_conn, uint32_t uid, - acct_association_cond_t *assoc_cond, - acct_association_rec_t *assoc) -{ - ListIterator itr = NULL; - List ret_list = NULL; - int rc = SLURM_SUCCESS; - char *object = NULL; - char *vals = NULL, *extra = NULL, *query = NULL, *name_char = NULL; - time_t now = time(NULL); - char *user_name = NULL; - int set = 0, i = 0, is_admin=0; - MYSQL_RES *result = NULL; - MYSQL_ROW row; - acct_user_rec_t user; - char *tmp_char1=NULL, *tmp_char2=NULL; - int set_qos_vals = 0; - int moved_parent = 0; - - char *massoc_req_inx[] = { - "id", - "acct", - "parent_acct", - "cluster", - "user", - "partition", - "lft", - "rgt", - "qos", - }; - - enum { - MASSOC_ID, - MASSOC_ACCT, - MASSOC_PACCT, - MASSOC_CLUSTER, - MASSOC_USER, - MASSOC_PART, - MASSOC_LFT, - MASSOC_RGT, - MASSOC_QOS, - MASSOC_COUNT - }; - - if(!assoc_cond || !assoc) { - error("we need something to change"); - return NULL; - } - - if(check_connection(mysql_conn) != SLURM_SUCCESS) - return NULL; - - memset(&user, 0, sizeof(acct_user_rec_t)); - user.uid = uid; - - if(!(is_admin = is_user_min_admin_level( - mysql_conn, uid, ACCT_ADMIN_OPERATOR))) { - if(!is_user_any_coord(mysql_conn, &user)) { - error("Only admins/coordinators can " - "modify associations"); - errno = ESLURM_ACCESS_DENIED; - return NULL; - } - } - - set = _setup_association_cond_limits(assoc_cond, &extra); - - /* This needs to be here to make sure we only modify the - correct set of associations The first clause was already - taken care of above. */ - if (assoc_cond->user_list && !list_count(assoc_cond->user_list)) { - debug4("no user specified looking at users"); - xstrcat(extra, " && user != '' "); - } else if (!assoc_cond->user_list) { - debug4("no user specified looking at accounts"); - xstrcat(extra, " && user = '' "); - } - - setup_association_limits(assoc, &tmp_char1, &tmp_char2, - &vals, QOS_LEVEL_MODIFY, 0); - xfree(tmp_char1); - xfree(tmp_char2); - - if(!extra || (!vals && !assoc->parent_acct - && (!assoc->qos_list || !list_count(assoc->qos_list)))) { - errno = SLURM_NO_CHANGE_IN_DATA; - error("Nothing to change"); - return NULL; - } - - for(i=0; i<MASSOC_COUNT; i++) { - if(i) - xstrcat(object, ", "); - xstrfmtcat(object, "t1.%s", massoc_req_inx[i]); - } - - query = xstrdup_printf("select distinct %s from %s as t1%s " - "order by lft FOR UPDATE;", - object, assoc_table, extra); - xfree(object); - xfree(extra); - - debug3("%d(%s:%d) query\n%s", - mysql_conn->conn, __FILE__, __LINE__, query); - if(!(result = mysql_db_query_ret( - mysql_conn->db_conn, query, 0))) { - xfree(query); - return NULL; - } - xfree(query); - - rc = SLURM_SUCCESS; - set = 0; - extra = NULL; - ret_list = list_create(slurm_destroy_char); - while((row = mysql_fetch_row(result))) { - acct_association_rec_t *mod_assoc = NULL; - int account_type=0; - /* If parent changes these also could change - so we need to keep track of the latest - ones. - */ - uint32_t lft = atoi(row[MASSOC_LFT]); - uint32_t rgt = atoi(row[MASSOC_RGT]); - - if(!is_admin) { - acct_coord_rec_t *coord = NULL; - char *account = row[MASSOC_ACCT]; - - /* Here we want to see if the person - * is a coord of the parent account - * since we don't want him to be able - * to alter the limits of the account - * he is directly coord of. They - * should be able to alter the - * sub-accounts though. If no parent account - * that means we are talking about a user - * association so account is really the parent - * of the user a coord can change that all day long. - */ - if(row[MASSOC_PACCT][0]) - account = row[MASSOC_PACCT]; - - if(!user.coord_accts) { // This should never - // happen - error("We are here with no coord accts."); - if(mysql_conn->rollback) { - mysql_db_rollback( - mysql_conn->db_conn); - } - errno = ESLURM_ACCESS_DENIED; - mysql_free_result(result); - xfree(vals); - list_destroy(ret_list); - return NULL; - } - itr = list_iterator_create(user.coord_accts); - while((coord = list_next(itr))) { - if(!strcasecmp(coord->name, account)) - break; - } - list_iterator_destroy(itr); - - if(!coord) { - if(row[MASSOC_PACCT][0]) - error("User %s(%d) can not modify " - "account (%s) because they " - "are not coordinators of " - "parent account \"%s\".", - user.name, user.uid, - row[MASSOC_ACCT], - row[MASSOC_PACCT]); - else - error("User %s(%d) does not have the " - "ability to modify the account " - "(%s).", - user.name, user.uid, - row[MASSOC_ACCT]); - - if(mysql_conn->rollback) { - mysql_db_rollback( - mysql_conn->db_conn); - } - errno = ESLURM_ACCESS_DENIED; - mysql_free_result(result); - xfree(vals); - list_destroy(ret_list); - return NULL; - } - } - - if(row[MASSOC_PART][0]) { - // see if there is a partition name - object = xstrdup_printf( - "C = %-10s A = %-20s U = %-9s P = %s", - row[MASSOC_CLUSTER], row[MASSOC_ACCT], - row[MASSOC_USER], row[MASSOC_PART]); - } else if(row[MASSOC_USER][0]){ - object = xstrdup_printf( - "C = %-10s A = %-20s U = %-9s", - row[MASSOC_CLUSTER], row[MASSOC_ACCT], - row[MASSOC_USER]); - } else { - if(assoc->parent_acct) { - if(!strcasecmp(row[MASSOC_ACCT], - assoc->parent_acct)) { - error("You can't make an account be a " - "child of it's self"); - xfree(object); - continue; - } - rc = _move_parent(mysql_conn, uid, - &lft, &rgt, - row[MASSOC_CLUSTER], - row[MASSOC_ID], - row[MASSOC_PACCT], - assoc->parent_acct, - now); - if((rc == ESLURM_INVALID_PARENT_ACCOUNT) - || (rc == ESLURM_SAME_PARENT_ACCOUNT)) { - continue; - } else if(rc != SLURM_SUCCESS) - break; - - moved_parent = 1; - } - if(row[MASSOC_PACCT][0]) { - object = xstrdup_printf( - "C = %-10s A = %s of %s", - row[MASSOC_CLUSTER], row[MASSOC_ACCT], - row[MASSOC_PACCT]); - } else { - object = xstrdup_printf( - "C = %-10s A = %s", - row[MASSOC_CLUSTER], row[MASSOC_ACCT]); - } - account_type = 1; - } - list_append(ret_list, object); - - if(!set) { - xstrfmtcat(name_char, "(id=%s", row[MASSOC_ID]); - set = 1; - } else { - xstrfmtcat(name_char, " || id=%s", row[MASSOC_ID]); + } else { + xfree(txn_query); + if(mysql_conn->rollback) { + mysql_db_rollback(mysql_conn->db_conn); } + list_flush(mysql_conn->update_list); + } - mod_assoc = xmalloc(sizeof(acct_association_rec_t)); - init_acct_association_rec(mod_assoc); - mod_assoc->id = atoi(row[MASSOC_ID]); - - mod_assoc->shares_raw = assoc->shares_raw; + return rc; +} - mod_assoc->grp_cpus = assoc->grp_cpus; - mod_assoc->grp_cpu_mins = assoc->grp_cpu_mins; - mod_assoc->grp_jobs = assoc->grp_jobs; - mod_assoc->grp_nodes = assoc->grp_nodes; - mod_assoc->grp_submit_jobs = assoc->grp_submit_jobs; - mod_assoc->grp_wall = assoc->grp_wall; +extern List mysql_modify_assocs(mysql_conn_t *mysql_conn, uint32_t uid, + acct_association_cond_t *assoc_cond, + acct_association_rec_t *assoc) +{ + ListIterator itr = NULL; + List ret_list = NULL; + int rc = SLURM_SUCCESS; + char *object = NULL; + char *vals = NULL, *extra = NULL, *query = NULL; + int set = 0, i = 0, is_admin=0; + MYSQL_RES *result = NULL; + acct_user_rec_t user; + char *tmp_char1=NULL, *tmp_char2=NULL; + char *cluster_name = NULL; + char *prefix = "t1"; + List use_cluster_list = mysql_cluster_list; - mod_assoc->max_cpus_pj = assoc->max_cpus_pj; - mod_assoc->max_cpu_mins_pj = assoc->max_cpu_mins_pj; - mod_assoc->max_jobs = assoc->max_jobs; - mod_assoc->max_nodes_pj = assoc->max_nodes_pj; - mod_assoc->max_submit_jobs = assoc->max_submit_jobs; - mod_assoc->max_wall_pj = assoc->max_wall_pj; + if(!assoc_cond || !assoc) { + error("we need something to change"); + return NULL; + } - /* no need to get the parent id since if we moved - * parent id's we will get it when we send the total list */ + if(check_connection(mysql_conn) != SLURM_SUCCESS) + return NULL; - if(!row[MASSOC_USER][0]) - mod_assoc->parent_acct = xstrdup(assoc->parent_acct); - if(assoc->qos_list && list_count(assoc->qos_list)) { - ListIterator new_qos_itr = - list_iterator_create(assoc->qos_list); - char *new_qos = NULL, *tmp_qos = NULL; + memset(&user, 0, sizeof(acct_user_rec_t)); + user.uid = uid; - mod_assoc->qos_list = list_create(slurm_destroy_char); + if(!(is_admin = is_user_min_admin_level( + mysql_conn, uid, ACCT_ADMIN_OPERATOR))) { + if(!is_user_any_coord(mysql_conn, &user)) { + error("Only admins/coordinators can " + "modify associations"); + errno = ESLURM_ACCESS_DENIED; + return NULL; + } + } - while((new_qos = list_next(new_qos_itr))) { - if(new_qos[0] == '-' || new_qos[0] == '+') { - list_append(mod_assoc->qos_list, - xstrdup(new_qos)); - } else if(new_qos[0]) { - list_append(mod_assoc->qos_list, - xstrdup_printf("=%s", - new_qos)); - } + if((assoc_cond->qos_list && list_count(assoc_cond->qos_list)) + || assoc_cond->with_sub_accts) + prefix = "t2"; - if(set_qos_vals) - continue; - /* Now we can set up the values and - make sure we aren't over writing - things that are really from the - parent - */ - if(new_qos[0] == '-') { - xstrfmtcat(vals, - ", qos=if(qos='', '', " - "replace(qos, ',%s', ''))" - ", delta_qos=if(qos='', " - "concat(replace(replace(" - "delta_qos, ',+%s', ''), " - "',-%s', ''), ',%s'), '')", - new_qos+1, new_qos+1, - new_qos+1, new_qos); - } else if(new_qos[0] == '+') { - xstrfmtcat(vals, - ", qos=if(qos='', '', " - "concat_ws(',', " - "replace(qos, ',%s', ''), " - "\"%s\")), delta_qos=if(" - "qos='', concat(" - "replace(replace(" - "delta_qos, ',+%s', ''), " - "',-%s', ''), ',%s'), '')", - new_qos+1, new_qos+1, - new_qos+1, new_qos+1, - new_qos); - } else if(new_qos[0]) - xstrfmtcat(tmp_qos, ",%s", new_qos); - else - xstrcat(tmp_qos, ""); + set = _setup_association_cond_limits(assoc_cond, prefix, &extra); - } - list_iterator_destroy(new_qos_itr); + /* This needs to be here to make sure we only modify the + correct set of associations The first clause was already + taken care of above. */ + if (assoc_cond->user_list && !list_count(assoc_cond->user_list)) { + debug4("no user specified looking at users"); + xstrcat(extra, " && user != '' "); + } else if (!assoc_cond->user_list) { + debug4("no user specified looking at accounts"); + xstrcat(extra, " && user = '' "); + } - if(!set_qos_vals && tmp_qos) - xstrfmtcat(vals, ", qos='%s', delta_qos=''", - tmp_qos); - xfree(tmp_qos); + setup_association_limits(assoc, &tmp_char1, &tmp_char2, + &vals, QOS_LEVEL_MODIFY, 0); + xfree(tmp_char1); + xfree(tmp_char2); - set_qos_vals=1; - } + if(!extra || (!vals && !assoc->parent_acct + && (!assoc->qos_list || !list_count(assoc->qos_list)))) { + errno = SLURM_NO_CHANGE_IN_DATA; + error("Nothing to change"); + return NULL; + } - if(addto_update_list(mysql_conn->update_list, - ACCT_MODIFY_ASSOC, - mod_assoc) != SLURM_SUCCESS) - error("couldn't add to the update list"); - if(account_type) { - _modify_unset_users(mysql_conn, - mod_assoc, - row[MASSOC_ACCT], - lft, rgt, - ret_list, - moved_parent); - } + for(i=0; i<MASSOC_COUNT; i++) { + if(i) + xstrcat(object, ", "); + xstrfmtcat(object, "t1.%s", massoc_req_inx[i]); } - mysql_free_result(result); - if(assoc->parent_acct) { - if(((rc == ESLURM_INVALID_PARENT_ACCOUNT) - || (rc == ESLURM_SAME_PARENT_ACCOUNT)) - && list_count(ret_list)) - rc = SLURM_SUCCESS; + + ret_list = list_create(slurm_destroy_char); + + if(assoc_cond->cluster_list && list_count(assoc_cond->cluster_list)) + use_cluster_list = assoc_cond->cluster_list; + else + slurm_mutex_lock(&mysql_cluster_list_lock); + + itr = list_iterator_create(use_cluster_list); + while((cluster_name = list_next(itr))) { + char *qos_extra = _setup_association_cond_qos( + assoc_cond, cluster_name); + + xstrfmtcat(query, "select distinct %s,'%s' " + "from %s_%s as t1%s%s " + "order by lft FOR UPDATE;", + object, cluster_name, + assoc_table, qos_extra, extra); + xfree(qos_extra); + debug3("%d(%s:%d) query\n%s", + mysql_conn->conn, __FILE__, __LINE__, query); + if(!(result = mysql_db_query_ret( + mysql_conn->db_conn, query, 0))) { + xfree(query); + list_destroy(ret_list); + ret_list = NULL; + break; + } + xfree(query); + rc = _process_modify_assoc_results(mysql_conn, result, assoc, + &user, cluster_name, + is_admin, ret_list); + mysql_free_result(result); if(rc != SLURM_SUCCESS) { - if(mysql_conn->rollback) { - mysql_db_rollback(mysql_conn->db_conn); - } - list_flush(mysql_conn->update_list); list_destroy(ret_list); - xfree(vals); - errno = rc; - return NULL; + ret_list = NULL; + break; } } + list_iterator_destroy(itr); + if(use_cluster_list == mysql_cluster_list) + slurm_mutex_unlock(&mysql_cluster_list_lock); + xfree(object); + xfree(extra); - - if(!list_count(ret_list)) { + if(!ret_list) + return NULL; + else if(!list_count(ret_list)) { if(mysql_conn->rollback) { mysql_db_rollback(mysql_conn->db_conn); } errno = SLURM_NO_CHANGE_IN_DATA; debug3("didn't effect anything"); - xfree(vals); return ret_list; } - xstrcat(name_char, ")"); - - if(vals) { - user_name = uid_to_string((uid_t) uid); - rc = modify_common(mysql_conn, DBD_MODIFY_ASSOCS, now, - user_name, assoc_table, name_char, vals); - xfree(user_name); - if (rc == SLURM_ERROR) { - if(mysql_conn->rollback) { - mysql_db_rollback(mysql_conn->db_conn); - } - list_flush(mysql_conn->update_list); - error("Couldn't modify associations"); - list_destroy(ret_list); - ret_list = NULL; - goto end_it; - } - } - if(moved_parent) { - List local_assoc_list = NULL; - ListIterator local_itr = NULL; - acct_association_rec_t *local_assoc = NULL; - //acct_association_cond_t local_assoc_cond; - /* now we need to send the update of the new parents and - * limits, so just to be safe, send the whole - * tree because we could have some limits that - * were affected but not noticed. - */ - /* we can probably just look at the mod time now but - * we will have to wait for the next revision number - * since you can't query on mod time here and I don't - * want to rewrite code to make it happen - */ - - //memset(&local_assoc_cond, 0, sizeof(acct_association_cond_t)); - - if(!(local_assoc_list = - mysql_get_assocs(mysql_conn, uid, NULL))) - return ret_list; - /* NOTE: you can not use list_pop, or list_push - anywhere either, since mysql is - exporting something of the same type as a macro, - which messes everything up (my_list.h is - the bad boy). - So we are just going to delete each item as it - comes out since we are moving it to the update_list. - */ - local_itr = list_iterator_create(local_assoc_list); - while((local_assoc = list_next(local_itr))) { - if(addto_update_list(mysql_conn->update_list, - ACCT_MODIFY_ASSOC, - local_assoc) == SLURM_SUCCESS) - list_remove(local_itr); - } - list_iterator_destroy(local_itr); - list_destroy(local_assoc_list); - } - -end_it: - xfree(name_char); - xfree(vals); return ret_list; } @@ -1888,27 +1947,7 @@ extern List mysql_remove_assocs(mysql_conn_t *mysql_conn, uint32_t uid, MYSQL_RES *result = NULL; MYSQL_ROW row; acct_user_rec_t user; - - /* if this changes you will need to edit the corresponding - * enum below also t1 is step_table */ - char *rassoc_req_inx[] = { - "id", - "acct", - "parent_acct", - "cluster", - "user", - "partition" - }; - - enum { - RASSOC_ID, - RASSOC_ACCT, - RASSOC_PACCT, - RASSOC_CLUSTER, - RASSOC_USER, - RASSOC_PART, - RASSOC_COUNT - }; + char *prefix = "t1"; if(!assoc_cond) { error("we need something to change"); @@ -1931,7 +1970,11 @@ extern List mysql_remove_assocs(mysql_conn_t *mysql_conn, uint32_t uid, } } - set = _setup_association_cond_limits(assoc_cond, &extra); + if((assoc_cond->qos_list && list_count(assoc_cond->qos_list)) + || assoc_cond->with_sub_accts) + prefix = "t2"; + + set = _setup_association_cond_limits(assoc_cond, prefix, &extra); for(i=0; i<RASSOC_COUNT; i++) { if(i) @@ -2128,6 +2171,7 @@ extern List mysql_get_assocs(mysql_conn_t *mysql_conn, uid_t uid, uint32_t parent_id = 0; uint16_t private_data = 0; acct_user_rec_t user; + char *prefix = "t1"; /* needed if we don't have an assoc_cond */ uint16_t without_parent_info = 0; @@ -2218,7 +2262,11 @@ extern List mysql_get_assocs(mysql_conn_t *mysql_conn, uid_t uid, is_user_any_coord(mysql_conn, &user); } - set = _setup_association_cond_limits(assoc_cond, &extra); + if((assoc_cond->qos_list && list_count(assoc_cond->qos_list)) + || assoc_cond->with_sub_accts) + prefix = "t2"; + + set = _setup_association_cond_limits(assoc_cond, prefix, &extra); with_raw_qos = assoc_cond->with_raw_qos; with_usage = assoc_cond->with_usage; diff --git a/src/plugins/accounting_storage/mysql/mysql_cluster.c b/src/plugins/accounting_storage/mysql/mysql_cluster.c index bde4b6426cc..335f94ece7f 100644 --- a/src/plugins/accounting_storage/mysql/mysql_cluster.c +++ b/src/plugins/accounting_storage/mysql/mysql_cluster.c @@ -325,7 +325,8 @@ extern List mysql_modify_clusters(mysql_conn_t *mysql_conn, uint32_t uid, send_char = xstrdup_printf("(%s)", name_char); user_name = uid_to_string((uid_t) uid); rc = modify_common(mysql_conn, DBD_MODIFY_CLUSTERS, now, - user_name, cluster_table, send_char, vals); + user_name, cluster_table, + send_char, vals, NULL); xfree(user_name); if (rc == SLURM_ERROR) { error("Couldn't modify cluster 1"); diff --git a/src/plugins/accounting_storage/mysql/mysql_qos.c b/src/plugins/accounting_storage/mysql/mysql_qos.c index 5bfcb601091..7817a70b2b8 100644 --- a/src/plugins/accounting_storage/mysql/mysql_qos.c +++ b/src/plugins/accounting_storage/mysql/mysql_qos.c @@ -590,7 +590,7 @@ extern List mysql_modify_qos(mysql_conn_t *mysql_conn, uint32_t uid, user_name = uid_to_string((uid_t) uid); rc = modify_common(mysql_conn, DBD_MODIFY_QOS, now, - user_name, qos_table, name_char, vals); + user_name, qos_table, name_char, vals, NULL); xfree(user_name); xfree(name_char); xfree(vals); diff --git a/src/plugins/accounting_storage/mysql/mysql_user.c b/src/plugins/accounting_storage/mysql/mysql_user.c index 2d8f194ac19..46d169576ee 100644 --- a/src/plugins/accounting_storage/mysql/mysql_user.c +++ b/src/plugins/accounting_storage/mysql/mysql_user.c @@ -482,7 +482,7 @@ extern List mysql_modify_users(mysql_conn_t *mysql_conn, uint32_t uid, user_name = uid_to_string((uid_t) uid); rc = modify_common(mysql_conn, DBD_MODIFY_USERS, now, - user_name, user_table, name_char, vals); + user_name, user_table, name_char, vals, NULL); xfree(user_name); xfree(name_char); xfree(vals); -- GitLab