From e64349e4daa484987f870f8e4b42d60ef212a4fc Mon Sep 17 00:00:00 2001 From: Ian Barwick Date: Wed, 25 Mar 2020 13:59:48 +0900 Subject: [PATCH] standby switchover: accept -S/--superuser option --- doc/repmgr-standby-switchover.xml | 22 +++++++-- repmgr-action-standby.c | 80 +++++++++++++++++++++++++++++-- repmgr-client.c | 1 + 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/doc/repmgr-standby-switchover.xml b/doc/repmgr-standby-switchover.xml index 9e51adcb..02503251 100644 --- a/doc/repmgr-standby-switchover.xml +++ b/doc/repmgr-standby-switchover.xml @@ -67,12 +67,17 @@ CHECKPOINT &repmgr; executes CHECKPOINT on the demotion candidate as part of the shutdown - process. + process to ensure it shuts down as smoothly as possible. Note that CHECKPOINT requires database superuser permissions to execute. - If the repmgr user is not a superuser, the checkpoint operation will - fail, though this is not a fatal error &repmgr; will continue the switchover process. + If the repmgr user is not a superuser, the name of a superuser should be + provided with the /. + + + If &repmgr; is unable to execute the CHECKPOINT command, the switchover + can still be carried out, albeit at a greater risk that the demotion candidate may not + be able to shut down as smoothly as might otherwise have been the case. pg_promote() (PostgreSQL 12 and later) @@ -211,6 +216,17 @@ + + + / + + + Use the named superuser instead of the normal &repmgr; user to perform + actions requiring superuser permissions. + + + + diff --git a/repmgr-action-standby.c b/repmgr-action-standby.c index ecb3469f..3b4cfd42 100644 --- a/repmgr-action-standby.c +++ b/repmgr-action-standby.c @@ -3430,6 +3430,7 @@ void do_standby_switchover(void) { PGconn *local_conn = NULL; + PGconn *superuser_conn = NULL; PGconn *remote_conn = NULL; t_node_info local_node_record = T_NODE_INFO_INITIALIZER; @@ -3525,6 +3526,41 @@ do_standby_switchover(void) local_node_record.node_id); } + /* if -S/--superuser option provided, check that a superuser connection can be made */ + + if (runtime_options.superuser[0] != '\0') + { + if (runtime_options.dry_run == true) + { + log_info(_("validating database connection for superuser \"%s\""), runtime_options.superuser); + } + + superuser_conn = establish_db_connection_with_replacement_param( + config_file_options.conninfo, + "user", + runtime_options.superuser, false); + + if (PQstatus(superuser_conn) != CONNECTION_OK) + { + log_error(_("unable to connect as provided superuser \"%s\""), + runtime_options.superuser); + exit(ERR_BAD_CONFIG); + } + + if (is_superuser_connection(superuser_conn, NULL) == false) + { + log_error(_("database connection established for provided superuser \"%s\" is not a superuser connection"), + runtime_options.superuser); + exit(ERR_BAD_CONFIG); + } + + if (runtime_options.dry_run == true) + { + log_info(_("successfully established database connection established for provided superuser \"%s\""), + runtime_options.superuser); + } + } + /* Check that this is a standby */ recovery_type = get_recovery_type(local_conn); if (recovery_type != RECTYPE_STANDBY) @@ -4604,6 +4640,13 @@ do_standby_switchover(void) remote_node_record.node_id); appendPQExpBufferStr(&remote_command_str, "node service --action=stop --checkpoint"); + + if (runtime_options.superuser[0] != '\0') + { + appendPQExpBuffer(&remote_command_str, + " --superuser=%s", + runtime_options.superuser); + } } /* XXX handle failure */ @@ -4820,8 +4863,21 @@ do_standby_switchover(void) format_lsn(replication_info.last_wal_receive_lsn), format_lsn(remote_last_checkpoint_lsn)); - /* promote standby (local node) */ - _do_standby_promote_internal(local_conn); + /* + * Promote standby (local node). + * + * If PostgreSQL 12 or later, and -S/--superuser provided, we will provide + * a superuser connection so that pg_promote() can be used. + */ + + if (PQserverVersion(local_conn) >= 120000 && superuser_conn != NULL) + { + _do_standby_promote_internal(superuser_conn); + } + else + { + _do_standby_promote_internal(local_conn); + } /* @@ -4832,8 +4888,23 @@ do_standby_switchover(void) */ if (runtime_options.force_rewind_used == true) { - log_notice(_("issuing CHECKPOINT")); - checkpoint(local_conn); + PGconn *checkpoint_conn = local_conn; + if (superuser_conn != NULL) + { + checkpoint_conn = superuser_conn; + } + + if (is_superuser_connection(checkpoint_conn, NULL) == true) + { + log_notice(_("issuing CHECKPOINT on node \"%s\" (ID: %i) "), + config_file_options.node_name, + config_file_options.node_id); + checkpoint(superuser_conn); + } + else + { + log_warning(_("no superuser connection available, unable to issue CHECKPOINT")); + } } /* @@ -8445,6 +8516,7 @@ do_standby_help(void) printf(_(" (9.3 and 9.4 - provide \"pg_rewind\" path)\n")); printf(_(" -R, --remote-user=USERNAME database server username for SSH operations (default: \"%s\")\n"), runtime_options.username); + printf(_(" -S, --superuser=USERNAME superuser to use, if repmgr user is not superuser\n")); printf(_(" --repmgrd-no-pause don't pause repmgrd\n")); printf(_(" --siblings-follow have other standbys follow new primary\n")); diff --git a/repmgr-client.c b/repmgr-client.c index d055e5ef..3d5fc7c9 100644 --- a/repmgr-client.c +++ b/repmgr-client.c @@ -1691,6 +1691,7 @@ check_cli_parameters(const int action) switch (action) { case STANDBY_CLONE: + case STANDBY_SWITCHOVER: case NODE_CHECK: case NODE_SERVICE: break;