Compare commits

...

31 Commits

Author SHA1 Message Date
Ian Barwick
b6ba0c3d45 Finalize 5.3.2 release 2022-05-25 15:59:51 +09:00
Ian Barwick
e4d6e2cd11 Add 5.3.2 release date 2022-05-25 14:03:04 +09:00
Ian Barwick
a28b6641b8 doc: update release notes 2022-05-25 14:01:51 +09:00
Ian Barwick
78d2acf204 doc: update release notes 2022-05-25 13:56:59 +09:00
Ian Barwick
b3d52c4332 shared library: remove redundant code
This has never actually served any purpose; see core commit ab02d702ef.
2022-05-17 19:56:48 +09:00
Ian Barwick
72ae977d0d Bump version number
5.3.2
2022-05-17 09:38:40 +09:00
Ian Barwick
599351eea8 Ensure replication slots can be dropped by a replication-only user
If the repmgr user is a non-superuser, and a replication-only user exists,
ensure redundant replication slots are dropped correctly.
2022-05-16 16:38:02 +09:00
Ian Barwick
fca2b3ade7 doc: update release notes 2022-05-16 12:05:55 +09:00
Ian Barwick
89ba005726 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.
2022-05-16 11:53:15 +09:00
Ian Barwick
5ddf450919 dbutils: move get_wal_receiver_pid() to a more consistent location 2022-05-16 10:41:31 +09:00
Ian Barwick
20342bb8ee doc: expand non-superuser permissions explanation
Information about using repmgr with a non-superuser was spread
throughout individual documentation systems; this commit creates
an overview of requirements and potential issues.
2022-05-13 14:30:09 +09:00
Ian Barwick
ea36c5dde3 doc: clarify permissions requirements in "standby switchover" 2022-05-13 14:26:50 +09:00
Ian Barwick
fc72e0bf93 doc: clarify permissions requirements in "standby clone" 2022-05-13 14:26:44 +09:00
Ian Barwick
b10e9b89dd standby clone: update source comment 2022-05-13 13:39:23 +09:00
Ian Barwick
a7d87d5992 doc: add missing short form option to "standby clone" 2022-05-13 11:56:06 +09:00
Ian Barwick
015c0c8458 dbutils.c: fix typo in comment 2022-05-13 11:56:02 +09:00
Ian Barwick
474d85d647 repmgr: fix error message
It's possible the missing node record might be for a witness server,
though we have no way of knowing that.
2022-05-11 14:57:34 +09:00
zhouhj43183
207057a159 repmgrd: ensure witness node marked active
Previously, if the witness node's PostgreSQL was unreachable, it would
be marked as "inactive" on the primary, and under some circumstances
would not be corrected to "active" once the witness node's PostgreSQL
came back.

PR #754; some modifications by Ian Barwick.
2022-05-11 13:36:46 +09:00
Ian Barwick
65d796ee3e doc: update release notes
Add notes about when PostgreSQL and/or repmgrd restart required.

GitHub #752.
2022-05-10 16:23:50 +09:00
Ian Barwick
0fb4c0930a doc: update release notes 2022-05-10 16:09:46 +09:00
Ian Barwick
cee3b8446a standby clone: don't error out if unable to determine cluster size
The cluster size check is purely informative, and is not in any way
essential for the standby clone operation. As it's possible the query
may fail if the repmgr user does not have sufficient privileges to
query all databases in the cluster, we can simply ignore any failure.

Note that the code comment indicated the query also served to sanity-
check that queries can actually be executed. While this was the case
historically, the preceding server version check now serves the same
purpose and will not have the same risk of failure due to missing
permissions.
2022-05-10 15:08:57 +09:00
Ian Barwick
90a700c7c0 node check: prevent WARNING in --downstream --nagios output 2022-04-20 17:46:39 +09:00
Ian Barwick
cc4475b8e2 node check: fix --downstream --nagios output
Ensure the performance data output (the bit after the pipe) contains
information in a pareseable format.

GitHub #749.
2022-04-20 17:46:34 +09:00
Ian Barwick
9f1c9ef829 node check: tweak --upstream --nagios output
No data follows the pipe, so omit it and add missing line break.
2022-04-20 17:46:27 +09:00
Ian Barwick
2a05f495f6 doc: fix XML error 2022-04-19 11:26:01 +09:00
Felix Dreissig
d342acfefe Doc: Update or remove references to recovery.conf
The recovery.conf file is not present anymore for Postgres >= 12.

PR 748.
2022-04-19 11:09:26 +09:00
Felix Dreissig
2f27fec510 Sample config: Update link to docs 2022-04-19 11:09:21 +09:00
James Stroud
a80ee17b6c Update install-packages.xml postgres 14 and not 11
Hi, I think you had a typo, you meant to say Postgres 14 and not 11.  If am wrong just ignore, thanks and take care James Stroud
2022-03-31 16:03:41 +09:00
Ian Barwick
595494f8a1 doc: use "note" rather than "important" 2022-03-16 10:40:51 +09:00
Ian Barwick
3ca4c273fa doc: update witness server notes
- clarify that a separate PostgreSQL instance is needed for each
  witness server
- remove historical 3.x reference
2022-03-16 10:33:56 +09:00
Ian Barwick
41f0688f69 docs: update package installation instructions
- use "dnf" in place of "yum"
- mention Rocky Linux
- remove 9.6 examples
2022-03-11 10:30:02 +09:00
21 changed files with 622 additions and 271 deletions

11
HISTORY
View File

@@ -1,5 +1,14 @@
5.3.1 2022-??-??
5.3.2 2022-??-??
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)
general: ensure replication slots can be dropped by a
replication-only user (Ian)
5.3.1 2022-02-15
repmgrd: fixes for potential connection leaks (hslightdb)
repmgr: fix upgrade path from repmgr 4.2 and 4.3 to repmgr 5.3 (Ian)
5.3.0 2021-10-12
standby switchover: improve handling of node rejoin failure (Ian)

View File

@@ -1,6 +1,6 @@
AC_INIT([repmgr], [5.3.1], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
AC_INIT([repmgr], [5.3.2], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
AC_COPYRIGHT([Copyright (c) 2010-2021, EnterpriseDB Corporation])
AC_COPYRIGHT([Copyright (c) 2010-2022, EnterpriseDB Corporation])
AC_CONFIG_HEADER(config.h)

132
dbutils.c
View File

@@ -61,6 +61,8 @@ static ReplSlotStatus _verify_replication_slot(PGconn *conn, char *slot_name, PQ
static bool _create_event(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details, t_event_info *event_info, bool send_notification);
static NodeAttached _is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state, bool quiet);
/*
* This provides a standardized way of logging database errors. Note
* that the provided PGconn can be a normal or a replication connection;
@@ -1289,21 +1291,16 @@ get_cluster_size(PGconn *conn, char *size)
initPQExpBuffer(&query);
appendPQExpBufferStr(&query,
"SELECT pg_catalog.pg_size_pretty(pg_catalog.sum(pg_catalog.pg_database_size(oid))::bigint) "
" FROM pg_catalog.pg_database ");
" FROM pg_catalog.pg_database ");
log_verbose(LOG_DEBUG, "get_cluster_size():\n%s", query.data);
res = PQexec(conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, query.data, _("get_cluster_size(): unable to execute query"));
success = false;
}
else
{
snprintf(size, MAXLEN, "%s", PQgetvalue(res, 0, 0));
}
termPQExpBuffer(&query);
PQclear(res);
@@ -1826,6 +1823,30 @@ get_timeline_history(PGconn *repl_conn, TimeLineID tli)
}
pid_t
get_wal_receiver_pid(PGconn *conn)
{
PGresult *res = NULL;
pid_t wal_receiver_pid = UNKNOWN_PID;
res = PQexec(conn, "SELECT repmgr.get_wal_receiver_pid()");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_error(_("unable to execute \"SELECT repmgr.get_wal_receiver_pid()\""));
log_detail("%s", PQerrorMessage(conn));
}
else if (!PQgetisnull(res, 0, 0))
{
wal_receiver_pid = atoi(PQgetvalue(res, 0, 0));
}
PQclear(res);
return wal_receiver_pid;
}
/* =============================== */
/* user/role information functions */
/* =============================== */
@@ -1867,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
@@ -2246,29 +2303,6 @@ repmgrd_pause(PGconn *conn, bool pause)
return success;
}
pid_t
get_wal_receiver_pid(PGconn *conn)
{
PGresult *res = NULL;
pid_t wal_receiver_pid = UNKNOWN_PID;
res = PQexec(conn, "SELECT repmgr.get_wal_receiver_pid()");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_error(_("unable to execute \"SELECT repmgr.get_wal_receiver_pid()\""));
log_detail("%s", PQerrorMessage(conn));
}
else if (!PQgetisnull(res, 0, 0))
{
wal_receiver_pid = atoi(PQgetvalue(res, 0, 0));
}
PQclear(res);
return wal_receiver_pid;
}
int
repmgrd_get_upstream_node_id(PGconn *conn)
@@ -4576,17 +4610,17 @@ drop_replication_slot_replprot(PGconn *repl_conn, char *slot_name)
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
"DROP_REPLICATION_SLOT %s",
"DROP_REPLICATION_SLOT %s;",
slot_name);
log_verbose(LOG_DEBUG, "drop_replication_slot_replprot():\n %s", query.data);
res = PQexec(repl_conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
if (PQresultStatus(res) != PGRES_TUPLES_OK || !PQntuples(res))
{
log_db_error(repl_conn, query.data,
_("drop_replication_slot_sql(): unable to drop replication slot \"%s\""),
_("drop_replication_slot_replprot(): unable to drop replication slot \"%s\""),
slot_name);
success = false;
@@ -5704,7 +5738,7 @@ get_node_timeline(PGconn *conn, char *timeline_id_str)
TimeLineID timeline_id = UNKNOWN_TIMELINE_ID;
/*
* PG_control_checkpoint() was introduced in PostgreSQL 9.6
* pg_control_checkpoint() was introduced in PostgreSQL 9.6
*/
if (PQserverVersion(conn) >= 90600)
{
@@ -5792,6 +5826,19 @@ get_node_replication_stats(PGconn *conn, t_node_info *node_info)
NodeAttached
is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
{
return _is_downstream_node_attached(conn, node_name, node_state, false);
}
NodeAttached
is_downstream_node_attached_quiet(PGconn *conn, char *node_name, char **node_state)
{
return _is_downstream_node_attached(conn, node_name, node_state, true);
}
NodeAttached
_is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state, bool quiet)
{
PQExpBufferData query;
PGresult *res = NULL;
@@ -5826,9 +5873,12 @@ is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
*/
if (PQntuples(res) > 1)
{
log_error(_("multiple entries with \"application_name\" set to \"%s\" found in \"pg_stat_replication\""),
node_name);
log_hint(_("verify that a unique node name is configured for each node"));
if (quiet == false)
{
log_error(_("multiple entries with \"application_name\" set to \"%s\" found in \"pg_stat_replication\""),
node_name);
log_hint(_("verify that a unique node name is configured for each node"));
}
PQclear(res);
@@ -5837,7 +5887,8 @@ is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
if (PQntuples(res) == 0)
{
log_warning(_("node \"%s\" not found in \"pg_stat_replication\""), node_name);
if (quiet == false)
log_warning(_("node \"%s\" not found in \"pg_stat_replication\""), node_name);
PQclear(res);
@@ -5863,9 +5914,10 @@ is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
if (strcmp(state, "streaming") != 0)
{
log_warning(_("node \"%s\" attached in state \"%s\""),
node_name,
state);
if (quiet == false)
log_warning(_("node \"%s\" attached in state \"%s\""),
node_name,
state);
PQclear(res);

View File

@@ -450,9 +450,11 @@ int get_ready_archive_files(PGconn *conn, const char *data_directory);
bool identify_system(PGconn *repl_conn, t_system_identification *identification);
uint64 system_identifier(PGconn *conn);
TimeLineHistoryEntry *get_timeline_history(PGconn *repl_conn, TimeLineID tli);
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);
@@ -467,7 +469,6 @@ pid_t repmgrd_get_pid(PGconn *conn);
bool repmgrd_is_running(PGconn *conn);
bool repmgrd_is_paused(PGconn *conn);
bool repmgrd_pause(PGconn *conn, bool pause);
pid_t get_wal_receiver_pid(PGconn *conn);
int repmgrd_get_upstream_node_id(PGconn *conn);
bool repmgrd_set_upstream_node_id(PGconn *conn, int node_id);
@@ -597,6 +598,7 @@ int get_replication_lag_seconds(PGconn *conn);
TimeLineID get_node_timeline(PGconn *conn, char *timeline_id_str);
void get_node_replication_stats(PGconn *conn, t_node_info *node_info);
NodeAttached is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state);
NodeAttached is_downstream_node_attached_quiet(PGconn *conn, char *node_name, char **node_state);
void set_upstream_last_seen(PGconn *conn, int upstream_node_id);
int get_upstream_last_seen(PGconn *conn, t_server_type node_type);

View File

@@ -249,16 +249,16 @@
For a standby which has been manually cloned or recovered from an external
backup manager such as Barman, the command
<command><link linkend="repmgr-standby-clone">repmgr standby clone --replication-conf-only</link></command>
can be used to create the correct <filename>recovery.conf</filename> file for
can be used to create the correct replication configuration file for
use with &repmgr; (and will create a replication slot if required). Once this has been done,
<link linkend="repmgr-standby-register">register the node</link> as usual.
</para>
</sect2>
<sect2 id="faq-repmgr-recovery-conf" >
<title>What does &repmgr; write in <filename>recovery.conf</filename>, and what options can be set there?</title>
<title>What does &repmgr; write in the replication configuration, and what options can be set there?</title>
<para>
See section <link linkend="repmgr-standby-clone-recovery-conf">Customising recovery.conf</link>.
See section <link linkend="repmgr-standby-clone-recovery-conf">Customising replication configuration</link>.
</para>
</sect2>
@@ -366,11 +366,11 @@
</para>
</sect2>
<sect2 id="faq-repmgr-recovery-conf-quoted-values" xreflabel="Quoted values in recovery.conf">
<title>Why are some values in <filename>recovery.conf</filename> surrounded by pairs of single quotes?</title>
<sect2 id="faq-repmgr-recovery-conf-quoted-values" xreflabel="Quoted values in replication.conf">
<title>Why are some values in <filename>recovery.conf</filename> (PostgreSQL 11 and earlier) surrounded by pairs of single quotes?</title>
<para>
This is to ensure that user-supplied values which are written as parameter values in <filename>recovery.conf</filename>
are escaped correctly and do not cause errors when <filename>recovery.conf</filename> is parsed.
are escaped correctly and do not cause errors when the file is parsed.
</para>
<para>
The escaping is performed by an internal PostgreSQL routine, which leaves strings consisting
@@ -419,9 +419,9 @@
<para>
&repmgrd; can monitor delayed standbys - those set up with
<varname>recovery_min_apply_delay</varname> set to a non-zero value
in <filename>recovery.conf</filename> - but as it's not currently possible
to directly examine the value applied to the standby, &repmgrd;
may not be able to properly evaluate the node as a promotion candidate.
in the replication configuration. However &repmgrd; does not currently
consider this setting, and therefore may not be able to properly evaluate
the node as a promotion candidate.
</para>
<para>
We recommend that delayed standbys are explicitly excluded from promotion

View File

@@ -15,13 +15,79 @@
See also: <xref linkend="upgrading-repmgr"/>
</para>
<!-- remember to update the release date in ../repmgr_version.h.in -->
<!-- remember to update the release date in ../repmgr_version.h.in -->
<sect1 id="release-5.3.2">
<title id="release-current">Release 5.3.2</title>
<para><emphasis>Wed 25 May, 2022</emphasis></para>
<para>
&repmgr; 5.3.2 is a minor release.
</para>
<para>
Any running &repmgrd; instances should be restarted following this upgrade.
</para>
<para>
If upgrading from &repmgr; 5.2.1 or earlier, a PostgreSQL restart <emphasis>is</emphasis> required.
</para>
<sect2>
<title>Bug fixes</title>
<para>
<itemizedlist>
<listitem>
<para>
<command><link linkend="repmgr-node-status">repmgr node status</link></command>:
fix output with <option>--downstream</option> <option>--nagios</option> option combination.
GitHub #749.
</para>
</listitem>
<listitem>
<para>
<command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>:
don't treat inability to determine the cluster size as a fatal error.
</para>
<para>
The cluster size is displayed for informational purposes and is not essential
for execution of the clone operation. As the &repmgr; user may not have permissions
for all databases in the cluster, ignore the cluster size query if it fails.
</para>
</listitem>
<listitem>
<para>
&repmgrd;: ensure the witness node record on the primary is always marked
as <literal>active</literal> if previously marked <literal>inactive</literal>.
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>
<listitem>
<para>
If the &repmgr; user is a non-superuser, and a replication-only user exists,
ensure redundant replication slots are dropped correctly even
if the <option>-S/--superuser</option> option is not provided.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="release-5.3.1">
<title id="release-current">Release 5.3.1</title>
<title>Release 5.3.1</title>
<para><emphasis>Tue 15 February, 2022</emphasis></para>
<para>
&repmgr; 5.3.1 is a minor release.
</para>
<para>
If &repmgrd; is in use, it should be restarted on all nodes where it is running.
</para>
<para>
If upgrading from &repmgr; 5.2.1 or earlier, a PostgreSQL restart <emphasis>is</emphasis> required.
</para>
<sect2>
<title>Bug fixes</title>
<para>
@@ -56,6 +122,11 @@
This release provides support for <ulink url="https://www.postgresql.org/docs/14/release-14.html">PostgreSQL 14</ulink>,
released in September 2021.
</para>
<para>
Note that this release includes changes to the &repmgr; shared library module, meaning a
PostgreSQL restart <emphasis>is</emphasis> required on all nodes where &repmgr; is installed.
</para>
<sect2>
<title>Improvements</title>
<para>

View File

@@ -197,7 +197,7 @@ description = "Main cluster"
<para>
As a fallback in case streaming replication is interrupted, PostgreSQL can optionally
retrieve WAL files from an archive, such as that provided by Barman. This is done by
setting <varname>restore_command</varname> in <filename>recovery.conf</filename> to
setting <varname>restore_command</varname> in the replication configuration to
a valid shell command which can retrieve a specified WAL file from the archive.
</para>
<para>
@@ -328,9 +328,9 @@ description = "Main cluster"
&repmgr; supports cascading replication. When cloning a standby,
set the command-line parameter <literal>--upstream-node-id</literal> to the
<varname>node_id</varname> of the server the standby should connect to, and
&repmgr; will create <filename>recovery.conf</filename> to point to it. Note
&repmgr; will create a replication configuration file to point to it. Note
that if <literal>--upstream-node-id</literal> is not explicitly provided,
&repmgr; will set the standby's <filename>recovery.conf</filename> to
&repmgr; will set the standby's replication configuration to
point to the primary node.
</para>
<para>
@@ -392,7 +392,7 @@ description = "Main cluster"
does not yet exist. In this case you can clone from the primary (or
another upstream node); provide the parameter <literal>--upstream-conninfo</literal>
to explicitly set the upstream's <varname>primary_conninfo</varname> string
in <filename>recovery.conf</filename>.
in the replication configuration.
</simpara>
</tip>
</sect1>
@@ -491,12 +491,12 @@ description = "Main cluster"
</note>
<para>
If, for whatever reason, you wish to include the password in <filename>recovery.conf</filename>,
If, for whatever reason, you wish to include the password in the replication configuration file,
set <varname>use_primary_conninfo_password</varname> to <literal>true</literal> in
<filename>repmgr.conf</filename>. This will read a password set in <varname>PGPASSWORD</varname>
(but not <filename>~/.pgpass</filename>) and place it into the <varname>primary_conninfo</varname>
string in <filename>recovery.conf</filename>. Note that <varname>PGPASSWORD</varname>
will need to be set during any action which causes <filename>recovery.conf</filename> to be
string in the replication configuration. Note that <varname>PGPASSWORD</varname>
will need to be set during any action which causes the replication configuration file to be
rewritten, e.g. <xref linkend="repmgr-standby-follow"/>.
</para>
</sect2>
@@ -508,7 +508,7 @@ description = "Main cluster"
user (in addition to the user who manages the &repmgr; metadata). In this case,
the replication user should be set in <filename>repmgr.conf</filename> via the parameter
<varname>replication_user</varname>; &repmgr; will use this value when making
replication connections and generating <filename>recovery.conf</filename>. This
replication connections and generating the replication configuration. This
value will also be stored in the parameter <literal>repmgr.nodes</literal>
table for each node; it no longer needs to be explicitly specified when
cloning a node or executing <xref linkend="repmgr-standby-follow"/>.

View File

@@ -7,19 +7,186 @@
</indexterm>
<para>
&repmgr; requires that the database defined in the <varname>conninfo</varname>
setting contains the <literal>repmgr</literal> extension. The database user defined in the
<varname>conninfo</varname> setting must be able to access this database and
the database objects contained within the extension.
</para>
<para>
The <literal>repmgr</literal> extension can only be installed by a superuser.
If the &repmgr; user is a superuser, &repmgr; will create the extension automatically.
If the &repmgr; database user (the PostgreSQL user defined in the
<varname>conninfo</varname> setting is a superuser, no further user permissions need
to be granted.
</para>
<para>
Alternatively, the extension can be created manually by a superuser
(with &quot;<command>CREATE EXTENSION repmgr</command>&quot;) before executing
<link linkend="repmgr-primary-register">repmgr primary register</link>.
</para>
<sect2 id="configuration-permissions-no-superuser" xreflabel="Non-super user permissions">
<title>repmgr user as a non-superuser</title>
<para>
In principle the &repmgr; database user does not need to be a superuser.
In this case the &repmgr; will need to be granted execution permissions on certain
functions, and membership of certain roles. However be aware that &repmgr; does
expect to be able to execute certain commands which are restricted to superusers;
in this case either a superuser must be specified with the <option>-S</option>/<option>--superuser</option>
(where available) option, or the corresponding action should be executed manually as a superuser.
</para>
<para>
The following sections describe the actions needed to use &repmgr; with a non-superuser,
and relevant caveats.
</para>
<sect3 id="configuration-permissions-replication" xreflabel="Replication role">
<title>Replication role</title>
<para>
&repmgr; requires a database user with the <literal>REPLICATION</literal> role
to be able to create a replication connection and (if configured) to administer
replication slots.
</para>
<para>
By default this is the database user defined in the <varname>conninfo</varname>
setting. This user can be:
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara>
a superuser
</simpara>
</listitem>
<listitem>
<simpara>
a non-superuser with the <literal>REPLICATION</literal> role
</simpara>
</listitem>
<listitem>
<simpara>
another user defined in the <filename>repmgr.conf</filename> parameter <varname>replication_user</varname> with the <literal>REPLICATION</literal> role
</simpara>
</listitem>
</itemizedlist>
</para>
</sect3>
<sect3 id="configuration-permissions-roles" xreflabel="Database roles for non-superusers">
<title>Database roles</title>
<para>
A non-superuser &repmgr; database user should be a member of the following
<ulink url="https://www.postgresql.org/docs/current/predefined-roles.html">predefined roles</ulink>
(PostgreSQL 10 and later):
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara>
<varname>pg_read_all_stats</varname>
(to read the <varname>status</varname> column of <literal>pg_stat_replication</literal>
and execute <function>pg_database_size()</function> on all databases)
</simpara>
</listitem>
<listitem>
<simpara>
<varname>pg_read_all_settings</varname> (to access the <varname>data_directory</varname> setting)
</simpara>
</listitem>
</itemizedlist>
Alternatively the meta-role <varname>pg_monitor</varname> can be granted, which includes membership
of the above predefined roles.
</para>
<para>
Membership of these roles can be granted with e.g. <command>GRANT pg_read_all_stats TO repmgr</command>.
</para>
<para>
Users of PostgreSQL 9.6 or earlier should upgrade to a supported PostgreSQL version, or provide
the <option>-S</option>/<option>--superuser</option> where available.
</para>
</sect3>
<sect3 id="configuration-permissions-extension" xreflabel="Extension creation">
<title>Extension creation</title>
<para>
&repmgr; requires that the database defined in the <varname>conninfo</varname>
setting contains the <literal>repmgr</literal> extension. The database user defined in the
<varname>conninfo</varname> setting must be able to access this database and
the database objects contained within the extension.
</para>
<para>
The <literal>repmgr</literal> extension can only be installed by a superuser.
If the &repmgr; user is a superuser, &repmgr; will create the extension automatically.
</para>
<para>
Alternatively, the extension can be created manually by a superuser
(with &quot;<command>CREATE EXTENSION repmgr</command>&quot;) before executing
<link linkend="repmgr-primary-register">repmgr primary register</link>.
</para>
</sect3>
<sect3 id="configuration-permissions-functions" xreflabel="Function permissions for non-superusers">
<title>Function permissions</title>
<para>
If the &repmgr; database user is not a superuser, <literal>EXECUTE</literal> permission should be
granted on the following function:
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara>
<function>pg_wal_replay_resume()</function> (required by &repmgrd; during failover operations;
if permission is not granted, the failoved process may not function reliably if a node
has WAL replay paused)
</simpara>
</listitem>
<listitem>
<simpara>
<function>pg_promote()</function> (PostgreSQL 12 and later; if permission is not granted,
&repmgr; will fall back to <command>pg_ctl promote</command>)
</simpara>
</listitem>
</itemizedlist>
</para>
<para>
<literal>EXECUTE</literal> permission on functions can be granted with e.g.:
<command>GRANT EXECUTE ON FUNCTION pg_catalog.pg_wal_replay_resume() TO repmgr</command>.
</para>
</sect3>
<sect3 id="configuration-permissions-superuser-required" xreflabel="repmgr actions requiring a superuser">
<title>repmgr actions requiring a superuser</title>
<para>
In some circumstances, &repmgr; may need to perform an operation which cannot be delegated to a
non-superuser.
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara>
The <command>CHECKPOINT</command> command is executed by
<link linkend="repmgr-standby-switchover">repmgr standby switchover</link>. This can only
be executed by a superuser; if the &repmgr; user is not a superuser,
the <option>-S</option>/<option>--superuser</option> should be used.
</simpara>
<simpara>
If &repmgr; is not able to execute <command>CHECKPOINT</command>,
there is a risk that the demotion candidate may not be able to shut down as smoothly as might otherwise
have been the case.
</simpara>
</listitem>
<listitem>
<simpara>
The <command>ALTER SYSTEM</command> is executed by &repmgrd; if
<varname>standby_disconnect_on_failover</varname> is set to <literal>true</literal> in
<filename>repmgr.conf</filename>. <command>ALTER SYSTEM</command> can only be executed by
a superuser; if the &repmgr; user is not a superuser, this functionality will not be available.
</simpara>
</listitem>
</itemizedlist>
</para>
</sect3>
<sect3 id="configuration-permissions-superuser-option" xreflabel="repmgr commands with --superuser option">
<title>repmgr commands with --superuser option</title>
<para>
The following repmgr commands provide the <option>-S</option>/<option>--superuser</option> option:
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara><link linkend="repmgr-standby-clone">repmgr standby clone</link> (to be able to copy configuration files outside of the data directory if <option>--copy-external-config-files</option> provided)</simpara>
</listitem>
<listitem>
<simpara><link linkend="repmgr-standby-switchover">repmgr standby switchover</link> (to execute <command>CHECKPOINT</command>)</simpara>
</listitem>
<listitem>
<simpara><link linkend="repmgr-node-check">repmgr node check</link> (to execute <command>repmgr node check --data-directory-config</command>; note this is also called by <link linkend="repmgr-standby-switchover">repmgr standby switchover</link>)</simpara>
</listitem>
<listitem>
<simpara><link linkend="repmgr-node-service">repmgr node service</link> (to execute <command>CHECKPOINT</command> via the <option>--checkpoint</option>; note this is also called by <link linkend="repmgr-standby-switchover">repmgr standby switchover</link>)</simpara>
</listitem>
</itemizedlist>
</para>
</sect3>
</sect2>
</sect1>

View File

@@ -92,47 +92,36 @@
(this enables the EDB repository as a source of &repmgr; packages).
</para>
<para>
For example, for PostgreSQL 11 on CentOS, execute:
For example, for PostgreSQL 14 on Rocky Linux 8, execute:
<programlisting>
curl https://dl.enterprisedb.com/default/release/get/11/rpm | sudo bash</programlisting>
curl https://dl.enterprisedb.com/default/release/get/14/rpm | sudo bash</programlisting>
</para>
<para>
For PostgreSQL 9.6 on CentOS, execute:
<programlisting>
curl https://dl.enterprisedb.com/default/release/get/9.6/rpm | sudo bash</programlisting>
</para>
<para>
Verify that the repository is installed with:
<programlisting>
sudo yum repolist</programlisting>
sudo dnf repolist</programlisting>
The output should contain two entries like this:
<programlisting>
2ndquadrant-dl-default-release-pg11/7/x86_64 2ndQuadrant packages (PG11) for 7 - x86_64 18
2ndquadrant-dl-default-release-pg11-debug/7/x86_64 2ndQuadrant packages (PG11) for 7 - x86_64 - Debug 8</programlisting>
2ndquadrant-dl-default-release-pg14 2ndQuadrant packages (PG14) for 8 - x86_64
2ndquadrant-dl-default-release-pg14-debug 2ndQuadrant packages (PG14) for 8 - x86_64 - Debug</programlisting>
</para>
</listitem>
<listitem>
<para>
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr14</literal>):
<programlisting>
sudo yum install repmgr11</programlisting>
sudo dnf install repmgr14</programlisting>
</para>
<note>
<para>
For packages for PostgreSQL 9.6 and earlier, the package name does not contain
a period between major and minor version numbers, e.g.
<literal>repmgr96</literal>.
</para>
</note>
<tip>
<para>
To determine the names of available packages, execute:
<programlisting>
yum search repmgr</programlisting>
dnf search repmgr</programlisting>
</para>
<para>
In CentOS 7 and earlier, use <literal>yum</literal> instead of <literal>dnf</literal>.
</para>
</tip>
@@ -153,36 +142,42 @@ yum search repmgr</programlisting>
the packages are installed from.
</para>
<para>
To ensure the EDB repository is always prioritised, install <literal>yum-plugin-priorities</literal>
and set the repository priorities accordingly.
To ensure the EDB repository is always prioritised, set the <literal>priority</literal> option
in the repository configuration file (e.g. <filename>/etc/yum.repos.d/2ndquadrant-dl-default-release-pg14.repo</filename>
accordingly.
</para>
<note>
<para>
With CentOS 7 and earlier, the package <literal>yum-plugin-priorities</literal> must be installed
to be able to set the repository priority.
</para>
</note>
<para>
<emphasis>Installing a specific package version</emphasis>
</para>
<para>
To install a specific package version, execute <command>yum --showduplicates list</command>
To install a specific package version, execute <command>dnf --showduplicates list</command>
for the package in question:
<programlisting>
[root@localhost ~]# yum --showduplicates list repmgr11
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: ftp.tsukuba.wide.ad.jp
* epel: nrt.edge.kernel.org
* extras: ftp.tsukuba.wide.ad.jp
* updates: ftp.tsukuba.wide.ad.jp
[root@localhost ~]# dnf --showduplicates list repmgr10
Last metadata expiration check: 0:09:15 ago on Fri 11 Mar 2022 01:09:19 AM UTC.
Installed Packages
repmgr11.x86_64 4.4.0-1.rhel7 @pgdg11
repmgr10.x86_64 5.3.1-1.el8 @2ndquadrant-dl-default-release-pg10
Available Packages
repmgr11.x86_64 4.2-1.el7 2ndquadrant-dl-default-release-pg11
repmgr11.x86_64 4.2-2.el7 2ndquadrant-dl-default-release-pg11
repmgr11.x86_64 4.3-1.el7 2ndquadrant-dl-default-release-pg11
repmgr11.x86_64 4.4-1.el7 2ndquadrant-dl-default-release-pg11</programlisting>
repmgr10.x86_64 5.0.0-1.rhel8 pgdg10
repmgr10.x86_64 5.1.0-1.el8 2ndquadrant-dl-default-release-pg10
repmgr10.x86_64 5.1.0-1.rhel8 pgdg10
repmgr10.x86_64 5.1.0-2.el8 2ndquadrant-dl-default-release-pg10
repmgr10.x86_64 5.2.0-1.el8 2ndquadrant-dl-default-release-pg10
repmgr10.x86_64 5.2.0-1.rhel8 pgdg10
repmgr10.x86_64 5.2.1-1.el8 2ndquadrant-dl-default-release-pg10
repmgr10.x86_64 5.3.0-1.el8 2ndquadrant-dl-default-release-pg10
repmgr10.x86_64 5.3.1-1.el8 2ndquadrant-dl-default-release-pg10</programlisting>
then append the appropriate version number to the package name with a hyphen, e.g.:
<programlisting>
[root@localhost ~]# yum install repmgr11-4.3-1.el7</programlisting>
[root@localhost ~]# dnf install repmgr10-5.3.0-1.el8</programlisting>
</para>
<para>
<emphasis>Installing old packages</emphasis>
</para>
@@ -190,7 +185,6 @@ repmgr11.x86_64 4.4-1.el7 2nd
See appendix <link linkend="packages-old-versions-rhel-centos">Installing old package versions</link>
for details on how to retrieve older package versions.
</para>
</sect3>
</sect2>

View File

@@ -405,9 +405,10 @@
</programlisting>
<para>
This has cloned the PostgreSQL data directory files from the primary <literal>node1</literal>
using PostgreSQL's <command>pg_basebackup</command> utility. A <filename>recovery.conf</filename>
file containing the correct parameters to start streaming from this primary server will be created
automatically.
using PostgreSQL's <command>pg_basebackup</command> utility. Replication configuration
containing the correct parameters to start streaming from this primary server will be
automatically appended to <filename>postgresql.auto.conf</filename>. (In PostgreSQL 11
and earlier the file <filename>recovery.conf</filename> will be created).
</para>
<note>
<simpara>
@@ -481,9 +482,10 @@
sender_port | 5432
conninfo | user=repmgr dbname=replication host=node1 application_name=node2
</programlisting>
Note that the <varname>conninfo</varname> value is that generated in <filename>recovery.conf</filename>
and will differ slightly from the primary's <varname>conninfo</varname> as set in <filename>repmgr.conf</filename> -
among others it will contain the connecting node's name as <varname>application_name</varname>.
Note that the <varname>conninfo</varname> value is that generated in <filename>postgresql.auto.conf</filename>
(PostgreSQL 11 and earlier: <filename>recovery.conf</filename>) and will differ slightly from the primary's
<varname>conninfo</varname> as set in <filename>repmgr.conf</filename> - among others it will contain the
connecting node's name as <varname>application_name</varname>.
</para>
</sect1>

View File

@@ -332,6 +332,12 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
node to the same path on the standby (default) or to the
PostgreSQL data directory.
</para>
<para>
Note that to be able to use this option, the &repmgr; user must be a superuser or
member of the <literal>pg_read_all_settings</literal> predefined role.
If this is not the case, provide a valid superuser with the
<option>-S</option>/<option>--superuser</option> option.
</para>
</listitem>
</varlistentry>
@@ -399,11 +405,15 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
</varlistentry>
<varlistentry>
<term><option>--superuser</option></term>
<term><option>-S</option>/<option>--superuser</option></term>
<listitem>
<para>
If the &repmgr; user is not a superuser, the name of a valid superuser must
be provided with this option.
The name of a valid PostgreSQL superuser can be provided with this option.
</para>
<para>
This is only required if the <option>--copy-external-config-files</option> was provided
and the &repmgr; user is not a superuser or member of the <literal>pg_read_all_settings</literal>
predefined role.
</para>
</listitem>
</varlistentry>

View File

@@ -64,6 +64,13 @@
<refsect1>
<title>User permission requirements</title>
<para><emphasis>data_directory</emphasis></para>
<para>
&repmgr; needs to be able to determine the location of the data directory on the
demotion candidate. If the &repmgr; is not a superuser or member of the <varname>pg_read_all_settings</varname>
<ulink url="https://www.postgresql.org/docs/current/predefined-roles.html">predefined roles</ulink>,
the name of a superuser should be provided with the <option>-S</option>/<option>--superuser</option> option.
</para>
<para><emphasis>CHECKPOINT</emphasis></para>
<para>
&repmgr; executes <command>CHECKPOINT</command> on the demotion candidate as part of the shutdown
@@ -72,7 +79,7 @@
<para>
Note that <command>CHECKPOINT</command> requires database superuser permissions to execute.
If the <literal>repmgr</literal> user is not a superuser, the name of a superuser should be
provided with the <option>-S</option>/<option>--superuser</option>.
provided with the <option>-S</option>/<option>--superuser</option> option.
</para>
<para>
If &repmgr; is unable to execute the <command>CHECKPOINT</command> command, the switchover

View File

@@ -81,11 +81,15 @@
</para>
<note>
<simpara>
&repmgr; 3.3 and earlier provided a <command>repmgr create witness</command>
command, which would automatically create a PostgreSQL instance. However
this often resulted in an unsatisfactory, hard-to-customise instance.
A PostgreSQL instance can only accommodate a single witness server.
</simpara>
<simpara>
If you are planning to use a single server to support more than one
witness server, a separate PostgreSQL instance is required for each
witness server in use.
</simpara>
</note>
<para>
The witness server should be configured in the same way as a normal
&repmgr; node; see section <xref linkend="configuration"/>.

View File

@@ -1327,7 +1327,7 @@ do_node_check_downstream(PGconn *conn, OutputMode mode, t_node_info *node_info,
continue;
}
if (is_downstream_node_attached(conn, cell->node_info->node_name, NULL) != NODE_ATTACHED)
if (is_downstream_node_attached_quiet(conn, cell->node_info->node_name, NULL) != NODE_ATTACHED)
{
missing_nodes_count++;
item_list_append_format(&missing_nodes,
@@ -1395,49 +1395,32 @@ do_node_check_downstream(PGconn *conn, OutputMode mode, t_node_info *node_info,
{
case OM_NAGIOS:
{
printf("REPMGR_DOWNSTREAM_SERVERS %s: %s | ",
output_check_status(status),
details.data);
if (missing_nodes_count)
{
ItemListCell *missing_cell = NULL;
bool first = true;
printf("missing: ");
appendPQExpBufferStr(&details, " (missing: ");
for (missing_cell = missing_nodes.head; missing_cell; missing_cell = missing_cell->next)
{
if (first == false)
printf(", ");
appendPQExpBufferStr(&details, ", ");
else
first = false;
if (first == false)
printf("%s", missing_cell->string);
appendPQExpBufferStr(&details, missing_cell->string);
}
appendPQExpBufferChar(&details, ')');
}
if (expected_nodes_count - missing_nodes_count)
{
ItemListCell *attached_cell = NULL;
bool first = true;
if (missing_nodes_count)
printf("; ");
printf("attached: ");
for (attached_cell = attached_nodes.head; attached_cell; attached_cell = attached_cell->next)
{
if (first == false)
printf(", ");
else
first = false;
if (first == false)
printf("%s", attached_cell->string);
}
}
printf("\n");
printf("REPMGR_DOWNSTREAM_SERVERS %s: %s | attached=%i, missing=%i\n",
output_check_status(status),
details.data,
expected_nodes_count - missing_nodes_count,
missing_nodes_count);
}
break;
case OM_CSV:
@@ -1535,7 +1518,7 @@ do_node_check_upstream(PGconn *conn, OutputMode mode, t_node_info *node_info, Ch
{
case OM_NAGIOS:
{
printf("REPMGR_UPSTREAM_SERVER %s: %s | ",
printf("REPMGR_UPSTREAM_SERVER %s: %s\n",
output_check_status(status),
details.data);
}

View File

@@ -95,6 +95,8 @@ static char barman_command_buf[MAXLEN] = "";
* be run and which of the available users, which will be one
* of the repmgr user, the replication user (if available) or
* the superuser (if available).
*
* This is determined in check_source_server().
*/
static t_user_type SettingsUser = REPMGR_USER;
@@ -3346,10 +3348,9 @@ do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_n
update_node_record_slot_name(primary_conn, config_file_options.node_id, local_node_record.slot_name);
}
if (create_replication_slot(follow_target_conn,
local_node_record.slot_name,
NULL,
follow_target_node_record,
output) == false)
{
log_error("%s", output->data);
@@ -5783,20 +5784,18 @@ check_source_server()
}
/*
* If a connection was established, perform some sanity checks on the
* provided upstream connection.
* The server version check will also serve as a sanity-check that we can
* actually execute queries on this connection.
*/
source_server_version_num = check_server_version(source_conn, "primary", true, NULL);
/*
* It's not essential to know the cluster size, but useful to sanity-check
* we can actually run a query before going any further.
* The cluster size is nice to have, but not essential to know, so only display
* something if the user has sufficient permissions to retrieve the size of
* all databases.
*/
if (get_cluster_size(source_conn, cluster_size) == false)
exit(ERR_DB_QUERY);
log_detail(_("current installation size is %s"),
if (get_cluster_size(source_conn, cluster_size) == true)
log_detail(_("current installation size is %s"),
cluster_size);
/*

View File

@@ -90,17 +90,22 @@ char pg_bindir[MAXPGPATH] = "";
*/
t_node_info target_node_info = T_NODE_INFO_INITIALIZER;
/* used by create_replication_slot() */
/* set by the first call to _determine_replication_slot_user() */
static t_user_type ReplicationSlotUser = USER_TYPE_UNKNOWN;
/* Collate command line errors and warnings here for friendlier reporting */
static ItemList cli_errors = {NULL, NULL};
static ItemList cli_warnings = {NULL, NULL};
static void _determine_replication_slot_user(PGconn *conn,
t_node_info *upstream_node_record,
char **replication_user);
static PGconn *_get_replication_slot_connection(PGconn *conn,
char *replication_user,
bool *use_replication_protocol);
int
main(int argc, char **argv)
{
@@ -3734,6 +3739,7 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
char *replication_user = NULL;
_determine_replication_slot_user(conn, upstream_node_record, &replication_user);
/*
* If called in --dry-run context, if the replication slot user is not the
* repmgr user, attempt to validate the connection.
@@ -3745,7 +3751,7 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
case USER_TYPE_UNKNOWN:
log_error("unable to determine user for replication slot creation");
return false;
case REPMGR_USER:
case REPMGR_USER:
log_info(_("replication slots will be created by user \"%s\""),
PQuser(conn));
return true;
@@ -3791,65 +3797,12 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
PQfinish(superuser_conn);
}
}
}
/*
* If we can't create a replication slot with the connection provided to
* the function, create an connection with appropriate permissions.
*/
switch (ReplicationSlotUser)
{
case USER_TYPE_UNKNOWN:
log_error("unable to determine user for replication slot creation");
return false;
case REPMGR_USER:
slot_conn = conn;
log_info(_("creating replication slot as user \"%s\""),
PQuser(conn));
break;
slot_conn = _get_replication_slot_connection(conn, replication_user, &use_replication_protocol);
case REPLICATION_USER_NODE:
case REPLICATION_USER_OPT:
{
slot_conn = duplicate_connection(conn,
replication_user,
true);
if (slot_conn == NULL || PQstatus(slot_conn) != CONNECTION_OK)
{
log_error(_("unable to create replication connection as user \"%s\""),
runtime_options.replication_user);
log_detail("%s", PQerrorMessage(slot_conn));
PQfinish(slot_conn);
return false;
}
use_replication_protocol = true;
log_info(_("creating replication slot as replication user \"%s\""),
replication_user);
}
break;
case SUPERUSER:
{
slot_conn = duplicate_connection(conn,
runtime_options.superuser,
false);
if (slot_conn == NULL || PQstatus(slot_conn )!= CONNECTION_OK)
{
log_error(_("unable to create super connection as user \"%s\""),
runtime_options.superuser);
log_detail("%s", PQerrorMessage(slot_conn));
PQfinish(slot_conn);
return false;
}
log_info(_("creating replication slot as superuser \"%s\""),
runtime_options.superuser);
}
break;
}
if (slot_conn == NULL)
return false;
if (use_replication_protocol == true)
{
@@ -3892,34 +3845,53 @@ drop_replication_slot_if_exists(PGconn *conn, int node_id, char *slot_name)
if (record_status != RECORD_FOUND)
{
/* this is not a bad good thing */
/* no slot, no problem */
log_verbose(LOG_INFO,
_("slot \"%s\" does not exist on node %i, nothing to remove"),
slot_name, node_id);
return true;
}
if (slot_info.active == false)
if (slot_info.active == true)
{
if (drop_replication_slot_sql(conn, slot_name) == true)
/*
* If an active replication slot exists, bail out as we have a problem
* we can't solve here.
*/
log_warning(_("replication slot \"%s\" is still active on node %i"), slot_name, node_id);
success = false;
}
else
{
/*
* Create the appropriate connection with which to drop the slot
*/
bool use_replication_protocol = false;
PGconn *slot_conn = _get_replication_slot_connection(conn,
replication_user,
&use_replication_protocol);
if (use_replication_protocol == true)
{
success = drop_replication_slot_replprot(slot_conn, slot_name);
}
else
{
success = drop_replication_slot_sql(slot_conn, slot_name);
}
if (success == true)
{
log_notice(_("replication slot \"%s\" deleted on node %i"), slot_name, node_id);
}
else
{
log_error(_("unable to delete replication slot \"%s\" on node %i"), slot_name, node_id);
success = false;
}
}
/*
* If an active replication slot exists, call Houston as we have a
* problem.
*/
else
{
log_warning(_("replication slot \"%s\" is still active on node %i"), slot_name, node_id);
success = false;
if (slot_conn != conn)
PQfinish(slot_conn);
}
return success;
@@ -3981,10 +3953,88 @@ _determine_replication_slot_user(PGconn *conn, t_node_info *upstream_node_record
ReplicationSlotUser = REPLICATION_USER_NODE;
*replication_user = upstream_node_record->repluser;
}
else
{
/* This should never happen */
log_error("unable to determine replication slot user");
if (upstream_node_record != NULL)
{
log_debug("%i %s %s", upstream_node_record->node_id, upstream_node_record->repluser, PQuser(conn));
}
else
{
log_debug("upstream_node_record not provided");
}
}
}
}
static PGconn *
_get_replication_slot_connection(PGconn *conn, char *replication_user, bool *use_replication_protocol)
{
PGconn *slot_conn = NULL;
/*
* If we can't create a replication slot with the connection provided to
* the function, create an connection with appropriate permissions.
*/
switch (ReplicationSlotUser)
{
case USER_TYPE_UNKNOWN:
log_error("unable to determine user for managing replication slots");
return NULL;
case REPMGR_USER:
slot_conn = conn;
log_verbose(LOG_INFO, _("managing replication slot as user \"%s\""),
PQuser(conn));
break;
case REPLICATION_USER_NODE:
case REPLICATION_USER_OPT:
{
slot_conn = duplicate_connection(conn,
replication_user,
true);
if (slot_conn == NULL || PQstatus(slot_conn) != CONNECTION_OK)
{
log_error(_("unable to manage replication connection as replication user \"%s\""),
runtime_options.replication_user);
log_detail("%s", PQerrorMessage(slot_conn));
PQfinish(slot_conn);
return NULL;
}
*use_replication_protocol = true;
log_verbose(LOG_INFO, _("managing replication slot as replication user \"%s\""),
replication_user);
}
break;
case SUPERUSER:
{
slot_conn = duplicate_connection(conn,
runtime_options.superuser,
false);
if (slot_conn == NULL || PQstatus(slot_conn )!= CONNECTION_OK)
{
log_error(_("unable to create superuser connection as user \"%s\""),
runtime_options.superuser);
log_detail("%s", PQerrorMessage(slot_conn));
PQfinish(slot_conn);
return NULL;
}
log_verbose(LOG_INFO, _("creating replication slot as superuser \"%s\""),
runtime_options.superuser);
}
break;
}
return slot_conn;
}
bool
check_replication_slots_available(int node_id, PGconn* conn)
{

View File

@@ -84,7 +84,6 @@ static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
void _PG_init(void);
void _PG_fini(void);
static void repmgr_shmem_startup(void);
@@ -133,17 +132,6 @@ _PG_init(void)
}
/*
* Module unload callback
*/
void
_PG_fini(void)
{
/* Uninstall hook */
shmem_startup_hook = prev_shmem_startup_hook;
}
/*
* shmem_startup hook: allocate or attach to shared memory,
*/

View File

@@ -398,7 +398,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
#
# Debian/Ubuntu users: use "sudo pg_ctlcluster" to execute service control commands.
#
# For more details, see: https://repmgr.org/docs/current/configuration-service-commands.html
# For more details, see: https://repmgr.org/docs/current/configuration-file-service-commands.html
#service_start_command = ''
#service_stop_command = ''

View File

@@ -1,7 +1,7 @@
#define REPMGR_VERSION_DATE ""
#define REPMGR_VERSION "5.3.1"
#define REPMGR_VERSION_NUM 50301
#define REPMGR_VERSION "5.3.2"
#define REPMGR_VERSION_NUM 50302
#define REPMGR_EXTENSION_VERSION "5.3"
#define REPMGR_EXTENSION_NUM 50300
#define REPMGR_RELEASE_DATE "2022-02-15"
#define REPMGR_RELEASE_DATE "2022-05-25"
#define PG_ACTUAL_VERSION_NUM

View File

@@ -2382,6 +2382,18 @@ monitor_streaming_witness(void)
log_warning(_("unable to retrieve node record from primary"));
}
/* refresh local node record from the primary */
record_status = get_node_record(primary_conn, config_file_options.node_id, &local_node_info);
if (record_status != RECORD_FOUND)
{
log_error(_("no metadata record found for this node on the current primary - terminating"));
log_hint(_("check that 'repmgr witness register' was executed for this node"));
close_connection(&primary_conn);
close_connection(&local_conn);
terminate(ERR_BAD_CONFIG);
}
initPQExpBuffer(&event_details);
appendPQExpBuffer(&event_details,
@@ -2850,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
@@ -2862,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);
/*
@@ -2959,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);

View File

@@ -479,7 +479,7 @@ main(int argc, char **argv)
switch (config_file_options.replication_type)
{
case REPLICATION_TYPE_PHYSICAL:
log_hint(_("check that 'repmgr (primary|standby) register' was executed for this node"));
log_hint(_("check that 'repmgr (primary|standby|witness) register' was executed for this node"));
break;
}