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.
This commit is contained in:
Ian Barwick
2022-05-16 11:51:55 +09:00
parent c0763c94c8
commit 6f87d2c61e
5 changed files with 58 additions and 13 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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);

View File

@@ -53,6 +53,12 @@
GitHub #754.
</para>
</listitem>
<listitem>
<para>
&repmgrd;: if <varname>standby_disconnect_on_failover</varname> is set, verify
&repmgr; is a superuser before attempting to disable the WAL receiver.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>

View File

@@ -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);