From 89ba0057267b179e41be387e1a810f706f979896 Mon Sep 17 00:00:00 2001 From: Ian Barwick Date: Mon, 16 May 2022 11:51:55 +0900 Subject: [PATCH] repmgrd: improve walsender disable check Specifically, don't attempt to disable walsenders if "standby_disconnect_on_failover" is "true", but the repmgr user is not a superuser. This restriction can be lifted from PostgreSQL 15. --- HISTORY | 1 + dbutils.c | 36 ++++++++++++++++++++++++++++++++++ dbutils.h | 1 + doc/appendix-release-notes.xml | 6 ++++++ repmgrd-physical.c | 27 +++++++++++++------------ 5 files changed, 58 insertions(+), 13 deletions(-) diff --git a/HISTORY b/HISTORY index 03cc84f5..c25ccca8 100644 --- a/HISTORY +++ b/HISTORY @@ -2,6 +2,7 @@ standby clone: don't error out if unable to determine cluster size (Ian) node check: fix --downstream --nagios output; GitHub #749 (Ian) repmgrd: ensure witness node marked active (hslightdb) + repmgrd: improve walsender disable check (Ian) 5.3.1 2022-02-15 repmgrd: fixes for potential connection leaks (hslightdb) diff --git a/dbutils.c b/dbutils.c index 7bf7d448..ec5a50ca 100644 --- a/dbutils.c +++ b/dbutils.c @@ -1888,6 +1888,42 @@ can_execute_pg_promote(PGconn *conn) } +/* + * Determine if the user associated with the current connection + * has sufficient permissions to disable the walsender + */ +bool +can_disable_walsender(PGconn *conn) +{ + /* + * Requires PostgreSQL 9.5 or later, because ALTER SYSTEM + */ + if (PQserverVersion(conn) < 90500) + { + log_warning(_("\"standby_disconnect_on_failover\" specified, but not available for this PostgreSQL version")); + /* TODO: format server version */ + log_detail(_("available from PostgreSQL 9.5; this PostgreSQL version is %i"), PQserverVersion(conn)); + + return false; + } + + /* + * Superusers can do anything + */ + if (is_superuser_connection(conn, NULL) == true) + return true; + + /* + * As of PostgreSQL 14, it is not possible for a non-superuser + * to execute ALTER SYSTEM, so further checks are superfluous. + * This will need modifying for PostgreSQL 15. + */ + log_warning(_("\"standby_disconnect_on_failover\" specified, but repmgr user is not a superuser")); + log_detail(_("superuser permission required to disable standbys on failover")); + + return false; +} + /* * Determine if the user associated with the current connection is * a member of the "pg_monitor" default role, or optionally one diff --git a/dbutils.h b/dbutils.h index 35387239..23bfff29 100644 --- a/dbutils.h +++ b/dbutils.h @@ -454,6 +454,7 @@ pid_t get_wal_receiver_pid(PGconn *conn); /* user/role information functions */ bool can_execute_pg_promote(PGconn *conn); +bool can_disable_walsender(PGconn *conn); bool connection_has_pg_monitor_role(PGconn *conn, const char *subrole); bool is_replication_role(PGconn *conn, char *rolname); bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo); diff --git a/doc/appendix-release-notes.xml b/doc/appendix-release-notes.xml index b935cc4c..5563f7a4 100644 --- a/doc/appendix-release-notes.xml +++ b/doc/appendix-release-notes.xml @@ -53,6 +53,12 @@ GitHub #754. + + + &repmgrd;: if standby_disconnect_on_failover is set, verify + &repmgr; is a superuser before attempting to disable the WAL receiver. + + diff --git a/repmgrd-physical.c b/repmgrd-physical.c index ef316490..f20f9b43 100644 --- a/repmgrd-physical.c +++ b/repmgrd-physical.c @@ -2862,6 +2862,7 @@ do_primary_failover(void) bool final_result = false; NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER; int new_primary_id = UNKNOWN_NODE_ID; + bool standby_disconnect_on_failover = false; /* * Double-check status of the local connection @@ -2874,20 +2875,20 @@ do_primary_failover(void) */ if (config_file_options.standby_disconnect_on_failover == true) { - NodeInfoListCell *cell = NULL; - NodeInfoList check_sibling_nodes = T_NODE_INFO_LIST_INITIALIZER; - int i; + /* + * Determine whether we can actually disable the walsender; this depends + * on PostgreSQL version and user permissions. + */ + standby_disconnect_on_failover = can_disable_walsender(local_conn); - bool sibling_node_wal_receiver_connected = false; + if (standby_disconnect_on_failover == true) + { + NodeInfoListCell *cell = NULL; + NodeInfoList check_sibling_nodes = T_NODE_INFO_LIST_INITIALIZER; + int i; + + bool sibling_node_wal_receiver_connected = false; - if (PQserverVersion(local_conn) < 90500) - { - log_warning(_("\"standby_disconnect_on_failover\" specified, but not available for this PostgreSQL version")); - /* TODO: format server version */ - log_detail(_("available from PostgreSQL 9.5, this PostgreSQL version is %i"), PQserverVersion(local_conn)); - } - else - { disable_wal_receiver(local_conn); /* @@ -2971,7 +2972,7 @@ do_primary_failover(void) log_debug("election result: %s", _print_election_result(election_result)); /* Reenable WAL receiver, if disabled */ - if (config_file_options.standby_disconnect_on_failover == true) + if (standby_disconnect_on_failover == true) { /* adjust "wal_retrieve_retry_interval" but don't wait for WAL receiver to start */ enable_wal_receiver(local_conn, false);