From 1e1b4b1a657fc0c37ce538173c9f72c38a1f9d4d Mon Sep 17 00:00:00 2001 From: Ian Barwick Date: Tue, 6 Feb 2018 09:36:46 +0900 Subject: [PATCH] "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 --- dbutils.c | 6 +- dbutils.h | 2 +- doc/event-notifications.sgml | 53 ++++++++++------ doc/repmgr-standby-follow.sgml | 7 ++- doc/repmgr-standby-register.sgml | 6 ++ repmgr-action-standby.c | 100 ++++++++++++++++++++----------- 6 files changed, 117 insertions(+), 57 deletions(-) diff --git a/dbutils.c b/dbutils.c index b6c9b8eb..d576bed6 100644 --- a/dbutils.c +++ b/dbutils.c @@ -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); diff --git a/dbutils.h b/dbutils.h index 3e4fa295..93fbf019 100644 --- a/dbutils.h +++ b/dbutils.h @@ -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 { \ diff --git a/doc/event-notifications.sgml b/doc/event-notifications.sgml index 4273944f..9b2c2010 100644 --- a/doc/event-notifications.sgml +++ b/doc/event-notifications.sgml @@ -37,7 +37,7 @@ repmgr.conf. - This parameter accepts the following format placeholders: + The following format placeholders are provided for all event notifications: @@ -84,18 +84,8 @@ - - - - - - - node ID of the demoted primary ( only) - - - - + The values provided for %t and %d 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"' + - Additionally the following format placeholders are available for the event - type bdr_failover and optionally bdr_recovery: + The following parameters are provided for a subset of event notifications: + + + + + + node ID of the current primary ( and ) + + + node ID of the demoted primary ( only) + + + - conninfo string of the next available node + conninfo string of the primary node + ( and ) + + + conninfo string of the next available node + (bdr_failover and bdr_recovery) + - name of the next available node + name of the current primary node ( and ) + + + name of the next available node (bdr_failover and bdr_recovery) + + - These should always be quoted. + The values provided for %c and %a + will probably contain spaces, so should always be quoted. + 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 + event_notifications parameter: @@ -222,6 +238,7 @@ + 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 diff --git a/doc/repmgr-standby-follow.sgml b/doc/repmgr-standby-follow.sgml index 0079dc37..d464361b 100644 --- a/doc/repmgr-standby-follow.sgml +++ b/doc/repmgr-standby-follow.sgml @@ -87,9 +87,14 @@ A standby_follow event notification will be generated. + + If provided, &repmgr; will subsitute the placeholders %p with the node ID of the primary + being followed, %c with its conninfo string, and + %a with its node name. + - + See also diff --git a/doc/repmgr-standby-register.sgml b/doc/repmgr-standby-register.sgml index b5e69efd..9e5f7b76 100644 --- a/doc/repmgr-standby-register.sgml +++ b/doc/repmgr-standby-register.sgml @@ -172,6 +172,12 @@ standby. + + If provided, &repmgr; will subsitute the placeholders %p with the node ID of the + primary node, %c with its conninfo string, and + %a with its node name. + + diff --git a/repmgr-action-standby.c b/repmgr-action-standby.c index 4a14563f..0d68a297 100644 --- a/repmgr-action-standby.c +++ b/repmgr-action-standby.c @@ -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')