mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-26 00:26:30 +00:00
Initial implementation of "failover_validation_command"
This commit is contained in:
@@ -362,6 +362,7 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
options->sibling_nodes_disconnect_timeout = DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT;
|
options->sibling_nodes_disconnect_timeout = DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT;
|
||||||
options->connection_check_type = CHECK_PING;
|
options->connection_check_type = CHECK_PING;
|
||||||
options->primary_visibility_consensus = false;
|
options->primary_visibility_consensus = false;
|
||||||
|
memset(options->failover_validation_command, 0, sizeof(options->failover_validation_command));
|
||||||
|
|
||||||
/*-------------
|
/*-------------
|
||||||
* witness settings
|
* witness settings
|
||||||
@@ -644,6 +645,8 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
}
|
}
|
||||||
else if (strcmp(name, "primary_visibility_consensus") == 0)
|
else if (strcmp(name, "primary_visibility_consensus") == 0)
|
||||||
options->primary_visibility_consensus = parse_bool(value, name, error_list);
|
options->primary_visibility_consensus = parse_bool(value, name, error_list);
|
||||||
|
else if (strcmp(name, "failover_validation_command") == 0)
|
||||||
|
strncpy(options->failover_validation_command, value, sizeof(options->failover_validation_command));
|
||||||
|
|
||||||
/* witness settings */
|
/* witness settings */
|
||||||
else if (strcmp(name, "witness_sync_interval") == 0)
|
else if (strcmp(name, "witness_sync_interval") == 0)
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ typedef struct
|
|||||||
int sibling_nodes_disconnect_timeout;
|
int sibling_nodes_disconnect_timeout;
|
||||||
ConnectionCheckType connection_check_type;
|
ConnectionCheckType connection_check_type;
|
||||||
bool primary_visibility_consensus;
|
bool primary_visibility_consensus;
|
||||||
|
char failover_validation_command[MAXPGPATH];
|
||||||
|
|
||||||
/* BDR settings */
|
/* BDR settings */
|
||||||
bool bdr_local_monitoring_only;
|
bool bdr_local_monitoring_only;
|
||||||
@@ -189,7 +190,7 @@ typedef struct
|
|||||||
/* node information */ \
|
/* node information */ \
|
||||||
UNKNOWN_NODE_ID, "", "", "", "", "", "", "", REPLICATION_TYPE_PHYSICAL, \
|
UNKNOWN_NODE_ID, "", "", "", "", "", "", "", REPLICATION_TYPE_PHYSICAL, \
|
||||||
/* log settings */ \
|
/* log settings */ \
|
||||||
"", "", "", DEFAULT_LOG_STATUS_INTERVAL, \
|
"", "", "", DEFAULT_LOG_STATUS_INTERVAL, \
|
||||||
/* standby clone settings */ \
|
/* standby clone settings */ \
|
||||||
false, "", "", { NULL, NULL }, "", false, "", false, "", \
|
false, "", "", { NULL, NULL }, "", false, "", false, "", \
|
||||||
/* standby promote settings */ \
|
/* standby promote settings */ \
|
||||||
@@ -216,7 +217,7 @@ typedef struct
|
|||||||
false, -1, \
|
false, -1, \
|
||||||
DEFAULT_ASYNC_QUERY_TIMEOUT, \
|
DEFAULT_ASYNC_QUERY_TIMEOUT, \
|
||||||
DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT, \
|
DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT, \
|
||||||
-1, "", false, DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT, CHECK_PING, true, \
|
-1, "", false, DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT, CHECK_PING, true, "", \
|
||||||
/* BDR settings */ \
|
/* BDR settings */ \
|
||||||
false, DEFAULT_BDR_RECOVERY_TIMEOUT, \
|
false, DEFAULT_BDR_RECOVERY_TIMEOUT, \
|
||||||
/* service settings */ \
|
/* service settings */ \
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#include "repmgrd.h"
|
#include "repmgrd.h"
|
||||||
#include "repmgrd-physical.h"
|
#include "repmgrd-physical.h"
|
||||||
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
FAILOVER_STATE_UNKNOWN = -1,
|
FAILOVER_STATE_UNKNOWN = -1,
|
||||||
@@ -88,7 +87,8 @@ static void update_monitoring_history(void);
|
|||||||
static void handle_sighup(PGconn **conn, t_server_type server_type);
|
static void handle_sighup(PGconn **conn, t_server_type server_type);
|
||||||
|
|
||||||
static const char *format_failover_state(FailoverState failover_state);
|
static const char *format_failover_state(FailoverState failover_state);
|
||||||
|
static const char * format_failover_state(FailoverState failover_state);
|
||||||
|
static void parse_failover_validation_command(const char *template, t_node_info *node_info, PQExpBufferData *out);
|
||||||
|
|
||||||
void
|
void
|
||||||
handle_sigint_physical(SIGNAL_ARGS)
|
handle_sigint_physical(SIGNAL_ARGS)
|
||||||
@@ -3571,7 +3571,58 @@ do_election(void)
|
|||||||
candidate_node->node_id);
|
candidate_node->node_id);
|
||||||
|
|
||||||
if (candidate_node->node_id == local_node_info.node_id)
|
if (candidate_node->node_id == local_node_info.node_id)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If "failover_validation_command" is set, execute that command.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (config_file_options.failover_validation_command[0] != '\0')
|
||||||
|
{
|
||||||
|
PQExpBufferData failover_validation_command;
|
||||||
|
PQExpBufferData command_output;
|
||||||
|
int return_value = -1;
|
||||||
|
|
||||||
|
initPQExpBuffer(&failover_validation_command);
|
||||||
|
initPQExpBuffer(&command_output);
|
||||||
|
|
||||||
|
parse_failover_validation_command(config_file_options.failover_validation_command,
|
||||||
|
candidate_node,
|
||||||
|
&failover_validation_command);
|
||||||
|
|
||||||
|
log_notice(_("executing \"failover_validation_command\""));
|
||||||
|
log_detail("%s", failover_validation_command.data);
|
||||||
|
|
||||||
|
/* we determine success of the command by the value placed into return_value */
|
||||||
|
(void) local_command_return_value(failover_validation_command.data,
|
||||||
|
&command_output,
|
||||||
|
&return_value);
|
||||||
|
|
||||||
|
termPQExpBuffer(&failover_validation_command);
|
||||||
|
|
||||||
|
if (return_value != 0)
|
||||||
|
log_warning(_("failover validation command returned %i"), return_value);
|
||||||
|
|
||||||
|
if (command_output.data[0] != '\0')
|
||||||
|
{
|
||||||
|
log_info("output returned by failover validation command:\n%s", command_output.data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_info(_("no output returned from command"));
|
||||||
|
}
|
||||||
|
|
||||||
|
termPQExpBuffer(&command_output);
|
||||||
|
|
||||||
|
if (return_value != 0)
|
||||||
|
{
|
||||||
|
/* create event here? */
|
||||||
|
log_notice(_("failover validation command returned a non-zero value (%i)"), return_value);
|
||||||
|
return ELECTION_LOST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ELECTION_WON;
|
return ELECTION_WON;
|
||||||
|
}
|
||||||
|
|
||||||
return ELECTION_LOST;
|
return ELECTION_LOST;
|
||||||
}
|
}
|
||||||
@@ -3782,3 +3833,47 @@ handle_sighup(PGconn **conn, t_server_type server_type)
|
|||||||
|
|
||||||
got_SIGHUP = false;
|
got_SIGHUP = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_failover_validation_command(const char *template, t_node_info *node_info, PQExpBufferData *out)
|
||||||
|
{
|
||||||
|
const char *src_ptr;
|
||||||
|
|
||||||
|
for (src_ptr = template; *src_ptr; src_ptr++)
|
||||||
|
{
|
||||||
|
if (*src_ptr == '%')
|
||||||
|
{
|
||||||
|
switch (src_ptr[1])
|
||||||
|
{
|
||||||
|
case '%':
|
||||||
|
/* %%: replace with % */
|
||||||
|
src_ptr++;
|
||||||
|
appendPQExpBufferChar(out, *src_ptr);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
/* %n: node id */
|
||||||
|
src_ptr++;
|
||||||
|
appendPQExpBuffer(out, "%i", node_info->node_id);
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
/* %a: node name */
|
||||||
|
src_ptr++;
|
||||||
|
appendPQExpBufferStr(out, node_info->node_name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* otherwise treat the % as not special */
|
||||||
|
appendPQExpBufferChar(out, *src_ptr);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appendPQExpBufferChar(out, *src_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user