1 /*****************************************************************************\
2  *  as_mysql_federation.c - functions dealing with federations.
3  *****************************************************************************
4  *
5  *  Copyright (C) 2016 SchedMD LLC.
6  *  Written by Brian Christiansen <brian@schedmd.com>
7  *
8  *  This file is part of Slurm, a resource management program.
9  *  For details, see <https://slurm.schedmd.com/>.
10  *  Please also read the included file: DISCLAIMER.
11  *
12  *  Slurm is free software; you can redistribute it and/or modify it under
13  *  the terms of the GNU General Public License as published by the Free
14  *  Software Foundation; either version 2 of the License, or (at your option)
15  *  any later version.
16  *
17  *  In addition, as a special exception, the copyright holders give permission
18  *  to link the code of portions of this program with the OpenSSL library under
19  *  certain conditions as described in each individual source file, and
20  *  distribute linked combinations including the two. You must obey the GNU
21  *  General Public License in all respects for all of the code used other than
22  *  OpenSSL. If you modify file(s) with this exception, you may extend this
23  *  exception to your version of the file(s), but you are not obligated to do
24  *  so. If you do not wish to do so, delete this exception statement from your
25  *  version.  If you delete this exception statement from all source files in
26  *  the program, then also delete it here.
27  *
28  *  Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
29  *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30  *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
31  *  details.
32  *
33  *  You should have received a copy of the GNU General Public License along
34  *  with Slurm; if not, write to the Free Software Foundation, Inc.,
35  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
36 \*****************************************************************************/
37 
38 #include "as_mysql_federation.h"
39 #include "as_mysql_cluster.h"
40 
41 char *fed_req_inx[] = {
42 	"t1.name",
43 	"t1.flags",
44 };
45 enum {
46 	FED_REQ_NAME,
47 	FED_REQ_FLAGS,
48 	FED_REQ_COUNT
49 };
50 
_setup_federation_cond_limits(slurmdb_federation_cond_t * fed_cond,char ** extra)51 static int _setup_federation_cond_limits(slurmdb_federation_cond_t *fed_cond,
52 					 char **extra)
53 {
54 	int set = 0;
55 	ListIterator itr = NULL;
56 	char *object = NULL;
57 
58 	if (!fed_cond)
59 		return 0;
60 
61 	if (fed_cond->with_deleted)
62 		xstrcat(*extra, " where (t1.deleted=0 || t1.deleted=1)");
63 	else
64 		xstrcat(*extra, " where t1.deleted=0");
65 
66 	if (fed_cond->cluster_list
67 	    && list_count(fed_cond->cluster_list)) {
68 		set = 0;
69 		xstrcat(*extra, " && (");
70 		itr = list_iterator_create(fed_cond->cluster_list);
71 		while ((object = list_next(itr))) {
72 			if (set)
73 				xstrcat(*extra, " || ");
74 			xstrfmtcat(*extra, "t2.name='%s'", object);
75 			set = 1;
76 		}
77 		list_iterator_destroy(itr);
78 		xstrcat(*extra, ")");
79 	}
80 
81 	if (fed_cond->federation_list
82 	    && list_count(fed_cond->federation_list)) {
83 		set = 0;
84 		xstrcat(*extra, " && (");
85 		itr = list_iterator_create(fed_cond->federation_list);
86 		while ((object = list_next(itr))) {
87 			if (set)
88 				xstrcat(*extra, " || ");
89 			xstrfmtcat(*extra, "t1.name='%s'", object);
90 			set = 1;
91 		}
92 		list_iterator_destroy(itr);
93 		xstrcat(*extra, ")");
94 	}
95 
96 	return set;
97 }
98 
_setup_federation_rec_limits(slurmdb_federation_rec_t * fed,char ** cols,char ** vals,char ** extra)99 static int _setup_federation_rec_limits(slurmdb_federation_rec_t *fed,
100 					char **cols, char **vals, char **extra)
101 {
102 	if (!fed)
103 		return SLURM_ERROR;
104 
105 	if (!(fed->flags & FEDERATION_FLAG_NOTSET)) {
106 		uint32_t flags;
107 		xstrcat(*cols, ", flags");
108 		if (fed->flags & FEDERATION_FLAG_REMOVE) {
109 			flags = fed->flags & ~FEDERATION_FLAG_REMOVE;
110 			xstrfmtcat(*vals, ", (flags & ~%u)", flags);
111 			xstrfmtcat(*extra, ", flags=(flags & ~%u)", flags);
112 		} else if (fed->flags & FEDERATION_FLAG_ADD) {
113 			flags = fed->flags & ~FEDERATION_FLAG_ADD;
114 			xstrfmtcat(*vals, ", (flags | %u)", flags);
115 			xstrfmtcat(*extra, ", flags=(flags | %u)", flags);
116 		} else {
117 			flags = fed->flags;
118 			xstrfmtcat(*vals, ", %u", flags);
119 			xstrfmtcat(*extra, ", flags=%u", flags);
120 		}
121 	}
122 
123 	return SLURM_SUCCESS;
124 }
125 
126 /*
127  * Remove all clusters from federation.
128  * IN: mysql_conn - mysql connection
129  * IN: fed - fed to remove clusters from
130  * IN: exceptions - list of clusters to not remove.
131  */
_remove_all_clusters_from_fed(mysql_conn_t * mysql_conn,const char * fed,List exceptions)132 static int _remove_all_clusters_from_fed(mysql_conn_t *mysql_conn,
133 					 const char *fed, List exceptions)
134 {
135 	int   rc    = SLURM_SUCCESS;
136 	char *query = NULL;
137 	char *exception_names = NULL;
138 
139 	if (exceptions && list_count(exceptions)) {
140 		char *tmp_name;
141 		ListIterator itr;
142 
143 		itr = list_iterator_create(exceptions);
144 		while ((tmp_name = list_next(itr)))
145 			xstrfmtcat(exception_names, "%s'%s'",
146 				   (exception_names) ? "," : "",
147 				   tmp_name);
148 		list_iterator_destroy(itr);
149 	}
150 
151 	xstrfmtcat(query, "UPDATE %s "
152 		   	  "SET federation='', fed_id=0, fed_state=%u "
153 			  "WHERE federation='%s' and deleted=0",
154 		   cluster_table, CLUSTER_FED_STATE_NA, fed);
155 	if (exception_names)
156 		xstrfmtcat(query, " AND name NOT IN (%s)", exception_names);
157 
158 	if (debug_flags & DEBUG_FLAG_FEDR)
159 		DB_DEBUG(mysql_conn->conn, "query\n%s", query);
160 
161 	rc = mysql_db_query(mysql_conn, query);
162 	xfree(query);
163 	if (rc)
164 		error("Failed to remove all clusters from federation %s", fed);
165 
166 	if (exception_names)
167 		xfree(exception_names);
168 
169 	return rc;
170 }
171 
_remove_clusters_from_fed(mysql_conn_t * mysql_conn,List clusters)172 static int _remove_clusters_from_fed(mysql_conn_t *mysql_conn, List clusters)
173 {
174 	int   rc    = SLURM_SUCCESS;
175 	char *query = NULL;
176 	char *name  = NULL;
177 	char *names = NULL;
178 	ListIterator itr = NULL;
179 
180 	xassert(clusters);
181 
182 	itr = list_iterator_create(clusters);
183 	while ((name = list_next(itr)))
184 	       xstrfmtcat(names, "%s'%s'", names ? "," : "", name );
185 
186 	xstrfmtcat(query, "UPDATE %s "
187 		   	  "SET federation='', fed_id=0, fed_state=%u "
188 			  "WHERE name IN (%s) and deleted=0",
189 		   cluster_table, CLUSTER_FED_STATE_NA, names);
190 
191 	if (debug_flags & DEBUG_FLAG_FEDR)
192 		DB_DEBUG(mysql_conn->conn, "query\n%s", query);
193 
194 	rc = mysql_db_query(mysql_conn, query);
195 	xfree(query);
196 	if (rc)
197 		error("Failed to remove clusters %s from federation", names);
198 	xfree(names);
199 
200 	return rc;
201 }
202 
_add_clusters_to_fed(mysql_conn_t * mysql_conn,List clusters,const char * fed)203 static int _add_clusters_to_fed(mysql_conn_t *mysql_conn, List clusters,
204 				const char *fed)
205 {
206 	int   rc      = SLURM_SUCCESS;
207 	char *query   = NULL;
208 	char *name    = NULL;
209 	char *names   = NULL;
210 	char *indexes = NULL;
211 	ListIterator itr = NULL;
212 	int   last_id = -1;
213 
214 	xassert(fed);
215 	xassert(clusters);
216 
217 	itr = list_iterator_create(clusters);
218 	while ((name = list_next(itr))) {
219 		int id;
220 		if ((rc = as_mysql_get_fed_cluster_id(mysql_conn, name, fed,
221 						      last_id, &id)))
222 			goto end_it;
223 		last_id = id;
224 		xstrfmtcat(indexes, "WHEN name='%s' THEN %d ", name, id);
225 		xstrfmtcat(names, "%s'%s'", names ? "," : "", name);
226 	}
227 
228 	/* Keep the same fed_state if the cluster isn't changing feds.
229 	 * Also note that mysql evaluates from left to right and uses the
230 	 * updated column values in case statements. So the check for federation
231 	 * in the fed_state case statement must happen before fed_state is set
232 	 * or the federation will always equal the federation in the case
233 	 * statement.  */
234 	xstrfmtcat(query, "UPDATE %s "
235 		   	  "SET "
236 			  "fed_state = CASE WHEN federation='%s' THEN fed_state ELSE %u END, "
237 			  "fed_id = CASE %s END, "
238 		   	  "federation='%s' "
239 			  "WHERE name IN (%s) and deleted=0",
240 		   cluster_table, fed, CLUSTER_FED_STATE_ACTIVE, indexes, fed,
241 		   names);
242 
243 	if (debug_flags & DEBUG_FLAG_FEDR)
244 		DB_DEBUG(mysql_conn->conn, "query\n%s", query);
245 
246 	rc = mysql_db_query(mysql_conn, query);
247 	if (rc)
248 		error("Failed to add clusters %s to federation %s",
249 		      names, fed);
250 
251 end_it:
252 	xfree(query);
253 	xfree(names);
254 	xfree(indexes);
255 	list_iterator_destroy(itr);
256 
257 	return rc;
258 }
259 
_assign_clusters_to_federation(mysql_conn_t * mysql_conn,const char * federation,List cluster_list)260 static int _assign_clusters_to_federation(mysql_conn_t *mysql_conn,
261 					  const char *federation,
262 					  List cluster_list)
263 {
264 	int  rc       = SLURM_SUCCESS;
265 	List add_list = NULL;
266 	List rem_list = NULL;
267 	ListIterator itr    = NULL;
268 	bool clear_clusters = false;
269 	slurmdb_cluster_rec_t *tmp_cluster = NULL;
270 
271 	xassert(federation);
272 	xassert(cluster_list);
273 
274 	if (!cluster_list || !federation) {
275 		rc = SLURM_ERROR;
276 		goto end_it;
277 	}
278 
279 	add_list = list_create(xfree_ptr);
280 	rem_list = list_create(xfree_ptr);
281 
282 	itr = list_iterator_create(cluster_list);
283 	while ((tmp_cluster = list_next(itr))) {
284 		if (!tmp_cluster->name)
285 			continue;
286 		if (tmp_cluster->name[0] == '-')
287 			list_append(rem_list, xstrdup(tmp_cluster->name + 1));
288 		else if (tmp_cluster->name[0] == '+')
289 			list_append(add_list, xstrdup(tmp_cluster->name + 1));
290 		else {
291 			list_append(add_list, xstrdup(tmp_cluster->name));
292 			clear_clusters = true;
293 		}
294 	}
295 	list_iterator_destroy(itr);
296 
297 	if (clear_clusters &&
298 	    (rc = _remove_all_clusters_from_fed(mysql_conn, federation,
299 						add_list)))
300 		goto end_it;
301 	if (!clear_clusters &&
302 	    list_count(rem_list) &&
303 	    (rc = _remove_clusters_from_fed(mysql_conn, rem_list)))
304 		goto end_it;
305 	if (list_count(add_list) &&
306 	    (rc = _add_clusters_to_fed(mysql_conn, add_list, federation)))
307 		goto end_it;
308 
309 end_it:
310 	list_destroy(add_list);
311 	list_destroy(rem_list);
312 
313 	return rc;
314 }
315 
as_mysql_add_federations(mysql_conn_t * mysql_conn,uint32_t uid,List federation_list)316 extern int as_mysql_add_federations(mysql_conn_t *mysql_conn, uint32_t uid,
317 				    List federation_list)
318 {
319 	ListIterator itr = NULL;
320 	int rc = SLURM_SUCCESS;
321 	slurmdb_federation_rec_t *object = NULL;
322 	char *cols = NULL, *vals = NULL, *extra = NULL, *query = NULL,
323 	     *tmp_extra = NULL;
324 	time_t now = time(NULL);
325 	char *user_name = NULL;
326 	int affect_rows = 0;
327 	int added = 0;
328 
329 	if (check_connection(mysql_conn) != SLURM_SUCCESS)
330 		return ESLURM_DB_CONNECTION;
331 
332 	if (!is_user_min_admin_level(mysql_conn, uid, SLURMDB_ADMIN_SUPER_USER))
333 		return ESLURM_ACCESS_DENIED;
334 
335 	user_name = uid_to_string((uid_t) uid);
336 
337 	itr = list_iterator_create(federation_list);
338 	while ((object = list_next(itr))) {
339 		if (object->cluster_list &&
340 		    (list_count(federation_list) > 1)) {
341 			xfree(user_name);
342 			error("Clusters can only be assigned to one "
343 			      "federation");
344 			errno = ESLURM_FED_CLUSTER_MULTIPLE_ASSIGNMENT;
345 			return  ESLURM_FED_CLUSTER_MULTIPLE_ASSIGNMENT;
346 		}
347 
348 		xstrcat(cols, "creation_time, mod_time, name");
349 		xstrfmtcat(vals, "%ld, %ld, '%s'", now, now, object->name);
350 		xstrfmtcat(extra, ", mod_time=%ld", now);
351 
352 		_setup_federation_rec_limits(object, &cols, &vals, &extra);
353 
354 		xstrfmtcat(query,
355 			   "insert into %s (%s) values (%s) "
356 			   "on duplicate key update deleted=0%s",
357 			   federation_table, cols, vals, extra);
358 		if (debug_flags & DEBUG_FLAG_FEDR)
359 			DB_DEBUG(mysql_conn->conn, "query\n%s", query);
360 		rc = mysql_db_query(mysql_conn, query);
361 		xfree(query);
362 		if (rc != SLURM_SUCCESS) {
363 			error("Couldn't add federation %s", object->name);
364 			xfree(cols);
365 			xfree(vals);
366 			xfree(extra);
367 			added = 0;
368 			break;
369 		}
370 
371 		affect_rows = last_affected_rows(mysql_conn);
372 		if (!affect_rows) {
373 			debug2("nothing changed %d", affect_rows);
374 			xfree(cols);
375 			xfree(vals);
376 			xfree(extra);
377 			continue;
378 		}
379 
380 		if (object->cluster_list &&
381 		    _assign_clusters_to_federation(mysql_conn, object->name,
382 						   object->cluster_list)) {
383 			xfree(cols);
384 			xfree(vals);
385 			xfree(extra);
386 			xfree(user_name);
387 			return SLURM_ERROR;
388 		}
389 
390 		/* Add Transaction */
391 		/* we always have a ', ' as the first 2 chars */
392 		tmp_extra = slurm_add_slash_to_quotes(extra+2);
393 
394 		xstrfmtcat(query,
395 			   "insert into %s "
396 			   "(timestamp, action, name, actor, info) "
397 			   "values (%ld, %u, '%s', '%s', '%s');",
398 			   txn_table, now, DBD_ADD_FEDERATIONS,
399 			   object->name, user_name, tmp_extra);
400 		xfree(cols);
401 		xfree(vals);
402 		xfree(tmp_extra);
403 		xfree(extra);
404 		debug4("%d(%s:%d) query\n%s",
405 		       mysql_conn->conn, THIS_FILE, __LINE__, query);
406 
407 		rc = mysql_db_query(mysql_conn, query);
408 		xfree(query);
409 		if (rc != SLURM_SUCCESS) {
410 			error("Couldn't add txn");
411 		} else {
412 			added++;
413 		}
414 	}
415 	list_iterator_destroy(itr);
416 	xfree(user_name);
417 
418 	if (!added)
419 		reset_mysql_conn(mysql_conn);
420 	else
421 		as_mysql_add_feds_to_update_list(mysql_conn);
422 
423 	return rc;
424 }
425 
as_mysql_get_federations(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_federation_cond_t * federation_cond)426 extern List as_mysql_get_federations(mysql_conn_t *mysql_conn, uid_t uid,
427 				     slurmdb_federation_cond_t *federation_cond)
428 {
429 	char *query = NULL;
430 	char *extra = NULL;
431 	char *tmp = NULL;
432 	List federation_list = NULL;
433 	int i=0;
434 	MYSQL_RES *result = NULL;
435 	MYSQL_ROW row;
436 	slurmdb_federation_rec_t *fed = NULL;
437 
438 	if (check_connection(mysql_conn) != SLURM_SUCCESS)
439 		return NULL;
440 
441 	if (!federation_cond) {
442 		xstrcat(extra, " where t1.deleted=0");
443 		goto empty;
444 	}
445 
446 	_setup_federation_cond_limits(federation_cond, &extra);
447 
448 empty:
449 
450 	xfree(tmp);
451 	i=0;
452 	xstrfmtcat(tmp, "%s", fed_req_inx[i]);
453 	for(i = 1; i < FED_REQ_COUNT; i++) {
454 		xstrfmtcat(tmp, ", %s", fed_req_inx[i]);
455 	}
456 
457 	query = xstrdup_printf(
458 		"select distinct %s from %s as t1 "
459 		"left join %s as t2 on t1.name=t2.federation and t2.deleted=0"
460 		"%s order by t1.name",
461 		tmp, federation_table, cluster_table, extra);
462 	xfree(tmp);
463 	xfree(extra);
464 
465 	if (debug_flags & DEBUG_FLAG_FEDR)
466 		DB_DEBUG(mysql_conn->conn, "query\n%s", query);
467 	if (!(result = mysql_db_query_ret(
468 		      mysql_conn, query, 0))) {
469 		xfree(query);
470 		return NULL;
471 	}
472 	xfree(query);
473 
474 	federation_list = list_create(slurmdb_destroy_federation_rec);
475 
476 	while ((row = mysql_fetch_row(result))) {
477  		slurmdb_cluster_cond_t clus_cond;
478  		List tmp_list = NULL;
479  		fed = xmalloc(sizeof(slurmdb_federation_rec_t));
480  		list_append(federation_list, fed);
481 
482  		fed->name  = xstrdup(row[FED_REQ_NAME]);
483  		fed->flags = slurm_atoul(row[FED_REQ_FLAGS]);
484 
485  		/* clusters in federation */
486  		slurmdb_init_cluster_cond(&clus_cond, 0);
487 		clus_cond.federation_list = list_create(xfree_ptr);
488  		list_append(clus_cond.federation_list, xstrdup(fed->name));
489 
490  		tmp_list = as_mysql_get_clusters(mysql_conn, uid, &clus_cond);
491  		FREE_NULL_LIST(clus_cond.federation_list);
492  		if (!tmp_list) {
493  			error("Unable to get federation clusters");
494  			continue;
495  		}
496  		fed->cluster_list = tmp_list;
497 	}
498 	mysql_free_result(result);
499 
500 	return federation_list;
501 }
502 
as_mysql_modify_federations(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_federation_cond_t * fed_cond,slurmdb_federation_rec_t * fed)503 extern List as_mysql_modify_federations(
504 				mysql_conn_t *mysql_conn, uint32_t uid,
505 				slurmdb_federation_cond_t *fed_cond,
506 				slurmdb_federation_rec_t *fed)
507 {
508 	List ret_list = NULL;
509 	int rc = SLURM_SUCCESS;
510 	int req_inx = 0;
511 	char *object = NULL;
512 	char *vals = NULL, *extra = NULL, *query = NULL,
513 	     *name_char = NULL, *fed_items = NULL;
514 	char *tmp_char1 = NULL, *tmp_char2 = NULL;
515 	time_t now = time(NULL);
516 	MYSQL_RES *result = NULL;
517 	MYSQL_ROW row;
518 
519 	if (!fed_cond || !fed) {
520 		error("we need something to change");
521 		return NULL;
522 	}
523 
524 	if (check_connection(mysql_conn) != SLURM_SUCCESS)
525 		return NULL;
526 
527 	if (!is_user_min_admin_level(mysql_conn, uid,
528 				     SLURMDB_ADMIN_SUPER_USER)) {
529 		errno = ESLURM_ACCESS_DENIED;
530 		return NULL;
531 	}
532 
533 	/* force to only do non-deleted federations */
534 	fed_cond->with_deleted = 0;
535 	_setup_federation_cond_limits(fed_cond, &extra);
536 	_setup_federation_rec_limits(fed, &tmp_char1, &tmp_char2, &vals);
537 	xfree(tmp_char1);
538 	xfree(tmp_char2);
539 
540 	if (!extra ||
541 	    (!vals && (!fed->cluster_list || !list_count(fed->cluster_list)))) {
542 		xfree(extra);
543 		xfree(vals);
544 		errno = SLURM_NO_CHANGE_IN_DATA;
545 		error("Nothing to change");
546 		return NULL;
547 	}
548 
549 	if (fed->cluster_list &&
550 	    fed_cond->federation_list &&
551 	    (list_count(fed_cond->federation_list) > 1)) {
552 		xfree(extra);
553 		xfree(vals);
554 		error("Clusters can only be assigned to one federation");
555 		errno = ESLURM_FED_CLUSTER_MULTIPLE_ASSIGNMENT;
556 		return NULL;
557 	}
558 
559 	/* Select records that are going to get updated.
560 	 * 1 - to be able to report what is getting updated
561 	 * 2 - to create an update object to let the controller know.  */
562 	xstrfmtcat(fed_items, "%s", fed_req_inx[req_inx]);
563 	for(req_inx = 1; req_inx < FED_REQ_COUNT; req_inx++) {
564 		xstrfmtcat(fed_items, ", %s", fed_req_inx[req_inx]);
565 	}
566 
567 	xstrfmtcat(query, "select %s from %s as t1 %s;",
568 		   fed_items, federation_table, extra);
569 	xfree(fed_items);
570 
571 	if (debug_flags & DEBUG_FLAG_FEDR)
572 		DB_DEBUG(mysql_conn->conn, "query\n%s", query);
573 	if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
574 		xfree(query);
575 		xfree(vals);
576 		xfree(extra);
577 		error("no result given for %s", extra);
578 		return NULL;
579 	}
580 	xfree(extra);
581 
582 	ret_list = list_create(xfree_ptr);
583 	while ((row = mysql_fetch_row(result))) {
584 		object = xstrdup(row[0]);
585 
586 		list_append(ret_list, object);
587 		if (!name_char) {
588 			xstrfmtcat(name_char, "(name='%s'", object);
589 		} else  {
590 			xstrfmtcat(name_char, " || name='%s'", object);
591 		}
592 	}
593 	mysql_free_result(result);
594 
595 	if (fed->cluster_list &&
596 	    (_assign_clusters_to_federation(mysql_conn, object,
597 					    fed->cluster_list))) {
598 		xfree(vals);
599 		xfree(name_char);
600 		xfree(query);
601 		FREE_NULL_LIST(ret_list);
602 		return NULL;
603 	}
604 
605 	if (!list_count(ret_list)) {
606 		errno = SLURM_NO_CHANGE_IN_DATA;
607 		if (debug_flags & DEBUG_FLAG_FEDR)
608 			DB_DEBUG(mysql_conn->conn,
609 				 "didn't effect anything\n%s", query);
610 		xfree(vals);
611 		xfree(name_char);
612 		xfree(query);
613 		return ret_list;
614 	}
615 	xfree(query);
616 	xstrcat(name_char, ")");
617 
618 	if (vals) {
619 		char *user_name = uid_to_string((uid_t) uid);
620 		rc = modify_common(mysql_conn, DBD_MODIFY_FEDERATIONS, now,
621 				   user_name, federation_table,
622 				   name_char, vals, NULL);
623 		xfree(user_name);
624 	}
625 	xfree(name_char);
626 	xfree(vals);
627 
628 	if (rc == SLURM_ERROR) {
629 		error("Couldn't modify federation");
630 		FREE_NULL_LIST(ret_list);
631 		ret_list = NULL;
632 	} else
633 		as_mysql_add_feds_to_update_list(mysql_conn);
634 
635 	return ret_list;
636 }
637 
as_mysql_remove_federations(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_federation_cond_t * fed_cond)638 extern List as_mysql_remove_federations(mysql_conn_t *mysql_conn, uint32_t uid,
639 					slurmdb_federation_cond_t *fed_cond)
640 {
641 	List ret_list = NULL;
642 	int rc = SLURM_SUCCESS;
643 	char *extra = NULL, *query = NULL, *name_char = NULL;
644 	time_t now = time(NULL);
645 	char *user_name = NULL;
646 	MYSQL_RES *result = NULL;
647 	MYSQL_ROW row;
648 
649 	if (!fed_cond) {
650 		error("we need something to change");
651 		return NULL;
652 	}
653 
654 	if (check_connection(mysql_conn) != SLURM_SUCCESS)
655 		return NULL;
656 
657 	if (!is_user_min_admin_level(
658 		    mysql_conn, uid, SLURMDB_ADMIN_SUPER_USER)) {
659 		errno = ESLURM_ACCESS_DENIED;
660 		return NULL;
661 	}
662 
663 	/* force to only do non-deleted federations */
664 	fed_cond->with_deleted = 0;
665 	_setup_federation_cond_limits(fed_cond, &extra);
666 
667 	if (!extra) {
668 		error("Nothing to remove");
669 		return NULL;
670 	}
671 
672 	query = xstrdup_printf("select name from %s as t1 %s;",
673 			       federation_table, extra);
674 	xfree(extra);
675 	if (!(result = mysql_db_query_ret( mysql_conn, query, 0))) {
676 		xfree(query);
677 		return NULL;
678 	}
679 	rc = 0;
680 	ret_list = list_create(xfree_ptr);
681 
682 	if (!mysql_num_rows(result)) {
683 		mysql_free_result(result);
684 		errno = SLURM_NO_CHANGE_IN_DATA;
685 		if (debug_flags & DEBUG_FLAG_FEDR)
686 			DB_DEBUG(mysql_conn->conn,
687 				 "didn't effect anything\n%s", query);
688 		xfree(query);
689 		return ret_list;
690 	}
691 	xfree(query);
692 
693 	user_name = uid_to_string((uid_t) uid);
694 	while ((row = mysql_fetch_row(result))) {
695 		char *object = xstrdup(row[0]);
696 		list_append(ret_list, object);
697 
698 		if ((rc = _remove_all_clusters_from_fed(mysql_conn, object,
699 							NULL)))
700 			break;
701 
702 		xfree(name_char);
703 		xstrfmtcat(name_char, "name='%s'", object);
704 
705 		if ((rc = remove_common(mysql_conn, DBD_REMOVE_FEDERATIONS, now,
706 					user_name, federation_table, name_char,
707 					NULL, NULL, ret_list, NULL)))
708 			break;
709 	}
710 	mysql_free_result(result);
711 	xfree(user_name);
712 	xfree(name_char);
713 
714 	if (rc != SLURM_SUCCESS) {
715 		FREE_NULL_LIST(ret_list);
716 		return NULL;
717 	} else
718 		as_mysql_add_feds_to_update_list(mysql_conn);
719 
720 	return ret_list;
721 }
722 
as_mysql_add_feds_to_update_list(mysql_conn_t * mysql_conn)723 extern int as_mysql_add_feds_to_update_list(mysql_conn_t *mysql_conn)
724 {
725 	int rc = SLURM_ERROR;
726 	List feds = as_mysql_get_federations(mysql_conn, 0, NULL);
727 
728 	/* Even if there are no feds, need to send an empty list for the case
729 	 * that all feds were removed. The controller needs to know that it was
730 	 * removed from a federation. */
731 	if (feds &&
732 	    ((rc = addto_update_list(mysql_conn->update_list,
733 				     SLURMDB_UPDATE_FEDS, feds))
734 	     != SLURM_SUCCESS)) {
735 			FREE_NULL_LIST(feds);
736 	}
737 	return rc;
738 }
739