From 64035ef701803faae88181d8ab7aa3cd089dfd1f 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 435cae33..6e638382 100644 --- a/dbutils.c +++ b/dbutils.c @@ -3265,14 +3265,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 9e4cd4d0..15b05b3d 100644 --- a/dbutils.h +++ b/dbutils.h @@ -175,7 +175,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 fe81710a..e28a206b 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: @@ -219,6 +235,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 1bee915b..ac1a8f8a 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 96a3649a..0f120596 100644 --- a/doc/repmgr-standby-register.sgml +++ b/doc/repmgr-standby-register.sgml @@ -105,6 +105,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 3dae11dc..4371020b 100644 --- a/repmgr-action-standby.c +++ b/repmgr-action-standby.c @@ -779,6 +779,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); @@ -863,7 +868,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); } /* @@ -887,6 +892,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 @@ -1141,12 +1156,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); @@ -1166,12 +1183,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); @@ -1266,12 +1285,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) { @@ -1605,9 +1626,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; @@ -1646,7 +1669,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) { @@ -1673,14 +1696,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) { @@ -1690,17 +1713,25 @@ do_standby_follow(void) exit(ERR_BAD_CONFIG); } + /* + * 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 */ @@ -1791,7 +1822,6 @@ do_standby_follow(void) exit(SUCCESS); } - initPQExpBuffer(&follow_output); success = do_standby_follow_internal(primary_conn, @@ -1799,12 +1829,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); @@ -2244,7 +2276,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; /* * If --force-rewind specified, check pg_rewind can be used, and