From 28e0984daf1fad3625731fdf23121c1d29a452cf Mon Sep 17 00:00:00 2001
From: Danny Auble <da@llnl.gov>
Date: Wed, 2 Sep 2009 22:52:11 +0000
Subject: [PATCH] added logic to make it possible for qos to be updated on the
 fly and added to associations when they are added to the mix

---
 src/common/assoc_mgr.c                        |  17 ++
 src/common/slurm_accounting_storage.c         |   4 +-
 .../mysql/accounting_storage_mysql.c          | 137 ++++++++++++++---
 testsuite/expect/globals_accounting           |   1 +
 testsuite/expect/test21.26                    | 145 ++++++++----------
 5 files changed, 192 insertions(+), 112 deletions(-)

diff --git a/src/common/assoc_mgr.c b/src/common/assoc_mgr.c
index 3679399e150..95b367abaac 100644
--- a/src/common/assoc_mgr.c
+++ b/src/common/assoc_mgr.c
@@ -178,6 +178,10 @@ static int _local_update_assoc_qos_list(acct_association_rec_t *assoc,
 		return SLURM_SUCCESS;
 	}			
 
+	/* Even though we only use the valid_qos bitstr for things we
+	   need to keep the list around for now since we don't pack the
+	   bitstr for state save.
+	*/
 	new_qos_itr = list_iterator_create(new_qos_list);
 	curr_qos_itr = list_iterator_create(assoc->qos_list);
 	
@@ -1699,6 +1703,19 @@ extern int assoc_mgr_update_assocs(acct_update_object_t *update)
 					rec->qos_list = object->qos_list;
 					object->qos_list = NULL;
 				}
+
+				if(rec->user && (g_qos_count > 0)) {
+					if(!rec->valid_qos
+					   || (bit_size(rec->valid_qos)
+					       != g_qos_count)) {
+						FREE_NULL_BITMAP(
+							rec->valid_qos);
+						rec->valid_qos = 
+							bit_alloc(g_qos_count);
+					} 
+					set_qos_bitstr_from_list(
+						rec->valid_qos, rec->qos_list);
+				}
 			}
 
 			if(!slurmdbd_conf && !parents_changed) {
diff --git a/src/common/slurm_accounting_storage.c b/src/common/slurm_accounting_storage.c
index 969f1b6e754..a44be40fe69 100644
--- a/src/common/slurm_accounting_storage.c
+++ b/src/common/slurm_accounting_storage.c
@@ -7585,8 +7585,8 @@ extern void log_assoc_rec(acct_association_rec_t *assoc_ptr, List qos_list)
 	if(assoc_ptr->user)
 		debug2("  User             : %s(%u)",
 		       assoc_ptr->user, assoc_ptr->uid);
-	debug2("  UsedJobs        : %u", assoc_ptr->used_jobs);
-	debug2("  RawUsage        : %Lf", assoc_ptr->usage_raw);
+	debug2("  UsedJobs         : %u", assoc_ptr->used_jobs);
+	debug2("  RawUsage         : %Lf", assoc_ptr->usage_raw);
 }
 
 /*
diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
index 4d031082310..b2cdecee040 100644
--- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
+++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
@@ -688,6 +688,9 @@ static int _setup_association_limits(acct_association_rec_t *assoc,
 		xstrcat(*cols, ", qos");
 		xstrfmtcat(*vals, ", '%s'", default_qos_str);
 		xstrfmtcat(*extra, ", qos=\"%s\"", default_qos_str);
+		if(!assoc->qos_list)
+			assoc->qos_list = list_create(slurm_destroy_char);
+		slurm_addto_char_list(assoc->qos_list, default_qos_str);
 	} else {
 		/* clear the qos */
 		xstrcat(*cols, ", qos, delta_qos");
@@ -1560,6 +1563,108 @@ static int _set_assoc_lft_rgt(
 	return rc;
 }
 
+static int _set_assoc_limits_for_add(
+	mysql_conn_t *mysql_conn, acct_association_rec_t *assoc)
+{
+	MYSQL_RES *result = NULL;
+	MYSQL_ROW row;
+	char *query = NULL;
+	char *parent = NULL;
+	char *qos_delta = NULL;
+
+	enum {
+		ASSOC_REQ_PARENT_ID,
+		ASSOC_REQ_MJ,
+		ASSOC_REQ_MSJ,
+		ASSOC_REQ_MCPJ,
+		ASSOC_REQ_MNPJ,
+		ASSOC_REQ_MWPJ,
+		ASSOC_REQ_MCMPJ,
+		ASSOC_REQ_QOS,
+		ASSOC_REQ_DELTA_QOS,
+	};
+
+	xassert(assoc);
+
+	if(assoc->parent_acct) 
+		parent = assoc->parent_acct;
+	else if(assoc->user) 
+		parent = assoc->acct;
+	else 
+		return SLURM_SUCCESS;
+	
+	query = xstrdup_printf("call get_parent_limits(\"%s\", "
+			       "\"%s\", \"%s\", %u);"
+			       "select @par_id, @mj, @msj, @mcpj, "
+			       "@mnpj, @mwpj, @mcmpj, @qos, @delta_qos;", 
+			       assoc_table, parent, assoc->cluster, 0);
+	debug4("%d(%d) query\n%s", mysql_conn->conn, __LINE__, query);
+	if(!(result = mysql_db_query_ret(mysql_conn->db_conn, query, 1))) {
+		xfree(query);
+		return SLURM_ERROR;
+	}
+	xfree(query);
+			
+	if(!(row = mysql_fetch_row(result))) 
+		goto end_it;
+	
+	if(row[ASSOC_REQ_MJ] && assoc->max_jobs == NO_VAL) 
+		assoc->max_jobs = atoi(row[ASSOC_REQ_MJ]);
+	if(row[ASSOC_REQ_MSJ] && assoc->max_submit_jobs == NO_VAL)
+		assoc->max_submit_jobs = atoi(row[ASSOC_REQ_MSJ]);
+	if(row[ASSOC_REQ_MCPJ] && assoc->max_cpus_pj == NO_VAL)
+		assoc->max_cpus_pj = atoi(row[ASSOC_REQ_MCPJ]);
+	if(row[ASSOC_REQ_MNPJ] && assoc->max_nodes_pj == NO_VAL)
+		assoc->max_nodes_pj = atoi(row[ASSOC_REQ_MNPJ]);
+	if(row[ASSOC_REQ_MWPJ] && assoc->max_wall_pj == NO_VAL)
+		assoc->max_wall_pj = atoi(row[ASSOC_REQ_MWPJ]);
+	if(row[ASSOC_REQ_MCMPJ] && assoc->max_cpu_mins_pj == NO_VAL)
+		assoc->max_cpu_mins_pj = atoi(row[ASSOC_REQ_MCMPJ]);
+
+	if(assoc->qos_list) {
+		int set = 0;
+		char *tmp_char = NULL;
+		ListIterator qos_itr = list_iterator_create(assoc->qos_list);
+		while((tmp_char = list_next(qos_itr))) {
+			/* we don't want to include blank names */
+			if(!tmp_char[0])
+				continue;
+
+			if(!set) {
+				if(tmp_char[0] != '+' && tmp_char[0] != '-')
+					break;
+				set = 1;
+			}
+			xstrfmtcat(qos_delta, ",%s", tmp_char);
+		}
+		list_iterator_destroy(qos_itr);
+
+		if(tmp_char) {
+			/* we have the qos here nothing from parents
+			   needed */
+			goto end_it;
+		}
+		list_flush(assoc->qos_list);
+	} else 
+		assoc->qos_list = list_create(slurm_destroy_char);
+
+	if(row[ASSOC_REQ_QOS][0])
+		slurm_addto_char_list(assoc->qos_list, row[ASSOC_REQ_QOS]+1);
+
+	if(row[ASSOC_REQ_DELTA_QOS][0])
+		slurm_addto_char_list(assoc->qos_list,
+				      row[ASSOC_REQ_DELTA_QOS]+1);
+	if(qos_delta) {
+		slurm_addto_char_list(assoc->qos_list, qos_delta+1);
+		xfree(qos_delta);
+	}
+		
+end_it:
+	mysql_free_result(result);
+
+	return SLURM_SUCCESS;
+}
+
 /* This function will take the object given and free it later so it
  * needed to be removed from a list if in one before 
  */
@@ -4435,8 +4540,7 @@ extern int acct_storage_p_add_associations(mysql_conn_t *mysql_conn,
 		 * the assoc_id will already be set
 		 */
 		if(!assoc_id) {
-			affect_rows = _last_affected_rows(
-				mysql_conn->db_conn);
+			affect_rows = _last_affected_rows(mysql_conn->db_conn);
 			assoc_id = mysql_insert_id(mysql_conn->db_conn);
 			//info("last id was %d", assoc_id);
 		}
@@ -4461,29 +4565,12 @@ extern int acct_storage_p_add_associations(mysql_conn_t *mysql_conn,
 			}
 		}
 		object->parent_id = my_par_id;
-
-		if(!moved_parent && !object->lft)
-			_set_assoc_lft_rgt(mysql_conn, object);
-
-
-               /* get the parent id only if we haven't moved the
-                * parent since we get the total list if that has
-                * happened */
-               if(!moved_parent &&
-                  (!last_parent || !last_cluster
-                   || strcmp(parent, last_parent)
-                   || strcmp(object->cluster, last_cluster))) {
-                       uint32_t tmp32 = 0;
-                       if((tmp32 = _get_parent_id(mysql_conn, 
-                                                  parent,
-                                                  object->cluster))) {
-                               my_par_id = tmp32;
-
-                               last_parent = parent;
-                               last_cluster = object->cluster;
-                       }
-               }
-               object->parent_id = my_par_id;
+		
+		if(!moved_parent) {
+			_set_assoc_limits_for_add(mysql_conn, object);
+			if(!object->lft)
+				_set_assoc_lft_rgt(mysql_conn, object);
+		}
 
 		if(_addto_update_list(mysql_conn->update_list, ACCT_ADD_ASSOC,
 				      object) == SLURM_SUCCESS) {
diff --git a/testsuite/expect/globals_accounting b/testsuite/expect/globals_accounting
index 999f6e8cd14..95b90e0d217 100644
--- a/testsuite/expect/globals_accounting
+++ b/testsuite/expect/globals_accounting
@@ -594,6 +594,7 @@ proc mod_acct { cluster wparent name wdesc worg qos fairshare grpcpumin grpcpu g
 		}
 		set scommand "$scommand qoslevel='$qos'"
 		set assoc_stuff 1
+		send_user "qos set to $qos\n"
 	}
 
 	incr expected $acct_stuff
diff --git a/testsuite/expect/test21.26 b/testsuite/expect/test21.26
index b0a58bf4f36..c0e9484a118 100755
--- a/testsuite/expect/test21.26
+++ b/testsuite/expect/test21.26
@@ -35,7 +35,7 @@ source ./globals_accounting
 
 set test_id     "test21.26"
 set exit_code   0
-set cluster1		qclustest
+set cluster1		[get_cluster_name]
 set account1		qacctest1
 set account2		qacctest2
 set qos1		qqostest
@@ -62,67 +62,85 @@ if { [string compare [check_accounting_admin_level] "Administrator"] } {
 	exit 0
 }
 
+proc end_test { } {
+	global user1 account1 account2 cluster1 qos1 qos_val
+	set exit_code 0
+	incr exit_code [remove_user "" "" "$user1"]
+	incr exit_code [remove_acct "" "$account1,$account2"]
+	incr exit_code [remove_qos "$qos1"]
+	incr exit_code [mod_acct "$cluster1" "" "root" "" "" "$qos_val" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
+}
+
+
 #
 # remove test associations to make sure we have a clean system
 #
 remove_user "" "" "$user1"
 remove_acct "" "$account1,$account2"
 remove_qos "$qos1"
-remove_cluster "$cluster1"
-if {$access_err != 0} {
-	send_user "\nWARNING: not authorized to perform this test\n"
-	exit $exit_code
+
+# get the qos of root on the cluster since we are going to set it to 
+# nothing here.  And put it back at the end of the test.
+set match 0
+set my_pid [eval spawn $sacctmgr list cluster $cluster1 format=cluster,qos -np]
+expect {
+	-re "There was a problem" {
+		send_user "FAILURE: there was a problem with the sacctmgr command\n"
+		exit 1
+	}
+	-re "$cluster1.(\[a-z,\]*)." {
+		set qos_val $expect_out(1,string)
+		set match 1
+		exp_continue
+	}
+
+	timeout {
+		send_user "\nFAILURE: sacctmgr list associations not responding\n"
+		slow_kill $my_pid
+		exit 1
+	}
+	eof {
+		wait
+	}
+}
+if { !$match } {
+	send_user "\nFAILURE: couldn't query qos\n"
+	exit 1
 }
 
-# Build test associations
-#=====Done Cleaning System=========Begin Add Cluster======
-#add cluster
-incr exit_code [add_cluster "$cluster1" " " "" "" "" "" "" "" "" "" "" "" ""]
+#now set default for cluster to ""
+incr exit_code [mod_acct "$cluster1" "" "root" "" "" " " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
 if { $exit_code } {
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
 	remove_qos "$qos1"
-	remove_cluster "$cluster1"
 	exit $exit_code
 }
-#=====Done Add Cluster========Begin Add QoS==========
+
+
 #add qos
 incr exit_code [add_qos "$qos1"]
 if { $exit_code } {
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
 	remove_qos "$qos1"
-	remove_cluster "$cluster1"
 	exit $exit_code
 }
 #====Done Add QoS===========Begin Add First Account========
 #add default account
 incr exit_code [add_acct "$cluster1" "" "$account1" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
 if { $exit_code } {
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit $exit_code
 }
 #====Done Add First Account====Begin Add Second Account====
 #add account
 incr exit_code [add_acct "$cluster1" "$account1" "$account2" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
 if { $exit_code } {
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit $exit_code
 }
 #=====Done Add Second Account========Begin Add User=========
 #add user
 incr exit_code [add_user "$cluster1" "$account1,$account2" "$user1" "" "" "$account1" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
 if { $exit_code } {
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit $exit_code
 }
 #====Done add user====Done building test associations===Begin test section=======
@@ -159,10 +177,7 @@ expect {
 
 if {$matches != 6} {
 	send_user "\nFAILURE: Initial sacctmgr add failed with ($matches)\n"
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit 1
 }
 
@@ -170,10 +185,7 @@ if {$matches != 6} {
 #modify test1 account to add test QoS
 incr exit_code [mod_acct "$cluster1" "" "$account1" "" "" "+$qos1" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
 if { $exit_code } {
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit $exit_code
 }
 
@@ -210,10 +222,7 @@ expect {
 
 if {$matches != 6} {
 	send_user "\nFAILURE: failed on verify of +$qos1 to account $account1 ($matches)\n"
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit 1
 }
 
@@ -221,10 +230,7 @@ if {$matches != 6} {
 #modify test2 account to remove test QoS
 incr exit_code [mod_acct "$cluster1" "" "$account2" "" "" "-$qos1" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
 if { $exit_code } {
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit $exit_code
 }
 
@@ -260,10 +266,7 @@ expect {
 
 if {$matches != 6} {
 	send_user "\nFAILURE: verify of -$qos1 from account $account2 ($matches)\n"
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit 1
 }
 
@@ -272,10 +275,7 @@ if {$matches != 6} {
 #modify test1 account to remove test QoS
 incr exit_code [mod_acct "$cluster1" "" "$account1" "" "" "-$qos1" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
 if { $exit_code } {
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit $exit_code
 }
 
@@ -311,10 +311,7 @@ expect {
 
 if {$matches != 6} {
 	send_user "\nFAILURE: verify of -$qos1 from account $account1 ($matches)\n"
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit 1
 }
 
@@ -322,10 +319,7 @@ if {$matches != 6} {
 #modify test2 account to add test QoS
 incr exit_code [mod_acct "$cluster1" "" "$account2" "" "" "+$qos1" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
 if { $exit_code } {
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit $exit_code
 }
 
@@ -362,10 +356,7 @@ expect {
 
 if {$matches != 6} {
 	send_user "\nFAILURE: failed on verify of +$qos1 to account $account2 ($matches)\n"
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit 1
 }
 
@@ -373,10 +364,7 @@ if {$matches != 6} {
 #modify root account to add test QoS
 incr exit_code [mod_acct "$cluster1" "" "root" "" "" "+$qos1" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
 if { $exit_code } {
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit $exit_code
 }
 
@@ -413,10 +401,7 @@ expect {
 
 if {$matches != 6} {
 	send_user "\nFAILURE: failed on verify of +$qos1 to account root ($matches)\n"
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit 1
 }
 
@@ -424,10 +409,7 @@ if {$matches != 6} {
 #modify test2 account to remove test QoS
 incr exit_code [mod_acct "$cluster1" "" "$account2" "" "" "-$qos1" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""]
 if { $exit_code } {
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit $exit_code
 }
 
@@ -464,10 +446,7 @@ expect {
 
 if {$matches != 6} {
 	send_user "\nFAILURE: failed on verify of -$qos1 to account $account2 ($matches)\n"
-	remove_user "" "" "$user1"
-	remove_acct "" "$account1,$account2"
-	remove_qos "$qos1"
-	remove_cluster "$cluster1"
+	end_test
 	exit 1
 }
 
@@ -475,11 +454,7 @@ if {$matches != 6} {
 #======Done With List====== Ending=======
 # This is the end below here
 #
-incr exit_code [remove_user "" "" "$user1"]
-incr exit_code [remove_acct "" "$account1,$account2"]
-incr exit_code [remove_qos "$qos1"]
-incr exit_code [remove_cluster "$cluster1"]
-
+incr exit_code [end_test]
 if {$exit_code == 0} {
 	send_user "\nSUCCESS: $test_id\n"
 } else {
-- 
GitLab