blob: 9e5bb5c7f3db59e74eef1bf7ffb4652660bb268a [file]
/****************************************************************************\
* dbd_conn.c - functions to manage the connection to the SlurmDBD
*****************************************************************************
* Copyright (C) SchedMD LLC.
* Copyright (C) 2008-2010 Lawrence Livermore National Security.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Morris Jette <jette1@llnl.gov>
* CODE-OCEC-09-009. All rights reserved.
*
* 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 "src/common/slurm_xlator.h"
#include "src/common/slurmdbd_pack.h"
#include "src/slurmctld/trigger_mgr.h"
#include "slurmdbd_agent.h"
#define SLURMDBD_TIMEOUT 900 /* Seconds SlurmDBD for response */
static void _acct_full(void)
{
if (running_in_slurmctld())
trigger_primary_ctld_acct_full();
}
static void _dbd_fail(void)
{
if (running_in_slurmctld())
trigger_primary_dbd_fail();
}
static void _dbd_res_op(void)
{
if (running_in_slurmctld())
trigger_primary_dbd_res_op();
}
static void _db_fail(void)
{
if (running_in_slurmctld())
trigger_primary_db_fail();
}
static void _db_res_op(void)
{
if (running_in_slurmctld())
trigger_primary_db_res_op();
}
static int _connect_dbd_conn(persist_conn_t *pc)
{
int rc;
char *backup_host = NULL;
xassert(pc);
/* Only setup a backup host on a non ext_dbd connection */
if (!(pc->flags & PERSIST_FLAG_EXT_DBD))
backup_host =
xstrdup(slurm_conf.accounting_storage_backup_host);
again:
// A connection failure is only an error if backup dne or also fails
if (backup_host)
pc->flags |= PERSIST_FLAG_SUPPRESS_ERR;
else
pc->flags &= (~PERSIST_FLAG_SUPPRESS_ERR);
pc->r_uid = SLURM_AUTH_UID_ANY;
if (((rc = slurm_persist_conn_open(pc)) != SLURM_SUCCESS) &&
backup_host) {
xfree(pc->rem_host);
// Force the next error to display
pc->comm_fail_time = 0;
pc->rem_host = backup_host;
backup_host = NULL;
goto again;
}
xfree(backup_host);
if (rc == SLURM_SUCCESS) {
/*
* Increase SLURMDBD_TIMEOUT to wait as long as we need for a
* query to complete.
*/
pc->timeout = MAX(pc->timeout, SLURMDBD_TIMEOUT * 1000);
(pc->trigger_callbacks.dbd_resumed)();
(pc->trigger_callbacks.db_resumed)();
}
if (rc == SLURM_SUCCESS) {
debug("Sent PersistInit msg");
/* clear errno (checked after this for errors) */
errno = 0;
} else {
if (rc == ESLURM_DB_CONNECTION)
(pc->trigger_callbacks.db_fail)();
slurm_persist_conn_close(pc);
/* This means errno was already set correctly */
if (rc != SLURM_ERROR)
errno = rc;
error("Sending PersistInit msg: %m");
}
return rc;
}
extern persist_conn_t *dbd_conn_open(uint16_t *persist_conn_flags,
char *cluster_name,
char *rem_host,
uint16_t rem_port)
{
persist_conn_t *pc = xmalloc(sizeof(*pc));
if (persist_conn_flags)
pc->flags = *persist_conn_flags;
pc->flags |= (PERSIST_FLAG_DBD | PERSIST_FLAG_RECONNECT);
pc->persist_type = PERSIST_TYPE_DBD;
if (cluster_name)
pc->cluster_name = xstrdup(cluster_name);
else
pc->cluster_name = xstrdup(slurm_conf.cluster_name);
pc->timeout = (slurm_conf.msg_timeout + 35) * 1000;
if (rem_host)
pc->rem_host = xstrdup(rem_host);
else
pc->rem_host = xstrdup(slurm_conf.accounting_storage_host);
if (rem_port)
pc->rem_port = rem_port;
else
pc->rem_port = slurm_conf.accounting_storage_port;
pc->version = SLURM_PROTOCOL_VERSION;
/* Initialize the callback pointers */
pc->trigger_callbacks.acct_full = _acct_full;
pc->trigger_callbacks.dbd_fail = _dbd_fail;
pc->trigger_callbacks.dbd_resumed = _dbd_res_op;
pc->trigger_callbacks.db_fail = _db_fail;
pc->trigger_callbacks.db_resumed = _db_res_op;
(void)_connect_dbd_conn(pc);
if (persist_conn_flags)
*persist_conn_flags = pc->flags;
return pc;
}
extern int dbd_conn_check_and_reopen(persist_conn_t *pc)
{
xassert(pc);
if (pc && pc->tls_conn) {
debug("Attempt to re-open slurmdbd socket");
/* clear errno (checked after this for errors) */
errno = 0;
return SLURM_SUCCESS;
}
/*
* Reset the rem_host just in case we were connected to the backup
* before.
*/
xfree(pc->rem_host);
pc->rem_host = xstrdup(slurm_conf.accounting_storage_host);
return _connect_dbd_conn(pc);
}
extern void dbd_conn_close(persist_conn_t **pc)
{
persist_msg_t req = { 0 };
dbd_fini_msg_t get_msg;
int resp_code = SLURM_SUCCESS;
int rc;
if (!pc)
return;
/*
* Only send the FINI message if we haven't shutdown
* (i.e. not slurmctld)
*/
if (*(*pc)->shutdown) {
log_flag(NET, "We are shutdown, not sending DB_FINI to %s:%u",
(*pc)->rem_host,
(*pc)->rem_port);
goto destroy_conn;
}
/* If the connection is already gone, we don't need to send a fini. */
if (slurm_persist_conn_writeable(*pc) == -1) {
log_flag(NET, "unable to send DB_FINI msg to %s:%u",
(*pc)->rem_host,
(*pc)->rem_port);
goto destroy_conn;
}
memset(&get_msg, 0, sizeof(dbd_fini_msg_t));
get_msg.close_conn = 0;
get_msg.commit = false;
req.msg_type = DBD_FINI;
req.conn = *pc;
req.data = &get_msg;
if ((rc = dbd_conn_send_recv_rc_msg(SLURM_PROTOCOL_VERSION, &req,
&resp_code))) {
log_flag(NET, "unable to send/recv DB_FINI msg to %s:%u: %s",
(*pc)->rem_host, (*pc)->rem_port,
slurm_strerror(rc));
goto destroy_conn;
}
if (resp_code != SLURM_SUCCESS) {
log_flag(NET, "got error in response to DB_FINI msg from %s:%u: %s",
(*pc)->rem_host, (*pc)->rem_port,
slurm_strerror(resp_code));
rc = resp_code;
goto destroy_conn;
}
log_flag(NET, "sent DB_FINI msg to %s:%u rc(%d):%s",
(*pc)->rem_host, (*pc)->rem_port,
rc, slurm_strerror(rc));
destroy_conn:
slurm_persist_conn_destroy(*pc);
*pc = NULL;
}
/*
* Send an RPC to the SlurmDBD and wait for an arbitrary reply message.
* The RPC will not be queued if an error occurs.
* The "resp" message must be freed by the caller.
* Returns SLURM_SUCCESS or an error code
*/
extern int dbd_conn_send_recv_direct(uint16_t rpc_version,
persist_msg_t *req,
persist_msg_t *resp)
{
int rc = SLURM_SUCCESS;
buf_t *buffer;
persist_conn_t *use_conn = req->conn;
xassert(req);
xassert(resp);
xassert(use_conn);
if (!use_conn->tls_conn) {
/* The connection has been closed, reopen */
rc = dbd_conn_check_and_reopen(use_conn);
if (rc != SLURM_SUCCESS || !use_conn->tls_conn) {
rc = SLURM_ERROR;
goto end_it;
}
}
if (!(buffer = pack_slurmdbd_msg(req, rpc_version))) {
rc = SLURM_ERROR;
goto end_it;
}
rc = slurm_persist_send_msg(use_conn, buffer);
FREE_NULL_BUFFER(buffer);
if (rc != SLURM_SUCCESS) {
error("Sending message type %s: %d: %s",
slurmdbd_msg_type_2_str(req->msg_type, 1), rc,
slurm_strerror(rc));
goto end_it;
}
buffer = slurm_persist_recv_msg(use_conn);
if (buffer == NULL) {
error("Getting response to message type: %s",
slurmdbd_msg_type_2_str(req->msg_type, 1));
rc = SLURM_ERROR;
goto end_it;
}
rc = unpack_slurmdbd_msg(resp, rpc_version, buffer);
/* check for the rc of the start job message */
if (rc == SLURM_SUCCESS && resp->msg_type == DBD_ID_RC)
rc = ((dbd_id_rc_msg_t *)resp->data)->return_code;
FREE_NULL_BUFFER(buffer);
end_it:
log_flag(PROTOCOL, "msg_type:%s protocol_version:%hu return_code:%d response_msg_type:%s",
slurmdbd_msg_type_2_str(req->msg_type, 1),
rpc_version, rc, slurmdbd_msg_type_2_str(resp->msg_type, 1));
return rc;
}
extern int dbd_conn_send_recv_rc_comment_msg(uint16_t rpc_version,
persist_msg_t *req,
int *resp_code,
char **comment)
{
int rc;
persist_msg_t resp;
xassert(req);
xassert(resp_code);
memset(&resp, 0, sizeof(persist_msg_t));
rc = dbd_conn_send_recv(rpc_version, req, &resp);
if (rc != SLURM_SUCCESS) {
; /* error message already sent */
} else if (resp.msg_type != PERSIST_RC) {
error("response is not type PERSIST_RC: %s(%u)",
slurmdbd_msg_type_2_str(resp.msg_type, 1),
resp.msg_type);
rc = SLURM_ERROR;
} else { /* resp.msg_type == PERSIST_RC */
persist_rc_msg_t *msg = resp.data;
*resp_code = msg->rc;
if ((msg->ret_info == DBD_REGISTER_CTLD) &&
(msg->rc & RC_AS_CLUSTER_ID))
msg->rc = SLURM_SUCCESS;
if (msg->rc != SLURM_SUCCESS &&
msg->rc != ACCOUNTING_FIRST_REG &&
msg->rc != ACCOUNTING_TRES_CHANGE_DB &&
msg->rc != ACCOUNTING_NODES_CHANGE_DB) {
char *comment = msg->comment;
if (!comment)
comment = slurm_strerror(msg->rc);
if (!req->conn &&
(msg->ret_info == DBD_REGISTER_CTLD) &&
slurm_conf.accounting_storage_enforce) {
error("Issue with call "
"%s(%u): %u(%s)",
slurmdbd_msg_type_2_str(
msg->ret_info, 1),
msg->ret_info, msg->rc,
comment);
fatal("You need to add this cluster "
"to accounting if you want to "
"enforce associations, or no "
"jobs will ever run.");
} else
debug("Issue with call "
"%s(%u): %u(%s)",
slurmdbd_msg_type_2_str(
msg->ret_info, 1),
msg->ret_info, msg->rc,
comment);
}
if (comment) {
*comment = msg->comment;
msg->comment = NULL;
}
slurm_persist_free_rc_msg(msg);
}
log_flag(PROTOCOL, "msg_type:%s protocol_version:%hu return_code:%d",
slurmdbd_msg_type_2_str(req->msg_type, 1),
rpc_version, rc);
return rc;
}
extern int dbd_conn_send_recv_rc_msg(uint16_t rpc_version,
persist_msg_t *req,
int *resp_code)
{
return dbd_conn_send_recv_rc_comment_msg(
rpc_version, req, resp_code, NULL);
}
extern int dbd_conn_send_recv(uint16_t rpc_version,
persist_msg_t *req,
persist_msg_t *resp)
{
if (running_in_slurmctld() &&
(!req->conn || (req->conn == slurmdbd_conn)))
return slurmdbd_agent_send_recv(rpc_version, req, resp);
else
return dbd_conn_send_recv_direct(rpc_version, req, resp);
}