blob: 298b71bd5a7dc39c81c58a803558b520e9fd9476 [file] [log] [blame]
/*****************************************************************************\
* jobcomp_mysql.c - Store/Get all information in a mysql storage.
*****************************************************************************
* Copyright (C) 2004-2007 The Regents of the University of California.
* Copyright (C) 2008-2009 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 <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.
\*****************************************************************************/
/*
* We can't include common/slurm_xlator.h here since it contains
* list_push and list_pop which are mysql macros what for some reason
* are given to us. So if you need something from the header just
* copy it here.
*/
#define error slurm_error
#include "mysql_jobcomp_process.h"
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include "src/common/id_util.h"
#include "src/common/parse_time.h"
#include "src/interfaces/select.h"
/*
* These variables are required by the generic plugin interface. If they
* are not found in the plugin, the plugin loader will ignore it.
*
* plugin_name - a string giving a human-readable description of the
* plugin. There is no maximum length, but the symbol must refer to
* a valid string.
*
* plugin_type - a string suggesting the type of the plugin or its
* applicability to a particular form of data or method of data handling.
* If the low-level plugin API is used, the contents of this string are
* unimportant and may be anything. Slurm uses the higher-level plugin
* interface which requires this string to be of the form
*
* <application>/<method>
*
* where <application> is a description of the intended application of
* the plugin (e.g., "jobacct" for Slurm job completion logging) and <method>
* is a description of how this plugin satisfies that application. Slurm will
* only load job completion logging plugins if the plugin_type string has a
* prefix of "jobacct/".
*
* plugin_version - an unsigned 32-bit integer containing the Slurm version
* (major.minor.micro combined into a single number).
*/
const char plugin_name[] = "Job completion MYSQL plugin";
const char plugin_type[] = "jobcomp/mysql";
const uint32_t plugin_version = SLURM_VERSION_NUMBER;
const char default_job_comp_loc[] = "slurm_jobcomp_db";
mysql_conn_t *jobcomp_mysql_conn = NULL;
char *jobcomp_table = "jobcomp_table";
storage_field_t jobcomp_table_fields[] = {
{ "jobid", "int not null" },
{ "uid", "int unsigned not null" },
{ "user_name", "tinytext not null" },
{ "gid", "int unsigned not null" },
{ "group_name", "tinytext not null" },
{ "name", "tinytext not null" },
{ "state", "int unsigned not null" },
{ "partition", "tinytext not null" },
{ "timelimit", "tinytext not null" },
{ "starttime", "int unsigned default 0 not null" },
{ "endtime", "int unsigned default 0 not null" },
{ "nodelist", "text" },
{ "nodecnt", "int unsigned not null" },
{ "proc_cnt", "int unsigned not null" },
{ "connect_type", "tinytext" },
{ "reboot", "tinytext" },
{ "rotate", "tinytext" },
{ "maxprocs", "int unsigned default 0 not null" },
{ "geometry", "tinytext" },
{ "start", "tinytext" },
{ "blockid", "tinytext" },
{ NULL, NULL}
};
static int _mysql_jobcomp_check_tables()
{
if (mysql_db_create_table(jobcomp_mysql_conn, jobcomp_table,
jobcomp_table_fields,
", primary key (jobid, starttime, endtime))")
== SLURM_ERROR)
return SLURM_ERROR;
return SLURM_SUCCESS;
}
extern int init(void)
{
static int first = 1;
if (first) {
/* since this can be loaded from many different places
only tell us once. */
verbose("%s loaded", plugin_name);
first = 0;
} else {
debug4("%s loaded", plugin_name);
}
return SLURM_SUCCESS;
}
extern void fini(void)
{
if (jobcomp_mysql_conn) {
destroy_mysql_conn(jobcomp_mysql_conn);
jobcomp_mysql_conn = NULL;
}
}
extern int jobcomp_p_set_location(void)
{
mysql_db_info_t *db_info;
int rc = SLURM_SUCCESS;
char *db_name = NULL;
if (jobcomp_mysql_conn && mysql_db_ping(jobcomp_mysql_conn) == 0)
return SLURM_SUCCESS;
if (!slurm_conf.job_comp_loc) {
slurm_conf.job_comp_loc = xstrdup(default_job_comp_loc);
db_name = slurm_conf.job_comp_loc;
} else {
if (xstrchr(slurm_conf.job_comp_loc, '.') ||
xstrchr(slurm_conf.job_comp_loc, '/')) {
debug("%s doesn't look like a database name using %s",
slurm_conf.job_comp_loc, default_job_comp_loc);
db_name = (char *) default_job_comp_loc;
} else
db_name = slurm_conf.job_comp_loc;
}
debug2("mysql_connect() called for db %s", db_name);
/* Just make sure our connection is gone. */
fini();
jobcomp_mysql_conn = create_mysql_conn(0, 0, NULL);
db_info = create_mysql_db_info(SLURM_MYSQL_PLUGIN_JC);
mysql_db_get_db_connection(jobcomp_mysql_conn, db_name, db_info);
rc = _mysql_jobcomp_check_tables();
destroy_mysql_db_info(db_info);
if (rc == SLURM_SUCCESS)
debug("Jobcomp database init finished");
else
debug("Jobcomp database init failed");
return rc;
}
extern int jobcomp_p_record_job_end(job_record_t *job_ptr, uint32_t event)
{
int rc = SLURM_SUCCESS;
char *usr_str = NULL, *grp_str = NULL, lim_str[32], *jname = NULL;
char *partition = NULL;
uint32_t job_state;
char *query = NULL, *on_dup = NULL;
uint32_t time_limit;
time_t start_time, end_time;
if (!jobcomp_mysql_conn || mysql_db_ping(jobcomp_mysql_conn) != 0) {
if (jobcomp_p_set_location())
return SLURM_ERROR;
}
usr_str = user_from_job(job_ptr);
grp_str = group_from_job(job_ptr);
partition = job_ptr->part_ptr ? job_ptr->part_ptr->name :
job_ptr->partition;
if ((job_ptr->time_limit == NO_VAL) && job_ptr->part_ptr)
time_limit = job_ptr->part_ptr->max_time;
else
time_limit = job_ptr->time_limit;
if (time_limit == INFINITE)
strcpy(lim_str, "UNLIMITED");
else {
snprintf(lim_str, sizeof(lim_str), "%lu",
(unsigned long) time_limit);
}
/* Job will typically be COMPLETING when this is called.
* We remove the flags to get the eventual completion state:
* JOB_FAILED, JOB_TIMEOUT, etc. */
if (IS_JOB_RESIZING(job_ptr)) {
job_state = JOB_RESIZING;
if (job_ptr->resize_time)
start_time = job_ptr->resize_time;
else
start_time = job_ptr->start_time;
end_time = time(NULL);
} else {
job_state = job_ptr->job_state & JOB_STATE_BASE;
if (job_ptr->resize_time)
start_time = job_ptr->resize_time;
else if (job_ptr->start_time > job_ptr->end_time) {
/* Job cancelled while pending and
* expected start time is in the future. */
start_time = 0;
} else
start_time = job_ptr->start_time;
end_time = job_ptr->end_time;
}
if (job_ptr->name && job_ptr->name[0])
jname = slurm_add_slash_to_quotes(job_ptr->name);
else
jname = xstrdup("allocation");
query = xstrdup_printf(
"insert into %s (jobid, uid, user_name, gid, group_name, "
"name, state, proc_cnt, `partition`, timelimit, "
"starttime, endtime, nodecnt",
jobcomp_table);
if (job_ptr->nodes)
xstrcat(query, ", nodelist");
if (job_ptr->details && (job_ptr->details->max_cpus != NO_VAL))
xstrcat(query, ", maxprocs");
xstrfmtcat(query, ") values (%u, %u, '%s', %u, '%s', '%s', %u, %u, "
"'%s', '%s', %ld, %ld, %u",
job_ptr->job_id, job_ptr->user_id, usr_str,
job_ptr->group_id, grp_str, jname,
job_state, job_ptr->total_cpus, partition, lim_str,
start_time, end_time, job_ptr->node_cnt);
xstrfmtcat(on_dup, "uid=%u, user_name='%s', gid=%u, group_name='%s', "
"name='%s', state=%u, proc_cnt=%u, `partition`='%s', "
"timelimit='%s', nodecnt=%u",
job_ptr->user_id, usr_str, job_ptr->group_id, grp_str, jname,
job_state, job_ptr->total_cpus, partition, lim_str,
job_ptr->node_cnt);
if (job_ptr->nodes) {
xstrfmtcat(query, ", '%s'", job_ptr->nodes);
xstrfmtcat(on_dup, ", nodelist='%s'", job_ptr->nodes);
}
if (job_ptr->details && (job_ptr->details->max_cpus != NO_VAL)) {
xstrfmtcat(query, ", '%u'", job_ptr->details->max_cpus);
xstrfmtcat(on_dup, ", maxprocs='%u'",
job_ptr->details->max_cpus);
}
xstrfmtcat(query, ") ON DUPLICATE KEY UPDATE %s;", on_dup);
debug3("(%s:%d) query\n%s",
THIS_FILE, __LINE__, query);
rc = mysql_db_query(jobcomp_mysql_conn, query);
xfree(usr_str);
xfree(grp_str);
xfree(jname);
xfree(query);
xfree(on_dup);
return rc;
}
/*
* get info from the storage
* in/out job_list list of job_rec_t *
* note list needs to be freed when called
*/
extern list_t *jobcomp_p_get_jobs(slurmdb_job_cond_t *job_cond)
{
list_t *job_list = NULL;
if (!jobcomp_mysql_conn || mysql_db_ping(jobcomp_mysql_conn) != 0) {
if (jobcomp_p_set_location())
return job_list;
}
job_list = mysql_jobcomp_process_get_jobs(job_cond);
return job_list;
}
extern int jobcomp_p_record_job_start(job_record_t *job_ptr, uint32_t event)
{
return SLURM_SUCCESS;
}