1 /*****************************************************************************\
2 * as_mysql_cluster.c - functions dealing with clusters.
3 *****************************************************************************
4 *
5 * Copyright (C) 2004-2007 The Regents of the University of California.
6 * Copyright (C) 2008-2011 Lawrence Livermore National Security.
7 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
8 * Written by Danny Auble <da@llnl.gov>
9 *
10 * This file is part of Slurm, a resource management program.
11 * For details, see <https://slurm.schedmd.com/>.
12 * Please also read the included file: DISCLAIMER.
13 *
14 * Slurm is free software; you can redistribute it and/or modify it under
15 * the terms of the GNU General Public License as published by the Free
16 * Software Foundation; either version 2 of the License, or (at your option)
17 * any later version.
18 *
19 * In addition, as a special exception, the copyright holders give permission
20 * to link the code of portions of this program with the OpenSSL library under
21 * certain conditions as described in each individual source file, and
22 * distribute linked combinations including the two. You must obey the GNU
23 * General Public License in all respects for all of the code used other than
24 * OpenSSL. If you modify file(s) with this exception, you may extend this
25 * exception to your version of the file(s), but you are not obligated to do
26 * so. If you do not wish to do so, delete this exception statement from your
27 * version. If you delete this exception statement from all source files in
28 * the program, then also delete it here.
29 *
30 * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
31 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
32 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
33 * details.
34 *
35 * You should have received a copy of the GNU General Public License along
36 * with Slurm; if not, write to the Free Software Foundation, Inc.,
37 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38 \*****************************************************************************/
39
40 #include "as_mysql_tres.h"
41 #include "as_mysql_assoc.h"
42 #include "as_mysql_cluster.h"
43 #include "as_mysql_federation.h"
44 #include "as_mysql_usage.h"
45 #include "as_mysql_wckey.h"
46 #include "src/common/node_select.h"
47
as_mysql_get_fed_cluster_id(mysql_conn_t * mysql_conn,const char * cluster,const char * federation,int last_id,int * ret_id)48 extern int as_mysql_get_fed_cluster_id(mysql_conn_t *mysql_conn,
49 const char *cluster,
50 const char *federation,
51 int last_id, int *ret_id)
52 {
53 /* find id for cluster in federation.
54 * don't do anything if cluster is already part of federation
55 * get list of clusters that are part of the federration.
56 * loop through each cluster and find the first id available.
57 * report error if all are full in 63 slots. */
58
59 int id = 1;
60 char *query = NULL;
61 MYSQL_ROW row;
62 MYSQL_RES *result = NULL;
63
64 xassert(cluster);
65 xassert(federation);
66 xassert(ret_id);
67
68 /* See if cluster is already part of federation */
69 xstrfmtcat(query, "SELECT name, fed_id "
70 "FROM %s "
71 "WHERE deleted=0 AND name='%s' AND federation='%s';",
72 cluster_table, cluster, federation);
73 if (debug_flags & DEBUG_FLAG_FEDR)
74 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
75 if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
76 xfree(query);
77 error("no result given for %s", query);
78 return SLURM_ERROR;
79 }
80 xfree(query);
81 while ((row = mysql_fetch_row(result))) {
82 int tmp_id = slurm_atoul(row[1]);
83 if (debug_flags & DEBUG_FLAG_FEDR)
84 info("cluster '%s' already part of federation '%s', "
85 "using existing id %d", cluster, federation,
86 tmp_id);
87 mysql_free_result(result);
88 *ret_id = tmp_id;
89 return SLURM_SUCCESS;
90 }
91 mysql_free_result(result);
92
93 /* Get all other clusters in the federation and find an open id. */
94 xstrfmtcat(query, "SELECT name, federation, fed_id "
95 "FROM %s "
96 "WHERE name!='%s' AND federation='%s' "
97 "AND fed_id > %d AND deleted=0 ORDER BY fed_id;",
98 cluster_table, cluster, federation, last_id);
99 if (debug_flags & DEBUG_FLAG_FEDR)
100 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
101 if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
102 xfree(query);
103 error("no result given for %s", query);
104 return SLURM_ERROR;
105 }
106 xfree(query);
107
108 if (last_id >= id)
109 id = last_id + 1;
110 while ((row = mysql_fetch_row(result))) {
111 if (id != slurm_atoul(row[2]))
112 break;
113 id++;
114 }
115 mysql_free_result(result);
116
117 if (id > MAX_FED_CLUSTERS) {
118 error("Too many clusters in this federation.");
119 errno = ESLURM_FED_CLUSTER_MAX_CNT;
120 return ESLURM_FED_CLUSTER_MAX_CNT;
121 }
122
123 *ret_id = id;
124 return SLURM_SUCCESS;
125 }
126
_setup_cluster_cond_limits(slurmdb_cluster_cond_t * cluster_cond,char ** extra)127 static int _setup_cluster_cond_limits(slurmdb_cluster_cond_t *cluster_cond,
128 char **extra)
129 {
130 int set = 0;
131 ListIterator itr = NULL;
132 char *object = NULL;
133
134 if (!cluster_cond)
135 return 0;
136
137 if (cluster_cond->with_deleted)
138 xstrcat(*extra, " where (deleted=0 || deleted=1)");
139 else
140 xstrcat(*extra, " where deleted=0");
141
142 if (cluster_cond->cluster_list
143 && list_count(cluster_cond->cluster_list)) {
144 set = 0;
145 xstrcat(*extra, " && (");
146 itr = list_iterator_create(cluster_cond->cluster_list);
147 while ((object = list_next(itr))) {
148 if (set)
149 xstrcat(*extra, " || ");
150 xstrfmtcat(*extra, "name='%s'", object);
151 set = 1;
152 }
153 list_iterator_destroy(itr);
154 xstrcat(*extra, ")");
155 }
156
157 if (cluster_cond->federation_list
158 && list_count(cluster_cond->federation_list)) {
159 set = 0;
160 xstrcat(*extra, " && (");
161 itr = list_iterator_create(cluster_cond->federation_list);
162 while ((object = list_next(itr))) {
163 if (set)
164 xstrcat(*extra, " || ");
165 xstrfmtcat(*extra, "federation='%s'", object);
166 set = 1;
167 }
168 list_iterator_destroy(itr);
169 xstrcat(*extra, ")");
170 }
171
172 if (cluster_cond->plugin_id_select_list
173 && list_count(cluster_cond->plugin_id_select_list)) {
174 set = 0;
175 xstrcat(*extra, " && (");
176 itr = list_iterator_create(cluster_cond->plugin_id_select_list);
177 while ((object = list_next(itr))) {
178 if (set)
179 xstrcat(*extra, " || ");
180 xstrfmtcat(*extra, "plugin_id_select='%s'", object);
181 set = 1;
182 }
183 list_iterator_destroy(itr);
184 xstrcat(*extra, ")");
185 }
186
187 if (cluster_cond->rpc_version_list
188 && list_count(cluster_cond->rpc_version_list)) {
189 set = 0;
190 xstrcat(*extra, " && (");
191 itr = list_iterator_create(cluster_cond->rpc_version_list);
192 while ((object = list_next(itr))) {
193 if (set)
194 xstrcat(*extra, " || ");
195 xstrfmtcat(*extra, "rpc_version='%s'", object);
196 set = 1;
197 }
198 list_iterator_destroy(itr);
199 xstrcat(*extra, ")");
200 }
201
202 if (cluster_cond->classification) {
203 xstrfmtcat(*extra, " && (classification & %u)",
204 cluster_cond->classification);
205 }
206
207 if (cluster_cond->flags != NO_VAL) {
208 xstrfmtcat(*extra, " && (flags & %u)",
209 cluster_cond->flags);
210 }
211
212 return set;
213 }
214
as_mysql_add_clusters(mysql_conn_t * mysql_conn,uint32_t uid,List cluster_list)215 extern int as_mysql_add_clusters(mysql_conn_t *mysql_conn, uint32_t uid,
216 List cluster_list)
217 {
218 ListIterator itr = NULL;
219 int rc = SLURM_SUCCESS;
220 slurmdb_cluster_rec_t *object = NULL;
221 char *cols = NULL, *vals = NULL, *extra = NULL,
222 *query = NULL, *tmp_extra = NULL;
223 time_t now = time(NULL);
224 char *user_name = NULL;
225 int affect_rows = 0;
226 int added = 0;
227 bool has_feds = false;
228 List assoc_list = NULL;
229 slurmdb_assoc_rec_t *assoc = NULL;
230 bool external_cluster = false;
231
232 if (check_connection(mysql_conn) != SLURM_SUCCESS)
233 return ESLURM_DB_CONNECTION;
234
235 if (!is_user_min_admin_level(mysql_conn, uid, SLURMDB_ADMIN_SUPER_USER))
236 return ESLURM_ACCESS_DENIED;
237
238 assoc_list = list_create(slurmdb_destroy_assoc_rec);
239
240 user_name = uid_to_string((uid_t) uid);
241 /* Since adding tables make it so you can't roll back, if
242 there is an error there is no way to easily remove entries
243 in the database, so we will create the tables first and
244 then after that works out then add them to the mix.
245 */
246 itr = list_iterator_create(cluster_list);
247 while ((object = list_next(itr))) {
248 if (!object->name || !object->name[0]) {
249 error("We need a cluster name to add.");
250 rc = SLURM_ERROR;
251 list_remove(itr);
252 continue;
253 }
254 if ((object->flags != NO_VAL) &&
255 (object->flags & CLUSTER_FLAG_EXT))
256 external_cluster = true;
257 if ((rc = create_cluster_tables(mysql_conn,
258 object->name))
259 != SLURM_SUCCESS) {
260 added = 0;
261 if (mysql_errno(mysql_conn->db_conn)
262 == ER_WRONG_TABLE_NAME)
263 rc = ESLURM_BAD_NAME;
264 goto end_it;
265 }
266 }
267
268 /* Now that all the tables were created successfully lets go
269 ahead and add it to the system.
270 */
271 list_iterator_reset(itr);
272 while ((object = list_next(itr))) {
273 int fed_id = 0;
274 uint16_t fed_state = CLUSTER_FED_STATE_NA;
275 char *features = NULL;
276 xstrcat(cols, "creation_time, mod_time, acct");
277 xstrfmtcat(vals, "%ld, %ld, 'root'", now, now);
278 xstrfmtcat(extra, ", mod_time=%ld", now);
279 if (object->root_assoc) {
280 rc = setup_assoc_limits(object->root_assoc, &cols,
281 &vals, &extra,
282 QOS_LEVEL_SET, 1);
283 if (rc) {
284 xfree(extra);
285 xfree(cols);
286 xfree(vals);
287 added=0;
288 error("%s: Failed, setup_assoc_limits functions returned error",
289 __func__);
290 goto end_it;
291
292 }
293 }
294
295 if (object->fed.name) {
296 has_feds = 1;
297 rc = as_mysql_get_fed_cluster_id(mysql_conn,
298 object->name,
299 object->fed.name, -1,
300 &fed_id);
301 if (rc) {
302 error("failed to get cluster id for "
303 "federation");
304 xfree(extra);
305 xfree(cols);
306 xfree(vals);
307 added=0;
308 goto end_it;
309 }
310
311 if (object->fed.state != NO_VAL)
312 fed_state = object->fed.state;
313 else
314 fed_state = CLUSTER_FED_STATE_ACTIVE;
315 }
316
317 if (object->fed.feature_list) {
318 features =
319 slurm_char_list_to_xstr(
320 object->fed.feature_list);
321 has_feds = 1;
322 }
323
324 xstrfmtcat(query,
325 "insert into %s (creation_time, mod_time, "
326 "name, classification, federation, fed_id, "
327 "fed_state, features) "
328 "values (%ld, %ld, '%s', %u, '%s', %d, %u, '%s') "
329 "on duplicate key update deleted=0, mod_time=%ld, "
330 "control_host='', control_port=0, "
331 "classification=%u, flags=0, federation='%s', "
332 "fed_id=%d, fed_state=%u, features='%s'",
333 cluster_table,
334 now, now, object->name, object->classification,
335 (object->fed.name) ? object->fed.name : "",
336 fed_id, fed_state, (features) ? features : "",
337 now, object->classification,
338 (object->fed.name) ? object->fed.name : "",
339 fed_id, fed_state, (features) ? features : "");
340 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
341 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
342 rc = mysql_db_query(mysql_conn, query);
343 xfree(query);
344 if (rc != SLURM_SUCCESS) {
345 error("Couldn't add cluster %s", object->name);
346 xfree(extra);
347 xfree(cols);
348 xfree(vals);
349 xfree(features);
350 added=0;
351 break;
352 }
353
354 affect_rows = last_affected_rows(mysql_conn);
355
356 if (!affect_rows) {
357 debug2("nothing changed %d", affect_rows);
358 xfree(extra);
359 xfree(cols);
360 xfree(vals);
361 xfree(features);
362 continue;
363 }
364
365 if (!external_cluster) {
366 /* Add root account */
367 xstrfmtcat(query,
368 "insert into \"%s_%s\" (%s, lft, rgt) "
369 "values (%s, 1, 2) "
370 "on duplicate key update deleted=0, "
371 "id_assoc=LAST_INSERT_ID(id_assoc)%s;",
372 object->name, assoc_table, cols,
373 vals,
374 extra);
375 xfree(cols);
376 xfree(vals);
377 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
378 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
379
380 rc = mysql_db_query(mysql_conn, query);
381 xfree(query);
382
383 if (rc != SLURM_SUCCESS) {
384 error("Couldn't add cluster root assoc");
385 xfree(extra);
386 xfree(features);
387 added=0;
388 break;
389 }
390 } else {
391 xfree(cols);
392 xfree(vals);
393 }
394
395 /* Build up extra with cluster specfic values for txn table */
396 xstrfmtcat(extra, ", federation='%s', fed_id=%d, fed_state=%u, "
397 "features='%s'",
398 (object->fed.name) ? object->fed.name : "",
399 fed_id, fed_state, (features) ? features : "");
400 xfree(features);
401
402 /* we always have a ', ' as the first 2 chars */
403 tmp_extra = slurm_add_slash_to_quotes(extra+2);
404
405 xstrfmtcat(query,
406 "insert into %s "
407 "(timestamp, action, name, actor, info) "
408 "values (%ld, %u, '%s', '%s', '%s');",
409 txn_table, now, DBD_ADD_CLUSTERS,
410 object->name, user_name, tmp_extra);
411 xfree(tmp_extra);
412 xfree(extra);
413 debug4("%d(%s:%d) query\n%s",
414 mysql_conn->conn, THIS_FILE, __LINE__, query);
415
416 rc = mysql_db_query(mysql_conn, query);
417 xfree(query);
418 if (rc != SLURM_SUCCESS) {
419 error("Couldn't add txn");
420 } else {
421 ListIterator check_itr;
422 char *tmp_name;
423
424 added++;
425 /* add it to the list and sort */
426 slurm_mutex_lock(&as_mysql_cluster_list_lock);
427 check_itr = list_iterator_create(as_mysql_cluster_list);
428 while ((tmp_name = list_next(check_itr))) {
429 if (!xstrcmp(tmp_name, object->name))
430 break;
431 }
432 list_iterator_destroy(check_itr);
433 if (!tmp_name) {
434 list_append(as_mysql_cluster_list,
435 xstrdup(object->name));
436 list_sort(as_mysql_cluster_list,
437 (ListCmpF)slurm_sort_char_list_asc);
438 } else
439 error("Cluster %s(%s) appears to already be in "
440 "our cache list, not adding.", tmp_name,
441 object->name);
442 slurm_mutex_unlock(&as_mysql_cluster_list_lock);
443 }
444
445 if (!external_cluster) {
446 /* Add user root by default to run from the root
447 * association. This gets popped off so we need to
448 * read it every time here.
449 */
450 assoc = xmalloc(sizeof(slurmdb_assoc_rec_t));
451 slurmdb_init_assoc_rec(assoc, 0);
452 list_append(assoc_list, assoc);
453
454 assoc->cluster = xstrdup(object->name);
455 assoc->user = xstrdup("root");
456 assoc->acct = xstrdup("root");
457 assoc->is_def = 1;
458
459 if (as_mysql_add_assocs(mysql_conn, uid, assoc_list)
460 == SLURM_ERROR) {
461 error("Problem adding root user association");
462 rc = SLURM_ERROR;
463 }
464 }
465 }
466 end_it:
467 list_iterator_destroy(itr);
468 xfree(user_name);
469
470 FREE_NULL_LIST(assoc_list);
471
472 if (!added)
473 reset_mysql_conn(mysql_conn);
474 else if (has_feds)
475 as_mysql_add_feds_to_update_list(mysql_conn);
476
477 return rc;
478 }
479
_reconcile_existing_features(void * object,void * arg)480 static int _reconcile_existing_features(void *object, void *arg)
481 {
482 char *new_feature = (char *)object;
483 List existing_features = (List)arg;
484
485 if (new_feature[0] == '-')
486 list_delete_all(existing_features, slurm_find_char_in_list,
487 new_feature + 1);
488 else if (new_feature[0] == '+')
489 list_append(existing_features, xstrdup(new_feature + 1));
490 else
491 list_append(existing_features, xstrdup(new_feature));
492
493 return SLURM_SUCCESS;
494 }
495
as_mysql_modify_clusters(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_cluster_cond_t * cluster_cond,slurmdb_cluster_rec_t * cluster)496 extern List as_mysql_modify_clusters(mysql_conn_t *mysql_conn, uint32_t uid,
497 slurmdb_cluster_cond_t *cluster_cond,
498 slurmdb_cluster_rec_t *cluster)
499 {
500 List ret_list = NULL;
501 int rc = SLURM_SUCCESS;
502 char *object = NULL;
503 char *vals = NULL, *extra = NULL, *query = NULL, *name_char = NULL;
504 time_t now = time(NULL);
505 char *user_name = NULL;
506 int set = 0;
507 MYSQL_RES *result = NULL;
508 MYSQL_ROW row;
509 bool clust_reg = false, fed_update = false;
510
511 /* If you need to alter the default values of the cluster use
512 * modify_assocs since this is used only for registering
513 * the controller when it loads
514 */
515
516 if (!cluster_cond || !cluster) {
517 error("we need something to change");
518 return NULL;
519 }
520
521 if (check_connection(mysql_conn) != SLURM_SUCCESS)
522 return NULL;
523
524 if (!is_user_min_admin_level(mysql_conn, uid,
525 SLURMDB_ADMIN_SUPER_USER)) {
526 errno = ESLURM_ACCESS_DENIED;
527 return NULL;
528 }
529
530 /* force to only do non-deleted clusters */
531 cluster_cond->with_deleted = 0;
532 _setup_cluster_cond_limits(cluster_cond, &extra);
533
534 /* Needed if talking to older Slurm versions < 2.2 */
535 if (!mysql_conn->cluster_name && cluster_cond->cluster_list
536 && list_count(cluster_cond->cluster_list))
537 mysql_conn->cluster_name =
538 xstrdup(list_peek(cluster_cond->cluster_list));
539
540 set = 0;
541 if (cluster->control_host) {
542 xstrfmtcat(vals, ", control_host='%s'", cluster->control_host);
543 set++;
544 clust_reg = true;
545 }
546
547 if (cluster->control_port) {
548 xstrfmtcat(vals, ", control_port=%u, last_port=%u",
549 cluster->control_port, cluster->control_port);
550 set++;
551 clust_reg = true;
552 }
553
554 if (cluster->rpc_version) {
555 xstrfmtcat(vals, ", rpc_version=%u", cluster->rpc_version);
556 set++;
557 clust_reg = true;
558 }
559
560 if (cluster->dimensions) {
561 xstrfmtcat(vals, ", dimensions=%u", cluster->dimensions);
562 clust_reg = true;
563 }
564
565 if (cluster->plugin_id_select) {
566 xstrfmtcat(vals, ", plugin_id_select=%u",
567 cluster->plugin_id_select);
568 clust_reg = true;
569 }
570 if (cluster->flags != NO_VAL) {
571 xstrfmtcat(vals, ", flags=%u", cluster->flags);
572 clust_reg = true;
573 }
574
575 if (cluster->classification) {
576 xstrfmtcat(vals, ", classification=%u",
577 cluster->classification);
578 }
579
580 if (cluster->fed.name) {
581 xstrfmtcat(vals, ", federation='%s'", cluster->fed.name);
582 fed_update = true;
583 }
584
585 if (cluster->fed.state != NO_VAL) {
586 xstrfmtcat(vals, ", fed_state=%u", cluster->fed.state);
587 fed_update = true;
588 }
589
590 if (!vals && !cluster->fed.feature_list) {
591 xfree(extra);
592 errno = SLURM_NO_CHANGE_IN_DATA;
593 error("Nothing to change");
594 return NULL;
595 } else if (clust_reg && (set != 3)) {
596 xfree(vals);
597 xfree(extra);
598 errno = EFAULT;
599 error("Need control host, port and rpc version "
600 "to register a cluster");
601 return NULL;
602 }
603
604 xstrfmtcat(query, "select name, control_port, federation, features from %s%s;",
605 cluster_table, extra);
606
607 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
608 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
609 if (!(result = mysql_db_query_ret(
610 mysql_conn, query, 0))) {
611 xfree(query);
612 xfree(vals);
613 error("no result given for %s", extra);
614 xfree(extra);
615 return NULL;
616 }
617 xfree(extra);
618
619 ret_list = list_create(xfree_ptr);
620 user_name = uid_to_string((uid_t) uid);
621 while ((row = mysql_fetch_row(result))) {
622 char *tmp_vals = xstrdup(vals);
623
624 object = xstrdup(row[0]);
625
626 if (cluster->fed.name) {
627 int id = 0;
628 char *curr_fed = NULL;
629 uint32_t set_state = NO_VAL;
630
631 if (cluster->fed.name[0] != '\0') {
632 rc = as_mysql_get_fed_cluster_id(
633 mysql_conn, object,
634 cluster->fed.name, -1,
635 &id);
636 if (rc) {
637 error("failed to get cluster id for "
638 "federation");
639 xfree(tmp_vals);
640 xfree(object);
641 FREE_NULL_LIST(ret_list);
642 mysql_free_result(result);
643 goto end_it;
644 }
645 }
646 /* will set fed_id=0 if being removed from fed. */
647 xstrfmtcat(tmp_vals, ", fed_id=%d", id);
648
649 curr_fed = xstrdup(row[2]);
650 if (cluster->fed.name[0] == '\0')
651 /* clear fed_state when leaving federation */
652 set_state = CLUSTER_FED_STATE_NA;
653 else if (cluster->fed.state != NO_VAL) {
654 /* NOOP: fed_state already set in vals */
655 } else if (xstrcmp(curr_fed, cluster->fed.name))
656 /* set state to active when joining fed * */
657 set_state = CLUSTER_FED_STATE_ACTIVE;
658 /* else use existing state */
659
660 if (set_state != NO_VAL)
661 xstrfmtcat(tmp_vals, ", fed_state=%u",
662 set_state);
663
664 xfree(curr_fed);
665 }
666
667 if (cluster->fed.feature_list) {
668 if (!list_count(cluster->fed.feature_list)) {
669 /* clear all existing features */
670 xstrfmtcat(tmp_vals, ", features=''");
671 } else {
672 char *features = NULL, *feature = NULL;
673 List existing_features = list_create(xfree_ptr);
674
675 if ((feature =
676 list_peek(cluster->fed.feature_list)) &&
677 (feature[0] == '+' || feature[0] == '-'))
678 slurm_addto_char_list(existing_features,
679 row[3]);
680
681 list_for_each(cluster->fed.feature_list,
682 _reconcile_existing_features,
683 existing_features);
684
685 features =
686 slurm_char_list_to_xstr(
687 existing_features);
688 xstrfmtcat(tmp_vals, ", features='%s'",
689 features ? features : "");
690
691 xfree(features);
692 FREE_NULL_LIST(existing_features);
693 }
694
695 fed_update = true;
696 }
697
698 list_append(ret_list, object);
699 xstrfmtcat(name_char, "name='%s'", object);
700
701 rc = modify_common(mysql_conn, DBD_MODIFY_CLUSTERS, now,
702 user_name, cluster_table,
703 name_char, tmp_vals, NULL);
704 xfree(name_char);
705 xfree(tmp_vals);
706 if (rc == SLURM_ERROR) {
707 error("Couldn't modify cluster 1");
708 FREE_NULL_LIST(ret_list);
709 mysql_free_result(result);
710 goto end_it;
711 }
712 }
713 mysql_free_result(result);
714 xfree(user_name);
715
716 if (!list_count(ret_list)) {
717 errno = SLURM_NO_CHANGE_IN_DATA;
718 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
719 DB_DEBUG(mysql_conn->conn,
720 "didn't effect anything\n%s", query);
721 xfree(name_char);
722 xfree(vals);
723 xfree(query);
724 return ret_list;
725 }
726
727 if (fed_update)
728 as_mysql_add_feds_to_update_list(mysql_conn);
729
730 end_it:
731 xfree(query);
732 xfree(vals);
733 xfree(user_name);
734
735 return ret_list;
736 }
737
as_mysql_remove_clusters(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_cluster_cond_t * cluster_cond)738 extern List as_mysql_remove_clusters(mysql_conn_t *mysql_conn, uint32_t uid,
739 slurmdb_cluster_cond_t *cluster_cond)
740 {
741 ListIterator itr = NULL;
742 List ret_list = NULL;
743 List tmp_list = NULL;
744 int rc = SLURM_SUCCESS;
745 char *object = NULL;
746 char *extra = NULL, *query = NULL, *cluster_name = NULL,
747 *name_char = NULL, *assoc_char = NULL;
748 time_t now = time(NULL);
749 char *user_name = NULL;
750 slurmdb_wckey_cond_t wckey_cond;
751 MYSQL_RES *result = NULL;
752 MYSQL_ROW row;
753 bool jobs_running = 0, fed_update = false;
754
755 if (!cluster_cond) {
756 error("we need something to change");
757 return NULL;
758 }
759
760 if (check_connection(mysql_conn) != SLURM_SUCCESS)
761 return NULL;
762
763 if (!is_user_min_admin_level(
764 mysql_conn, uid, SLURMDB_ADMIN_SUPER_USER)) {
765 errno = ESLURM_ACCESS_DENIED;
766 return NULL;
767 }
768
769 /* force to only do non-deleted clusters */
770 cluster_cond->with_deleted = 0;
771 _setup_cluster_cond_limits(cluster_cond, &extra);
772
773 if (!extra) {
774 error("Nothing to remove");
775 return NULL;
776 }
777
778 query = xstrdup_printf("select name,federation from %s%s;",
779 cluster_table, extra);
780 xfree(extra);
781 if (!(result = mysql_db_query_ret(
782 mysql_conn, query, 0))) {
783 xfree(query);
784 return NULL;
785 }
786 rc = 0;
787 ret_list = list_create(xfree_ptr);
788
789 if (!mysql_num_rows(result)) {
790 mysql_free_result(result);
791 errno = SLURM_NO_CHANGE_IN_DATA;
792 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
793 DB_DEBUG(mysql_conn->conn,
794 "didn't effect anything\n%s", query);
795 xfree(query);
796 return ret_list;
797 }
798 xfree(query);
799
800 assoc_char = xstrdup_printf("t2.acct='root'");
801
802 user_name = uid_to_string((uid_t) uid);
803 while ((row = mysql_fetch_row(result))) {
804 char *object = xstrdup(row[0]);
805 if (!jobs_running) {
806 /* strdup the cluster name because ret_list will be
807 * flushed if there are running jobs. This will cause an
808 * invalid read because _check_jobs_before_remove() will
809 * still try to access "cluster_name" which was
810 * "object". */
811 list_append(ret_list, xstrdup(object));
812 }
813
814 if (row[1] && (*row[1] != '\0'))
815 fed_update = true;
816
817 xfree(name_char);
818 xstrfmtcat(name_char, "name='%s'", object);
819 /* We should not need to delete any cluster usage just set it
820 * to deleted */
821 xstrfmtcat(query,
822 "update \"%s_%s\" set time_end=%ld where time_end=0;"
823 "update \"%s_%s\" set mod_time=%ld, deleted=1;"
824 "update \"%s_%s\" set mod_time=%ld, deleted=1;"
825 "update \"%s_%s\" set mod_time=%ld, deleted=1;",
826 object, event_table, now,
827 object, cluster_day_table, now,
828 object, cluster_hour_table, now,
829 object, cluster_month_table, now);
830 rc = remove_common(mysql_conn, DBD_REMOVE_CLUSTERS, now,
831 user_name, cluster_table, name_char,
832 assoc_char, object, ret_list, &jobs_running);
833 xfree(object);
834 if (rc != SLURM_SUCCESS)
835 break;
836 }
837 mysql_free_result(result);
838 xfree(user_name);
839 xfree(name_char);
840 xfree(assoc_char);
841
842 if (rc != SLURM_SUCCESS) {
843 FREE_NULL_LIST(ret_list);
844 xfree(query);
845 return NULL;
846 }
847 if (!jobs_running) {
848 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
849 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
850 rc = mysql_db_query(mysql_conn, query);
851 xfree(query);
852 if (rc != SLURM_SUCCESS) {
853 reset_mysql_conn(mysql_conn);
854 FREE_NULL_LIST(ret_list);
855 return NULL;
856 }
857
858 /* We need to remove these clusters from the wckey table */
859 memset(&wckey_cond, 0, sizeof(slurmdb_wckey_cond_t));
860 wckey_cond.cluster_list = ret_list;
861 tmp_list = as_mysql_remove_wckeys(mysql_conn, uid, &wckey_cond);
862 FREE_NULL_LIST(tmp_list);
863
864 itr = list_iterator_create(ret_list);
865 while ((object = list_next(itr))) {
866 if ((rc = remove_cluster_tables(mysql_conn, object))
867 != SLURM_SUCCESS)
868 break;
869 cluster_name = xstrdup(object);
870 if (addto_update_list(mysql_conn->update_list,
871 SLURMDB_REMOVE_CLUSTER,
872 cluster_name) != SLURM_SUCCESS)
873 xfree(cluster_name);
874 }
875 list_iterator_destroy(itr);
876
877 if (rc != SLURM_SUCCESS) {
878 reset_mysql_conn(mysql_conn);
879 FREE_NULL_LIST(ret_list);
880 errno = rc;
881 return NULL;
882 }
883
884 if (fed_update)
885 as_mysql_add_feds_to_update_list(mysql_conn);
886
887 errno = SLURM_SUCCESS;
888 } else
889 errno = ESLURM_JOBS_RUNNING_ON_ASSOC;
890
891 xfree(query);
892
893 return ret_list;
894 }
895
as_mysql_get_clusters(mysql_conn_t * mysql_conn,uid_t uid,slurmdb_cluster_cond_t * cluster_cond)896 extern List as_mysql_get_clusters(mysql_conn_t *mysql_conn, uid_t uid,
897 slurmdb_cluster_cond_t *cluster_cond)
898 {
899 char *query = NULL;
900 char *extra = NULL;
901 char *tmp = NULL;
902 List cluster_list = NULL;
903 ListIterator itr = NULL;
904 int i=0;
905 MYSQL_RES *result = NULL;
906 MYSQL_ROW row;
907 slurmdb_assoc_cond_t assoc_cond;
908 ListIterator assoc_itr = NULL;
909 slurmdb_cluster_rec_t *cluster = NULL;
910 slurmdb_assoc_rec_t *assoc = NULL;
911 List assoc_list = NULL;
912
913 /* if this changes you will need to edit the corresponding enum */
914 char *cluster_req_inx[] = {
915 "name",
916 "classification",
917 "control_host",
918 "control_port",
919 "features",
920 "federation",
921 "fed_id",
922 "fed_state",
923 "rpc_version",
924 "dimensions",
925 "flags",
926 "plugin_id_select"
927 };
928 enum {
929 CLUSTER_REQ_NAME,
930 CLUSTER_REQ_CLASS,
931 CLUSTER_REQ_CH,
932 CLUSTER_REQ_CP,
933 CLUSTER_REQ_FEATURES,
934 CLUSTER_REQ_FEDR,
935 CLUSTER_REQ_FEDID,
936 CLUSTER_REQ_FEDSTATE,
937 CLUSTER_REQ_VERSION,
938 CLUSTER_REQ_DIMS,
939 CLUSTER_REQ_FLAGS,
940 CLUSTER_REQ_PI_SELECT,
941 CLUSTER_REQ_COUNT
942 };
943
944 if (check_connection(mysql_conn) != SLURM_SUCCESS)
945 return NULL;
946
947
948 if (!cluster_cond) {
949 xstrcat(extra, " where deleted=0");
950 goto empty;
951 }
952
953 _setup_cluster_cond_limits(cluster_cond, &extra);
954
955 empty:
956
957 xfree(tmp);
958 i=0;
959 xstrfmtcat(tmp, "%s", cluster_req_inx[i]);
960 for(i=1; i<CLUSTER_REQ_COUNT; i++) {
961 xstrfmtcat(tmp, ", %s", cluster_req_inx[i]);
962 }
963
964 query = xstrdup_printf("select %s from %s%s",
965 tmp, cluster_table, extra);
966 xfree(tmp);
967 xfree(extra);
968
969 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
970 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
971 if (!(result = mysql_db_query_ret(
972 mysql_conn, query, 0))) {
973 xfree(query);
974 return NULL;
975 }
976 xfree(query);
977
978 cluster_list = list_create(slurmdb_destroy_cluster_rec);
979
980 memset(&assoc_cond, 0, sizeof(slurmdb_assoc_cond_t));
981
982 if (cluster_cond) {
983 /* I don't think we want the with_usage flag here.
984 * We do need the with_deleted though. */
985 //assoc_cond.with_usage = cluster_cond->with_usage;
986 assoc_cond.with_deleted = cluster_cond->with_deleted;
987 }
988 assoc_cond.cluster_list = list_create(NULL);
989
990 while ((row = mysql_fetch_row(result))) {
991 MYSQL_RES *result2 = NULL;
992 MYSQL_ROW row2;
993 char *features = NULL;
994 cluster = xmalloc(sizeof(slurmdb_cluster_rec_t));
995 slurmdb_init_cluster_rec(cluster, 0);
996 list_append(cluster_list, cluster);
997
998 cluster->name = xstrdup(row[CLUSTER_REQ_NAME]);
999
1000 list_append(assoc_cond.cluster_list, cluster->name);
1001
1002 cluster->classification = slurm_atoul(row[CLUSTER_REQ_CLASS]);
1003 cluster->control_host = xstrdup(row[CLUSTER_REQ_CH]);
1004 cluster->control_port = slurm_atoul(row[CLUSTER_REQ_CP]);
1005 cluster->fed.name = xstrdup(row[CLUSTER_REQ_FEDR]);
1006 features = row[CLUSTER_REQ_FEATURES];
1007 if (features && *features) {
1008 cluster->fed.feature_list = list_create(xfree_ptr);
1009 slurm_addto_char_list(cluster->fed.feature_list,
1010 features);
1011 }
1012 cluster->fed.id = slurm_atoul(row[CLUSTER_REQ_FEDID]);
1013 cluster->fed.state = slurm_atoul(row[CLUSTER_REQ_FEDSTATE]);
1014 cluster->rpc_version = slurm_atoul(row[CLUSTER_REQ_VERSION]);
1015 cluster->dimensions = slurm_atoul(row[CLUSTER_REQ_DIMS]);
1016 cluster->flags = slurm_atoul(row[CLUSTER_REQ_FLAGS]);
1017 cluster->plugin_id_select =
1018 slurm_atoul(row[CLUSTER_REQ_PI_SELECT]);
1019
1020 query = xstrdup_printf(
1021 "select tres, cluster_nodes from "
1022 "\"%s_%s\" where time_end=0 and node_name='' limit 1",
1023 cluster->name, event_table);
1024 if (debug_flags & DEBUG_FLAG_DB_TRES)
1025 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
1026 if (!(result2 = mysql_db_query_ret(mysql_conn, query, 0))) {
1027 xfree(query);
1028 continue;
1029 }
1030 xfree(query);
1031 if ((row2 = mysql_fetch_row(result2))) {
1032 cluster->tres_str = xstrdup(row2[0]);
1033 if (row2[1] && row2[1][0])
1034 cluster->nodes = xstrdup(row2[1]);
1035 }
1036 mysql_free_result(result2);
1037
1038 /* get the usage if requested */
1039 if (cluster_cond && cluster_cond->with_usage) {
1040 as_mysql_get_usage(
1041 mysql_conn, uid, cluster,
1042 DBD_GET_CLUSTER_USAGE,
1043 cluster_cond->usage_start,
1044 cluster_cond->usage_end);
1045 }
1046
1047 }
1048 mysql_free_result(result);
1049
1050 if (!list_count(assoc_cond.cluster_list)) {
1051 FREE_NULL_LIST(assoc_cond.cluster_list);
1052 return cluster_list;
1053 }
1054
1055 assoc_cond.acct_list = list_create(NULL);
1056 list_append(assoc_cond.acct_list, "root");
1057
1058 assoc_cond.user_list = list_create(NULL);
1059 list_append(assoc_cond.user_list, "");
1060
1061 assoc_list = as_mysql_get_assocs(mysql_conn, uid, &assoc_cond);
1062 FREE_NULL_LIST(assoc_cond.cluster_list);
1063 FREE_NULL_LIST(assoc_cond.acct_list);
1064 FREE_NULL_LIST(assoc_cond.user_list);
1065
1066 if (!assoc_list)
1067 return cluster_list;
1068
1069 itr = list_iterator_create(cluster_list);
1070 assoc_itr = list_iterator_create(assoc_list);
1071 while ((cluster = list_next(itr))) {
1072 while ((assoc = list_next(assoc_itr))) {
1073 if (xstrcmp(assoc->cluster, cluster->name))
1074 continue;
1075
1076 if (cluster->root_assoc) {
1077 debug("This cluster %s already has "
1078 "an association.", cluster->name);
1079 continue;
1080 }
1081 cluster->root_assoc = assoc;
1082 list_remove(assoc_itr);
1083 }
1084 list_iterator_reset(assoc_itr);
1085 }
1086 list_iterator_destroy(itr);
1087 list_iterator_destroy(assoc_itr);
1088 if (list_count(assoc_list))
1089 error("I have %d left over associations",
1090 list_count(assoc_list));
1091 FREE_NULL_LIST(assoc_list);
1092
1093 return cluster_list;
1094 }
1095
as_mysql_get_cluster_events(mysql_conn_t * mysql_conn,uint32_t uid,slurmdb_event_cond_t * event_cond)1096 extern List as_mysql_get_cluster_events(mysql_conn_t *mysql_conn, uint32_t uid,
1097 slurmdb_event_cond_t *event_cond)
1098 {
1099 char *query = NULL;
1100 char *extra = NULL;
1101 char *tmp = NULL;
1102 List ret_list = NULL;
1103 ListIterator itr = NULL;
1104 char *object = NULL;
1105 int set = 0;
1106 int i=0;
1107 MYSQL_RES *result = NULL;
1108 MYSQL_ROW row;
1109 uint16_t private_data = 0;
1110 time_t now = time(NULL);
1111 List use_cluster_list = as_mysql_cluster_list;
1112 slurmdb_user_rec_t user;
1113
1114 /* if this changes you will need to edit the corresponding enum */
1115 char *event_req_inx[] = {
1116 "cluster_nodes",
1117 "node_name",
1118 "state",
1119 "time_start",
1120 "time_end",
1121 "reason",
1122 "reason_uid",
1123 "tres",
1124 };
1125
1126 enum {
1127 EVENT_REQ_CNODES,
1128 EVENT_REQ_NODE,
1129 EVENT_REQ_STATE,
1130 EVENT_REQ_START,
1131 EVENT_REQ_END,
1132 EVENT_REQ_REASON,
1133 EVENT_REQ_REASON_UID,
1134 EVENT_REQ_TRES,
1135 EVENT_REQ_COUNT
1136 };
1137
1138 if (check_connection(mysql_conn) != SLURM_SUCCESS)
1139 return NULL;
1140
1141 memset(&user, 0, sizeof(slurmdb_user_rec_t));
1142 user.uid = uid;
1143
1144 private_data = slurm_get_private_data();
1145
1146 if (private_data & PRIVATE_DATA_EVENTS) {
1147 if (!is_user_min_admin_level(
1148 mysql_conn, uid, SLURMDB_ADMIN_OPERATOR)) {
1149 error("UID %u tried to access events, only administrators can look at events",
1150 uid);
1151 errno = ESLURM_ACCESS_DENIED;
1152 return NULL;
1153 }
1154 }
1155
1156 if (!event_cond)
1157 goto empty;
1158
1159 if (event_cond->cpus_min) {
1160 if (extra)
1161 xstrcat(extra, " && (");
1162 else
1163 xstrcat(extra, " where (");
1164
1165 if (event_cond->cpus_max) {
1166 xstrfmtcat(extra, "count between %u and %u)",
1167 event_cond->cpus_min, event_cond->cpus_max);
1168
1169 } else {
1170 xstrfmtcat(extra, "count='%u')",
1171 event_cond->cpus_min);
1172
1173 }
1174 }
1175
1176 switch(event_cond->event_type) {
1177 case SLURMDB_EVENT_ALL:
1178 break;
1179 case SLURMDB_EVENT_CLUSTER:
1180 if (extra)
1181 xstrcat(extra, " && (");
1182 else
1183 xstrcat(extra, " where (");
1184 xstrcat(extra, "node_name = '')");
1185
1186 break;
1187 case SLURMDB_EVENT_NODE:
1188 if (extra)
1189 xstrcat(extra, " && (");
1190 else
1191 xstrcat(extra, " where (");
1192 xstrcat(extra, "node_name != '')");
1193
1194 break;
1195 default:
1196 error("Unknown event %u doing all", event_cond->event_type);
1197 break;
1198 }
1199
1200 if (event_cond->node_list) {
1201 int dims = 0;
1202 hostlist_t temp_hl = NULL;
1203
1204 if (get_cluster_dims(mysql_conn,
1205 (char *)list_peek(event_cond->cluster_list),
1206 &dims))
1207 return NULL;
1208
1209 temp_hl = hostlist_create_dims(event_cond->node_list, dims);
1210 if (hostlist_count(temp_hl) <= 0) {
1211 error("we didn't get any real hosts to look for.");
1212 return NULL;
1213 }
1214
1215 set = 0;
1216 if (extra)
1217 xstrcat(extra, " && (");
1218 else
1219 xstrcat(extra, " where (");
1220
1221 while ((object = hostlist_shift(temp_hl))) {
1222 if (set)
1223 xstrcat(extra, " || ");
1224 xstrfmtcat(extra, "node_name='%s'", object);
1225 set = 1;
1226 free(object);
1227 }
1228 xstrcat(extra, ")");
1229 hostlist_destroy(temp_hl);
1230 }
1231
1232 if (event_cond->period_start) {
1233 if (!event_cond->period_end)
1234 event_cond->period_end = now;
1235
1236 if (extra)
1237 xstrcat(extra, " && (");
1238 else
1239 xstrcat(extra, " where (");
1240
1241 xstrfmtcat(extra,
1242 "(time_start < %ld) "
1243 "&& (time_end >= %ld || time_end = 0))",
1244 event_cond->period_end, event_cond->period_start);
1245 }
1246
1247 if (event_cond->reason_list
1248 && list_count(event_cond->reason_list)) {
1249 set = 0;
1250 if (extra)
1251 xstrcat(extra, " && (");
1252 else
1253 xstrcat(extra, " where (");
1254 itr = list_iterator_create(event_cond->reason_list);
1255 while ((object = list_next(itr))) {
1256 if (set)
1257 xstrcat(extra, " || ");
1258 xstrfmtcat(extra, "reason like '%%%s%%'", object);
1259 set = 1;
1260 }
1261 list_iterator_destroy(itr);
1262 xstrcat(extra, ")");
1263 }
1264
1265 if (event_cond->reason_uid_list
1266 && list_count(event_cond->reason_uid_list)) {
1267 set = 0;
1268 if (extra)
1269 xstrcat(extra, " && (");
1270 else
1271 xstrcat(extra, " where (");
1272 itr = list_iterator_create(event_cond->reason_uid_list);
1273 while ((object = list_next(itr))) {
1274 if (set)
1275 xstrcat(extra, " || ");
1276 xstrfmtcat(extra, "reason_uid='%s'", object);
1277 set = 1;
1278 }
1279 list_iterator_destroy(itr);
1280 xstrcat(extra, ")");
1281 }
1282
1283 if (event_cond->state_list
1284 && list_count(event_cond->state_list)) {
1285 set = 0;
1286 if (extra)
1287 xstrcat(extra, " && (");
1288 else
1289 xstrcat(extra, " where (");
1290 itr = list_iterator_create(event_cond->state_list);
1291 while ((object = list_next(itr))) {
1292 uint32_t tmp_state = strtol(object, NULL, 10);
1293 if (set)
1294 xstrcat(extra, " || ");
1295 if (tmp_state & NODE_STATE_BASE)
1296 xstrfmtcat(extra, "(state&%u)=%u",
1297 NODE_STATE_BASE,
1298 tmp_state & NODE_STATE_BASE);
1299 else
1300 xstrfmtcat(extra, "state&%u", tmp_state);
1301 set = 1;
1302 }
1303 list_iterator_destroy(itr);
1304 xstrcat(extra, ")");
1305 }
1306
1307 if (event_cond->cluster_list && list_count(event_cond->cluster_list))
1308 use_cluster_list = event_cond->cluster_list;
1309 empty:
1310 xfree(tmp);
1311 xstrfmtcat(tmp, "%s", event_req_inx[0]);
1312 for(i=1; i<EVENT_REQ_COUNT; i++) {
1313 xstrfmtcat(tmp, ", %s", event_req_inx[i]);
1314 }
1315
1316 if (use_cluster_list == as_mysql_cluster_list)
1317 slurm_mutex_lock(&as_mysql_cluster_list_lock);
1318
1319 ret_list = list_create(slurmdb_destroy_event_rec);
1320
1321 itr = list_iterator_create(use_cluster_list);
1322 while ((object = list_next(itr))) {
1323 query = xstrdup_printf("select %s from \"%s_%s\"",
1324 tmp, object, event_table);
1325 if (extra)
1326 xstrfmtcat(query, " %s", extra);
1327
1328 if (debug_flags & DEBUG_FLAG_DB_ASSOC)
1329 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
1330 if (!(result = mysql_db_query_ret(
1331 mysql_conn, query, 0))) {
1332 xfree(query);
1333 if (mysql_errno(mysql_conn->db_conn)
1334 != ER_NO_SUCH_TABLE) {
1335 FREE_NULL_LIST(ret_list);
1336 ret_list = NULL;
1337 }
1338 break;
1339 }
1340 xfree(query);
1341
1342 while ((row = mysql_fetch_row(result))) {
1343 slurmdb_event_rec_t *event =
1344 xmalloc(sizeof(slurmdb_event_rec_t));
1345
1346 list_append(ret_list, event);
1347
1348 event->cluster = xstrdup(object);
1349
1350 if (row[EVENT_REQ_NODE] && row[EVENT_REQ_NODE][0]) {
1351 event->node_name = xstrdup(row[EVENT_REQ_NODE]);
1352 event->event_type = SLURMDB_EVENT_NODE;
1353 } else
1354 event->event_type = SLURMDB_EVENT_CLUSTER;
1355
1356 event->state = slurm_atoul(row[EVENT_REQ_STATE]);
1357 event->period_start = slurm_atoul(row[EVENT_REQ_START]);
1358 event->period_end = slurm_atoul(row[EVENT_REQ_END]);
1359
1360 if (row[EVENT_REQ_REASON] && row[EVENT_REQ_REASON][0])
1361 event->reason = xstrdup(row[EVENT_REQ_REASON]);
1362 event->reason_uid =
1363 slurm_atoul(row[EVENT_REQ_REASON_UID]);
1364
1365 if (row[EVENT_REQ_CNODES] && row[EVENT_REQ_CNODES][0])
1366 event->cluster_nodes =
1367 xstrdup(row[EVENT_REQ_CNODES]);
1368
1369 if (row[EVENT_REQ_TRES] && row[EVENT_REQ_TRES][0])
1370 event->tres_str = xstrdup(row[EVENT_REQ_TRES]);
1371 }
1372 mysql_free_result(result);
1373 }
1374 list_iterator_destroy(itr);
1375 xfree(tmp);
1376 xfree(extra);
1377
1378 if (use_cluster_list == as_mysql_cluster_list)
1379 slurm_mutex_unlock(&as_mysql_cluster_list_lock);
1380
1381 return ret_list;
1382 }
1383
as_mysql_node_down(mysql_conn_t * mysql_conn,node_record_t * node_ptr,time_t event_time,char * reason,uint32_t reason_uid)1384 extern int as_mysql_node_down(mysql_conn_t *mysql_conn,
1385 node_record_t *node_ptr,
1386 time_t event_time, char *reason,
1387 uint32_t reason_uid)
1388 {
1389 int rc = SLURM_SUCCESS;
1390 char *query = NULL;
1391 char *my_reason;
1392 MYSQL_RES *result = NULL;
1393 MYSQL_ROW row;
1394
1395 if (check_connection(mysql_conn) != SLURM_SUCCESS)
1396 return ESLURM_DB_CONNECTION;
1397
1398 if (!mysql_conn->cluster_name) {
1399 error("%s:%d no cluster name", THIS_FILE, __LINE__);
1400 return SLURM_ERROR;
1401 }
1402
1403 if (!node_ptr) {
1404 error("No node_ptr given!");
1405 return SLURM_ERROR;
1406 }
1407
1408 if (!node_ptr->tres_str) {
1409 error("node ptr has no tres_list!");
1410 return SLURM_ERROR;
1411 }
1412
1413 query = xstrdup_printf("select state, reason, time_start from \"%s_%s\" where "
1414 "time_end=0 and node_name='%s';",
1415 mysql_conn->cluster_name, event_table,
1416 node_ptr->name);
1417 /* info("%d(%s:%d) query\n%s", */
1418 /* mysql_conn->conn, THIS_FILE, __LINE__, query); */
1419 result = mysql_db_query_ret(mysql_conn, query, 0);
1420 xfree(query);
1421
1422 if (!result)
1423 return SLURM_ERROR;
1424
1425 if (reason)
1426 my_reason = reason;
1427 else
1428 my_reason = node_ptr->reason;
1429
1430 if (!my_reason)
1431 my_reason = "";
1432
1433 row = mysql_fetch_row(result);
1434 if (row && (node_ptr->node_state == slurm_atoul(row[0])) &&
1435 !xstrcasecmp(my_reason, row[1])) {
1436 if (debug_flags & DEBUG_FLAG_DB_EVENT)
1437 DB_DEBUG(mysql_conn->conn,
1438 "no change to %s(%s) needed %u == %s and %s == %s",
1439 node_ptr->name, mysql_conn->cluster_name,
1440 node_ptr->node_state, row[0],
1441 my_reason, row[1]);
1442 mysql_free_result(result);
1443 return SLURM_SUCCESS;
1444 }
1445
1446 if (row && (event_time == slurm_atoul(row[2]))) {
1447 /*
1448 * If you are clean-restarting the controller over and over
1449 * again you could get records that are duplicates in the
1450 * database. If this is the case we will zero out the time_end
1451 * we are just filled in. This will cause the last time to be
1452 * erased from the last restart, but if you are restarting
1453 * things this often the pervious one didn't mean anything
1454 * anyway. This way we only get one for the last time we let it
1455 * run.
1456 */
1457 query = xstrdup_printf(
1458 "update \"%s_%s\" set reason='%s' where "
1459 "time_start=%ld and node_name='%s';",
1460 mysql_conn->cluster_name, event_table,
1461 my_reason, event_time, node_ptr->name);
1462 if (debug_flags & DEBUG_FLAG_DB_EVENT)
1463 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
1464 rc = mysql_db_query(mysql_conn, query);
1465 xfree(query);
1466
1467 mysql_free_result(result);
1468 return rc;
1469 }
1470
1471 mysql_free_result(result);
1472
1473 if (debug_flags & DEBUG_FLAG_DB_EVENT)
1474 DB_DEBUG(mysql_conn->conn,
1475 "inserting %s(%s) with tres of '%s'",
1476 node_ptr->name, mysql_conn->cluster_name,
1477 node_ptr->tres_str);
1478
1479 query = xstrdup_printf(
1480 "update \"%s_%s\" set time_end=%ld where "
1481 "time_end=0 and node_name='%s';",
1482 mysql_conn->cluster_name, event_table,
1483 event_time, node_ptr->name);
1484 xstrfmtcat(query,
1485 "insert into \"%s_%s\" "
1486 "(node_name, state, tres, time_start, "
1487 "reason, reason_uid) "
1488 "values ('%s', %u, '%s', %ld, '%s', %u);",
1489 mysql_conn->cluster_name, event_table,
1490 node_ptr->name, node_ptr->node_state,
1491 node_ptr->tres_str, event_time, my_reason, reason_uid);
1492 if (debug_flags & DEBUG_FLAG_DB_EVENT)
1493 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
1494 rc = mysql_db_query(mysql_conn, query);
1495 xfree(query);
1496
1497 return rc;
1498 }
1499
as_mysql_node_up(mysql_conn_t * mysql_conn,node_record_t * node_ptr,time_t event_time)1500 extern int as_mysql_node_up(mysql_conn_t *mysql_conn,
1501 node_record_t *node_ptr,
1502 time_t event_time)
1503 {
1504 char* query;
1505 int rc = SLURM_SUCCESS;
1506
1507 if (check_connection(mysql_conn) != SLURM_SUCCESS)
1508 return ESLURM_DB_CONNECTION;
1509
1510 if (!mysql_conn->cluster_name) {
1511 error("%s:%d no cluster name", THIS_FILE, __LINE__);
1512 return SLURM_ERROR;
1513 }
1514
1515 query = xstrdup_printf(
1516 "update \"%s_%s\" set time_end=%ld where "
1517 "time_end=0 and node_name='%s';",
1518 mysql_conn->cluster_name, event_table,
1519 event_time, node_ptr->name);
1520 if (debug_flags & DEBUG_FLAG_DB_EVENT)
1521 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
1522 rc = mysql_db_query(mysql_conn, query);
1523 xfree(query);
1524 return rc;
1525 }
1526
1527 /* This function is not used in the slurmdbd. */
as_mysql_register_ctld(mysql_conn_t * mysql_conn,char * cluster,uint16_t port)1528 extern int as_mysql_register_ctld(mysql_conn_t *mysql_conn,
1529 char *cluster, uint16_t port)
1530 {
1531 return SLURM_ERROR;
1532 }
1533
as_mysql_fini_ctld(mysql_conn_t * mysql_conn,slurmdb_cluster_rec_t * cluster_rec)1534 extern int as_mysql_fini_ctld(mysql_conn_t *mysql_conn,
1535 slurmdb_cluster_rec_t *cluster_rec)
1536 {
1537 int rc = SLURM_SUCCESS;
1538 time_t now = time(NULL);
1539 char *query = NULL;
1540 bool free_it = false;
1541
1542 if (check_connection(mysql_conn) != SLURM_SUCCESS)
1543 return ESLURM_DB_CONNECTION;
1544
1545 /* Here we need to check make sure we are updating the entry
1546 correctly just in case the backup has already gained
1547 control. If we check the ip and port it is a pretty safe
1548 bet we have the right ctld.
1549 */
1550 query = xstrdup_printf(
1551 "update %s set mod_time=%ld, control_host='', "
1552 "control_port=0 where name='%s' && "
1553 "control_host='%s' && control_port=%u;",
1554 cluster_table, now, cluster_rec->name,
1555 cluster_rec->control_host, cluster_rec->control_port);
1556 if (debug_flags & DEBUG_FLAG_DB_EVENT)
1557 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
1558 rc = mysql_db_query(mysql_conn, query);
1559 xfree(query);
1560
1561 if (rc != SLURM_SUCCESS)
1562 return SLURM_ERROR;
1563
1564 if (!last_affected_rows(mysql_conn) || !slurmdbd_conf->track_ctld)
1565 return rc;
1566
1567 /* If tres is NULL we can get the current number of tres by
1568 sending NULL for the tres param in the as_mysql_cluster_tres
1569 function.
1570 */
1571 if (!cluster_rec->tres_str) {
1572 free_it = true;
1573 as_mysql_cluster_tres(
1574 mysql_conn, cluster_rec->control_host,
1575 &cluster_rec->tres_str, now,
1576 cluster_rec->rpc_version);
1577 }
1578
1579 /* Since as_mysql_cluster_tres could change the
1580 last_affected_rows we can't group this with the above
1581 return.
1582 */
1583 if (!cluster_rec->tres_str)
1584 return rc;
1585
1586 /* If we affected things we need to now drain the nodes in the
1587 * cluster. This is to give better stats on accounting that
1588 * the ctld was gone so no jobs were able to be scheduled. We
1589 * drain the nodes since the rollup functionality understands
1590 * how to deal with that and running jobs so we don't get bad
1591 * info.
1592 */
1593 query = xstrdup_printf(
1594 "insert into \"%s_%s\" (tres, state, time_start, reason) "
1595 "values ('%s', %u, %ld, 'slurmctld disconnect');",
1596 cluster_rec->name, event_table,
1597 cluster_rec->tres_str, NODE_STATE_DOWN, (long)now);
1598
1599 if (free_it)
1600 xfree(cluster_rec->tres_str);
1601
1602 if (debug_flags & DEBUG_FLAG_DB_EVENT)
1603 DB_DEBUG(mysql_conn->conn, "query\n%s", query);
1604 rc = mysql_db_query(mysql_conn, query);
1605 xfree(query);
1606
1607 return rc;
1608 }
1609
as_mysql_cluster_tres(mysql_conn_t * mysql_conn,char * cluster_nodes,char ** tres_str_in,time_t event_time,uint16_t rpc_version)1610 extern int as_mysql_cluster_tres(mysql_conn_t *mysql_conn,
1611 char *cluster_nodes, char **tres_str_in,
1612 time_t event_time, uint16_t rpc_version)
1613 {
1614 char* query;
1615 int rc = SLURM_SUCCESS;
1616 int response = 0;
1617 MYSQL_RES *result = NULL;
1618 MYSQL_ROW row;
1619 bool handle_disconnect = true;
1620
1621 xassert(tres_str_in);
1622
1623 if (check_connection(mysql_conn) != SLURM_SUCCESS)
1624 return ESLURM_DB_CONNECTION;
1625
1626 if (!mysql_conn->cluster_name) {
1627 error("%s:%d no cluster name", THIS_FILE, __LINE__);
1628 return SLURM_ERROR;
1629 }
1630
1631 /* Record the processor count */
1632 query = xstrdup_printf(
1633 "select tres, cluster_nodes from \"%s_%s\" where "
1634 "time_end=0 and node_name='' and state=0 limit 1",
1635 mysql_conn->cluster_name, event_table);
1636 if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
1637 xfree(query);
1638 if (mysql_errno(mysql_conn->db_conn) == ER_NO_SUCH_TABLE)
1639 rc = ESLURM_ACCESS_DENIED;
1640 else
1641 rc = SLURM_ERROR;
1642 return rc;
1643 }
1644 xfree(query);
1645
1646 /* we only are checking the first one here */
1647 if (!(row = mysql_fetch_row(result))) {
1648 debug("We don't have an entry for this machine %s "
1649 "most likely a first time running.",
1650 mysql_conn->cluster_name);
1651
1652 /* Get all nodes in a down state and jobs pending or running.
1653 * This is for the first time a cluster registers
1654 *
1655 * We will return ACCOUNTING_FIRST_REG so this
1656 * is taken care of since the message thread
1657 * may not be up when we run this in the controller or
1658 * in the slurmdbd.
1659 */
1660 if (!*tres_str_in) {
1661 rc = 0;
1662 goto end_it;
1663 }
1664
1665 response = ACCOUNTING_FIRST_REG;
1666 goto add_it;
1667 }
1668
1669 /* If tres is NULL we want to return the tres for this cluster */
1670 if (!*tres_str_in) {
1671 *tres_str_in = xstrdup(row[0]);
1672 goto end_it;
1673 } else if (xstrcmp(*tres_str_in, row[0])) {
1674 debug("%s has changed tres from %s to %s",
1675 mysql_conn->cluster_name,
1676 row[0], *tres_str_in);
1677
1678 /*
1679 * Reset all the entries for this cluster since the tres changed
1680 * some of the downed nodes may have gone away.
1681 * Request them again with ACCOUNTING_NODES_CHANGE_DB
1682 */
1683
1684 if (xstrcmp(cluster_nodes, row[1])) {
1685 if (debug_flags & DEBUG_FLAG_DB_EVENT)
1686 DB_DEBUG(mysql_conn->conn,
1687 "Nodes on the cluster have changed.");
1688 response = ACCOUNTING_NODES_CHANGE_DB;
1689 } else
1690 response = ACCOUNTING_TRES_CHANGE_DB;
1691 } else if (xstrcmp(cluster_nodes, row[1])) {
1692 if (debug_flags & DEBUG_FLAG_DB_EVENT)
1693 DB_DEBUG(mysql_conn->conn,
1694 "Node names on the cluster have changed.");
1695 response = ACCOUNTING_NODES_CHANGE_DB;
1696 } else {
1697 if (debug_flags & DEBUG_FLAG_DB_EVENT)
1698 DB_DEBUG(mysql_conn->conn,
1699 "We have the same TRES and node names as before for %s, no need to update the database.",
1700 mysql_conn->cluster_name);
1701 goto remove_disconnect;
1702 }
1703
1704 query = xstrdup_printf(
1705 "update \"%s_%s\" set time_end=%ld where time_end=0",
1706 mysql_conn->cluster_name, event_table, event_time);
1707
1708 rc = mysql_db_query(mysql_conn, query);
1709 xfree(query);
1710 handle_disconnect = false;
1711
1712 if (rc != SLURM_SUCCESS)
1713 goto end_it;
1714 add_it:
1715 query = xstrdup_printf(
1716 "insert into \"%s_%s\" (cluster_nodes, tres, "
1717 "time_start, reason) "
1718 "values ('%s', '%s', %ld, 'Cluster Registered TRES');",
1719 mysql_conn->cluster_name, event_table,
1720 cluster_nodes, *tres_str_in, event_time);
1721
1722 rc = mysql_db_query(mysql_conn, query);
1723 xfree(query);
1724
1725 if (rc != SLURM_SUCCESS)
1726 goto end_it;
1727
1728 remove_disconnect:
1729 /*
1730 * The above update clears all with time_end=0, so no
1731 * need to do this again.
1732 */
1733 if (handle_disconnect) {
1734 query = xstrdup_printf(
1735 "update \"%s_%s\" set time_end=%ld where time_end=0 and state=%u and node_name='';",
1736 mysql_conn->cluster_name,
1737 event_table, event_time,
1738 NODE_STATE_DOWN);
1739 (void) mysql_db_query(mysql_conn, query);
1740 xfree(query);
1741 }
1742
1743 end_it:
1744 mysql_free_result(result);
1745 if (response && rc == SLURM_SUCCESS)
1746 rc = response;
1747
1748 return rc;
1749 }
1750