| /*****************************************************************************\ |
| * as_mysql_resource.c - functions dealing with resources. |
| ***************************************************************************** |
| * Copyright (C) 2013 Bull S. A. S. |
| * Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois. |
| * |
| * Written by Bill Brophy <bill.brophy@bull.com> |
| * |
| * This file is part of Slurm, a resource management program. |
| * For details, see <https://slurm.schedmd.com>. |
| * Please also read the included file: DISCLAIMER. |
| * |
| * Slurm is free software; you can redistribute it and/or modify it under |
| * the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * In addition, as a special exception, the copyright holders give permission |
| * to link the code of portions of this program with the OpenSSL library under |
| * certain conditions as described in each individual source file, and |
| * distribute linked combinations including the two. You must obey the GNU |
| * General Public License in all respects for all of the code used other than |
| * OpenSSL. If you modify file(s) with this exception, you may extend this |
| * exception to your version of the file(s), but you are not obligated to do |
| * so. If you do not wish to do so, delete this exception statement from your |
| * version. If you delete this exception statement from all source files in |
| * the program, then also delete it here. |
| * |
| * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| * details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with Slurm; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| \*****************************************************************************/ |
| |
| #include "as_mysql_assoc.h" |
| #include "as_mysql_resource.h" |
| #include "as_mysql_usage.h" |
| #include "as_mysql_wckey.h" |
| |
| #include "src/interfaces/select.h" |
| |
| static void _setup_res_cond(slurmdb_res_cond_t *res_cond, |
| char **extra) |
| { |
| int set = 0; |
| list_itr_t *itr = NULL; |
| char *object = NULL; |
| |
| if (!res_cond) { |
| xstrcat(*extra, "where t1.deleted=0"); |
| return; |
| } |
| |
| if (res_cond->with_deleted) |
| xstrcat(*extra, "where (t1.deleted=0 || t1.deleted=1)"); |
| else |
| xstrcat(*extra, "where t1.deleted=0"); |
| |
| if (res_cond->description_list |
| && list_count(res_cond->description_list)) { |
| set = 0; |
| xstrcat(*extra, " && ("); |
| itr = list_iterator_create(res_cond->description_list); |
| while ((object = list_next(itr))) { |
| if (set) |
| xstrcat(*extra, " || "); |
| xstrfmtcat(*extra, "description='%s'", object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(*extra, ")"); |
| } |
| |
| if (!(res_cond->flags & SLURMDB_RES_FLAG_NOTSET)) { |
| xstrfmtcat(*extra, " && (flags & %u)", |
| res_cond->flags & SLURMDB_RES_FLAG_BASE); |
| } |
| |
| if (res_cond->id_list |
| && list_count(res_cond->id_list)) { |
| set = 0; |
| xstrcat(*extra, " && ("); |
| itr = list_iterator_create(res_cond->id_list); |
| while ((object = list_next(itr))) { |
| if (set) |
| xstrcat(*extra, " || "); |
| xstrfmtcat(*extra, "id='%s'", object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(*extra, ")"); |
| } |
| |
| if (res_cond->manager_list |
| && list_count(res_cond->manager_list)) { |
| set = 0; |
| xstrcat(*extra, " && ("); |
| itr = list_iterator_create(res_cond->manager_list); |
| while ((object = list_next(itr))) { |
| if (set) |
| xstrcat(*extra, " || "); |
| xstrfmtcat(*extra, "manager='%s'", object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(*extra, ")"); |
| } |
| |
| if (res_cond->name_list |
| && list_count(res_cond->name_list)) { |
| set = 0; |
| xstrcat(*extra, " && ("); |
| itr = list_iterator_create(res_cond->name_list); |
| while ((object = list_next(itr))) { |
| if (set) |
| xstrcat(*extra, " || "); |
| xstrfmtcat(*extra, "name='%s'", object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(*extra, ")"); |
| } |
| |
| if (res_cond->server_list |
| && list_count(res_cond->server_list)) { |
| set = 0; |
| xstrcat(*extra, " && ("); |
| itr = list_iterator_create(res_cond->server_list); |
| while ((object = list_next(itr))) { |
| if (set) |
| xstrcat(*extra, " || "); |
| xstrfmtcat(*extra, "server='%s'", object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(*extra, ")"); |
| } |
| |
| if (res_cond->type_list |
| && list_count(res_cond->type_list)) { |
| set = 0; |
| xstrcat(*extra, " && ("); |
| itr = list_iterator_create(res_cond->type_list); |
| while ((object = list_next(itr))) { |
| if (set) |
| xstrcat(*extra, " || "); |
| xstrfmtcat(*extra, "type='%s'", object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(*extra, ")"); |
| } |
| } |
| |
| static int _setup_clus_res_cond(slurmdb_res_cond_t *res_cond, char **extra) |
| { |
| list_itr_t *itr; |
| bool set = 0; |
| char *tmp = NULL; |
| int query_clusters = 0; |
| |
| if (!res_cond) { |
| xstrfmtcat(*extra, "%st2.deleted=0", *extra ? " && " : ""); |
| return SLURM_SUCCESS; |
| } |
| |
| if (res_cond->with_deleted) |
| xstrfmtcat(*extra, "%s(t2.deleted=0 || t2.deleted=1)", |
| *extra ? " && " : ""); |
| else |
| xstrfmtcat(*extra, "%st2.deleted=0", *extra ? " && " : ""); |
| |
| if (res_cond->cluster_list && list_count(res_cond->cluster_list)) { |
| set = 0; |
| xstrcat(*extra, " && ("); |
| itr = list_iterator_create(res_cond->cluster_list); |
| while ((tmp = list_next(itr))) { |
| if (set) |
| xstrcat(*extra, " || "); |
| xstrfmtcat(*extra, "t2.cluster='%s'", tmp); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(*extra, ")"); |
| query_clusters += set; |
| } |
| |
| if (res_cond->allowed_list && list_count(res_cond->allowed_list)) { |
| set = 0; |
| xstrcat(*extra, " && ("); |
| itr = list_iterator_create(res_cond->allowed_list); |
| while ((tmp = list_next(itr))) { |
| if (set) |
| xstrcat(*extra, " || "); |
| xstrfmtcat(*extra, "t2.allowed='%s'", tmp); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(*extra, ")"); |
| query_clusters += set; |
| } |
| |
| return query_clusters; |
| } |
| |
| static int _setup_res_limits(slurmdb_res_rec_t *res, |
| char **cols, char **vals, |
| char **extra, bool for_add, bool *send_update) |
| { |
| if (!res) |
| return SLURM_ERROR; |
| |
| if (for_add) { |
| /* If we are adding we should make sure we don't get |
| old residue sitting around from a former life. |
| */ |
| if (res->count == NO_VAL) |
| res->count = 0; |
| if (res->type == SLURMDB_RESOURCE_NOTSET) |
| res->type = SLURMDB_RESOURCE_LICENSE; |
| } |
| |
| if (res->count != NO_VAL) { |
| if (cols) |
| xstrcat(*cols, ", count"); |
| xstrfmtcat(*vals, ", %u", res->count); |
| xstrfmtcat(*extra, ", count=%u", res->count); |
| if (send_update) |
| *send_update = 1; |
| } |
| |
| if (res->description) { |
| if (cols) |
| xstrcat(*cols, ", description"); |
| xstrfmtcat(*vals, ", '%s'", res->description); |
| xstrfmtcat(*extra, ", description='%s'", |
| res->description); |
| } |
| |
| if (!(res->flags & SLURMDB_RES_FLAG_NOTSET)) { |
| uint32_t base_flags = (res->flags & SLURMDB_RES_FLAG_BASE); |
| if (cols) |
| xstrcat(*cols, ", flags"); |
| if (res->flags & SLURMDB_RES_FLAG_REMOVE) { |
| xstrfmtcat(*vals, ", (VALUES(flags) & ~%u)'", |
| base_flags); |
| xstrfmtcat(*extra, ", flags=(flags & ~%u)", |
| base_flags); |
| } else if (res->flags & SLURMDB_RES_FLAG_ADD) { |
| xstrfmtcat(*vals, ", (VALUES(flags) | %u)'", |
| base_flags); |
| xstrfmtcat(*extra, ", flags=(flags | %u)", |
| base_flags); |
| } else { |
| xstrfmtcat(*vals, ", '%u'", base_flags); |
| xstrfmtcat(*extra, ", flags=%u", base_flags); |
| } |
| if (send_update) |
| *send_update = 1; |
| } |
| |
| if (res->last_consumed != NO_VAL) { |
| if (cols) |
| xstrcat(*cols, ", last_consumed"); |
| xstrfmtcat(*vals, ", %u", res->last_consumed); |
| xstrfmtcat(*extra, ", last_consumed=%u", res->last_consumed); |
| if (send_update) |
| *send_update = 1; |
| } |
| |
| if (res->manager) { |
| if (cols) |
| xstrcat(*cols, ", manager"); |
| xstrfmtcat(*vals, ", '%s'", res->manager); |
| xstrfmtcat(*extra, ", manager='%s'", res->manager); |
| } |
| |
| if (res->type != SLURMDB_RESOURCE_NOTSET) { |
| if (cols) |
| xstrcat(*cols, ", type"); |
| xstrfmtcat(*vals, ", %u", res->type); |
| xstrfmtcat(*extra, ", type=%u", res->type); |
| if (send_update) |
| *send_update = 1; |
| } |
| |
| return SLURM_SUCCESS; |
| } |
| |
| |
| static uint32_t _get_res_used(mysql_conn_t *mysql_conn, uint32_t res_id, |
| char *extra) |
| { |
| char *query = NULL; |
| MYSQL_RES *result = NULL; |
| MYSQL_ROW row; |
| uint32_t allocated = NO_VAL; |
| |
| xassert(res_id != NO_VAL); |
| |
| /* When extra comes in it will have deleted in there as well, |
| * it appears mysql only uses the first one here and gives us |
| * what we want. |
| */ |
| query = xstrdup_printf("select distinct SUM(allowed) " |
| "from %s as t2 where deleted=0 && res_id=%u", |
| clus_res_table, res_id); |
| if (extra) |
| xstrfmtcat(query, " && !(%s)", extra); |
| |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { |
| xfree(query); |
| return allocated; |
| } |
| xfree(query); |
| |
| if (!(row = mysql_fetch_row(result))) { |
| error("Resource id %u is not known on the system", res_id); |
| mysql_free_result(result); |
| return allocated; |
| } |
| |
| /* Overwrite everything just to make sure the client side |
| didn't try anything tricky. |
| */ |
| if (row[0] && row[0][0]) |
| allocated = slurm_atoul(row[0]); |
| |
| mysql_free_result(result); |
| |
| return allocated; |
| } |
| |
| static int _fill_in_res_rec(mysql_conn_t *mysql_conn, slurmdb_res_rec_t *res) |
| { |
| int rc = SLURM_SUCCESS, i; |
| char *query = NULL; |
| MYSQL_RES *result = NULL; |
| MYSQL_ROW row; |
| char *tmp = NULL; |
| |
| /* if this changes you will need to edit the corresponding enum */ |
| char *res_req_inx[] = { |
| "count", |
| "flags", |
| "id", |
| "last_consumed", |
| "name", |
| "server", |
| "type", |
| "SUM(allowed)", |
| }; |
| enum { |
| RES_REQ_COUNT, |
| RES_REQ_FLAGS, |
| RES_REQ_ID, |
| RES_REQ_LAST_CONSUMED, |
| RES_REQ_NAME, |
| RES_REQ_SERVER, |
| RES_REQ_TYPE, |
| RES_REQ_PU, |
| RES_REQ_NUMBER, |
| }; |
| |
| xassert(res); |
| xassert(res->id != NO_VAL); |
| |
| xfree(tmp); |
| xstrfmtcat(tmp, "%s", res_req_inx[0]); |
| for (i=1; i<RES_REQ_NUMBER; i++) { |
| xstrfmtcat(tmp, ", %s", res_req_inx[i]); |
| } |
| |
| query = xstrdup_printf("select distinct %s from %s as t1 " |
| "left outer join " |
| "%s as t2 on (res_id=id && " |
| "t2.deleted=0) " |
| "where id=%u group by id", |
| tmp, res_table, clus_res_table, res->id); |
| |
| xfree(tmp); |
| |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { |
| xfree(query); |
| return SLURM_ERROR; |
| } |
| xfree(query); |
| |
| if (!(row = mysql_fetch_row(result))) { |
| error("Resource id %u is not known on the system", res->id); |
| mysql_free_result(result); |
| return SLURM_ERROR; |
| } |
| |
| /* Overwrite everything just to make sure the client side |
| didn't try anything tricky. |
| */ |
| if (row[RES_REQ_COUNT] && row[RES_REQ_COUNT][0]) |
| res->count = slurm_atoul(row[RES_REQ_COUNT]); |
| if (row[RES_REQ_FLAGS] && row[RES_REQ_FLAGS][0]) |
| res->flags = slurm_atoul(row[RES_REQ_FLAGS]); |
| if (row[RES_REQ_LAST_CONSUMED] && row[RES_REQ_LAST_CONSUMED][0]) |
| res->last_consumed = slurm_atoul(row[RES_REQ_LAST_CONSUMED]); |
| if (row[RES_REQ_NAME] && row[RES_REQ_NAME][0]) { |
| xfree(res->name); |
| res->name = xstrdup(row[RES_REQ_NAME]); |
| } |
| if (row[RES_REQ_SERVER] && row[RES_REQ_SERVER][0]) { |
| xfree(res->server); |
| res->server = xstrdup(row[RES_REQ_SERVER]); |
| } |
| if (row[RES_REQ_TYPE] && row[RES_REQ_TYPE][0]) |
| res->type = slurm_atoul(row[RES_REQ_TYPE]); |
| if (row[RES_REQ_PU] && row[RES_REQ_PU][0]) |
| res->allocated = slurm_atoul(row[RES_REQ_PU]); |
| else |
| res->allocated = 0; |
| |
| mysql_free_result(result); |
| |
| return rc; |
| } |
| |
| static int _add_res(mysql_conn_t *mysql_conn, slurmdb_res_rec_t *object, |
| char *user_name, int *added, list_itr_t *itr_in) |
| { |
| char *cols = NULL, *extra = NULL, *vals = NULL, *query = NULL, |
| *tmp_extra = NULL; |
| time_t now = time(NULL); |
| int affect_rows = 0; |
| int rc = SLURM_SUCCESS; |
| |
| if (!object->name || !object->name[0]) { |
| error("We need a resource name to add."); |
| return SLURM_ERROR; |
| } |
| if (!object->server || !object->server[0]) { |
| error("We need a resource server to add."); |
| return SLURM_ERROR; |
| } |
| |
| xstrcat(cols, "creation_time, mod_time, name, server"); |
| xstrfmtcat(vals, "%ld, %ld, '%s', '%s'", now, now, |
| object->name, object->server); |
| xstrfmtcat(extra, ", mod_time=%ld", now); |
| |
| /* |
| * Add the Absolute flag if we are adding the resource, |
| * and we are configured for Absolute resources. |
| */ |
| if (slurmdbd_conf->flags & DBD_CONF_FLAG_ALL_RES_ABS) { |
| object->flags &= ~SLURMDB_RES_FLAG_NOTSET; |
| object->flags |= SLURMDB_RES_FLAG_ABSOLUTE; |
| } |
| |
| _setup_res_limits(object, &cols, &vals, &extra, 1, NULL); |
| |
| xstrfmtcat(query, |
| "insert into %s (%s) values (%s) " |
| "on duplicate key update deleted=0, " |
| "id=LAST_INSERT_ID(id)%s;", |
| res_table, cols, vals, extra); |
| |
| |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| object->id = (uint32_t)mysql_db_insert_ret_id(mysql_conn, query); |
| xfree(query); |
| if (!object->id) { |
| error("Couldn't add server resource %s", object->name); |
| (*added) = 0; |
| xfree(cols); |
| xfree(extra); |
| xfree(vals); |
| return SLURM_ERROR; |
| } |
| |
| affect_rows = last_affected_rows(mysql_conn); |
| |
| if (!affect_rows) { |
| xfree(cols); |
| xfree(extra); |
| xfree(vals); |
| return SLURM_SUCCESS; |
| } |
| |
| /* we always have a ', ' as the first 2 chars */ |
| tmp_extra = slurm_add_slash_to_quotes(extra+2); |
| |
| xstrfmtcat(query, |
| "insert into %s " |
| "(timestamp, action, name, actor, info) " |
| "values (%ld, %u, '%u', '%s', '%s');", |
| txn_table, |
| now, DBD_ADD_RES, object->id, user_name, |
| tmp_extra); |
| |
| xfree(tmp_extra); |
| xfree(cols); |
| xfree(extra); |
| xfree(vals); |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| rc = mysql_db_query(mysql_conn, query); |
| xfree(query); |
| if (rc != SLURM_SUCCESS) |
| error("Couldn't add txn"); |
| else |
| (*added)++; |
| |
| return rc; |
| } |
| |
| static int _add_clus_res(mysql_conn_t *mysql_conn, slurmdb_res_rec_t *res, |
| char *user_name, int *added) |
| { |
| char *cols = NULL, *extra = NULL, *vals = NULL, *query = NULL, |
| *tmp_extra = NULL, *name = NULL; |
| time_t now = time(NULL); |
| int rc = SLURM_SUCCESS, cluster_cnt; |
| slurmdb_clus_res_rec_t *object; |
| list_itr_t *itr; |
| uint32_t total_pos = 100; |
| char *percent_str = "%"; |
| |
| if (res->id == NO_VAL) { |
| error("We need a server resource name to add to."); |
| return SLURM_ERROR; |
| } else if (!res->clus_res_list |
| || !(cluster_cnt = list_count(res->clus_res_list))) { |
| error("No clusters given to add to %s@%s", |
| res->name, res->server); |
| return SLURM_ERROR; |
| } |
| |
| if (res->flags & SLURMDB_RES_FLAG_ABSOLUTE) { |
| total_pos = res->count; |
| percent_str = ""; |
| } |
| |
| xstrcat(cols, "creation_time, mod_time, " |
| "res_id, cluster, allowed"); |
| xstrfmtcat(vals, "%ld, %ld, '%u'", now, now, res->id); |
| |
| itr = list_iterator_create(res->clus_res_list); |
| while ((object = list_next(itr))) { |
| res->allocated += object->allowed; |
| if (res->allocated > total_pos) { |
| rc = ESLURM_OVER_ALLOCATE; |
| DB_DEBUG(DB_RES, mysql_conn->conn, |
| "Adding a new cluster with %u%s allowed to resource %s@%s would put the usage at %u%s, (which is more than possible). Please redo your math and resubmit.", |
| object->allowed, percent_str, res->name, |
| res->server, res->allocated, percent_str); |
| break; |
| } |
| xfree(extra); |
| xstrfmtcat(extra, ", mod_time=%ld, allowed=%u", |
| now, object->allowed); |
| xstrfmtcat(query, |
| "insert into %s (%s) values (%s, '%s', %u) " |
| "on duplicate key update deleted=0%s;", |
| clus_res_table, cols, vals, |
| object->cluster, object->allowed, extra); |
| |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| rc = mysql_db_query(mysql_conn, query); |
| xfree(query); |
| if (rc != SLURM_SUCCESS) { |
| error("Couldn't add cluster %s to resource %s@%s", |
| object->cluster, res->name, res->server); |
| (*added) = 0; |
| xfree(extra); |
| continue; |
| } |
| |
| /* we always have a ', ' as the first 2 chars */ |
| tmp_extra = slurm_add_slash_to_quotes(extra+2); |
| name = xstrdup_printf("%u@%s", res->id, object->cluster); |
| |
| xstrfmtcat(query, |
| "insert into %s " |
| "(timestamp, action, name, actor, info) " |
| "values (%ld, %u, '%s', '%s', '%s');", |
| txn_table, |
| now, DBD_ADD_RES, name, user_name, tmp_extra); |
| xfree(name); |
| xfree(tmp_extra); |
| xfree(extra); |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| rc = mysql_db_query(mysql_conn, query); |
| xfree(query); |
| if (rc != SLURM_SUCCESS) |
| error("Couldn't add txn"); |
| else { |
| slurmdb_res_rec_t *res_rec = |
| xmalloc(sizeof(slurmdb_res_rec_t)); |
| slurmdb_init_res_rec(res_rec, 0); |
| |
| res_rec->count = res->count; |
| if (res->last_consumed != NO_VAL) |
| res_rec->last_consumed = res->last_consumed; |
| else |
| res_rec->last_consumed = 0; |
| res_rec->flags = res->flags; |
| res_rec->id = res->id; |
| res_rec->name = xstrdup(res->name); |
| res_rec->server = xstrdup(res->server); |
| res_rec->type = res->type; |
| res_rec->last_update = now; |
| |
| res_rec->clus_res_rec = |
| xmalloc(sizeof(slurmdb_clus_res_rec_t)); |
| res_rec->clus_res_rec->cluster = |
| xstrdup(object->cluster); |
| res_rec->clus_res_rec->allowed = |
| object->allowed; |
| |
| if (addto_update_list(mysql_conn->update_list, |
| SLURMDB_ADD_RES, |
| res_rec) != SLURM_SUCCESS) |
| slurmdb_destroy_res_rec(res_rec); |
| else |
| (*added)++; |
| } |
| } |
| xfree(cols); |
| xfree(vals); |
| |
| return rc; |
| } |
| |
| static list_t *_get_clus_res(mysql_conn_t *mysql_conn, uint32_t res_id, |
| char *extra) |
| { |
| list_t *ret_list; |
| char *query = NULL, *tmp = NULL; |
| MYSQL_RES *result = NULL; |
| MYSQL_ROW row; |
| int i; |
| |
| /* if this changes you will need to edit the corresponding enum */ |
| char *res_req_inx[] = { |
| "cluster", |
| "allowed", |
| }; |
| enum { |
| RES_REQ_CLUSTER, |
| RES_REQ_PA, |
| RES_REQ_NUMBER, |
| }; |
| |
| xfree(tmp); |
| xstrfmtcat(tmp, "%s", res_req_inx[0]); |
| for(i=1; i<RES_REQ_NUMBER; i++) { |
| xstrfmtcat(tmp, ", %s", res_req_inx[i]); |
| } |
| |
| query = xstrdup_printf( |
| "select %s from %s as t2 where %s && (res_id=%u);", |
| tmp, clus_res_table, extra, res_id); |
| xfree(tmp); |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { |
| xfree(query); |
| return NULL; |
| } |
| xfree(query); |
| |
| if (!mysql_num_rows(result)) { |
| mysql_free_result(result); |
| return NULL; |
| } |
| |
| ret_list = list_create(slurmdb_destroy_clus_res_rec); |
| |
| while ((row = mysql_fetch_row(result))) { |
| slurmdb_clus_res_rec_t *clus_res_rec = |
| xmalloc(sizeof(slurmdb_clus_res_rec_t)); |
| |
| list_append(ret_list, clus_res_rec); |
| |
| if (row[0] && row[0][0]) |
| clus_res_rec->cluster = xstrdup(row[0]); |
| if (row[1] && row[1][0]) |
| clus_res_rec->allowed = slurm_atoul(row[1]); |
| } |
| mysql_free_result(result); |
| |
| return ret_list; |
| } |
| |
| extern int as_mysql_add_res(mysql_conn_t *mysql_conn, uint32_t uid, |
| list_t *res_list) |
| { |
| list_itr_t *itr = NULL; |
| int rc = SLURM_SUCCESS; |
| slurmdb_res_rec_t *object = NULL; |
| char *user_name = NULL; |
| int added = 0; |
| |
| if (check_connection(mysql_conn) != SLURM_SUCCESS) |
| return ESLURM_DB_CONNECTION; |
| |
| if (!is_user_min_admin_level(mysql_conn, uid, SLURMDB_ADMIN_SUPER_USER)) |
| return ESLURM_ACCESS_DENIED; |
| |
| if (!res_list || !list_count(res_list)) { |
| error("%s: Trying to add empty resource list", __func__); |
| return ESLURM_EMPTY_LIST; |
| } |
| |
| user_name = uid_to_string((uid_t) uid); |
| itr = list_iterator_create(res_list); |
| while ((object = list_next(itr))) { |
| if (object->id == NO_VAL) { |
| if (!object->name || !object->name[0]) { |
| error("We need a server resource name to add."); |
| rc = SLURM_ERROR; |
| continue; |
| } |
| if ((rc = _add_res(mysql_conn, object, |
| user_name, &added, itr)) |
| != SLURM_SUCCESS) |
| break; |
| |
| /* Since we are adding it make sure we don't |
| * over commit it on the clusters we add. |
| */ |
| object->allocated = 0; |
| } else { |
| if (_fill_in_res_rec(mysql_conn, object) != |
| SLURM_SUCCESS) { |
| rc = SLURM_ERROR; |
| error("Unknown id %u", object->id); |
| continue; |
| } |
| } |
| |
| if (object->clus_res_list |
| && list_count(object->clus_res_list)) { |
| if ((rc = _add_clus_res(mysql_conn, object, |
| user_name, &added)) |
| != SLURM_SUCCESS) |
| break; |
| } |
| } |
| list_iterator_destroy(itr); |
| xfree(user_name); |
| |
| if (!added) |
| reset_mysql_conn(mysql_conn); |
| |
| return rc; |
| } |
| |
| extern list_t *as_mysql_get_res(mysql_conn_t *mysql_conn, uid_t uid, |
| slurmdb_res_cond_t *res_cond) |
| { |
| char *query = NULL; |
| char *extra = NULL; |
| char *clus_extra = NULL; |
| char *tmp = NULL; |
| list_t *res_list = NULL; |
| int i=0; |
| MYSQL_RES *result = NULL; |
| MYSQL_ROW row; |
| |
| /* if this changes you will need to edit the corresponding enum */ |
| char *res_req_inx[] = { |
| "count", |
| "description", |
| "flags", |
| "id", |
| "last_consumed", |
| "manager", |
| "t1.mod_time", |
| "name", |
| "server", |
| "type", |
| "SUM(allowed)", |
| }; |
| enum { |
| RES_REQ_COUNT, |
| RES_REQ_DESC, |
| RES_REQ_FLAGS, |
| RES_REQ_ID, |
| RES_REQ_LAST_CONSUMED, |
| RES_REQ_MANAGER, |
| RES_REQ_MOD_TIME, |
| RES_REQ_NAME, |
| RES_REQ_SERVER, |
| RES_REQ_TYPE, |
| RES_REQ_PU, |
| RES_REQ_NUMBER, |
| }; |
| |
| if (check_connection(mysql_conn) != SLURM_SUCCESS) |
| return NULL; |
| |
| _setup_res_cond(res_cond, &extra); |
| |
| xfree(tmp); |
| xstrfmtcat(tmp, "%s", res_req_inx[0]); |
| for(i=1; i<RES_REQ_NUMBER; i++) { |
| xstrfmtcat(tmp, ", %s", res_req_inx[i]); |
| } |
| |
| query = xstrdup_printf("select distinct %s from %s as t1 " |
| "left outer join " |
| "%s as t2 on (res_id=id%s) %s group by " |
| "id", |
| tmp, res_table, clus_res_table, |
| (!res_cond || !res_cond->with_deleted) ? |
| " && t2.deleted=0" : "", |
| extra); |
| xfree(tmp); |
| xfree(extra); |
| |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { |
| xfree(query); |
| return NULL; |
| } |
| xfree(query); |
| |
| if (res_cond && res_cond->with_clusters) |
| _setup_clus_res_cond(res_cond, &clus_extra); |
| |
| res_list = list_create(slurmdb_destroy_res_rec); |
| while ((row = mysql_fetch_row(result))) { |
| uint32_t id = 0; |
| list_t *clus_res_list = NULL; |
| slurmdb_res_rec_t *res; |
| |
| if (row[RES_REQ_ID] && row[RES_REQ_ID][0]) |
| id = slurm_atoul(row[RES_REQ_ID]); |
| else { |
| error("as_mysql_get_res: no id? this " |
| "should never happen"); |
| continue; |
| } |
| |
| if (res_cond && res_cond->with_clusters) { |
| clus_res_list = _get_clus_res( |
| mysql_conn, id, clus_extra); |
| /* This means the clusters requested don't have |
| claim to this resource, so continue. */ |
| if (!clus_res_list && (res_cond->with_clusters == 1)) |
| continue; |
| } |
| |
| res = xmalloc(sizeof(slurmdb_res_rec_t)); |
| list_append(res_list, res); |
| |
| slurmdb_init_res_rec(res, 0); |
| |
| res->id = id; |
| res->clus_res_list = clus_res_list; |
| clus_res_list = NULL; |
| |
| if (row[RES_REQ_COUNT] && row[RES_REQ_COUNT][0]) |
| res->count = slurm_atoul(row[RES_REQ_COUNT]); |
| if (row[RES_REQ_LAST_CONSUMED] && row[RES_REQ_LAST_CONSUMED][0]) |
| res->last_consumed = |
| slurm_atoul(row[RES_REQ_LAST_CONSUMED]); |
| if (row[RES_REQ_DESC] && row[RES_REQ_DESC][0]) |
| res->description = xstrdup(row[RES_REQ_DESC]); |
| if (row[RES_REQ_FLAGS] && row[RES_REQ_FLAGS][0]) |
| res->flags = slurm_atoul(row[RES_REQ_FLAGS]); |
| if (row[RES_REQ_MANAGER] && row[RES_REQ_MANAGER][0]) |
| res->manager = xstrdup(row[RES_REQ_MANAGER]); |
| if (row[RES_REQ_MOD_TIME] && row[RES_REQ_MOD_TIME][0]) |
| res->last_update = slurm_atoul(row[RES_REQ_MOD_TIME]); |
| if (row[RES_REQ_NAME] && row[RES_REQ_NAME][0]) |
| res->name = xstrdup(row[RES_REQ_NAME]); |
| if (row[RES_REQ_SERVER] && row[RES_REQ_SERVER][0]) |
| res->server = xstrdup(row[RES_REQ_SERVER]); |
| if (row[RES_REQ_TYPE] && row[RES_REQ_TYPE][0]) |
| res->type = slurm_atoul(row[RES_REQ_TYPE]); |
| |
| if (row[RES_REQ_PU] && row[RES_REQ_PU][0]) |
| res->allocated = slurm_atoul(row[RES_REQ_PU]); |
| else |
| res->allocated = 0; |
| } |
| mysql_free_result(result); |
| xfree(clus_extra); |
| |
| return res_list; |
| } |
| |
| extern list_t *as_mysql_remove_res(mysql_conn_t *mysql_conn, uint32_t uid, |
| slurmdb_res_cond_t *res_cond) |
| { |
| list_t *ret_list = NULL; |
| char *name_char = NULL, *clus_char = NULL; |
| char *query = NULL, *extra = NULL, *clus_extra = NULL; |
| MYSQL_RES *result = NULL; |
| MYSQL_ROW row; |
| int query_clusters; |
| bool res_added = 0; |
| bool have_clusters = 0; |
| int last_res = -1; |
| remove_common_args_t args = { |
| .mysql_conn = mysql_conn, |
| .table = clus_res_table, |
| .type = DBD_REMOVE_CLUS_RES, |
| }; |
| |
| if (!res_cond) { |
| error("we need something to remove"); |
| return NULL; |
| } |
| |
| if (check_connection(mysql_conn) != SLURM_SUCCESS) |
| return NULL; |
| |
| if (!is_user_min_admin_level( |
| mysql_conn, uid, SLURMDB_ADMIN_SUPER_USER)) { |
| errno = ESLURM_ACCESS_DENIED; |
| return NULL; |
| } |
| /* force to only do non-deleted server resources */ |
| res_cond->with_deleted = 0; |
| |
| _setup_res_cond(res_cond, &extra); |
| query_clusters = _setup_clus_res_cond(res_cond, &clus_extra); |
| |
| query = xstrdup_printf("select id, name, server, cluster " |
| "from %s as t1 left outer join " |
| "%s as t2 on (res_id = id%s) %s && %s;", |
| res_table, clus_res_table, |
| (!res_cond || !res_cond->with_deleted) ? |
| " && t2.deleted=0" : "", |
| extra, clus_extra); |
| xfree(clus_extra); |
| |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { |
| xfree(query); |
| return NULL; |
| } |
| xfree(query); |
| |
| if (!mysql_num_rows(result)) { |
| mysql_free_result(result); |
| query_clusters = 0; |
| query = xstrdup_printf("select id, name, server " |
| "from %s as t1 %s;", |
| res_table, extra); |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { |
| xfree(query); |
| xfree(extra); |
| return NULL; |
| } |
| xfree(query); |
| } else |
| have_clusters = 1; |
| |
| xfree(extra); |
| |
| name_char = NULL; |
| ret_list = list_create(xfree_ptr); |
| while ((row = mysql_fetch_row(result))) { |
| char *name = NULL; |
| int curr_res = atoi(row[0]); |
| |
| if (last_res != curr_res) { |
| res_added = 0; |
| last_res = curr_res; |
| } |
| |
| if (query_clusters) { |
| xstrfmtcat(clus_char, |
| "%s(res_id='%s' && cluster='%s')", |
| clus_char ? " || " : "", row[0], row[3]); |
| } else { |
| if (!res_added) { |
| name = xstrdup_printf("%s@%s", row[1], row[2]); |
| list_append(ret_list, name); |
| res_added = 1; |
| name = NULL; |
| } |
| xstrfmtcat(name_char, "%sid='%s'", |
| name_char ? " || " : "", row[0]); |
| xstrfmtcat(clus_char, "%sres_id='%s'", |
| clus_char ? " || " : "", row[0]); |
| } |
| if (have_clusters && row[3] && row[3][0]) { |
| slurmdb_res_rec_t *res_rec = |
| xmalloc(sizeof(slurmdb_res_rec_t)); |
| slurmdb_init_res_rec(res_rec, 0); |
| res_rec->id = curr_res; |
| res_rec->clus_res_rec = |
| xmalloc(sizeof(slurmdb_clus_res_rec_t)); |
| res_rec->clus_res_rec->cluster = xstrdup(row[3]); |
| if (addto_update_list(mysql_conn->update_list, |
| SLURMDB_REMOVE_RES, res_rec) |
| != SLURM_SUCCESS) |
| slurmdb_destroy_res_rec(res_rec); |
| |
| name = xstrdup_printf("Cluster - %s\t- %s@%s", |
| row[3], row[1], row[2]); |
| } else if (!res_added) |
| name = xstrdup_printf("%s@%s", row[1], row[2]); |
| |
| if (name) |
| list_append(ret_list, name); |
| } |
| mysql_free_result(result); |
| |
| if (!list_count(ret_list)) { |
| errno = SLURM_NO_CHANGE_IN_DATA; |
| DB_DEBUG(DB_RES, mysql_conn->conn, |
| "didn't affect anything\n%s", query); |
| xfree(query); |
| xfree(name_char); |
| xfree(clus_extra); |
| return ret_list; |
| } |
| |
| xfree(query); |
| |
| args.name_char = clus_char; |
| args.user_name = uid_to_string((uid_t) uid); |
| args.now = time(NULL); |
| |
| if (query_clusters) { |
| remove_common(&args); |
| } else { |
| remove_common(&args); |
| |
| args.name_char = name_char; |
| args.table = res_table; |
| remove_common(&args); |
| } |
| |
| xfree(clus_char); |
| xfree(name_char); |
| xfree(args.user_name); |
| |
| return ret_list; |
| } |
| |
| extern list_t *as_mysql_modify_res(mysql_conn_t *mysql_conn, uint32_t uid, |
| slurmdb_res_cond_t *res_cond, |
| slurmdb_res_rec_t *res) |
| { |
| list_t *ret_list = NULL; |
| char *vals = NULL, *clus_vals = NULL; |
| time_t now = time(NULL); |
| char *user_name = NULL, *tmp = NULL, *col_names = NULL; |
| char *name_char = NULL, *clus_char = NULL; |
| char *query = NULL; |
| char *extra = NULL; |
| char *clus_extra = NULL; |
| MYSQL_RES *result = NULL; |
| MYSQL_ROW row; |
| int query_clusters = 0; |
| bool send_update = 0; |
| bool res_added = 0; |
| bool have_clusters = 0; |
| int last_res = -1; |
| uint32_t allocated = 0; |
| |
| /* if this changes you will need to edit the corresponding enum */ |
| char *res_req_inx[] = { |
| "id", |
| "name", |
| "server", |
| "flags", |
| "count", |
| }; |
| enum { |
| RES_REQ_ID, |
| RES_REQ_NAME, |
| RES_REQ_SERVER, |
| RES_REQ_FLAGS, |
| RES_REQ_COUNT, |
| RES_REQ_NUMBER |
| }; |
| |
| /* |
| * This will be added if we are looking for clusters so pretend it is |
| * added to the enum above. |
| */ |
| int RES_REQ_CLUSTER = RES_REQ_NUMBER; |
| |
| if (!res_cond || !res) { |
| error("we need something to change"); |
| return NULL; |
| } |
| |
| if (!is_user_min_admin_level(mysql_conn, uid, SLURMDB_ADMIN_OPERATOR)) { |
| errno = ESLURM_ACCESS_DENIED; |
| return NULL; |
| } |
| |
| if (check_connection(mysql_conn) != SLURM_SUCCESS) { |
| return NULL; |
| } |
| |
| _setup_res_limits(res, NULL, &tmp, &vals, 0, &send_update); |
| |
| xfree(tmp); |
| |
| /* overloaded for easibility */ |
| if (res->allocated != NO_VAL) { |
| xstrfmtcat(clus_vals, ", allowed=%u", res->allocated); |
| send_update = 1; |
| query_clusters++; |
| } |
| |
| if (!vals && !clus_vals) { |
| errno = SLURM_NO_CHANGE_IN_DATA; |
| error("Nothing to change"); |
| return NULL; |
| } |
| |
| /* force to only do non-deleted resources */ |
| res_cond->with_deleted = 0; |
| _setup_res_cond(res_cond, &extra); |
| query_clusters += _setup_clus_res_cond(res_cond, &clus_extra); |
| |
| xfree(col_names); |
| xstrfmtcat(col_names, "%s", res_req_inx[0]); |
| for (int i = 1; i < RES_REQ_NUMBER; i++) { |
| xstrfmtcat(col_names, ", %s", res_req_inx[i]); |
| } |
| |
| if (query_clusters || send_update) |
| query = xstrdup_printf("select %s, cluster " |
| "from %s as t1 left outer join " |
| "%s as t2 on (res_id = id%s) %s && %s;", |
| col_names, res_table, clus_res_table, |
| (!res_cond || !res_cond->with_deleted) ? |
| " && t2.deleted=0" : "", |
| extra, clus_extra); |
| else |
| query = xstrdup_printf("select %s from %s as t1 %s;", |
| col_names, res_table, extra); |
| |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { |
| xfree(col_names); |
| xfree(extra); |
| xfree(vals); |
| xfree(clus_extra); |
| xfree(clus_vals); |
| xfree(query); |
| return NULL; |
| } |
| |
| if (!mysql_num_rows(result)) { |
| xfree(query); |
| mysql_free_result(result); |
| result = NULL; |
| /* since no clusters are there no reason to send |
| updates */ |
| query_clusters = 0; |
| send_update = 0; |
| } else |
| have_clusters = 1; |
| |
| if (!query_clusters && !vals) { |
| xfree(col_names); |
| xfree(clus_vals); |
| if (result) |
| mysql_free_result(result); |
| errno = SLURM_NO_CHANGE_IN_DATA; |
| error("Nothing to change"); |
| return NULL; |
| } |
| |
| if (!result) { |
| query = xstrdup_printf("select %s from %s as t1 %s;", |
| col_names, res_table, extra); |
| DB_DEBUG(DB_RES, mysql_conn->conn, "query\n%s", query); |
| if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) { |
| xfree(col_names); |
| xfree(extra); |
| xfree(vals); |
| xfree(clus_extra); |
| xfree(clus_vals); |
| xfree(query); |
| return NULL; |
| } |
| } |
| |
| xfree(col_names); |
| xfree(extra); |
| |
| name_char = NULL; |
| ret_list = list_create(xfree_ptr); |
| while ((row = mysql_fetch_row(result))) { |
| char *name = NULL; |
| int curr_res = atoi(row[RES_REQ_ID]); |
| uint32_t total_pos = 100; |
| char *percent_str = "%"; |
| |
| if ((res->flags & SLURMDB_RES_FLAG_ABSOLUTE) && |
| (res->flags & SLURMDB_RES_FLAG_REMOVE)) { |
| } else if ((res->flags & SLURMDB_RES_FLAG_ABSOLUTE) || |
| (slurm_atoul(row[RES_REQ_FLAGS]) & |
| SLURMDB_RES_FLAG_ABSOLUTE)) { |
| total_pos = slurm_atoul(row[RES_REQ_COUNT]); |
| percent_str = ""; |
| } |
| |
| if (last_res != curr_res) { |
| res_added = 0; |
| last_res = curr_res; |
| |
| if (have_clusters && (res->allocated != NO_VAL)) { |
| allocated = _get_res_used( |
| mysql_conn, curr_res, clus_extra); |
| |
| if (allocated == NO_VAL) |
| allocated = 0; |
| } |
| } |
| |
| if (query_clusters) { |
| xstrfmtcat(clus_char, |
| "%s(res_id='%s' && cluster='%s')", |
| clus_char ? " || " : "", |
| row[RES_REQ_ID], |
| row[RES_REQ_CLUSTER]); |
| } else { |
| if (!res_added) { |
| name = xstrdup_printf("%s@%s", |
| row[RES_REQ_NAME], |
| row[RES_REQ_SERVER]); |
| list_append(ret_list, name); |
| res_added = 1; |
| name = NULL; |
| } |
| xstrfmtcat(name_char, "%sid='%s'", |
| name_char ? " || " : "", row[RES_REQ_ID]); |
| xstrfmtcat(clus_char, "%sres_id='%s'", |
| clus_char ? " || " : "", row[RES_REQ_ID]); |
| } |
| if (have_clusters && |
| row[RES_REQ_CLUSTER] && |
| row[RES_REQ_CLUSTER][0]) { |
| slurmdb_res_rec_t *res_rec; |
| |
| if (res->allocated != NO_VAL) |
| allocated += res->allocated; |
| if (allocated > total_pos) { |
| DB_DEBUG(DB_RES, mysql_conn->conn, |
| "Modifying resource %s@%s with %u%s allowed to each cluster would put the usage at %u%s, (which is more than possible). Please redo your math and resubmit.", |
| row[RES_REQ_NAME], row[RES_REQ_SERVER], |
| res->allocated, percent_str, |
| allocated, percent_str); |
| |
| mysql_free_result(result); |
| xfree(clus_extra); |
| xfree(query); |
| xfree(vals); |
| xfree(name_char); |
| xfree(clus_char); |
| FREE_NULL_LIST(ret_list); |
| errno = ESLURM_OVER_ALLOCATE; |
| |
| return NULL; |
| } |
| |
| res_rec = xmalloc(sizeof(slurmdb_res_rec_t)); |
| slurmdb_init_res_rec(res_rec, 0); |
| res_rec->count = res->count; |
| res_rec->flags = res->flags; |
| res_rec->id = curr_res; |
| res_rec->last_consumed = res->last_consumed; |
| res_rec->type = res->type; |
| res_rec->last_update = now; |
| |
| res_rec->clus_res_rec = |
| xmalloc(sizeof(slurmdb_clus_res_rec_t)); |
| res_rec->clus_res_rec->cluster = |
| xstrdup(row[RES_REQ_CLUSTER]); |
| res_rec->clus_res_rec->allowed = res->allocated; |
| if (addto_update_list(mysql_conn->update_list, |
| SLURMDB_MODIFY_RES, res_rec) |
| != SLURM_SUCCESS) |
| slurmdb_destroy_res_rec(res_rec); |
| |
| name = xstrdup_printf("Cluster - %s\t- %s@%s", |
| row[RES_REQ_CLUSTER], |
| row[RES_REQ_NAME], |
| row[RES_REQ_SERVER]); |
| } else if (!res_added) |
| name = xstrdup_printf("%s@%s", |
| row[RES_REQ_NAME], |
| row[RES_REQ_SERVER]); |
| |
| if (name) |
| list_append(ret_list, name); |
| } |
| mysql_free_result(result); |
| |
| xfree(clus_extra); |
| |
| if (!list_count(ret_list)) { |
| errno = SLURM_NO_CHANGE_IN_DATA; |
| DB_DEBUG(DB_RES, mysql_conn->conn, |
| "didn't affect anything\n%s", query); |
| xfree(query); |
| xfree(vals); |
| xfree(name_char); |
| xfree(clus_char); |
| |
| return ret_list; |
| } |
| xfree(query); |
| |
| user_name = uid_to_string((uid_t) uid); |
| if (query_clusters) { |
| modify_common(mysql_conn, DBD_MODIFY_CLUS_RES, |
| now, user_name, clus_res_table, |
| clus_char, clus_vals, NULL); |
| } else { |
| if (clus_char && clus_vals) { |
| modify_common(mysql_conn, DBD_MODIFY_CLUS_RES, |
| now, user_name, clus_res_table, |
| clus_char, clus_vals, NULL); |
| } |
| modify_common(mysql_conn, DBD_MODIFY_RES, |
| now, user_name, res_table, |
| name_char, vals, NULL); |
| } |
| |
| xfree(vals); |
| xfree(clus_vals); |
| xfree(clus_char); |
| xfree(name_char); |
| xfree(user_name); |
| |
| return ret_list; |
| } |