"standby register/follow": provide primary node details for event notifications

For events generated by these commands, it may be useful to know details
of the primary node. This makes following additional parameters available
to event notification scripts:

- %p: node ID of the primary
- %a: node name of the primary
- %c: conninfo string for the primary

Implements GitHub #375
This commit is contained in:
Ian Barwick
2018-02-06 09:36:46 +09:00
parent cf64f9e95c
commit 1e1b4b1a65
6 changed files with 117 additions and 57 deletions

View File

@@ -3303,14 +3303,14 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
}
break;
case 'p':
/* %p: former primary id ("repmgr standby switchover") */
/* %p: primary id ("standby_switchover": former primary id) */
src_ptr++;
if (event_info->former_primary_id != UNKNOWN_NODE_ID)
if (event_info->node_id != UNKNOWN_NODE_ID)
{
PQExpBufferData node_id;
initPQExpBuffer(&node_id);
appendPQExpBuffer(&node_id,
"%i", event_info->former_primary_id);
"%i", event_info->node_id);
strlcpy(dst_ptr, node_id.data, end_ptr - dst_ptr);
dst_ptr += strlen(dst_ptr);
termPQExpBuffer(&node_id);

View File

@@ -183,7 +183,7 @@ typedef struct s_event_info
{
char *node_name;
char *conninfo_str;
int former_primary_id;
int node_id;
} t_event_info;
#define T_EVENT_INFO_INITIALIZER { \

View File

@@ -37,7 +37,7 @@
<filename>repmgr.conf</filename>.
</para>
<para>
This parameter accepts the following format placeholders:
The following format placeholders are provided for all event notifications:
</para>
<variablelist>
@@ -84,18 +84,8 @@
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>%p</option></term>
<listitem>
<para>
node ID of the demoted primary (<xref linkend="repmgr-standby-switchover"> only)
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
The values provided for <literal>%t</literal> and <literal>%d</literal>
will probably contain spaces, so should be quoted in the provided command
@@ -104,34 +94,60 @@
event_notification_command='/path/to/some/script %n %e %s "%t" "%d"'
</programlisting>
</para>
<para>
Additionally the following format placeholders are available for the event
type <varname>bdr_failover</varname> and optionally <varname>bdr_recovery</varname>:
The following parameters are provided for a subset of event notifications:
</para>
<variablelist>
<varlistentry>
<term><option>%p</option></term>
<listitem>
<para>
node ID of the current primary (<xref linkend="repmgr-standby-register"> and <xref linkend="repmgr-standby-follow">)
</para>
<para>
node ID of the demoted primary (<xref linkend="repmgr-standby-switchover"> only)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>%c</option></term>
<listitem>
<para>
conninfo string of the next available node
<literal>conninfo</literal> string of the primary node
(<xref linkend="repmgr-standby-register"> and <xref linkend="repmgr-standby-follow">)
</para>
<para>
<literal>conninfo</literal> string of the next available node
(<varname>bdr_failover</varname> and <varname>bdr_recovery</varname>)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>%a</option></term>
<listitem>
<para>
name of the next available node
name of the current primary node (<xref linkend="repmgr-standby-register"> and <xref linkend="repmgr-standby-follow">)
</para>
<para>
name of the next available node (<varname>bdr_failover</varname> and <varname>bdr_recovery</varname>)
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
These should always be quoted.
The values provided for <literal>%c</literal> and <literal>%a</literal>
will probably contain spaces, so should always be quoted.
</para>
<para>
By default, all notification types will be passed to the designated script;
the notification types can be filtered to explicitly named ones:
the notification types can be filtered to explicitly named ones using the
<varname>event_notifications</varname> parameter:
<itemizedlist spacing="compact" mark="bullet">
@@ -222,6 +238,7 @@
</itemizedlist>
</para>
<para>
Note that under some circumstances (e.g. when no replication cluster primary
could be located), it will not be possible to write an entry into the

View File

@@ -87,9 +87,14 @@
<para>
A <literal>standby_follow</literal> <link linkend="event-notifications">event notification</link> will be generated.
</para>
<para>
If provided, &repmgr; will subsitute the placeholders <literal>%p</literal> with the node ID of the primary
being followed, <literal>%c</literal> with its <literal>conninfo</literal> string, and
<literal>%a</literal> with its node name.
</para>
</refsect1>
<refsect1>
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-node-rejoin">

View File

@@ -172,6 +172,12 @@
standby.
</para>
<para>
If provided, &repmgr; will subsitute the placeholders <literal>%p</literal> with the node ID of the
primary node, <literal>%c</literal> with its <literal>conninfo</literal> string, and
<literal>%a</literal> with its node name.
</para>
</refsect1>
</refentry>

View File

@@ -1192,6 +1192,11 @@ do_standby_register(void)
PQExpBufferData details;
/* so we can pass info about the primary to event notification scripts */
t_event_info event_info = T_EVENT_INFO_INITIALIZER;
t_node_info primary_node_record = T_NODE_INFO_INITIALIZER;
int primary_node_id = UNKNOWN_NODE_ID;
log_info(_("connecting to local node \"%s\" (ID: %i)"),
config_file_options.node_name,
config_file_options.node_id);
@@ -1276,7 +1281,7 @@ do_standby_register(void)
/* Normal case - we can connect to the local node */
if (PQstatus(conn) == CONNECTION_OK)
{
primary_conn = get_primary_connection(conn, NULL, NULL);
primary_conn = get_primary_connection(conn, &primary_node_id, NULL);
}
/*
@@ -1300,6 +1305,16 @@ do_standby_register(void)
exit(ERR_BAD_CONFIG);
}
/*
* Populate "event_info" with info about the primary for event notifications
*/
record_status = get_node_record(primary_conn,
primary_node_id,
&primary_node_record);
event_info.node_id = primary_node_id;
event_info.node_name = primary_node_record.node_name;
event_info.conninfo_str = primary_node_record.conninfo;
/*
* Verify that standby and primary are supported and compatible server
* versions
@@ -1554,12 +1569,14 @@ do_standby_register(void)
&details,
" (-F/--force option was used)");
create_event_notification(primary_conn,
&config_file_options,
config_file_options.node_id,
"standby_register",
false,
details.data);
create_event_notification_extended(
primary_conn,
&config_file_options,
config_file_options.node_id,
"standby_register",
false,
details.data,
&event_info);
termPQExpBuffer(&details);
PQfinish(primary_conn);
@@ -1579,12 +1596,14 @@ do_standby_register(void)
/* Log the event */
create_event_notification(primary_conn,
&config_file_options,
config_file_options.node_id,
"standby_register",
true,
details.data);
create_event_notification_extended(
primary_conn,
&config_file_options,
config_file_options.node_id,
"standby_register",
true,
details.data,
&event_info);
termPQExpBuffer(&details);
@@ -1679,12 +1698,14 @@ do_standby_register(void)
timer);
}
create_event_notification(primary_conn,
&config_file_options,
config_file_options.node_id,
"standby_register_sync",
sync_ok,
details.data);
create_event_notification_extended(
primary_conn,
&config_file_options,
config_file_options.node_id,
"standby_register_sync",
sync_ok,
details.data,
&event_info);
if (sync_ok == false)
{
@@ -2016,9 +2037,11 @@ do_standby_follow(void)
PGconn *local_conn = NULL;
PGconn *primary_conn = NULL;
int primary_id = UNKNOWN_NODE_ID;
int primary_node_id = UNKNOWN_NODE_ID;
t_node_info primary_node_record = T_NODE_INFO_INITIALIZER;
RecordStatus record_status = RECORD_NOT_FOUND;
/* so we can pass info about the primary to event notification scripts */
t_event_info event_info = T_EVENT_INFO_INITIALIZER;
int timer = 0;
int server_version_num = UNKNOWN_SERVER_VERSION_NUM;
@@ -2057,7 +2080,7 @@ do_standby_follow(void)
for (timer = 0; timer < config_file_options.primary_follow_timeout; timer++)
{
primary_conn = get_primary_connection_quiet(local_conn,
&primary_id,
&primary_node_id,
NULL);
if (PQstatus(primary_conn) == CONNECTION_OK || runtime_options.wait == false)
{
@@ -2084,14 +2107,14 @@ do_standby_follow(void)
if (runtime_options.dry_run == true)
{
log_info(_("connected to node %i, checking for current primary"), primary_id);
log_info(_("connected to node %i, checking for current primary"), primary_node_id);
}
else
{
log_verbose(LOG_INFO, _("connected to node %i, checking for current primary"), primary_id);
log_verbose(LOG_INFO, _("connected to node %i, checking for current primary"), primary_node_id);
}
record_status = get_node_record(primary_conn, primary_id, &primary_node_record);
record_status = get_node_record(primary_conn, primary_node_id, &primary_node_record);
if (record_status != RECORD_FOUND)
{
@@ -2101,17 +2124,25 @@ do_standby_follow(void)
exit(ERR_FOLLOW_FAIL);
}
/*
* Populate "event_info" with info about the primary for event notifications
*/
event_info.node_id = primary_node_id;
event_info.node_name = primary_node_record.node_name;
event_info.conninfo_str = primary_node_record.conninfo;
if (runtime_options.dry_run == true)
{
log_info(_("primary node is \"%s\" (ID: %i)"),
primary_node_record.node_name,
primary_id);
primary_node_id);
}
else
{
log_verbose(LOG_INFO, ("primary node is \"%s\" (ID: %i)"),
primary_node_record.node_name,
primary_id);
primary_node_id);
}
/* if replication slots in use, check at least one free slot is available */
@@ -2202,7 +2233,6 @@ do_standby_follow(void)
exit(SUCCESS);
}
initPQExpBuffer(&follow_output);
success = do_standby_follow_internal(primary_conn,
@@ -2210,12 +2240,14 @@ do_standby_follow(void)
&follow_output,
&follow_error_code);
create_event_notification(primary_conn,
&config_file_options,
config_file_options.node_id,
"standby_follow",
success,
follow_output.data);
create_event_notification_extended(
primary_conn,
&config_file_options,
config_file_options.node_id,
"standby_follow",
success,
follow_output.data,
&event_info);
PQfinish(primary_conn);
@@ -2659,7 +2691,7 @@ do_standby_switchover(void)
log_verbose(LOG_DEBUG, "remote node name is \"%s\"", remote_node_record.node_name);
/* this will fill the %p event notification parameter */
event_info.former_primary_id = remote_node_record.node_id;
event_info.node_id = remote_node_record.node_id;
/* keep a running total of how many nodes will require a replication slot */
if (remote_node_record.slot_name[0] != '\0')