From c9c380a0221bd4ed3080807b37104d0ecc87d8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Marqu=C3=A9s?= Date: Sat, 28 Mar 2026 15:29:18 +0100 Subject: [PATCH] Provide fix for failing pg_rewind with non-superuser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #829 was opened indicating, with a reproducible, that repmgr was not able to run `node rejoin` with minimal privileged user. The main obstacle is that pg_rewind is not able to execute the rewind operation if the user has REPLICATION privileges, but the user repmgr uses requires REPLICATION. This is a typical catch22. The solution provided here adds a --superuser, similar to what other commands have, to `node rejoin` AI-assisted development notes: The approach was designed and directed by Martín Marqués, who also reviewed and refined the output. Code was written by Claude (AI), with some additions from Martín in the documentation. Fixes #829 Co-Authored-By: Claude Opus 4.6 Signed-off-by: Martín Marqués --- doc/configuration-permissions.xml | 3 +++ doc/repmgr-node-rejoin.xml | 40 +++++++++++++++++++++++++++++++ repmgr-action-node.c | 27 ++++++++++++++++++--- repmgr-action-standby.c | 7 ++++++ repmgr-client.c | 1 + 5 files changed, 75 insertions(+), 3 deletions(-) diff --git a/doc/configuration-permissions.xml b/doc/configuration-permissions.xml index f27d1807..6237e41b 100644 --- a/doc/configuration-permissions.xml +++ b/doc/configuration-permissions.xml @@ -192,6 +192,9 @@ repmgr node service (to execute CHECKPOINT via the ; note this is also called by repmgr standby switchover) + + repmgr node rejoin (to execute repmgr node rejoin --force-rewind) + diff --git a/doc/repmgr-node-rejoin.xml b/doc/repmgr-node-rejoin.xml index bae78f4c..590b6915 100644 --- a/doc/repmgr-node-rejoin.xml +++ b/doc/repmgr-node-rejoin.xml @@ -113,6 +113,29 @@ + + + + + Specify a superuser to be used by pg_rewind + for its source server connection. + + + pg_rewind requires a normal (non-replication) + connection with pg_read_server_files privilege or + superuser rights. If the &repmgr; user has the REPLICATION + attribute but lacks these privileges, use this option to specify + a suitably privileged user for the pg_rewind + connection. The superuser's password should be configured in + .pgpass. + + + This option is only effective in combination with + . + + + + @@ -281,6 +304,23 @@ a "magic bullet" which can resolve all problematic replication situations. + + + pg_rewind requires a normal (non-replication) connection to + the source server. The user for this connection must have superuser rights or + the pg_read_server_files role. + + + If the &repmgr; user has the REPLICATION attribute but does + not have the privileges required by pg_rewind, use the + option to specify a suitably privileged user + for the pg_rewind source connection. For example: + + repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \ + --force-rewind -S postgres + + + A typical use-case for pg_rewind is when a scenario like the following is encountered: diff --git a/repmgr-action-node.c b/repmgr-action-node.c index 32e5ab14..b2d4bea3 100644 --- a/repmgr-action-node.c +++ b/repmgr-action-node.c @@ -2838,9 +2838,29 @@ do_node_rejoin(void) appendShellString(&command, config_file_options.data_directory); - appendPQExpBuffer(&command, - " --source-server='%s'", - primary_node_record.conninfo); + if (runtime_options.superuser[0] != '\0') + { + t_conninfo_param_list rewind_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER; + char *rewind_conninfo_str = NULL; + + initialize_conninfo_params(&rewind_conninfo, false); + parse_conninfo_string(primary_node_record.conninfo, &rewind_conninfo, NULL, false); + param_set(&rewind_conninfo, "user", runtime_options.superuser); + rewind_conninfo_str = param_list_to_string(&rewind_conninfo); + + appendPQExpBuffer(&command, + " --source-server='%s'", + rewind_conninfo_str); + + pfree(rewind_conninfo_str); + free_conninfo_params(&rewind_conninfo); + } + else + { + appendPQExpBuffer(&command, + " --source-server='%s'", + primary_node_record.conninfo); + } if (runtime_options.dry_run == true) { @@ -3698,6 +3718,7 @@ do_node_help(void) printf(_(" --config-archive-dir directory to temporarily store retained configuration files\n" \ " (default: /tmp)\n")); printf(_(" -W, --no-wait don't wait for the node to rejoin cluster\n")); + printf(_(" -S, --superuser=USERNAME superuser to use for pg_rewind if repmgr user is not superuser\n")); puts(""); printf(_("NODE SERVICE\n")); diff --git a/repmgr-action-standby.c b/repmgr-action-standby.c index a55462b0..249c6e59 100644 --- a/repmgr-action-standby.c +++ b/repmgr-action-standby.c @@ -5359,6 +5359,13 @@ do_standby_switchover(void) } appendPQExpBufferChar(&node_rejoin_options, ' '); + + if (runtime_options.superuser[0] != '\0') + { + appendPQExpBuffer(&node_rejoin_options, + "--superuser=%s ", + runtime_options.superuser); + } } key_value_list_free(&remote_config_files); diff --git a/repmgr-client.c b/repmgr-client.c index 022ccec9..af319b8f 100644 --- a/repmgr-client.c +++ b/repmgr-client.c @@ -1761,6 +1761,7 @@ check_cli_parameters(const int action) case STANDBY_SWITCHOVER: case NODE_CHECK: case NODE_SERVICE: + case NODE_REJOIN: break; default: item_list_append_format(&cli_warnings,