blob: 21e82a4a2c7b8e67f3e27f6ff4c04d66e785c87d [file]
/*****************************************************************************\
* as_mysql_acct.c - functions dealing with accounts.
*****************************************************************************
*
* Copyright (C) 2004-2007 The Regents of the University of California.
* Copyright (C) 2008-2010 Lawrence Livermore National Security.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Danny Auble <da@llnl.gov>
*
* This file is part of SLURM, a resource management program.
* For details, see <http://www.schedmd.com/slurmdocs/>.
* 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_acct.h"
#include "as_mysql_user.h"
/* Fill in all the users that are coordinator for this account. This
* will fill in if there are coordinators from a parent account also.
*/
static int _get_account_coords(mysql_conn_t *mysql_conn,
slurmdb_account_rec_t *acct)
{
char *query = NULL, *cluster_name = NULL;
slurmdb_coord_rec_t *coord = NULL;
MYSQL_RES *result = NULL;
MYSQL_ROW row;
ListIterator itr;
if (!acct) {
error("We need a account to fill in.");
return SLURM_ERROR;
}
if (!acct->coordinators)
acct->coordinators = list_create(slurmdb_destroy_coord_rec);
query = xstrdup_printf(
"select user from %s where acct='%s' && deleted=0",
acct_coord_table, acct->name);
if (!(result =
mysql_db_query_ret(mysql_conn, query, 0))) {
xfree(query);
return SLURM_ERROR;
}
xfree(query);
while ((row = mysql_fetch_row(result))) {
coord = xmalloc(sizeof(slurmdb_coord_rec_t));
list_append(acct->coordinators, coord);
coord->name = xstrdup(row[0]);
coord->direct = 1;
}
mysql_free_result(result);
slurm_mutex_lock(&as_mysql_cluster_list_lock);
itr = list_iterator_create(as_mysql_cluster_list);
while ((cluster_name = list_next(itr))) {
if (query)
xstrcat(query, " union ");
xstrfmtcat(query,
"select distinct t0.user from %s as t0, "
"\"%s_%s\" as t1, \"%s_%s\" as t2 "
"where t0.acct=t1.acct && "
"t1.lft<t2.lft && t1.rgt>t2.lft && "
"t1.user='' && t2.acct='%s' "
"&& t1.acct!='%s' && !t0.deleted",
acct_coord_table, cluster_name, assoc_table,
cluster_name, assoc_table,
acct->name, acct->name);
}
list_iterator_destroy(itr);
slurm_mutex_unlock(&as_mysql_cluster_list_lock);
if (!query) {
error("No clusters defined? How could there be accts?");
return SLURM_SUCCESS;
}
xstrcat(query, ";");
if (!(result = mysql_db_query_ret(mysql_conn, query, 0))) {
xfree(query);
return SLURM_ERROR;
}
xfree(query);
while ((row = mysql_fetch_row(result))) {
coord = xmalloc(sizeof(slurmdb_coord_rec_t));
list_append(acct->coordinators, coord);
coord->name = xstrdup(row[0]);
coord->direct = 0;
}
mysql_free_result(result);
return SLURM_SUCCESS;
}
extern int as_mysql_add_accts(mysql_conn_t *mysql_conn, uint32_t uid,
List acct_list)
{
ListIterator itr = NULL;
int rc = SLURM_SUCCESS;
slurmdb_account_rec_t *object = NULL;
char *cols = NULL, *vals = NULL, *query = NULL, *txn_query = NULL;
time_t now = time(NULL);
char *user_name = NULL;
char *extra = NULL, *tmp_extra = NULL;
int affect_rows = 0;
List assoc_list = list_create(slurmdb_destroy_association_rec);
if (check_connection(mysql_conn) != SLURM_SUCCESS)
return ESLURM_DB_CONNECTION;
user_name = uid_to_string((uid_t) uid);
itr = list_iterator_create(acct_list);
while ((object = list_next(itr))) {
if (!object->name || !object->name[0]
|| !object->description || !object->description[0]
|| !object->organization || !object->organization[0]) {
error("We need an account name, description, and "
"organization to add. %s %s %s",
object->name, object->description,
object->organization);
rc = SLURM_ERROR;
continue;
}
xstrcat(cols, "creation_time, mod_time, name, "
"description, organization");
xstrfmtcat(vals, "%ld, %ld, '%s', '%s', '%s'",
now, now, object->name,
object->description, object->organization);
xstrfmtcat(extra, ", description='%s', organization='%s'",
object->description, object->organization);
query = xstrdup_printf(
"insert into %s (%s) values (%s) "
"on duplicate key update deleted=0, mod_time=%ld %s;",
acct_table, cols, vals,
now, extra);
debug3("%d(%s:%d) query\n%s",
mysql_conn->conn, THIS_FILE, __LINE__, query);
rc = mysql_db_query(mysql_conn, query);
xfree(cols);
xfree(vals);
xfree(query);
if (rc != SLURM_SUCCESS) {
error("Couldn't add acct");
xfree(extra);
continue;
}
affect_rows = last_affected_rows(mysql_conn);
/* debug3("affected %d", affect_rows); */
if (!affect_rows) {
debug3("nothing changed");
xfree(extra);
continue;
}
/* we always have a ', ' as the first 2 chars */
tmp_extra = slurm_add_slash_to_quotes(extra+2);
if (txn_query)
xstrfmtcat(txn_query,
", (%ld, %u, '%s', '%s', '%s')",
now, DBD_ADD_ACCOUNTS, object->name,
user_name, tmp_extra);
else
xstrfmtcat(txn_query,
"insert into %s "
"(timestamp, action, name, actor, info) "
"values (%ld, %u, '%s', '%s', '%s')",
txn_table,
now, DBD_ADD_ACCOUNTS, object->name,
user_name, tmp_extra);
xfree(tmp_extra);
xfree(extra);
if (!object->assoc_list)
continue;
list_transfer(assoc_list, object->assoc_list);
}
list_iterator_destroy(itr);
xfree(user_name);
if (rc != SLURM_ERROR) {
if (txn_query) {
xstrcat(txn_query, ";");
rc = mysql_db_query(mysql_conn,
txn_query);
xfree(txn_query);
if (rc != SLURM_SUCCESS) {
error("Couldn't add txn");
rc = SLURM_SUCCESS;
}
}
} else
xfree(txn_query);
if (list_count(assoc_list)) {
if (as_mysql_add_assocs(mysql_conn, uid, assoc_list)
== SLURM_ERROR) {
error("Problem adding user associations");
rc = SLURM_ERROR;
}
}
list_destroy(assoc_list);
return rc;
}
extern List as_mysql_modify_accts(mysql_conn_t *mysql_conn, uint32_t uid,
slurmdb_account_cond_t *acct_cond,
slurmdb_account_rec_t *acct)
{
ListIterator itr = NULL;
List ret_list = NULL;
int rc = SLURM_SUCCESS;
char *object = NULL;
char *vals = NULL, *extra = NULL, *query = NULL, *name_char = NULL;
time_t now = time(NULL);
char *user_name = NULL;
int set = 0;
MYSQL_RES *result = NULL;
MYSQL_ROW row;
if (!acct_cond || !acct) {
error("we need something to change");
return NULL;
}
if (check_connection(mysql_conn) != SLURM_SUCCESS)
return NULL;
xstrcat(extra, "where deleted=0");
if (acct_cond->assoc_cond
&& acct_cond->assoc_cond->acct_list
&& list_count(acct_cond->assoc_cond->acct_list)) {
set = 0;
xstrcat(extra, " && (");
itr = list_iterator_create(acct_cond->assoc_cond->acct_list);
while ((object = list_next(itr))) {
if (set)
xstrcat(extra, " || ");
xstrfmtcat(extra, "name='%s'", object);
set = 1;
}
list_iterator_destroy(itr);
xstrcat(extra, ")");
}
if (acct_cond->description_list
&& list_count(acct_cond->description_list)) {
set = 0;
xstrcat(extra, " && (");
itr = list_iterator_create(acct_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 (acct_cond->organization_list
&& list_count(acct_cond->organization_list)) {
set = 0;
xstrcat(extra, " && (");
itr = list_iterator_create(acct_cond->organization_list);
while ((object = list_next(itr))) {
if (set)
xstrcat(extra, " || ");
xstrfmtcat(extra, "organization='%s'", object);
set = 1;
}
list_iterator_destroy(itr);
xstrcat(extra, ")");
}
if (acct->description)
xstrfmtcat(vals, ", description='%s'", acct->description);
if (acct->organization)
xstrfmtcat(vals, ", organization='%s'", acct->organization);
if (!extra || !vals) {
errno = SLURM_NO_CHANGE_IN_DATA;
error("Nothing to change");
return NULL;
}
query = xstrdup_printf("select name from %s %s;", acct_table, extra);
xfree(extra);
debug3("%d(%s:%d) query\n%s",
mysql_conn->conn, THIS_FILE, __LINE__, query);
if (!(result = mysql_db_query_ret(
mysql_conn, query, 0))) {
xfree(query);
xfree(vals);
return NULL;
}
rc = 0;
ret_list = list_create(slurm_destroy_char);
while ((row = mysql_fetch_row(result))) {
object = xstrdup(row[0]);
list_append(ret_list, object);
if (!rc) {
xstrfmtcat(name_char, "(name='%s'", object);
rc = 1;
} else {
xstrfmtcat(name_char, " || name='%s'", object);
}
}
mysql_free_result(result);
if (!list_count(ret_list)) {
errno = SLURM_NO_CHANGE_IN_DATA;
debug3("didn't effect anything\n%s", query);
xfree(query);
xfree(vals);
return ret_list;
}
xfree(query);
xstrcat(name_char, ")");
user_name = uid_to_string((uid_t) uid);
rc = modify_common(mysql_conn, DBD_MODIFY_ACCOUNTS, now,
user_name, acct_table, name_char, vals, NULL);
xfree(user_name);
if (rc == SLURM_ERROR) {
error("Couldn't modify accounts");
list_destroy(ret_list);
errno = SLURM_ERROR;
ret_list = NULL;
}
xfree(name_char);
xfree(vals);
return ret_list;
}
extern List as_mysql_remove_accts(mysql_conn_t *mysql_conn, uint32_t uid,
slurmdb_account_cond_t *acct_cond)
{
ListIterator itr = NULL;
List ret_list = NULL;
List coord_list = NULL;
int rc = SLURM_SUCCESS;
char *object = NULL;
char *extra = NULL, *query = NULL,
*name_char = NULL, *assoc_char = NULL;
time_t now = time(NULL);
char *user_name = NULL;
int set = 0;
MYSQL_RES *result = NULL;
MYSQL_ROW row;
bool jobs_running = 0;
if (!acct_cond) {
error("we need something to change");
return NULL;
}
if (check_connection(mysql_conn) != SLURM_SUCCESS)
return NULL;
xstrcat(extra, "where deleted=0");
if (acct_cond->assoc_cond
&& acct_cond->assoc_cond->acct_list
&& list_count(acct_cond->assoc_cond->acct_list)) {
set = 0;
xstrcat(extra, " && (");
itr = list_iterator_create(acct_cond->assoc_cond->acct_list);
while ((object = list_next(itr))) {
if (!object[0])
continue;
if (set)
xstrcat(extra, " || ");
xstrfmtcat(extra, "name='%s'", object);
set = 1;
}
list_iterator_destroy(itr);
xstrcat(extra, ")");
}
if (acct_cond->description_list
&& list_count(acct_cond->description_list)) {
set = 0;
xstrcat(extra, " && (");
itr = list_iterator_create(acct_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 (acct_cond->organization_list
&& list_count(acct_cond->organization_list)) {
set = 0;
xstrcat(extra, " && (");
itr = list_iterator_create(acct_cond->organization_list);
while ((object = list_next(itr))) {
if (set)
xstrcat(extra, " || ");
xstrfmtcat(extra, "organization='%s'", object);
set = 1;
}
list_iterator_destroy(itr);
xstrcat(extra, ")");
}
if (!extra) {
error("Nothing to remove");
return NULL;
}
query = xstrdup_printf("select name from %s %s;", acct_table, extra);
xfree(extra);
if (!(result = mysql_db_query_ret(
mysql_conn, query, 0))) {
xfree(query);
return NULL;
}
rc = 0;
ret_list = list_create(slurm_destroy_char);
while ((row = mysql_fetch_row(result))) {
char *object = xstrdup(row[0]);
list_append(ret_list, object);
if (!rc) {
xstrfmtcat(name_char, "name='%s'", object);
xstrfmtcat(assoc_char, "t2.acct='%s'", object);
rc = 1;
} else {
xstrfmtcat(name_char, " || name='%s'", object);
xstrfmtcat(assoc_char, " || t2.acct='%s'", object);
}
}
mysql_free_result(result);
if (!list_count(ret_list)) {
errno = SLURM_NO_CHANGE_IN_DATA;
debug3("didn't effect anything\n%s", query);
xfree(query);
return ret_list;
}
xfree(query);
/* We need to remove these accounts from the coord's that have it */
coord_list = as_mysql_remove_coord(
mysql_conn, uid, ret_list, NULL);
if (coord_list)
list_destroy(coord_list);
user_name = uid_to_string((uid_t) uid);
slurm_mutex_lock(&as_mysql_cluster_list_lock);
itr = list_iterator_create(as_mysql_cluster_list);
while ((object = list_next(itr))) {
if ((rc = remove_common(mysql_conn, DBD_REMOVE_ACCOUNTS, now,
user_name, acct_table, name_char,
assoc_char, object, ret_list,
&jobs_running))
!= SLURM_SUCCESS)
break;
}
list_iterator_destroy(itr);
slurm_mutex_unlock(&as_mysql_cluster_list_lock);
xfree(user_name);
xfree(name_char);
xfree(assoc_char);
if (rc == SLURM_ERROR) {
list_destroy(ret_list);
return NULL;
}
if (jobs_running)
errno = ESLURM_JOBS_RUNNING_ON_ASSOC;
else
errno = SLURM_SUCCESS;
return ret_list;
}
extern List as_mysql_get_accts(mysql_conn_t *mysql_conn, uid_t uid,
slurmdb_account_cond_t *acct_cond)
{
char *query = NULL;
char *extra = NULL;
char *tmp = NULL;
List acct_list = NULL;
ListIterator itr = NULL;
char *object = NULL;
int set = 0;
int i=0, is_admin=1;
MYSQL_RES *result = NULL;
MYSQL_ROW row;
uint16_t private_data = 0;
slurmdb_user_rec_t user;
/* if this changes you will need to edit the corresponding enum */
char *acct_req_inx[] = {
"name",
"description",
"organization"
};
enum {
SLURMDB_REQ_NAME,
SLURMDB_REQ_DESC,
SLURMDB_REQ_ORG,
SLURMDB_REQ_COUNT
};
if (check_connection(mysql_conn) != SLURM_SUCCESS)
return NULL;
memset(&user, 0, sizeof(slurmdb_user_rec_t));
user.uid = uid;
private_data = slurm_get_private_data();
if (private_data & PRIVATE_DATA_ACCOUNTS) {
if (!(is_admin = is_user_min_admin_level(
mysql_conn, uid, SLURMDB_ADMIN_OPERATOR))) {
if (!is_user_any_coord(mysql_conn, &user)) {
error("Only admins/coordinators "
"can look at account usage");
errno = ESLURM_ACCESS_DENIED;
return NULL;
}
}
}
if (!acct_cond) {
xstrcat(extra, "where deleted=0");
goto empty;
}
if (acct_cond->with_deleted)
xstrcat(extra, "where (deleted=0 || deleted=1)");
else
xstrcat(extra, "where deleted=0");
if (acct_cond->assoc_cond
&& acct_cond->assoc_cond->acct_list
&& list_count(acct_cond->assoc_cond->acct_list)) {
set = 0;
xstrcat(extra, " && (");
itr = list_iterator_create(acct_cond->assoc_cond->acct_list);
while ((object = list_next(itr))) {
if (set)
xstrcat(extra, " || ");
xstrfmtcat(extra, "name='%s'", object);
set = 1;
}
list_iterator_destroy(itr);
xstrcat(extra, ")");
}
if (acct_cond->description_list
&& list_count(acct_cond->description_list)) {
set = 0;
xstrcat(extra, " && (");
itr = list_iterator_create(acct_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 (acct_cond->organization_list
&& list_count(acct_cond->organization_list)) {
set = 0;
xstrcat(extra, " && (");
itr = list_iterator_create(acct_cond->organization_list);
while ((object = list_next(itr))) {
if (set)
xstrcat(extra, " || ");
xstrfmtcat(extra, "organization='%s'", object);
set = 1;
}
list_iterator_destroy(itr);
xstrcat(extra, ")");
}
empty:
xfree(tmp);
xstrfmtcat(tmp, "%s", acct_req_inx[i]);
for(i=1; i<SLURMDB_REQ_COUNT; i++) {
xstrfmtcat(tmp, ", %s", acct_req_inx[i]);
}
/* This is here to make sure we are looking at only this user
* if this flag is set. We also include any accounts they may be
* coordinator of.
*/
if (!is_admin && (private_data & PRIVATE_DATA_ACCOUNTS)) {
slurmdb_coord_rec_t *coord = NULL;
set = 0;
itr = list_iterator_create(user.coord_accts);
while ((coord = list_next(itr))) {
if (set) {
xstrfmtcat(extra, " || name='%s'",
coord->name);
} else {
set = 1;
xstrfmtcat(extra, " && (name='%s'",
coord->name);
}
}
list_iterator_destroy(itr);
if (set)
xstrcat(extra,")");
}
query = xstrdup_printf("select %s from %s %s", tmp, acct_table, extra);
xfree(tmp);
xfree(extra);
debug3("%d(%s:%d) query\n%s",
mysql_conn->conn, THIS_FILE, __LINE__, query);
if (!(result = mysql_db_query_ret(
mysql_conn, query, 0))) {
xfree(query);
return NULL;
}
xfree(query);
acct_list = list_create(slurmdb_destroy_account_rec);
if (acct_cond && acct_cond->with_assocs) {
/* We are going to be freeing the inners of
this list in the acct->name so we don't
free it here
*/
if (acct_cond->assoc_cond->acct_list)
list_destroy(acct_cond->assoc_cond->acct_list);
acct_cond->assoc_cond->acct_list = list_create(NULL);
acct_cond->assoc_cond->with_deleted = acct_cond->with_deleted;
}
while ((row = mysql_fetch_row(result))) {
slurmdb_account_rec_t *acct =
xmalloc(sizeof(slurmdb_account_rec_t));
list_append(acct_list, acct);
acct->name = xstrdup(row[SLURMDB_REQ_NAME]);
acct->description = xstrdup(row[SLURMDB_REQ_DESC]);
acct->organization = xstrdup(row[SLURMDB_REQ_ORG]);
if (acct_cond && acct_cond->with_coords) {
_get_account_coords(mysql_conn, acct);
}
if (acct_cond && acct_cond->with_assocs) {
if (!acct_cond->assoc_cond) {
acct_cond->assoc_cond = xmalloc(
sizeof(slurmdb_association_cond_t));
}
list_append(acct_cond->assoc_cond->acct_list,
acct->name);
}
}
mysql_free_result(result);
if (acct_cond && acct_cond->with_assocs
&& list_count(acct_cond->assoc_cond->acct_list)) {
ListIterator assoc_itr = NULL;
slurmdb_account_rec_t *acct = NULL;
slurmdb_association_rec_t *assoc = NULL;
List assoc_list = as_mysql_get_assocs(
mysql_conn, uid, acct_cond->assoc_cond);
if (!assoc_list) {
error("no associations");
return acct_list;
}
itr = list_iterator_create(acct_list);
assoc_itr = list_iterator_create(assoc_list);
while ((acct = list_next(itr))) {
while ((assoc = list_next(assoc_itr))) {
if (strcmp(assoc->acct, acct->name))
continue;
if (!acct->assoc_list)
acct->assoc_list = list_create(
slurmdb_destroy_association_rec);
list_append(acct->assoc_list, assoc);
list_remove(assoc_itr);
}
list_iterator_reset(assoc_itr);
if (!acct->assoc_list)
list_remove(itr);
}
list_iterator_destroy(itr);
list_iterator_destroy(assoc_itr);
list_destroy(assoc_list);
}
return acct_list;
}