From e4ce1aa9624f647535643d67496d2d4c3021391b Mon Sep 17 00:00:00 2001
From: Danny Auble <da@llnl.gov>
Date: Thu, 13 Aug 2009 21:15:49 +0000
Subject: [PATCH]  -- Added functionality for sacctmgr show problems.  Current
 problems include     Accounts/Users with no associations, Accounts with no
 users or subaccounts     attached in a cluster, and Users with No UID on the
 system.  -- Added new option for sacctmgr list assoc and list cluster
 WOLimits.  This     gives a smaller default format without the limit
 information.  This may     be the new default for list assocations and list
 clusters.  -- Users are now required to have an association with there
 default account.     Sacctmgr will now complain when you try to modify a
 users default account     which they are not associated anywhere.

---
 NEWS                                          |   9 +
 doc/man/man1/sacctmgr.1                       |  10 +
 src/common/slurm_accounting_storage.c         |  45 +++
 src/common/slurm_accounting_storage.h         |   9 +-
 .../mysql/accounting_storage_mysql.c          |  24 +-
 .../accounting_storage/mysql/mysql_problems.c | 307 +++++++++++++++++-
 .../accounting_storage/mysql/mysql_problems.h |  13 +-
 src/sacctmgr/association_functions.c          |  19 +-
 src/sacctmgr/cluster_functions.c              |  11 +-
 src/sacctmgr/problem_functions.c              |  43 +--
 src/sacctmgr/sacctmgr.c                       |   6 +-
 src/sacctmgr/user_functions.c                 |  72 +++-
 12 files changed, 495 insertions(+), 73 deletions(-)

diff --git a/NEWS b/NEWS
index 9534fa90d05..4c1e2357404 100644
--- a/NEWS
+++ b/NEWS
@@ -49,6 +49,15 @@ documents those changes that are of interest to users and admins.
     and is packaged as a separate RPM.
  -- Added configuration parameter MaxTasksPerNode.
  -- Remove configuration parameter SrunIOTimeout.
+ -- Added functionality for sacctmgr show problems.  Current problems include
+    Accounts/Users with no associations, Accounts with no users or subaccounts
+    attached in a cluster, and Users with No UID on the system.
+ -- Added new option for sacctmgr list assoc and list cluster WOLimits.  This 
+    gives a smaller default format without the limit information.  This may 
+    be the new default for list assocations and list clusters.
+ -- Users are now required to have an association with there default account.
+    Sacctmgr will now complain when you try to modify a users default account
+    which they are not associated anywhere.
 
 * Changes in SLURM 2.1.0-pre2
 =============================
diff --git a/doc/man/man1/sacctmgr.1 b/doc/man/man1/sacctmgr.1
index 72edafa0b54..f3323d75c8f 100644
--- a/doc/man/man1/sacctmgr.1
+++ b/doc/man/man1/sacctmgr.1
@@ -443,6 +443,11 @@ Display information with subaccounts.  Only really valuable when used
 with the account= option.  This will display all the subaccount
 associations along with the accounts listed in the option.
               
+.TP
+\fIWOLimits\fP
+Display information without limit information. This is for a smaller
+default format of Cluster,Account,User,Partition
+
 .TP
 \fIWOPInfo\fP
 Display information without parent information. (i.e. parent id, and
@@ -465,6 +470,11 @@ The name of a cluster.
 This should be equal to the \fIClusterName\fR parameter in the \fIslurm.conf\fR 
 configuration file for some Slurm\-managed cluster. 
 
+.TP
+\fIWOLimits\fP
+Display information without limit information. This is for a smaller
+default format of Cluster,ControlHost,ControlPort,RPC
+
 .SH ""
 NOTE: You can also use the general specifications list above in the
 \fIGENERAL SPECIFICATIONS FOR ASSOCIATION BASED ENTITIES\fP section.
diff --git a/src/common/slurm_accounting_storage.c b/src/common/slurm_accounting_storage.c
index a1817029dc4..2d5d79a4166 100644
--- a/src/common/slurm_accounting_storage.c
+++ b/src/common/slurm_accounting_storage.c
@@ -7299,6 +7299,51 @@ extern uint16_t str_2_classification(char *class)
 	return type;
 }
 
+extern char *get_acct_problem_str(uint16_t problem)
+{
+	acct_problem_type_t type = problem;
+
+	switch(type) {
+	case ACCT_PROBLEM_NOT_SET:
+		return NULL;
+		break;
+	case ACCT_PROBLEM_ACCT_NO_ASSOC:
+		return "Account has no Associations";
+		break;
+	case ACCT_PROBLEM_ACCT_NO_USERS:
+		return "Account has no users";
+		break;
+	case ACCT_PROBLEM_USER_NO_ASSOC:
+		return "User has no Associations";
+		break;
+	case ACCT_PROBLEM_USER_NO_UID:
+		return "User does not have a uid";
+		break;
+	default:
+		return "Unknown";
+		break;
+	}
+}
+
+extern uint16_t str_2_acct_problem(char *problem)
+{
+	uint16_t type = 0;
+
+	if(!problem)
+		return type;
+
+	if(slurm_strcasestr(problem, "account no associations"))
+		type = ACCT_PROBLEM_USER_NO_ASSOC;
+	else if(slurm_strcasestr(problem, "account no users"))
+		type = ACCT_PROBLEM_ACCT_NO_USERS;
+	else if(slurm_strcasestr(problem, "user no associations"))
+		type = ACCT_PROBLEM_USER_NO_ASSOC;
+	else if(slurm_strcasestr(problem, "user no uid"))
+		type = ACCT_PROBLEM_USER_NO_UID;
+       
+	return type;
+}
+
 extern void log_assoc_rec(acct_association_rec_t *assoc_ptr, List qos_list)
 {
 	xassert(assoc_ptr);
diff --git a/src/common/slurm_accounting_storage.h b/src/common/slurm_accounting_storage.h
index 03eb6d4e0ea..23b862391b7 100644
--- a/src/common/slurm_accounting_storage.h
+++ b/src/common/slurm_accounting_storage.h
@@ -82,10 +82,10 @@ typedef enum {
 
 typedef enum {
 	ACCT_PROBLEM_NOT_SET,
+	ACCT_PROBLEM_ACCT_NO_ASSOC,
+	ACCT_PROBLEM_ACCT_NO_USERS,
 	ACCT_PROBLEM_USER_NO_ASSOC,
-	ACCT_PROBLEM_USER_NO_DEFAULT,
-	ACCT_PROBLEM_ACCT_NO_CHILD,
-	ACCT_PROBLEM_CLUS_ONLY_ROOT,
+	ACCT_PROBLEM_USER_NO_UID,
 } acct_problem_type_t;
 
 #define ACCT_CLASSIFIED_FLAG 0x0100
@@ -694,6 +694,9 @@ extern char *get_qos_complete_str(List qos_list, List num_qos_list);
 extern char *get_classification_str(uint16_t class);
 extern uint16_t str_2_classification(char *class);
 
+extern char *get_acct_problem_str(uint16_t problem);
+extern uint16_t str_2_acct_problem(char *problem);
+
 extern void log_assoc_rec(acct_association_rec_t *assoc_ptr, List qos_list);
 
 extern int slurm_acct_storage_init(char *loc); /* load the plugin */
diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
index f3ef8ea9649..985f56a7dd9 100644
--- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
+++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
@@ -50,6 +50,7 @@
 #include <strings.h>
 #include "mysql_jobacct_process.h"
 #include "mysql_rollup.h"
+#include "mysql_problems.h"
 #include "src/common/slurmdbd_defs.h"
 #include "src/common/slurm_auth.h"
 #include "src/common/uid.h"
@@ -8280,7 +8281,7 @@ extern List acct_storage_p_get_associations(mysql_conn_t *mysql_conn,
 	set = _setup_association_cond_limits(assoc_cond, &extra);
 
 	with_raw_qos = assoc_cond->with_raw_qos;
-	with_usage = assoc_cond->with_usage;
+	with_usage = assoc_cond->with_usage;	
 	without_parent_limits = assoc_cond->without_parent_limits;
 	without_parent_info = assoc_cond->without_parent_info;
 
@@ -8638,8 +8639,27 @@ empty:
 extern List acct_storage_p_get_problems(mysql_conn_t *mysql_conn, uint32_t uid,
 					acct_association_cond_t *assoc_cond)
 {
+	List ret_list = NULL;
 	
-	return NULL;
+	if(_check_connection(mysql_conn) != SLURM_SUCCESS)
+		return NULL;
+
+	ret_list = list_create(destroy_acct_association_rec);
+
+	if(mysql_acct_no_assocs(mysql_conn, assoc_cond, ret_list)
+	   != SLURM_SUCCESS)
+		goto end_it;
+	if(mysql_acct_no_users(mysql_conn, assoc_cond, ret_list)
+	   != SLURM_SUCCESS)
+		goto end_it;
+
+	if(mysql_user_no_assocs_or_default(mysql_conn, assoc_cond, ret_list)
+	   != SLURM_SUCCESS)
+		goto end_it;
+
+end_it:
+
+	return ret_list;
 }
 
 extern List acct_storage_p_get_config(void *db_conn)
diff --git a/src/plugins/accounting_storage/mysql/mysql_problems.c b/src/plugins/accounting_storage/mysql/mysql_problems.c
index 2afa764ac63..a5e114adce7 100644
--- a/src/plugins/accounting_storage/mysql/mysql_problems.c
+++ b/src/plugins/accounting_storage/mysql/mysql_problems.c
@@ -39,18 +39,313 @@
 \*****************************************************************************/
 
 #include "mysql_problems.h"
+#include "src/common/uid.h"
 
-extern List mysql_acct_no_assocs(mysql_conn_t *mysql_conn)
+static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond,
+					  char **extra, bool user_query)
 {
-	return NULL;
+	int set = 0;
+	ListIterator itr = NULL;
+	char *object = NULL;
+
+	xstrfmtcat(*extra, "where deleted=0");
+
+	if(!assoc_cond)
+		return 0;
+
+	if(assoc_cond->acct_list && list_count(assoc_cond->acct_list)) {
+		set = 0;
+		xstrcat(*extra, " && (");
+		itr = list_iterator_create(assoc_cond->acct_list);
+		while((object = list_next(itr))) {
+			if(set) 
+				xstrcat(*extra, " || ");
+			xstrfmtcat(*extra, "acct=\"%s\"", object);
+			set = 1;
+		}
+		list_iterator_destroy(itr);
+		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, "cluster=\"%s\"", object);
+			set = 1;
+		}
+		list_iterator_destroy(itr);
+		xstrcat(*extra, ")");
+	}
+
+	if(assoc_cond->user_list && list_count(assoc_cond->user_list)) {
+		set = 0;
+		xstrcat(*extra, " && (");
+		itr = list_iterator_create(assoc_cond->user_list);
+		while((object = list_next(itr))) {
+			if(set) 
+				xstrcat(*extra, " || ");
+			xstrfmtcat(*extra, "user=\"%s\"", object);
+			set = 1;
+		}
+		list_iterator_destroy(itr);
+		xstrcat(*extra, ")");
+	} else if(user_query) {
+		/* we want all the users, but no non-user associations */
+		set = 1;
+		xstrcat(*extra, " && (user!='')");
+	}
+
+	if(assoc_cond->partition_list 
+	   && list_count(assoc_cond->partition_list)) {
+		set = 0;
+		xstrcat(*extra, " && (");
+		itr = list_iterator_create(assoc_cond->partition_list);
+		while((object = list_next(itr))) {
+			if(set) 
+				xstrcat(*extra, " || ");
+			xstrfmtcat(*extra, "partition=\"%s\"", object);
+			set = 1;
+		}
+		list_iterator_destroy(itr);
+		xstrcat(*extra, ")");
+	}
+	
+	return set;
 }
 
-extern List mysql_cluster_no_assocs(mysql_conn_t *mysql_conn)
+
+extern int mysql_acct_no_assocs(mysql_conn_t *mysql_conn,
+				acct_association_cond_t *assoc_cond,
+				List ret_list)
 {
-	return NULL;
+	int rc = SLURM_SUCCESS;
+	char *query = NULL;
+	MYSQL_RES *result = NULL;
+	MYSQL_ROW row;
+
+	xassert(ret_list);
+
+	query = xstrdup_printf("select name from %s where deleted=0",
+			       acct_table);
+	if(assoc_cond && 
+	   assoc_cond->acct_list && list_count(assoc_cond->acct_list)) {
+		int set = 0;
+		ListIterator itr = NULL;
+		char *object = NULL;
+		xstrcat(query, " && (");
+		itr = list_iterator_create(assoc_cond->acct_list);
+		while((object = list_next(itr))) {
+			if(set) 
+				xstrcat(query, " || ");
+			xstrfmtcat(query, "name=\"%s\"", object);
+			set = 1;
+		}
+		list_iterator_destroy(itr);
+		xstrcat(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))) {
+		MYSQL_RES *result2 = NULL;
+		int cnt = 0;
+		acct_association_rec_t *assoc = NULL;
+		/* See if we have at least 1 association in the system */
+		query = xstrdup_printf("select distinct id from %s "
+				       "where deleted=0 && "
+				       "acct='%s' limit 1;", 
+				       assoc_table, row[0]);
+		if(!(result2 = mysql_db_query_ret(
+			     mysql_conn->db_conn, query, 0))) {
+			xfree(query);
+			rc = SLURM_ERROR;
+			break;
+		}
+		xfree(query);
+		
+		cnt = mysql_num_rows(result2);
+		mysql_free_result(result2);
+
+		if(cnt) 
+			continue;
+			
+		assoc =	xmalloc(sizeof(acct_association_rec_t));
+		list_append(ret_list, assoc);
+
+		assoc->id = ACCT_PROBLEM_ACCT_NO_ASSOC;
+		assoc->acct = xstrdup(row[0]);		
+	}
+	mysql_free_result(result);
+
+	return rc;
 }
 
-extern List mysql_user_no_assocs_or_default(mysql_conn_t *mysql_conn)
+extern int mysql_acct_no_users(mysql_conn_t *mysql_conn,
+				acct_association_cond_t *assoc_cond,
+				List ret_list)
 {
-	return NULL;
+	int rc = SLURM_SUCCESS;
+	char *query = NULL, *tmp = NULL;
+	char *extra = NULL;
+	int i = 0;
+	MYSQL_RES *result = NULL;
+	MYSQL_ROW row;
+
+	xassert(ret_list);
+
+	_setup_association_cond_limits(assoc_cond, &extra, 0);
+
+	/* if this changes you will need to edit the corresponding enum */
+	char *assoc_req_inx[] = {
+		"id",
+		"user",
+		"acct",
+		"cluster",
+		"partition",
+		"parent_acct",
+	};
+	enum {
+		ASSOC_REQ_ID,
+		ASSOC_REQ_USER,
+		ASSOC_REQ_ACCT,
+		ASSOC_REQ_CLUSTER,
+		ASSOC_REQ_PART,
+		ASSOC_REQ_PARENT,
+		ASSOC_REQ_COUNT
+	};
+
+	xfree(tmp);
+	xstrfmtcat(tmp, "%s", assoc_req_inx[i]);
+	for(i=1; i<ASSOC_REQ_COUNT; i++) {
+		xstrfmtcat(tmp, ", %s", assoc_req_inx[i]);
+	}
+
+	/* only get the account associations */
+	query = xstrdup_printf("select distinct %s from %s %s "
+			       "&& user='' && lft=(rgt-1)"
+			       "order by cluster,acct;", 
+			       tmp, assoc_table, extra);
+	xfree(tmp);
+	xfree(extra);
+	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))) {
+		acct_association_rec_t *assoc =
+			xmalloc(sizeof(acct_association_rec_t));
+
+		list_append(ret_list, assoc);
+		
+		assoc->id = ACCT_PROBLEM_ACCT_NO_USERS;
+
+		if(row[ASSOC_REQ_USER][0])
+			assoc->user = xstrdup(row[ASSOC_REQ_USER]);
+		assoc->acct = xstrdup(row[ASSOC_REQ_ACCT]);
+		assoc->cluster = xstrdup(row[ASSOC_REQ_CLUSTER]);
+
+		if(row[ASSOC_REQ_PARENT][0]) 
+			assoc->parent_acct = xstrdup(row[ASSOC_REQ_PARENT]);
+		
+		if(row[ASSOC_REQ_PART][0])
+			assoc->partition = xstrdup(row[ASSOC_REQ_PART]);
+	}
+	mysql_free_result(result);
+
+	return rc;
+}
+
+extern int mysql_user_no_assocs_or_default(mysql_conn_t *mysql_conn,
+					   acct_association_cond_t *assoc_cond,
+					   List ret_list)
+{
+	int rc = SLURM_SUCCESS;
+	char *query = NULL;
+	MYSQL_RES *result = NULL;
+	MYSQL_ROW row;
+	xassert(ret_list);
+
+	query = xstrdup_printf("select name from %s where deleted=0",
+			       user_table);
+	if(assoc_cond && 
+	   assoc_cond->user_list && list_count(assoc_cond->user_list)) {
+		int set = 0;
+		ListIterator itr = NULL;
+		char *object = NULL;
+		xstrcat(query, " && (");
+		itr = list_iterator_create(assoc_cond->user_list);
+		while((object = list_next(itr))) {
+			if(set) 
+				xstrcat(query, " || ");
+			xstrfmtcat(query, "name=\"%s\"", object);
+			set = 1;
+		}
+		list_iterator_destroy(itr);
+		xstrcat(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))) {
+		MYSQL_RES *result2 = NULL;
+		int cnt = 0;
+		acct_association_rec_t *assoc = NULL;
+		uid_t pw_uid;
+
+		if (uid_from_string (row[0], &pw_uid) < 0) {
+			assoc =	xmalloc(sizeof(acct_association_rec_t));
+			list_append(ret_list, assoc);
+			
+			assoc->id = ACCT_PROBLEM_USER_NO_UID;
+			assoc->user = xstrdup(row[0]);		
+			
+			continue;
+		}
+
+		/* See if we have at least 1 association in the system */
+		query = xstrdup_printf("select distinct id from %s "
+				       "where deleted=0 && "
+				       "user='%s' limit 1;", 
+				       assoc_table, row[0]);
+		if(!(result2 = mysql_db_query_ret(
+			     mysql_conn->db_conn, query, 0))) {
+			xfree(query);
+			rc = SLURM_ERROR;
+			break;
+		}
+		xfree(query);
+		
+		cnt = mysql_num_rows(result2);
+		mysql_free_result(result2);
+
+		if(cnt) 
+			continue;
+		
+		assoc =	xmalloc(sizeof(acct_association_rec_t));
+		list_append(ret_list, assoc);
+
+		assoc->id = ACCT_PROBLEM_ACCT_NO_ASSOC;
+		assoc->user = xstrdup(row[0]);		
+	}
+	mysql_free_result(result);
+
+	return rc;
 }
diff --git a/src/plugins/accounting_storage/mysql/mysql_problems.h b/src/plugins/accounting_storage/mysql/mysql_problems.h
index 12a11a5177e..553e737b946 100644
--- a/src/plugins/accounting_storage/mysql/mysql_problems.h
+++ b/src/plugins/accounting_storage/mysql/mysql_problems.h
@@ -43,7 +43,14 @@
 
 #include "mysql_jobacct_process.h"
 
-extern List mysql_acct_no_assocs(mysql_conn_t *mysql_conn);
-extern List mysql_cluster_no_assocs(mysql_conn_t *mysql_conn);
-extern List mysql_user_no_assocs_or_default(mysql_conn_t *mysql_conn);
+extern int mysql_acct_no_assocs(mysql_conn_t *mysql_conn,
+				acct_association_cond_t *assoc_cond, 
+				List ret_list);
+extern int mysql_acct_no_users(mysql_conn_t *mysql_conn,
+			       acct_association_cond_t *assoc_cond, 
+			       List ret_list);
+extern int mysql_user_no_assocs_or_no_uid(
+	mysql_conn_t *mysql_conn, acct_association_cond_t *assoc_cond, 
+	List ret_list);
+
 #endif
diff --git a/src/sacctmgr/association_functions.c b/src/sacctmgr/association_functions.c
index 6a35a8df4b4..91ab83aa971 100644
--- a/src/sacctmgr/association_functions.c
+++ b/src/sacctmgr/association_functions.c
@@ -39,6 +39,7 @@
 
 #include "src/sacctmgr/sacctmgr.h"
 static bool tree_display = 0;
+static bool without_limits = 0;
 
 static int _set_cond(int *start, int argc, char *argv[],
 		     acct_association_cond_t *assoc_cond,
@@ -81,6 +82,10 @@ static int _set_cond(int *start, int argc, char *argv[],
 		} else if (!end && !strncasecmp (argv[i], "WOPLimits",
 						 MAX(command_len, 4))) {
 			assoc_cond->without_parent_limits = 1;
+		} else if (!end && !strncasecmp (argv[i], "WOLimits",
+						 MAX(command_len, 3))) {
+			without_limits = 1;
+			assoc_cond->without_parent_limits = 1;
 		} else if(!end && !strncasecmp(argv[i], "where", 
 					       MAX(command_len, 5))) {
 			continue;
@@ -362,12 +367,14 @@ extern int sacctmgr_list_association(int argc, char *argv[])
 		destroy_acct_association_cond(assoc_cond);
 		list_destroy(format_list);
 		return SLURM_ERROR;
-	} else if(!list_count(format_list)) 
-		slurm_addto_char_list(format_list,
-				      "C,A,U,Part,F,"
-				      "GrpCPUMins,GrpJ,GrpN,GrpS,GrpWall,"
-				      "MaxJ,MaxN,MaxS,MaxW,QOS");
-
+	} else if(!list_count(format_list)) {
+		slurm_addto_char_list(format_list, "C,A,U,Part");
+		if(!without_limits) 
+			slurm_addto_char_list(format_list,
+					      "F,GrpCPUMins,GrpJ,GrpN,"
+					      "GrpS,GrpWall,"
+					      "MaxJ,MaxN,MaxS,MaxW,QOS");
+	}
 	print_fields_list = list_create(destroy_print_field);
 
 	itr = list_iterator_create(format_list);
diff --git a/src/sacctmgr/cluster_functions.c b/src/sacctmgr/cluster_functions.c
index 18c8c1d3e7f..807275b3336 100644
--- a/src/sacctmgr/cluster_functions.c
+++ b/src/sacctmgr/cluster_functions.c
@@ -40,6 +40,7 @@
 
 #include "src/sacctmgr/sacctmgr.h"
 #include "src/common/uid.h"
+static bool without_limits = 0;
 
 static int _set_cond(int *start, int argc, char *argv[],
 		     List cluster_list,
@@ -79,6 +80,9 @@ static int _set_cond(int *start, int argc, char *argv[],
 							 argv[i]+end))
 					set = 1;
 			}
+		} else if (!end && !strncasecmp (argv[i], "WOLimits",
+						 MAX(command_len, 3))) {
+			without_limits = 1;
 		} else if (!strncasecmp (argv[i], "Classification", 
 					 MAX(command_len, 3))) {
 			if(classification) {
@@ -473,8 +477,11 @@ extern int sacctmgr_list_cluster(int argc, char *argv[])
 
 	if(!list_count(format_list)) {
 		slurm_addto_char_list(format_list, 
-				      "Cl,Controlh,Controlp,RPC,F,"
-				      "GrpJ,GrpN,GrpS,MaxJ,MaxN,MaxS,MaxW,QOS");
+				      "Cl,Controlh,Controlp,RPC");
+		if(!without_limits) 
+			slurm_addto_char_list(format_list, 
+					      "F,GrpJ,GrpN,GrpS,MaxJ,MaxN,"
+					      "MaxS,MaxW,QOS");
 	}
 
 	itr = list_iterator_create(format_list);
diff --git a/src/sacctmgr/problem_functions.c b/src/sacctmgr/problem_functions.c
index cf22038b40f..1c39597bb60 100644
--- a/src/sacctmgr/problem_functions.c
+++ b/src/sacctmgr/problem_functions.c
@@ -108,15 +108,6 @@ static int _set_cond(int *start, int argc, char *argv[],
 			slurm_addto_char_list(assoc_cond->partition_list,
 					argv[i]+end);
 			set = 1;
-		} else if (!strncasecmp (argv[i], "Parent",
-					 MAX(command_len, 4))) {
-			if(!assoc_cond->parent_acct_list) {
-				assoc_cond->parent_acct_list = 
-					list_create(slurm_destroy_char);
-			}
-			if(slurm_addto_char_list(assoc_cond->parent_acct_list,
-						 argv[i]+end))
-			set = 1;
 		} else if (!strncasecmp (argv[i], "Users",
 					 MAX(command_len, 1))) {
 			if(!assoc_cond->user_list)
@@ -149,7 +140,6 @@ extern int sacctmgr_list_problem(int argc, char *argv[])
 	ListIterator itr = NULL;
 	ListIterator itr2 = NULL;
 	char *object = NULL;
-	char *print_acct = NULL, *last_cluster = NULL;
 	List tree_list = NULL;
 	List qos_list = NULL;
 
@@ -265,41 +255,12 @@ extern int sacctmgr_list_problem(int argc, char *argv[])
 
 	while((assoc = list_next(itr))) {
 		int curr_inx = 1;
-		if(!last_cluster || strcmp(last_cluster, assoc->cluster)) {
-			if(tree_list) {
-				list_flush(tree_list);
-			} else {
-				tree_list = 
-					list_create(destroy_acct_print_tree);
-			}
-			last_cluster = assoc->cluster;
-		} 
 		while((field = list_next(itr2))) {
 			switch(field->type) {
 			case PRINT_ACCOUNT:
-				if(tree_display) {
-					char *local_acct = NULL;
-					char *parent_acct = NULL;
-					if(assoc->user) {
-						local_acct = xstrdup_printf(
-							"|%s", assoc->acct);
-						parent_acct = assoc->acct;
-					} else {
-						local_acct =
-							xstrdup(assoc->acct);
-						parent_acct = 
-							assoc->parent_acct;
-					}
-					print_acct = get_tree_acct_name(
-						local_acct,
-						parent_acct, tree_list);
-					xfree(local_acct);
-				} else {
-					print_acct = assoc->acct;
-				}
 				field->print_routine(
 					field, 
-					print_acct,
+					assoc->acct,
 					(curr_inx == field_count));
 				break;
 			case PRINT_CLUSTER:
@@ -316,7 +277,7 @@ extern int sacctmgr_list_problem(int argc, char *argv[])
 				*/
 				field->print_routine(
 					field,
-					NULL,
+					get_acct_problem_str(assoc->id),
 					(curr_inx == field_count));
 				break;
 			case PRINT_USER:
diff --git a/src/sacctmgr/sacctmgr.c b/src/sacctmgr/sacctmgr.c
index 8296ac30768..45963780770 100644
--- a/src/sacctmgr/sacctmgr.c
+++ b/src/sacctmgr/sacctmgr.c
@@ -817,10 +817,10 @@ sacctmgr [<OPTION>] [<COMMAND>]                                            \n\
                                                                            \n\
        list associations  - Accounts=, Clusters=, Format=, IDs=,           \n\
                             Partitions=, Parent=, Tree, Users=,            \n\
-                            WithSubAccounts, WithDeleted, WOPInfo,         \n\
-                            and WOPLimits                                  \n\
+                            WithSubAccounts, WithDeleted, WOLimits,        \n\
+                            WOPInfo, and WOPLimits                         \n\
                                                                            \n\
-       list cluster       - Format=, Names=                                \n\
+       list cluster       - Format=, Names=, WOLimits                      \n\
        add cluster        - Fairshare=, GrpCPUs=, GrpJobs=,                \n\
                             GrpNodes=, GrpSubmitJob=, MaxCPUMins=          \n\
                             MaxJobs=, MaxNodes=, MaxWall=, and Name=       \n\
diff --git a/src/sacctmgr/user_functions.c b/src/sacctmgr/user_functions.c
index 19d9d76114a..fd8c03840c8 100644
--- a/src/sacctmgr/user_functions.c
+++ b/src/sacctmgr/user_functions.c
@@ -638,6 +638,25 @@ static int _check_coord_request(acct_user_cond_t *user_cond, bool check)
 	return rc;
 }
 
+static int _check_user_has_acct(char *user, char *acct)
+{
+	acct_association_cond_t assoc_cond;
+	List ret_list = NULL;
+	
+	memset(&assoc_cond, 0, sizeof(acct_association_cond_t));
+	assoc_cond.acct_list = list_create(NULL);
+	list_push(assoc_cond.acct_list, acct);
+	assoc_cond.user_list = list_create(NULL);
+	list_push(assoc_cond.user_list, user);
+	ret_list = acct_storage_g_get_associations(db_conn, my_uid,
+						   &assoc_cond);
+				
+	if(ret_list && (list_count(ret_list)))
+		return 1;
+
+	return 0;
+}
+
 extern int sacctmgr_add_user(int argc, char *argv[])
 {
 	int rc = SLURM_SUCCESS;
@@ -735,7 +754,7 @@ extern int sacctmgr_add_user(int argc, char *argv[])
 			}
 			default_acct = strip_quotes(argv[i]+end, NULL, 1);
 			slurm_addto_char_list(assoc_cond->acct_list,
-					default_acct);
+					      default_acct);
 		} else if (!strncasecmp (argv[i], "DefaultWCKey",
 					 MAX(command_len, 8))) {
 			if(default_wckey) {
@@ -2109,7 +2128,7 @@ extern int sacctmgr_modify_user(int argc, char *argv[])
 			return SLURM_SUCCESS;
 		}		
 	}
-
+	
 	notice_thread_init();
 	if(rec_set == 3 || rec_set == 1) { // process the account changes
 		if(cond_set == 2) {
@@ -2137,18 +2156,57 @@ extern int sacctmgr_modify_user(int argc, char *argv[])
 			}
 			notice_thread_init();
 		}
-			
+		
 		ret_list = acct_storage_g_modify_users(
 			db_conn, my_uid, user_cond, user);
 		if(ret_list && list_count(ret_list)) {
 			char *object = NULL;
+			List regret_list = NULL;
 			ListIterator itr = list_iterator_create(ret_list);
-			printf(" Modified users...\n");
+
 			while((object = list_next(itr))) {
-				printf("  %s\n", object);
+				/* We have to check here for the user names to
+				 * make sure the user has an association with
+				 * the new default account.  We have to wait
+				 * until we get the ret_list of names since
+				 * names are required to change a user since
+				 * you can specfy a user by something else
+				 * like default_account or something.  If the
+				 * user doesn't have the account make
+				 * note of it. 
+				 */
+				if(user->default_acct &&
+				   !_check_user_has_acct(
+					   object, user->default_acct)) {
+					if(!regret_list)
+						regret_list = list_create(NULL);
+					list_append(regret_list, object);
+					continue;
+				} 
+			}
+			if(regret_list) {
+				list_iterator_destroy(itr);
+				itr = list_iterator_create(regret_list);
+				printf(" Can modify because these users "
+				       "aren't associated with new "
+				       "default account '%s'...\n",
+				       user->default_acct);
+				while((object = list_next(itr))) {
+					printf("  %s\n", object);
+				}
+				list_iterator_destroy(itr);
+				exit_code=1;
+				rc = SLURM_ERROR;
+				list_destroy(regret_list);
+			} else {
+				list_iterator_reset(itr);
+				printf(" Modified users...\n");
+				while((object = list_next(itr))) {
+					printf("  %s\n", object);
+				}
+				list_iterator_destroy(itr);
+				set = 1;
 			}
-			list_iterator_destroy(itr);
-			set = 1;
 		} else if(ret_list) {
 			printf(" Nothing modified\n");
 		} else {
-- 
GitLab