Compare commits

..

136 Commits

Author SHA1 Message Date
Ian Barwick
4a73bdcfd0 need to provide the follow target node record for node follow internal
otherwise fails when using a dedicated replication user.

WIP.
2022-05-16 15:50:02 +09:00
Ian Barwick
e27f213949 split out replication slot connection creation code into function
WIP
2022-05-16 13:51:45 +09:00
Ian Barwick
cce5ca2245 doc: update release notes 2022-05-16 12:05:35 +09:00
Ian Barwick
6f87d2c61e 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:52:10 +09:00
Ian Barwick
c0763c94c8 dbutils: move get_wal_receiver_pid() to a more consistent location 2022-05-16 10:40:42 +09:00
Ian Barwick
ea689d17b5 repmgr: add code comment about pg_stat_tmp in PostgreSQL 15+
See core commit 6f0cf8787.
2022-05-15 15:19:02 +09:00
Ian Barwick
de343f0cbe shared library: update for PostgreSQL 15
Core commit 4f2400cb3f adds shmem_request_hook, meaning the
memory initialization previously carried out in _PG_init() needs
to be handled in that hook.
2022-05-14 18:31:05 +09:00
Ian Barwick
e6f1b8c279 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:03 +09:00
Ian Barwick
8e5f469fa1 doc: clarify permissions requirements in "standby switchover" 2022-05-13 14:26:34 +09:00
Ian Barwick
73cb3abd44 doc: clarify permissions requirements in "standby clone" 2022-05-13 14:26:28 +09:00
Ian Barwick
a3c77cac41 standby clone: update source comment 2022-05-13 13:39:05 +09:00
Ian Barwick
706d570790 doc: add missing short form option to "standby clone" 2022-05-13 11:53:49 +09:00
Ian Barwick
433bde82e8 dbutils.c: fix typo in comment 2022-05-13 11:51:58 +09:00
Ian Barwick
8f5319ce75 Disable exclusive backup check in PostgreSQL 15 and later
Exclusive backup functionality was removed in core commit 39969e2a
so we can and must avoid checking for exclusive backups.
2022-05-11 15:25:38 +09:00
Ian Barwick
4c05307da1 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:58:36 +09:00
zhouhj43183
743e0e5480 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:35:48 +09:00
Ian Barwick
35c4ba1fbe doc: update release notes
Add notes about when PostgreSQL and/or repmgrd restart required.

GitHub #752.
2022-05-10 16:22:51 +09:00
Ian Barwick
30082eab02 doc: update release notes 2022-05-10 16:09:17 +09:00
Ian Barwick
d9d60fa420 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:02 +09:00
Ian Barwick
2756d6fd94 node check: prevent WARNING in --downstream --nagios output 2022-04-20 17:45:00 +09:00
Ian Barwick
bb63fb08d0 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:35:44 +09:00
Ian Barwick
9508673e00 node check: tweak --upstream --nagios output
No data follows the pipe, so omit it and add missing line break.
2022-04-20 16:40:53 +09:00
Ian Barwick
3e3803fa32 doc: fix XML error 2022-04-19 11:26:22 +09:00
Felix Dreissig
8119aef378 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:06:08 +09:00
Felix Dreissig
35c8a53790 Sample config: Update link to docs 2022-04-19 10:20:18 +09:00
Doug Calobrisi
1c7fec9a1a Add SonarQube (#751) 2022-04-18 10:04:54 -04:00
James Stroud
3b8294e4cb 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:02 +09:00
Ian Barwick
f5e42e1851 doc: use "note" rather than "important" 2022-03-16 10:40:28 +09:00
Ian Barwick
f7b9e11d6f 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:26:47 +09:00
Ian Barwick
197c87d13b docs: update package installation instructions
- use "dnf" in place of "yum"
- mention Rocky Linux
- remove 9.6 examples
2022-03-11 10:23:51 +09:00
Ian Barwick
67e2e8e613 docs: update one more instance of the company name 2022-02-15 17:25:11 +09:00
Ian Barwick
c6f137d438 docs: update other instances of the company name, where appropriate 2022-02-15 17:25:07 +09:00
Ian Barwick
6cd41aaaf6 docs: update company name on cover pages 2022-02-15 17:25:03 +09:00
Ian Barwick
b4dca347b4 docs: finalize 5.3.1 release notes 2022-02-15 13:39:33 +09:00
Ian Barwick
2e1d1f9a57 Add include for pwd.h
This was previously included via the PostgreSQL source, but that
seems to have gone away in recent HEAD builds.
2022-02-03 14:20:22 +09:00
Ian Barwick
fa851ea38f doc: update version matrix
5.2.1 is the latest release in the 5.2.x series.
2022-02-03 13:31:04 +09:00
Ian Barwick
593bffb18f doc: repmgr 5.2 is no longer supported. 2022-02-03 13:26:26 +09:00
Ian Barwick
8a36cc3b2d doc: update version matrix 2022-02-03 13:26:20 +09:00
Ian Barwick
2733579a76 doc: update release notes 2022-02-03 13:09:42 +09:00
Ian Barwick
947d14979f Fix upgrade paths from 4.1 ~ 4.3 to 5.2 and later
A number of C functions were added in releases 4.2 to 4.4; however
these were renamed in 5.3 to prevent naming clashes with other
extensions.

This does however mean that when upgrading from one of the above
versions, the intermediate upgrade steps will attempt to create
SQL functions referencing C functions which no longer exist in
repmgr.so, and hence cause the upgrade to fail.

We can work around this by providing empty upgrade scripts
from these versions to 4.4, which skip the problematic CREATE
FUNCTION commands. The functions will be correctly created in
the 5.2--5.3 upgrade script.
2022-02-03 12:59:52 +09:00
Ian Barwick
b8cb1feb49 repmgrd: move connection pointer declaration inside relevant block
As it's used only there and nowhere else.
2022-01-04 12:45:28 +09:00
Ian Barwick
5de74d9e18 doc: update release notes 2022-01-04 12:32:43 +09:00
zhouhj43183
2dce8e14f9 repmgrd: ensure potentially open connections are closed
When recovering from degraded state in local node monitoring, in some
cases a new connection was opened to the local node without closing
the old one, which will result in memory leakage.
2022-01-04 12:22:09 +09:00
Ian Barwick
81f9c0ebd0 doc: update repmgr.conf.sample
Minor formatting fix.
2021-12-08 09:50:37 +09:00
Ian Barwick
9f53d45c74 doc: update repmgr.conf.sample
Remove bogus -W option in "repmgr standby follow" example invocation
for the "follow_command" parameter.

The option (which corresponds to "--no-wait") is not used by
"repmgr standby follow".

Per report from Jimmy Angelakos.
2021-12-08 09:50:19 +09:00
Ian Barwick
aef5a4f8cf doc: fix typo 2021-11-05 09:12:06 +09:00
Ian Barwick
580d112d3d Removed temporary include file workaround 2021-10-29 15:41:53 +09:00
Ian Barwick
6ba27a9c6b Add dummy include file
This is a workaround required to facilitate Debian package builds
against PostgreSQL Extended.
2021-10-12 16:51:51 +09:00
Ian Barwick
51e7025747 doc: update release notes 2021-10-12 10:13:42 +09:00
Ian Barwick
ded20be505 repmgrd: improve node activation at startup
Commit 79d1f00 modified repmgrd to automatically set an inactive node
to "active" at startup.

However we need to avoid doing that for cases where the node role has
changed (e.g. a former primary was recloned as a standby) but the node
record was not updated.
2021-10-11 14:39:04 +09:00
Ian Barwick
e7e62f7f35 repmgrd: add %p event notification parameter for "repmgrd_failover_promote"
This enables an event notification script to identify the former primary
node.
2021-09-28 10:25:27 +09:00
Ian Barwick
3870768d80 Add --repmgrd option to "repmgr node check"
This provides a simple way for checking whether the node's repmgrd is
running.

GitHub #719.
2021-09-28 09:46:31 +09:00
Ian Barwick
16349d95e9 Update Makefile for 5.4dev 2021-09-16 14:43:35 +09:00
Ian Barwick
bba282a131 Add extension script files for 5.4dev. 2021-09-16 14:32:55 +09:00
Ian Barwick
02c29dc860 Add extension script for unpackaged upgrades to 5.3 2021-09-16 13:56:38 +09:00
Ian Barwick
7c5efe2baa doc: update 5.3.0 release notes 2021-09-16 13:42:58 +09:00
Ian Barwick
b2756806d9 Bump master branch to 5.4dev 2021-09-16 10:15:20 +09:00
Ian Barwick
bf0478088c standby: add missing include 2021-08-18 10:26:56 +09:00
Ian Barwick
efd5792de4 Remove redundant shared library function prototypes
From PostgreSQL 9.4 (commit e7128e8d), explicit function prototypes
are not required as they will be generated by the PG_FUNCTION_INFO_V1
macro.

(We were supporting PostgreSQL 9.3 until relatively recently, so there
was nothing particular to gain by removing these earlier).
2021-08-18 10:19:13 +09:00
Ian Barwick
17987a2690 standby switchover: detect if demotion candidate is running as a primary
This shouldn't happen, but if it does, log the fact for easier analysis.
2021-07-28 11:50:57 +09:00
Ian Barwick
5f1ba6db3d standby switchover: improve handling of node rejoin failure
Explicitly check whether the "repmgr node rejoin" command on the
demotion candidate succeeded. Due to the way SSH execution is
currently implemented, we can return either the command execution
status or the command output; to ensure any errors are available,
log them to a temporary file on the demotion candidate and note
its location in case of an error.

While we're at it, improve error message handling when the demotion
candidate fails to rejoin.
2021-07-28 11:42:40 +09:00
Ian Barwick
55efbe60ea standby switchover: optionally delay promotion
This is for testing purposes only and should not be used in production.
2021-07-27 17:01:27 +09:00
Ian Barwick
132f5ebc08 standby switchover: improve logging of repmgrd pause actions
- state how many nodes are to be operated on
- if errors were encountered with any nodes, emit the total number
  of nodes as well as the number of affected nodes
- log nodes where repmgrd was not running anyway as NOTICE, not
  WARNING
2021-07-26 17:46:58 +09:00
Ian Barwick
c901f36f81 Standardize formatting of node ID in log messages
Mostly we have "(ID: %i)", so use that rather than "(ID %i)" which has
crept into a few places.
2021-07-26 17:27:36 +09:00
Ian Barwick
edb49b2747 doc: link to main documentation section about RemoveIPC 2021-07-26 11:01:03 +09:00
Ian Barwick
a35d85ed70 doc: link to service commands section from switchover docs 2021-07-26 09:47:14 +09:00
Ian Barwick
b6b91425d9 doc: document pg_bindir setting
Per suggestion in GitHub #705.
2021-07-20 13:36:08 +09:00
Ian Barwick
32329ca55a doc: link to sample configuration file
Unfortunately it hasn't been possible yet to include all available
configuration items in the main documentation, but we should at least
make it easier to find the full list.
2021-07-20 13:18:57 +09:00
Ian Barwick
79d1f005db repmgrd: activate inactive node record at startup
If a PostgreSQL instance was shut down while repmgrd was running, and
repmgrd was subsequently restarted (this chain of events could occur
during e.g. a server reboot), the node record will have been set to
"inactive". Previously, in this case repmgrd would refuse to start up.
However, as we can determine the node is running, it should normally
be no problem to automatically set the node record to "active".

The old behaviour can be restored by setting the new parameter
"repmgrd_exit_on_inactive_node" to "true".

RM19604.
2021-07-12 17:46:09 +09:00
Ian Barwick
f64f498afb Be more flexible when parsing the output from pg_config --version
The string may not always start with "PostgreSQL" when building
against non-community versions.

Life would be much easier here if there was an option like
"pg_config --version-number" or similar.
2021-07-05 15:38:34 +09:00
Ian Barwick
f10c013e89 doc: note PostgreSQL 14 support
repmgr 5.3 will provide support for PostgreSQL 14.
2021-07-01 16:00:21 +09:00
Ian Barwick
2059a55a99 doc: update release notes 2021-07-01 13:44:33 +09:00
Ian Barwick
99ed17b838 doc: update release notes 2021-07-01 13:28:15 +09:00
Ian Barwick
078b4ad863 standby clone: set "slot_name" in node record if required
If executing "repmgr standby clone --replication-conf-only" on a node
which was set up without replication slots, but the repmgr configuration
was since changed to "use_replication_slots=1", repmgr will attempt to
create the replication slot. This will however fail if "slot_name"
is not set in the node's record, so have repmgr set the slot_name in
this case.

It might be preferable to preemptively create the slot name for each
node when configuring the cluster, however this would be a behavioural
change which would be better off in a major release (for example, it's
conceivable a user runs sanity checks on the node records and expects
to find the slot names empty if replication slots are not in use).
2021-07-01 13:04:23 +09:00
Ian Barwick
2af71c6426 repmgrd: ensure short option "-s" is accepted
The long option --show-pid-file was fine.
2021-06-03 18:41:11 +09:00
Ian Barwick
9349520530 Remove reference to PostgreSQL 9.3 in --help output
It is not supported by repmgr 5.2 and later.
2021-04-15 15:31:59 +09:00
Ian Barwick
14851e61de doc: clarify "connection_check_type='query'" 2021-03-03 13:12:58 +09:00
Ian Barwick
888e1d7a3b docs: update repmgr.conf.sample
Fix description for connection_check_type='connection'.
2021-03-02 11:44:14 +09:00
Ian Barwick
1b4c2a60bb docs: update README
Note latest version number.
2021-03-02 11:26:15 +09:00
Ian Barwick
da163e811c doc: update README
Fix and update broken link.
2021-03-02 11:14:16 +09:00
Ian Barwick
80d1beef7e doc: update GitHub links to new location 2021-03-02 08:58:49 +09:00
Ian Barwick
4f009548f6 doc: remove generated .fo files 2021-03-01 11:06:41 +09:00
Ian Barwick
d266df3143 Change copyright information to "EnterpriseDB Corporation"
RM20485.
2021-03-01 11:03:52 +09:00
Ian Barwick
dd8204e013 Rename various shared library functions
Some of the more generically named functions are at risk of colliding
with functions defined in other libraries. To mitigate that risk,
prefix with "repmgr_", unless the name already has some reference
to repmgr.

This requires an extension version bump.

RM20471.
2021-02-23 10:14:28 +09:00
Ian Barwick
d34b4e71a6 Fix incorrect comment 2021-02-22 13:28:27 +09:00
Ian Barwick
12749c3f63 doc: fix XML markup
An incorrect column count was causing PDF builds to fail.
2021-02-19 20:39:41 +09:00
Ian Barwick
ce59d92731 doc: update repmgr.conf.sample 2021-01-14 15:27:24 +09:00
Ian Barwick
cfbeed50d6 node rejoin: emit rejoin target note information as NOTICE
As it's possible to specify the connection information for any available
node, but currently not possible to rejoin to a node other than the
primary, explicitly mention what the rejoin target will be.
2021-01-06 14:11:37 +09:00
Ian Barwick
da3eaee127 doc: "repmgr node rejoin" clarifications
- make it clearer a node can only be joined to the primary
- update patch status
2021-01-06 12:36:11 +09:00
Ian Barwick
b37a599fc6 Update copyright notices to 2021 2021-01-04 12:54:54 +09:00
Ian Barwick
f011e552d0 Add missing PQconninfoFree() call 2020-12-24 18:07:18 +09:00
Ian Barwick
d1cc05faf9 repmgrd: edit code comment for clarity 2020-12-22 13:58:34 +09:00
Ian Barwick
7ceba84e32 doc: minor grammar tweak 2020-12-22 13:57:31 +09:00
Josh Soref
842c67ca18 doc: various spelling fixes
Via GitHub #687.
2020-12-22 13:47:56 +09:00
Josh Soref
f619c3a8ff Fix various typos in code comments.
Via GitHub #687.
2020-12-22 13:43:06 +09:00
Josh Soref
5a88858596 repmgr: various log ouput typo fixes
Via GitHub #687.
2020-12-22 13:18:11 +09:00
Josh Soref
02bc143c75 repmgr: fix typo in "repmgr node --help" output
Via GitHub #687.
2020-12-22 13:07:16 +09:00
Ian Barwick
c480d01f9c Improve HINT about upgrading the repmgr extension
Per feedback in GitHub #685.
2020-12-15 08:41:46 +09:00
Ian Barwick
e762200a12 doc: update README
Link to recent-ish EDB blog article.
2020-12-08 13:31:21 +09:00
Ian Barwick
2133e1097e standby switchover: remove extraneous space in log message 2020-12-08 13:14:45 +09:00
Ian Barwick
77d7a098a1 doc: add 5.2.1 release date 2020-12-08 12:41:46 +09:00
Ian Barwick
4e9cdf0267 doc: update 5.2.1 release notes 2020-12-04 14:49:20 +09:00
Ian Barwick
0d8bf2a935 Minor string formatting optimization 2020-12-04 10:16:21 +09:00
Ian Barwick
debbda6074 standby clone: tweak error message
Probably a remnant from the 9.1 era, where it was not possible to
take a base backup from a standby.
2020-12-04 10:13:45 +09:00
Ian Barwick
d5b94431f2 standby follow: fix standby.signal generation
Oversight from previous a93c6dfc.
2020-12-02 09:11:20 +09:00
Ian Barwick
93187e9743 Add missing connection close
In a corner-case situation where a standby is unable to attach to
the new primary due to a mismatch in the WAL stream, the connection
used to verify the recovery status of the new primary was not being
closed, leading to a risk of connection exhaustion on the new primary.

Addresses GitHub #682.
2020-12-01 21:33:07 +09:00
Ian Barwick
f7e45863ad standby clone: fix data directory permissions handling for Pg11 and later
Previously, repmgr would forcibly change the permissions on a data
directory to 0700. However from PostgreSQL 11, 0750 is also valid,
so that value should not be changed.
2020-12-01 11:48:22 +09:00
Ian Barwick
89556d6488 standby clone: add --recovery-min-apply-delay to help output 2020-11-30 16:44:48 +09:00
Ian Barwick
4ad868d119 doc: update 5.2.1 release notes 2020-11-30 16:44:48 +09:00
Ian Barwick
a93c6dfca7 Ensure standby.signal is set correctly if -D/--data-directory supplied
When cloning a standby, it's possible to do a "raw" clone by providing
-D/--data-directory but no repmgr.conf file. However the code which
creates "standby.signal" was assuming the presence of a valid
repmgr.conf complete with "data_directory" configuration.

This is very much a niche-use case.
2020-11-27 11:24:15 +09:00
Ian Barwick
4d8bc63834 repmgrd: fix issue with incorrect reconnect_interval
Addresses GitHub #673.
2020-11-25 20:40:28 +09:00
Ian Barwick
7bca9df223 Update Makefile
We don't actually need $(LIBS) in there; this was cargo-culted in
from somewhere.
2020-11-24 17:37:48 +09:00
Ian Barwick
1ac62a4352 Avoid compiler warnings for various strncpy() operations
Here the compiler may complain that the source length is being used,
though in all cases the source length was previously used to
define the length of the destination buffer, so it's not actually
a problem.
2020-11-24 15:42:49 +09:00
Ian Barwick
8f7a32a9a2 repmgr: prevent termination in corner-case situation
If neither the local node nor the upstream are available, and
"standby_disconnect_on_failover" is set, attempting to fetch
the walreceiver PID will result in repmgrd terminating.

Add a check that the connection is valid before attempting to
fetch the walreceiver PID.

Addresses GitHub #675.
2020-11-17 16:34:55 +09:00
Ian Barwick
9c04de11fc standby clone: various clarifications for --replication-conf-only option
In particular, the emitted HINT was not really appropriate for Pg13 and
later.
2020-11-17 09:58:51 +09:00
Ian Barwick
040b1ae4e3 Update corner-case error message
Not possible to build repmgr compatible with Pg12+ against Pg11
and earlier due to the addition of FullTransactionId.
2020-11-17 09:39:41 +09:00
Ian Barwick
703aed3fa3 doc: tweak "repmgr standby clone" reference
As recovery.conf starts to fade away, mention that last.
2020-11-10 16:07:22 +09:00
Ian Barwick
7ee0098771 standby clone: add option --recovery-min-apply-delay
This overrides the equivalent setting in repmgr.conf, if present.

Note this option was available in repmgr versions prior to 4.0, but
was assumed to be redundant. However recently a use-case was made
for its reintroduction.
2020-11-10 15:55:04 +09:00
Ian Barwick
430d12b870 Fix typo 2020-11-10 13:40:38 +09:00
Romain Jacquier
c8b2d23361 Fix help witness
Fix the `repmgr witness --help` command where at the "Unregister" section the message shown was
```
"witness register" unregisters a witness node.
```
instead of
```
"witness unregister" unregisters a witness node.
```

GitHub #676.
2020-11-09 13:34:08 +09:00
Ian Barwick
8543c0bcf6 standby clone: emit pg_basebackup command in --dry-run mode 2020-11-04 12:00:42 +09:00
Ian Barwick
674c06d01c Decouple extension version check from binary version
Until now the extension version has always moved in lock-step
with the binary version, but that doesn't always need to be
the case, so make it possible to have an extension version
which does not match the binary version.
2020-10-30 14:42:58 +09:00
Ian Barwick
970d7a136f Fix return value of pg_reload_conf() database utility function
Would always return "false", but as the value wasn't used anywhere,
the issue was inconsequential.

However while we're at it, actually check the return value in the
two places it's called, to help diagnose any issues in the unlikely
event they occur.

Per issue reported via GitHub PR #671 from user duzhgg.
2020-10-30 14:25:11 +09:00
Ian Barwick
7bde686796 standby clone: handle missing "postgresql.auto.conf"
In PostgreSQL 12 and later we need to append replication configuration
to "postgresql.auto.conf" to guarantee it will be read last, and hence
override any preceding replication configuration which may be haunting
the configuration files.

We've been assuming that "postgresql.auto.conf" will always be present,
but at least one corner case has been observed where that was not the
case on the node being cloned from. Moreover it's perfectly acceptable
that this file does not exist (it will be recreated the next time
ALTER SYSTEM is executed), so we should be prepared to handle that case.

In passing, improve handling of more unlikely errors which might be
encountered when processing "postgresql.auto.conf".
2020-10-30 12:25:03 +09:00
Ian Barwick
ab1447aeca Standardize code style 2020-10-30 11:06:15 +09:00
Ian Barwick
293e37688f config: fix parsing of "replication_type"
This is a legacy parameter which can currently only contain one value,
"physical" (the default).

It can be safely omitted.

Addresses GitHub #672.
2020-10-30 10:14:04 +09:00
Ian Barwick
96718151a6 doc: update README
- remove partial sentence
- remove links to very dated blog entries
2020-10-27 13:58:07 +09:00
Ian Barwick
65ffe51bb4 doc: update README
Link to release notes as a simple way of providing the latest release
information.
2020-10-27 13:52:19 +09:00
Ian Barwick
b6d0288a82 Finalize release date 2020-10-22 21:23:50 +09:00
Ian Barwick
f888407ad8 Additional fix to upgrade script
Drop old "repl_events" table.
2020-10-22 21:22:52 +09:00
Ian Barwick
1512c7b761 Fix extension script for unpackaged upgrades to 5.2
Apparently "ALTER TABLE" (which we were using to convert the
"repl_events" table) does not mark the table as being part of the
extension. Instead, we need to create the new table and copy the
data, as is done with the other tables.
2020-10-22 21:22:47 +09:00
Ian Barwick
8877d4d508 doc: add missing "unpackaged" reference 2020-10-22 21:22:43 +09:00
Ian Barwick
f18b2e900d standby clone: improve Barman source server check
Use "remote_command()" to execute the remote psql command, and
provide the -X option to psql to ensure it doesn't read ~/.psqlrc.
2020-10-22 21:22:04 +09:00
Ian Barwick
5c4aa1856c doc: update README 2020-10-22 21:20:17 +09:00
Ian Barwick
091a2df167 doc: update release notes 2020-10-20 14:09:44 +09:00
Ian Barwick
17a1732eb0 Bump master branch to 5.3dev
Also update the minimum version check to PostgreSQL 9.4.
2020-10-20 13:41:49 +09:00
93 changed files with 2935 additions and 821 deletions

37
.github/workflows/sonarqube-scan.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: SonarQube Scan
on:
pull_request:
push:
branches: [ master ]
workflow_dispatch:
jobs:
sonarQube:
name: SonarQube-Job
runs-on: ubuntu-latest
steps:
- name: Checkout source repo
uses: actions/checkout@v1
with:
ref: '${{ github.head_ref }}'
- name: Checkout GitHub Action Repo
uses: actions/checkout@master
with:
repository: EnterpriseDB/edb-github-actions.git
ref: master
token: ${{ secrets.GH_SLONIK }}
path: .github/actions/edb-github-actions
- name: SonarQube Scan
uses: ./.github/actions/edb-github-actions/sonarqube
with:
REPO_NAME: '${{github.event.repository.name}}'
SONAR_PROJECT_KEY: EnterpriseDB_repmgr
SONAR_URL: '${{secrets.SONARQUBE_URL}}'
SONAR_LOGIN: '${{secrets.SONARQUBE_LOGIN}}'
PULL_REQUEST_KEY: '${{github.event.number}}'
PULL_REQUEST_BRANCH: '${{github.head_ref}}'
PULL_REQUEST_BASE_BRANCH: '${{github.base_ref}}'
REPO_DEFAULT_BRANCH: '${{github.event.repository.default_branch}}'
REPO_EXCLUDE_FILES: '*properties*,**/src/test/**/*,**/*.sql,**/docs/**/*,**/*/*.java'

18
.github/workflows/sonarqube/configure-env.sh vendored Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/bash
DEBIAN_FRONTEND=noninteractive sudo apt-get -y install debhelper curl autoconf zlib1g-dev \
libedit-dev libxml2-dev libxslt1-dev libkrb5-dev libssl-dev libpam0g-dev systemtap-sdt-dev \
libselinux1-dev build-essential bison apt-utils lsb-release devscripts \
software-properties-common git shellcheck flex
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get -y install libpq-dev postgresql-13 postgresql-server-dev-13
./configure
export PG_CONFIG=/usr/bin/pg_config
/home/buildfarm/sonar/depends/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir build_wrapper_output_directory make

View File

@@ -2,7 +2,7 @@ License and Contributions
========================= =========================
`repmgr` is licensed under the GPL v3. All of its code and documentation is `repmgr` is licensed under the GPL v3. All of its code and documentation is
Copyright 2010-2020, 2ndQuadrant Limited. See the files COPYRIGHT and LICENSE for Copyright 2010-2021, EnterpriseDB Corporation. See the files COPYRIGHT and LICENSE for
details. details.
The development of repmgr has primarily been sponsored by 2ndQuadrant customers. The development of repmgr has primarily been sponsored by 2ndQuadrant customers.
@@ -12,10 +12,10 @@ which has received funding from the European Union's Seventh Framework Programme
(FP7/2007-2013) under grant agreement 258862. (FP7/2007-2013) under grant agreement 258862.
Contributions to `repmgr` are welcome, and will be listed in the file `CREDITS`. Contributions to `repmgr` are welcome, and will be listed in the file `CREDITS`.
2ndQuadrant Limited requires that any contributions provide a copyright EnterpriseDB Corporation requires that any contributions provide a copyright
assignment and a disclaimer of any work-for-hire ownership claims from the assignment and a disclaimer of any work-for-hire ownership claims from the
employer of the developer. This lets us make sure that all of the repmgr employer of the developer. This lets us make sure that all of the repmgr
distribution remains free code. Please contact info@2ndQuadrant.com for a distribution remains free code. Please contact info@enterprise.com for a
copy of the relevant Copyright Assignment Form. copy of the relevant Copyright Assignment Form.
Code style Code style

View File

@@ -1,4 +1,4 @@
Copyright (c) 2010-2020, 2ndQuadrant Limited Copyright (c) 2010-2021, EnterpriseDB Corporation
All rights reserved. All rights reserved.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify

2
FAQ.md
View File

@@ -5,6 +5,6 @@ The repmgr 4 FAQ is located here: [repmgr FAQ (Frequently Asked Questions)](http
The repmgr 3.x FAQ can be found here: The repmgr 3.x FAQ can be found here:
https://github.com/2ndQuadrant/repmgr/blob/REL3_3_STABLE/FAQ.md https://github.com/EnterpriseDB/repmgr/blob/REL3_3_STABLE/FAQ.md
Note that repmgr 3.x is no longer supported. Note that repmgr 3.x is no longer supported.

33
HISTORY
View File

@@ -1,3 +1,34 @@
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)
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)
repmgrd: prefix all shared library functions with "repmgr_" to
minimize the risk of clashes with other shared libraries (Ian)
repmgrd: at startup, if node record is marked as "inactive", attempt
to set it to "active" (Ian)
standby clone: set "slot_name" in node record if required (Ian)
node rejoin: emit rejoin target note information as NOTICE (Ian)
repmgrd: ensure short option "-s" is accepted (Ian)
5.2.1 2020-12-07
config: fix parsing of "replication_type"; GitHub #672 (Ian)
standby clone: handle missing "postgresql.auto.conf" (Ian)
standby clone: add option --recovery-min-apply-delay (Ian)
standby clone: fix data directory permissions handling for
PostgreSQL 11 and later (Ian)
repmgrd: prevent termination when local node not available and
standby_disconnect_on_failover; GitHub #675 (Ian)
repmgrd: ensure reconnect_interval" is correctly handled;
GitHub #673 (Ian)
5.2.0 2020-10-22 5.2.0 2020-10-22
general: add support for PostgreSQL 13 (Ian) general: add support for PostgreSQL 13 (Ian)
general: remove support for PostgreSQL 9.3 (Ian) general: remove support for PostgreSQL 9.3 (Ian)
@@ -32,7 +63,7 @@
repmgr: ensure postgresql.auto.conf is created with correct permissions (Ian) repmgr: ensure postgresql.auto.conf is created with correct permissions (Ian)
repmgr: minimize requirement to check upstream data directory location repmgr: minimize requirement to check upstream data directory location
during "standby clone" (Ian) during "standby clone" (Ian)
repmgr: warn about missing pg_rewind prerequisites when excuting repmgr: warn about missing pg_rewind prerequisites when executing
"standby clone" (Ian) "standby clone" (Ian)
repmgr: add --upstream option to "node check" repmgr: add --upstream option to "node check"
repmgr: report error code on follow/rejoin failure due to non-available repmgr: report error code on follow/rejoin failure due to non-available

View File

@@ -13,6 +13,7 @@ DATA = \
repmgr--unpackaged--4.0.sql \ repmgr--unpackaged--4.0.sql \
repmgr--unpackaged--5.1.sql \ repmgr--unpackaged--5.1.sql \
repmgr--unpackaged--5.2.sql \ repmgr--unpackaged--5.2.sql \
repmgr--unpackaged--5.3.sql \
repmgr--4.0.sql \ repmgr--4.0.sql \
repmgr--4.0--4.1.sql \ repmgr--4.0--4.1.sql \
repmgr--4.1.sql \ repmgr--4.1.sql \
@@ -27,7 +28,11 @@ DATA = \
repmgr--5.0--5.1.sql \ repmgr--5.0--5.1.sql \
repmgr--5.1.sql \ repmgr--5.1.sql \
repmgr--5.1--5.2.sql \ repmgr--5.1--5.2.sql \
repmgr--5.2.sql repmgr--5.2.sql \
repmgr--5.2--5.3.sql \
repmgr--5.3.sql \
repmgr--5.3--5.4.sql \
repmgr--5.4.sql
REGRESS = repmgr_extension REGRESS = repmgr_extension
@@ -76,10 +81,10 @@ configfile-scan.c: configfile-scan.l
$(REPMGR_CLIENT_OBJS): repmgr-client.h repmgr_version.h $(REPMGR_CLIENT_OBJS): repmgr-client.h repmgr_version.h
repmgr: $(REPMGR_CLIENT_OBJS) repmgr: $(REPMGR_CLIENT_OBJS)
$(CC) $(CFLAGS) $(REPMGR_CLIENT_OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) $(CC) $(CFLAGS) $(REPMGR_CLIENT_OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) -o $@$(X)
repmgrd: $(REPMGRD_OBJS) repmgrd: $(REPMGRD_OBJS)
$(CC) $(CFLAGS) $(REPMGRD_OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) $(CC) $(CFLAGS) $(REPMGRD_OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) -o $@$(X)
$(REPMGR_CLIENT_OBJS): $(HEADERS) $(REPMGR_CLIENT_OBJS): $(HEADERS)
$(REPMGRD_OBJS): $(HEADERS) $(REPMGRD_OBJS): $(HEADERS)

View File

@@ -7,10 +7,10 @@ replication capabilities with utilities to set up standby servers, monitor
replication, and perform administrative tasks such as failover or switchover replication, and perform administrative tasks such as failover or switchover
operations. operations.
PostgreSQL 12, 11, 10, 9.6 and 9.5 are fully supported. The most recent `repmgr` version (5.2.1) supports all PostgreSQL versions from
PostgreSQL 9.4 and 9.3 are supported, with some restrictions. 9.5 to 13. PostgreSQL 9.4 is also supported, with some restrictions.
`repmgr` is distributed under the GNU GPL 3 and maintained by 2ndQuadrant. `repmgr` is distributed under the GNU GPL 3 and maintained by EnterpriseDB.
Documentation Documentation
------------- -------------
@@ -21,10 +21,11 @@ The full `repmgr` documentation is available here:
The old `README` file for `repmgr` 3.x is available here: The old `README` file for `repmgr` 3.x is available here:
> https://github.com/2ndQuadrant/repmgr/blob/REL3_3_STABLE/README.md > https://github.com/EnterpriseDB/repmgr/blob/REL3_3_STABLE/README.md
Note that the `repmgr` 3.x series is no longer supported and contains known bugs; Note that the `repmgr` 3.x series is no longer supported and contains known bugs;
please upgrade to the current `repmgr` version as soon as possible. please upgrade to the [current repmgr version](https://repmgr.org/docs/current/appendix-release-notes.html)
as soon as possible.
Versions Versions
-------- --------
@@ -54,11 +55,11 @@ Directories
Support and Assistance Support and Assistance
---------------------- ----------------------
2ndQuadrant provides 24x7 production support for `repmgr`, including EnterpriseDB provides 24x7 production support for `repmgr`, including
configuration assistance, installation verification and training for configuration assistance, installation verification and training for
running a robust replication cluster. For further details see: running a robust replication cluster. For further details see:
* https://2ndquadrant.com/en/support/ * [EDB Support Services](https://www.enterprisedb.com/support/postgresql-support-overview-get-the-most-out-of-postgresql)
There is a mailing list/forum to discuss contributions or issues: There is a mailing list/forum to discuss contributions or issues:
@@ -68,23 +69,12 @@ The IRC channel #repmgr is registered with freenode.
Please report bugs and other issues to: Please report bugs and other issues to:
* https://github.com/2ndQuadrant/repmgr * https://github.com/EnterpriseDB/repmgr
See
Further information is available at https://repmgr.org/ Further information is available at https://repmgr.org/
We'd love to hear from you about how you use repmgr. Case studies and We'd love to hear from you about how you use repmgr. Case studies and
news are always welcome. Send us an email at info@2ndQuadrant.com, or news are always welcome.
send a postcard to
repmgr
c/o 2ndQuadrant
7200 The Quorum
Oxford Business Park North
Oxford
OX4 2JZ
United Kingdom
Thanks from the repmgr core team. Thanks from the repmgr core team.
@@ -100,7 +90,4 @@ Further reading
* [repmgr documentation](https://repmgr.org/docs/current/index.html) * [repmgr documentation](https://repmgr.org/docs/current/index.html)
* [How to Automate PostgreSQL 12 Replication and Failover with repmgr - Part 1](https://www.2ndquadrant.com/en/blog/how-to-automate-postgresql-12-replication-and-failover-with-repmgr-part-1/) * [How to Automate PostgreSQL 12 Replication and Failover with repmgr - Part 1](https://www.2ndquadrant.com/en/blog/how-to-automate-postgresql-12-replication-and-failover-with-repmgr-part-1/)
* [How to Automate PostgreSQL 12 Replication and Failover with repmgr - Part 2](https://www.2ndquadrant.com/en/blog/how-to-automate-postgresql-12-replication-and-failover-with-repmgr-part-2/) * [How to Automate PostgreSQL 12 Replication and Failover with repmgr - Part 2](https://www.2ndquadrant.com/en/blog/how-to-automate-postgresql-12-replication-and-failover-with-repmgr-part-2/)
* https://blog.2ndquadrant.com/repmgr-3-2-is-here-barman-support-brand-new-high-availability-features/ * [How to implement repmgr for PostgreSQL automatic failover](https://www.enterprisedb.com/postgres-tutorials/how-implement-repmgr-postgresql-automatic-failover)
* https://blog.2ndquadrant.com/improvements-in-repmgr-3-1-4/
* https://blog.2ndquadrant.com/managing-useful-clusters-repmgr/
* https://blog.2ndquadrant.com/easier_postgresql_90_clusters/

View File

@@ -1,7 +1,7 @@
TODO TODO
==== ====
This file contains a list of improvements which are desireable and/or have This file contains a list of improvements which are desirable and/or have
been requested, and which we aim to address/implement when time and resources been requested, and which we aim to address/implement when time and resources
permit. permit.
@@ -17,4 +17,4 @@ repmgrd nodes to prevent unintended failover; this is obviously inconvenient.
We'll need to implement some way of notifying each repmgrd to suspend automatic We'll need to implement some way of notifying each repmgrd to suspend automatic
failover until further notice. failover until further notice.
Requested in GitHub #410 ( https://github.com/2ndQuadrant/repmgr/issues/410 ) Requested in GitHub #410 ( https://github.com/EnterpriseDB/repmgr/issues/410 )

View File

@@ -6,7 +6,7 @@
* supported PostgreSQL versions. They're unlikely to change but * supported PostgreSQL versions. They're unlikely to change but
* it would be worth keeping an eye on them for any fixes/improvements. * it would be worth keeping an eye on them for any fixes/improvements.
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California

View File

@@ -1,6 +1,6 @@
/* /*
* compat.h * compat.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California

View File

@@ -1,7 +1,7 @@
/* /*
* configdata.c - contains structs with parsed configuration data * configdata.c - contains structs with parsed configuration data
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -120,10 +120,10 @@ struct ConfigFileSetting config_file_settings[] =
/* replication_type */ /* replication_type */
{ {
"replication_type", "replication_type",
CONFIG_INT, CONFIG_REPLICATION_TYPE,
{ .intptr = &config_file_options.replication_type }, { .replicationtypeptr = &config_file_options.replication_type },
{ .intdefault = REPLICATION_TYPE_PHYSICAL }, { .replicationtypedefault = DEFAULT_REPLICATION_TYPE },
{ .intminval = -1 }, {},
{}, {},
{} {}
}, },
@@ -581,6 +581,16 @@ struct ConfigFileSetting config_file_settings[] =
{ .strmaxlen = sizeof(config_file_options.repmgrd_pid_file) }, { .strmaxlen = sizeof(config_file_options.repmgrd_pid_file) },
{ .postprocess_func = &repmgr_canonicalize_path } { .postprocess_func = &repmgr_canonicalize_path }
}, },
/* repmgrd_exit_on_inactive_node */
{
"repmgrd_exit_on_inactive_node",
CONFIG_BOOL,
{ .boolptr = &config_file_options.repmgrd_exit_on_inactive_node},
{ .booldefault = DEFAULT_REPMGRD_EXIT_ON_INACTIVE_NODE },
{},
{},
{}
},
/* standby_disconnect_on_failover */ /* standby_disconnect_on_failover */
{ {
"standby_disconnect_on_failover", "standby_disconnect_on_failover",

View File

@@ -107,9 +107,9 @@ ProcessRepmgrConfigFile(const char *config_file, const char *base_dir, ItemList
extern bool extern bool
ProcessPostgresConfigFile(const char *config_file, const char *base_dir, KeyValueList *contents, ItemList *error_list, ItemList *warning_list) ProcessPostgresConfigFile(const char *config_file, const char *base_dir, bool strict, KeyValueList *contents, ItemList *error_list, ItemList *warning_list)
{ {
return ProcessConfigFile(base_dir, config_file, NULL, true, 0, contents, error_list, warning_list); return ProcessConfigFile(base_dir, config_file, NULL, strict, 0, contents, error_list, warning_list);
} }
static bool static bool

View File

@@ -1,7 +1,7 @@
/* /*
* configfile.c - parse repmgr.conf and other configuration-related functionality * configfile.c - parse repmgr.conf and other configuration-related functionality
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -313,6 +313,9 @@ _parse_config(ItemList *error_list, ItemList *warning_list)
case CONFIG_CONNECTION_CHECK_TYPE: case CONFIG_CONNECTION_CHECK_TYPE:
*setting->val.checktypeptr = setting->defval.checktypedefault; *setting->val.checktypeptr = setting->defval.checktypedefault;
break; break;
case CONFIG_REPLICATION_TYPE:
*setting->val.replicationtypeptr = setting->defval.replicationtypedefault;
break;
case CONFIG_EVENT_NOTIFICATION_LIST: case CONFIG_EVENT_NOTIFICATION_LIST:
case CONFIG_TABLESPACE_MAPPING: case CONFIG_TABLESPACE_MAPPING:
/* no default for these types; lists cleared above */ /* no default for these types; lists cleared above */
@@ -566,6 +569,20 @@ parse_configuration_item(ItemList *error_list, ItemList *warning_list, const cha
} }
break; break;
} }
case CONFIG_REPLICATION_TYPE:
{
if (strcasecmp(value, "physical") == 0)
{
*(ReplicationType *)setting->val.replicationtypeptr = REPLICATION_TYPE_PHYSICAL;
}
else
{
item_list_append_format(error_list,
_("value for \"%s\" must be \"physical\"\n"),
name);
}
break;
}
case CONFIG_EVENT_NOTIFICATION_LIST: case CONFIG_EVENT_NOTIFICATION_LIST:
{ {
parse_event_notifications_list((EventNotificationList *)setting->val.notificationlistptr, parse_event_notifications_list((EventNotificationList *)setting->val.notificationlistptr,
@@ -1394,6 +1411,9 @@ dump_config(void)
case CONFIG_CONNECTION_CHECK_TYPE: case CONFIG_CONNECTION_CHECK_TYPE:
printf("%s", print_connection_check_type(*setting->val.checktypeptr)); printf("%s", print_connection_check_type(*setting->val.checktypeptr));
break; break;
case CONFIG_REPLICATION_TYPE:
printf("%s", print_replication_type(*setting->val.replicationtypeptr));
break;
case CONFIG_EVENT_NOTIFICATION_LIST: case CONFIG_EVENT_NOTIFICATION_LIST:
{ {
char *list = print_event_notification_list(setting->val.notificationlistptr); char *list = print_event_notification_list(setting->val.notificationlistptr);
@@ -1765,7 +1785,7 @@ modify_auto_conf(const char *data_dir, KeyValueList *items)
FILE *fp; FILE *fp;
mode_t um; mode_t um;
struct stat auto_conf_st; struct stat data_dir_st;
KeyValueList config = {NULL, NULL}; KeyValueList config = {NULL, NULL};
KeyValueListCell *cell = NULL; KeyValueListCell *cell = NULL;
@@ -1776,7 +1796,12 @@ modify_auto_conf(const char *data_dir, KeyValueList *items)
appendPQExpBuffer(&auto_conf, "%s/%s", appendPQExpBuffer(&auto_conf, "%s/%s",
data_dir, PG_AUTOCONF_FILENAME); data_dir, PG_AUTOCONF_FILENAME);
success = ProcessPostgresConfigFile(auto_conf.data, NULL, &config, NULL, NULL); success = ProcessPostgresConfigFile(auto_conf.data,
NULL,
false, /* we don't care if the file does not exist */
&config,
NULL,
NULL);
if (success == false) if (success == false)
{ {
@@ -1787,7 +1812,7 @@ modify_auto_conf(const char *data_dir, KeyValueList *items)
} }
/* /*
* Append requested items to items extracted from the existing file. * Append requested items to any items extracted from the existing file.
*/ */
for (cell = items->head; cell; cell = cell->next) for (cell = items->head; cell; cell = cell->next)
{ {
@@ -1816,27 +1841,46 @@ modify_auto_conf(const char *data_dir, KeyValueList *items)
cell->key, cell->value); cell->key, cell->value);
} }
stat(auto_conf.data, &auto_conf_st); /* stat the data directory for the file mode */
if (stat(data_dir, &data_dir_st) != 0)
{
/*
* This is highly unlikely to happen, but if it does (e.g. freak
* race condition with some rogue process which is messing about
* with the data directory), there's not a lot we can do.
*/
log_error(_("error encountered when checking \"%s\""),
data_dir);
log_detail("%s", strerror(errno));
exit(ERR_BAD_CONFIG);
}
/* /*
* Set umask so the temporary file is created in the same mode as the original * Set umask so the temporary file is created in the same mode as the data
* postgresql.auto.conf file. * directory. In PostgreSQL 11 and later this can be 0700 or 0750.
*/ */
um = umask(~(auto_conf_st.st_mode)); um = umask(~(data_dir_st.st_mode));
fp = fopen(auto_conf_tmp.data, "w"); fp = fopen(auto_conf_tmp.data, "w");
umask(um); umask(um);
if (fp == NULL) if (fp == NULL)
{ {
fprintf(stderr, "unable to open \"%s\": %s\n", fprintf(stderr, "unable to open \"%s\" for writing: %s\n",
auto_conf_tmp.data, auto_conf_tmp.data,
strerror(errno)); strerror(errno));
success = false;
} }
else else
{ {
if (fwrite(auto_conf_contents.data, strlen(auto_conf_contents.data), 1, fp) != 1) if (fwrite(auto_conf_contents.data, strlen(auto_conf_contents.data), 1, fp) != 1)
{ {
fprintf(stderr, "unable to write to \"%s\": %s\n",
auto_conf_tmp.data,
strerror(errno));
fclose(fp); fclose(fp);
success = false;
} }
else else
{ {
@@ -1845,7 +1889,7 @@ modify_auto_conf(const char *data_dir, KeyValueList *items)
/* /*
* Note: durable_rename() is not exposed to frontend code before Pg 10. * Note: durable_rename() is not exposed to frontend code before Pg 10.
* We only really need to be modifying postgresql.auto.conf from Pg 12, * We only really need to be modifying postgresql.auto.conf from Pg 12,
* but provide backwards compatibitilty for Pg 9.6 and earlier for the * but provide backwards compatibility for Pg 9.6 and earlier for the
* (unlikely) event that a repmgr built against one of those versions * (unlikely) event that a repmgr built against one of those versions
* is being used against Pg 12 and later. * is being used against Pg 12 and later.
*/ */
@@ -2167,6 +2211,20 @@ parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_opti
} }
const char *
print_replication_type(ReplicationType type)
{
switch (type)
{
case REPLICATION_TYPE_PHYSICAL:
return "physical";
}
/* should never reach here */
return "UNKNOWN";
}
const char * const char *
print_connection_check_type(ConnectionCheckType type) print_connection_check_type(ConnectionCheckType type)
{ {
@@ -2192,6 +2250,7 @@ print_event_notification_list(EventNotificationList *list)
PQExpBufferData buf; PQExpBufferData buf;
char *ptr; char *ptr;
EventNotificationListCell *cell; EventNotificationListCell *cell;
int ptr_len;
initPQExpBuffer(&buf); initPQExpBuffer(&buf);
cell = list->head; cell = list->head;
@@ -2206,8 +2265,10 @@ print_event_notification_list(EventNotificationList *list)
cell = cell->next; cell = cell->next;
} }
ptr = palloc0(strlen(buf.data) + 1); ptr_len = strlen(buf.data);
strncpy(ptr, buf.data, strlen(buf.data)); ptr = palloc0(ptr_len + 1);
strncpy(ptr, buf.data, ptr_len);
termPQExpBuffer(&buf); termPQExpBuffer(&buf);

View File

@@ -1,7 +1,7 @@
/* /*
* configfile.h * configfile.h
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@@ -50,6 +50,11 @@ typedef enum
CHECK_CONNECTION CHECK_CONNECTION
} ConnectionCheckType; } ConnectionCheckType;
typedef enum
{
REPLICATION_TYPE_PHYSICAL
} ReplicationType;
typedef struct EventNotificationListCell typedef struct EventNotificationListCell
{ {
struct EventNotificationListCell *next; struct EventNotificationListCell *next;
@@ -86,7 +91,8 @@ typedef enum
CONFIG_FAILOVER_MODE, CONFIG_FAILOVER_MODE,
CONFIG_CONNECTION_CHECK_TYPE, CONFIG_CONNECTION_CHECK_TYPE,
CONFIG_EVENT_NOTIFICATION_LIST, CONFIG_EVENT_NOTIFICATION_LIST,
CONFIG_TABLESPACE_MAPPING CONFIG_TABLESPACE_MAPPING,
CONFIG_REPLICATION_TYPE
} ConfigItemType; } ConfigItemType;
@@ -103,6 +109,7 @@ typedef struct ConfigFileSetting
ConnectionCheckType *checktypeptr; ConnectionCheckType *checktypeptr;
EventNotificationList *notificationlistptr; EventNotificationList *notificationlistptr;
TablespaceList *tablespacemappingptr; TablespaceList *tablespacemappingptr;
ReplicationType *replicationtypeptr;
} val; } val;
union { union {
int intdefault; int intdefault;
@@ -110,6 +117,7 @@ typedef struct ConfigFileSetting
bool booldefault; bool booldefault;
failover_mode_opt failovermodedefault; failover_mode_opt failovermodedefault;
ConnectionCheckType checktypedefault; ConnectionCheckType checktypedefault;
ReplicationType replicationtypedefault;
} defval; } defval;
union { union {
int intminval; int intminval;
@@ -138,7 +146,7 @@ typedef struct
char config_directory[MAXPGPATH]; char config_directory[MAXPGPATH];
char pg_bindir[MAXPGPATH]; char pg_bindir[MAXPGPATH];
char repmgr_bindir[MAXPGPATH]; char repmgr_bindir[MAXPGPATH];
int replication_type; ReplicationType replication_type;
/* log settings */ /* log settings */
char log_level[MAXLEN]; char log_level[MAXLEN];
@@ -198,6 +206,7 @@ typedef struct
int primary_notification_timeout; int primary_notification_timeout;
int repmgrd_standby_startup_timeout; int repmgrd_standby_startup_timeout;
char repmgrd_pid_file[MAXPGPATH]; char repmgrd_pid_file[MAXPGPATH];
bool repmgrd_exit_on_inactive_node;
bool standby_disconnect_on_failover; bool standby_disconnect_on_failover;
int sibling_nodes_disconnect_timeout; int sibling_nodes_disconnect_timeout;
ConnectionCheckType connection_check_type; ConnectionCheckType connection_check_type;
@@ -241,7 +250,7 @@ typedef struct
/* /*
* undocumented settings * undocumented settings
* *
* These settings are for testing or experimential features * These settings are for testing or experimental features
* and may be changed without notice. * and may be changed without notice.
*/ */
@@ -356,6 +365,7 @@ const char *format_failover_mode(failover_mode_opt failover);
void exit_with_cli_errors(ItemList *error_list, const char *repmgr_command); void exit_with_cli_errors(ItemList *error_list, const char *repmgr_command);
void print_item_list(ItemList *item_list); void print_item_list(ItemList *item_list);
const char *print_replication_type(ReplicationType type);
const char *print_connection_check_type(ConnectionCheckType type); const char *print_connection_check_type(ConnectionCheckType type);
char *print_event_notification_list(EventNotificationList *list); char *print_event_notification_list(EventNotificationList *list);
char *print_tablespace_mapping(TablespaceList *tablespacemappingptr); char *print_tablespace_mapping(TablespaceList *tablespacemappingptr);
@@ -364,6 +374,6 @@ extern bool modify_auto_conf(const char *data_dir, KeyValueList *items);
extern bool ProcessRepmgrConfigFile(const char *config_file, const char *base_dir, ItemList *error_list, ItemList *warning_list); extern bool ProcessRepmgrConfigFile(const char *config_file, const char *base_dir, ItemList *error_list, ItemList *warning_list);
extern bool ProcessPostgresConfigFile(const char *config_file, const char *base_dir, KeyValueList *contents, ItemList *error_list, ItemList *warning_list); extern bool ProcessPostgresConfigFile(const char *config_file, const char *base_dir, bool strict, KeyValueList *contents, ItemList *error_list, ItemList *warning_list);
#endif /* _REPMGR_CONFIGFILE_H_ */ #endif /* _REPMGR_CONFIGFILE_H_ */

28
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for repmgr 5.2.0. # Generated by GNU Autoconf 2.69 for repmgr 5.4.0.
# #
# Report bugs to <repmgr@googlegroups.com>. # Report bugs to <repmgr@googlegroups.com>.
# #
@@ -11,7 +11,7 @@
# This configure script is free software; the Free Software Foundation # This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it. # gives unlimited permission to copy, distribute and modify it.
# #
# Copyright (c) 2010-2020, 2ndQuadrant Ltd. # Copyright (c) 2010-2021, EnterpriseDB Corporation
## -------------------- ## ## -------------------- ##
## M4sh Initialization. ## ## M4sh Initialization. ##
## -------------------- ## ## -------------------- ##
@@ -582,8 +582,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='repmgr' PACKAGE_NAME='repmgr'
PACKAGE_TARNAME='repmgr' PACKAGE_TARNAME='repmgr'
PACKAGE_VERSION='5.2.0' PACKAGE_VERSION='5.4.0'
PACKAGE_STRING='repmgr 5.2.0' PACKAGE_STRING='repmgr 5.4.0'
PACKAGE_BUGREPORT='repmgr@googlegroups.com' PACKAGE_BUGREPORT='repmgr@googlegroups.com'
PACKAGE_URL='https://repmgr.org/' PACKAGE_URL='https://repmgr.org/'
@@ -1181,7 +1181,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures repmgr 5.2.0 to adapt to many kinds of systems. \`configure' configures repmgr 5.4.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1242,7 +1242,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of repmgr 5.2.0:";; short | recursive ) echo "Configuration of repmgr 5.4.0:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@@ -1316,14 +1316,14 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
repmgr configure 5.2.0 repmgr configure 5.4.0
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it. gives unlimited permission to copy, distribute and modify it.
Copyright (c) 2010-2020, 2ndQuadrant Ltd. Copyright (c) 2010-2021, EnterpriseDB Corporation
_ACEOF _ACEOF
exit exit
fi fi
@@ -1335,7 +1335,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by repmgr $as_me 5.2.0, which was It was created by repmgr $as_me 5.4.0, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@@ -1811,11 +1811,11 @@ fi
pgac_pg_config_version=$($PG_CONFIG --version 2>/dev/null) pgac_pg_config_version=$($PG_CONFIG --version 2>/dev/null)
major_version_num=$(echo "$pgac_pg_config_version"| major_version_num=$(echo "$pgac_pg_config_version"|
$SED -e 's/^PostgreSQL \([0-9]\{1,2\}\).*$/\1/') $SED -e 's/^[^0-9]\+ \([0-9]\{1,2\}\).*$/\1/')
if test "$major_version_num" -lt '10'; then if test "$major_version_num" -lt '10'; then
version_num=$(echo "$pgac_pg_config_version"| version_num=$(echo "$pgac_pg_config_version"|
$SED -e 's/^PostgreSQL \([0-9]*\)\.\([0-9]*\)\([a-zA-Z0-9.]*\)$/\1.\2/') $SED -e 's/^[^0-9]\+ \([0-9]*\)\.\([0-9]*\)\([a-zA-Z0-9.]*\)$/\1.\2/')
if test -z "$version_num"; then if test -z "$version_num"; then
as_fn_error $? "could not detect the PostgreSQL version, wrong or broken pg_config?" "$LINENO" 5 as_fn_error $? "could not detect the PostgreSQL version, wrong or broken pg_config?" "$LINENO" 5
@@ -1829,7 +1829,7 @@ if test "$major_version_num" -lt '10'; then
fi fi
else else
version_num=$(echo "$pgac_pg_config_version"| version_num=$(echo "$pgac_pg_config_version"|
$SED -e 's/^PostgreSQL \(.\+\)$/\1/') $SED -e 's/^[^0-9]\+ \(.\+\)$/\1/')
if test -z "$version_num"; then if test -z "$version_num"; then
as_fn_error $? "could not detect the PostgreSQL version, wrong or broken pg_config?" "$LINENO" 5 as_fn_error $? "could not detect the PostgreSQL version, wrong or broken pg_config?" "$LINENO" 5
@@ -2487,7 +2487,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by repmgr $as_me 5.2.0, which was This file was extended by repmgr $as_me 5.4.0, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -2550,7 +2550,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
repmgr config.status 5.2.0 repmgr config.status 5.4.0
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@@ -1,6 +1,6 @@
AC_INIT([repmgr], [5.2.0], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/]) AC_INIT([repmgr], [5.4.0], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
AC_COPYRIGHT([Copyright (c) 2010-2020, 2ndQuadrant Ltd.]) AC_COPYRIGHT([Copyright (c) 2010-2021, EnterpriseDB Corporation])
AC_CONFIG_HEADER(config.h) AC_CONFIG_HEADER(config.h)
@@ -19,11 +19,11 @@ fi
pgac_pg_config_version=$($PG_CONFIG --version 2>/dev/null) pgac_pg_config_version=$($PG_CONFIG --version 2>/dev/null)
major_version_num=$(echo "$pgac_pg_config_version"| major_version_num=$(echo "$pgac_pg_config_version"|
$SED -e 's/^PostgreSQL \([[0-9]]\{1,2\}\).*$/\1/') $SED -e 's/^[[^0-9]]\+ \([[0-9]]\{1,2\}\).*$/\1/')
if test "$major_version_num" -lt '10'; then if test "$major_version_num" -lt '10'; then
version_num=$(echo "$pgac_pg_config_version"| version_num=$(echo "$pgac_pg_config_version"|
$SED -e 's/^PostgreSQL \([[0-9]]*\)\.\([[0-9]]*\)\([[a-zA-Z0-9.]]*\)$/\1.\2/') $SED -e 's/^[[^0-9]]\+ \([[0-9]]*\)\.\([[0-9]]*\)\([[a-zA-Z0-9.]]*\)$/\1.\2/')
if test -z "$version_num"; then if test -z "$version_num"; then
AC_MSG_ERROR([could not detect the PostgreSQL version, wrong or broken pg_config?]) AC_MSG_ERROR([could not detect the PostgreSQL version, wrong or broken pg_config?])
@@ -37,7 +37,7 @@ if test "$major_version_num" -lt '10'; then
fi fi
else else
version_num=$(echo "$pgac_pg_config_version"| version_num=$(echo "$pgac_pg_config_version"|
$SED -e 's/^PostgreSQL \(.\+\)$/\1/') $SED -e 's/^[[^0-9]]\+ \(.\+\)$/\1/')
if test -z "$version_num"; then if test -z "$version_num"; then
AC_MSG_ERROR([could not detect the PostgreSQL version, wrong or broken pg_config?]) AC_MSG_ERROR([could not detect the PostgreSQL version, wrong or broken pg_config?])

View File

@@ -2,11 +2,11 @@
* controldata.c - functions for reading the pg_control file * controldata.c - functions for reading the pg_control file
* *
* The functions provided here enable repmgr to read a pg_control file * The functions provided here enable repmgr to read a pg_control file
* in a version-indepent way, even if the PostgreSQL instance is not * in a version-independent way, even if the PostgreSQL instance is not
* running. For that reason we can't use on the pg_control_*() functions * running. For that reason we can't use on the pg_control_*() functions
* provided in PostgreSQL 9.6 and later. * provided in PostgreSQL 9.6 and later.
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
@@ -333,7 +333,7 @@ get_controlfile(const char *DataDir)
control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI; control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI;
control_file_info->minRecoveryPoint = ptr->minRecoveryPoint; control_file_info->minRecoveryPoint = ptr->minRecoveryPoint;
#else #else
fprintf(stderr, "ERROR: please use a repmgr version built for PostgreSQL 12\n"); fprintf(stderr, "ERROR: please use a repmgr version built for PostgreSQL 12 or later\n");
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
#endif #endif
} }

View File

@@ -1,6 +1,6 @@
/* /*
* controldata.h * controldata.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California

181
dbutils.c
View File

@@ -1,7 +1,7 @@
/* /*
* dbutils.c - Database connection/management functions * dbutils.c - Database connection/management functions
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@@ -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 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 * This provides a standardized way of logging database errors. Note
* that the provided PGconn can be a normal or a replication connection; * that the provided PGconn can be a normal or a replication connection;
@@ -730,6 +732,8 @@ validate_conninfo_string(const char *conninfo_str, char **errmsg)
if (connOptions == NULL) if (connOptions == NULL)
return false; return false;
PQconninfoFree(connOptions);
return true; return true;
} }
@@ -1255,7 +1259,7 @@ bool
pg_reload_conf(PGconn *conn) pg_reload_conf(PGconn *conn)
{ {
PGresult *res = NULL; PGresult *res = NULL;
bool success = false; bool success = true;
res = PQexec(conn, "SELECT pg_catalog.pg_reload_conf()"); res = PQexec(conn, "SELECT pg_catalog.pg_reload_conf()");
@@ -1287,21 +1291,16 @@ get_cluster_size(PGconn *conn, char *size)
initPQExpBuffer(&query); initPQExpBuffer(&query);
appendPQExpBufferStr(&query, appendPQExpBufferStr(&query,
"SELECT pg_catalog.pg_size_pretty(pg_catalog.sum(pg_catalog.pg_database_size(oid))::bigint) " "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); log_verbose(LOG_DEBUG, "get_cluster_size():\n%s", query.data);
res = PQexec(conn, query.data); res = PQexec(conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK) if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, query.data, _("get_cluster_size(): unable to execute query"));
success = false; success = false;
}
else else
{
snprintf(size, MAXLEN, "%s", PQgetvalue(res, 0, 0)); snprintf(size, MAXLEN, "%s", PQgetvalue(res, 0, 0));
}
termPQExpBuffer(&query); termPQExpBuffer(&query);
PQclear(res); PQclear(res);
@@ -1824,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 */ /* user/role information functions */
/* =============================== */ /* =============================== */
@@ -1865,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 * Determine if the user associated with the current connection is
* a member of the "pg_monitor" default role, or optionally one * a member of the "pg_monitor" default role, or optionally one
@@ -2080,7 +2139,13 @@ server_in_exclusive_backup_mode(PGconn *conn)
{ {
BackupState backup_state = BACKUP_STATE_UNKNOWN; BackupState backup_state = BACKUP_STATE_UNKNOWN;
const char *sqlquery = "SELECT pg_catalog.pg_is_in_backup()"; const char *sqlquery = "SELECT pg_catalog.pg_is_in_backup()";
PGresult *res = PQexec(conn, sqlquery); PGresult *res = NULL;
/* Exclusive backup removed from PostgreSQL 15 */
if (PQserverVersion(conn) >= 150000)
return BACKUP_STATE_NO_BACKUP;
res = PQexec(conn, sqlquery);
if (PQresultStatus(res) != PGRES_TUPLES_OK) if (PQresultStatus(res) != PGRES_TUPLES_OK)
{ {
@@ -2244,29 +2309,6 @@ repmgrd_pause(PGconn *conn, bool pause)
return success; 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 int
repmgrd_get_upstream_node_id(PGconn *conn) repmgrd_get_upstream_node_id(PGconn *conn)
@@ -4240,7 +4282,7 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
} }
break; break;
case 'p': case 'p':
/* %p: primary id ("standby_switchover": former primary id) */ /* %p: primary id ("standby_switchover"/"repmgrd_failover_promote": former primary id) */
src_ptr++; src_ptr++;
if (event_info->node_id != UNKNOWN_NODE_ID) if (event_info->node_id != UNKNOWN_NODE_ID)
{ {
@@ -4825,7 +4867,7 @@ cancel_query(PGconn *conn, int timeout)
* Wait until current query finishes, ignoring any results. * Wait until current query finishes, ignoring any results.
* Usually this will be an async query or query cancellation. * Usually this will be an async query or query cancellation.
* *
* Returns 1 for success; 0 if any error ocurred; -1 if timeout reached. * Returns 1 for success; 0 if any error occurred; -1 if timeout reached.
*/ */
int int
wait_connection_availability(PGconn *conn, int timeout) wait_connection_availability(PGconn *conn, int timeout)
@@ -5702,7 +5744,7 @@ get_node_timeline(PGconn *conn, char *timeline_id_str)
TimeLineID timeline_id = UNKNOWN_TIMELINE_ID; 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) if (PQserverVersion(conn) >= 90600)
{ {
@@ -5790,6 +5832,19 @@ get_node_replication_stats(PGconn *conn, t_node_info *node_info)
NodeAttached NodeAttached
is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state) 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; PQExpBufferData query;
PGresult *res = NULL; PGresult *res = NULL;
@@ -5824,9 +5879,12 @@ is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
*/ */
if (PQntuples(res) > 1) if (PQntuples(res) > 1)
{ {
log_error(_("multiple entries with \"application_name\" set to \"%s\" found in \"pg_stat_replication\""), if (quiet == false)
node_name); {
log_hint(_("verify that a unique node name is configured for each node")); 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); PQclear(res);
@@ -5835,7 +5893,8 @@ is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
if (PQntuples(res) == 0) 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); PQclear(res);
@@ -5861,9 +5920,10 @@ is_downstream_node_attached(PGconn *conn, char *node_name, char **node_state)
if (strcmp(state, "streaming") != 0) if (strcmp(state, "streaming") != 0)
{ {
log_warning(_("node \"%s\" attached in state \"%s\""), if (quiet == false)
node_name, log_warning(_("node \"%s\" attached in state \"%s\""),
state); node_name,
state);
PQclear(res); PQclear(res);
@@ -6006,6 +6066,43 @@ is_wal_replay_paused(PGconn *conn, bool check_pending_wal)
return is_paused; return is_paused;
} }
/* repmgrd status functions */
CheckStatus
get_repmgrd_status(PGconn *conn)
{
PQExpBufferData query;
PGresult *res = NULL;
CheckStatus repmgrd_status = CHECK_STATUS_CRITICAL;
initPQExpBuffer(&query);
appendPQExpBufferStr(&query,
" SELECT "
" CASE "
" WHEN repmgr.repmgrd_is_running() "
" THEN "
" CASE "
" WHEN repmgr.repmgrd_is_paused() THEN 1 ELSE 0 "
" END "
" ELSE 2 "
" END AS repmgrd_status");
res = PQexec(conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, query.data, _("unable to execute repmgrd status query"));
}
else
{
repmgrd_status = atoi(PQgetvalue(res, 0, 0));
}
termPQExpBuffer(&query);
PQclear(res);
return repmgrd_status;
}
/* miscellaneous debugging functions */ /* miscellaneous debugging functions */

View File

@@ -1,7 +1,7 @@
/* /*
* dbutils.h * dbutils.h
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -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); bool identify_system(PGconn *repl_conn, t_system_identification *identification);
uint64 system_identifier(PGconn *conn); uint64 system_identifier(PGconn *conn);
TimeLineHistoryEntry *get_timeline_history(PGconn *repl_conn, TimeLineID tli); TimeLineHistoryEntry *get_timeline_history(PGconn *repl_conn, TimeLineID tli);
pid_t get_wal_receiver_pid(PGconn *conn);
/* user/role information functions */ /* user/role information functions */
bool can_execute_pg_promote(PGconn *conn); 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 connection_has_pg_monitor_role(PGconn *conn, const char *subrole);
bool is_replication_role(PGconn *conn, char *rolname); bool is_replication_role(PGconn *conn, char *rolname);
bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo); 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_running(PGconn *conn);
bool repmgrd_is_paused(PGconn *conn); bool repmgrd_is_paused(PGconn *conn);
bool repmgrd_pause(PGconn *conn, bool pause); bool repmgrd_pause(PGconn *conn, bool pause);
pid_t get_wal_receiver_pid(PGconn *conn);
int repmgrd_get_upstream_node_id(PGconn *conn); int repmgrd_get_upstream_node_id(PGconn *conn);
bool repmgrd_set_upstream_node_id(PGconn *conn, int node_id); bool repmgrd_set_upstream_node_id(PGconn *conn, int node_id);
@@ -597,11 +598,15 @@ int get_replication_lag_seconds(PGconn *conn);
TimeLineID get_node_timeline(PGconn *conn, char *timeline_id_str); TimeLineID get_node_timeline(PGconn *conn, char *timeline_id_str);
void get_node_replication_stats(PGconn *conn, t_node_info *node_info); 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(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); void set_upstream_last_seen(PGconn *conn, int upstream_node_id);
int get_upstream_last_seen(PGconn *conn, t_server_type node_type); int get_upstream_last_seen(PGconn *conn, t_server_type node_type);
bool is_wal_replay_paused(PGconn *conn, bool check_pending_wal); bool is_wal_replay_paused(PGconn *conn, bool check_pending_wal);
/* repmgrd status functions */
CheckStatus get_repmgrd_status(PGconn *conn);
/* miscellaneous debugging functions */ /* miscellaneous debugging functions */
const char *print_node_status(NodeStatus node_status); const char *print_node_status(NodeStatus node_status);
const char *print_pqping_status(PGPing ping_status); const char *print_pqping_status(PGPing ping_status);

View File

@@ -3,7 +3,7 @@
* dirmod.c * dirmod.c
* directory handling functions * directory handling functions
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -109,9 +109,56 @@ create_dir(const char *path)
bool bool
set_dir_permissions(const char *path) set_dir_permissions(const char *path, int server_version_num)
{ {
return (chmod(path, 0700) != 0) ? false : true; struct stat stat_buf;
bool no_group_access =
(server_version_num != UNKNOWN_SERVER_VERSION_NUM) &&
(server_version_num < 110000);
/*
* At this point the path should exist, so this check is very
* much just-in-case.
*/
if (stat(path, &stat_buf) != 0)
{
if (errno == ENOENT)
{
log_warning(_("directory \"%s\" does not exist"), path);
}
else
{
log_warning(_("could not read permissions of directory \"%s\""),
path);
log_detail("%s", strerror(errno));
}
return false;
}
/*
* If mode is not 0700 or 0750, attempt to change.
*/
if ((no_group_access == true && (stat_buf.st_mode & (S_IRWXG | S_IRWXO)))
|| (no_group_access == false && (stat_buf.st_mode & (S_IWGRP | S_IRWXO))))
{
/*
* Currently we default to 0700.
* There is no facility to override this directly,
* but the user can manually create the directory with
* the desired permissions.
*/
if (chmod(path, 0700) != 0) {
log_error(_("unable to change permissions of directory \"%s\""), path);
log_detail("%s", strerror(errno));
return false;
}
return true;
}
/* Leave as-is */
return true;
} }
@@ -158,7 +205,7 @@ mkdir_p(char *path, mode_t omode)
/* /*
* POSIX 1003.2: For each dir operand that does not name an * POSIX 1003.2: For each dir operand that does not name an
* existing directory, effects equivalent to those caused by the * existing directory, effects equivalent to those caused by the
* following command shall occcur: * following command shall occur:
* *
* mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode] * mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode]
* dir * dir
@@ -242,7 +289,7 @@ is_pg_running(const char *path)
{ {
/* /*
* No PID file - PostgreSQL shouldn't be running. From 9.3 (the * No PID file - PostgreSQL shouldn't be running. From 9.3 (the
* earliesty version we care about) removal of the PID file will * earliest version we care about) removal of the PID file will
* cause the postmaster to shut down, so it's highly unlikely * cause the postmaster to shut down, so it's highly unlikely
* that PostgreSQL will still be running. * that PostgreSQL will still be running.
*/ */
@@ -303,7 +350,7 @@ create_pg_dir(const char *path, bool force)
switch (check_dir(path)) switch (check_dir(path))
{ {
case DIR_NOENT: case DIR_NOENT:
/* directory does not exist, attempt to create it */ /* Directory does not exist, attempt to create it. */
log_info(_("creating directory \"%s\"..."), path); log_info(_("creating directory \"%s\"..."), path);
if (!create_dir(path)) if (!create_dir(path))
@@ -314,14 +361,23 @@ create_pg_dir(const char *path, bool force)
} }
break; break;
case DIR_EMPTY: case DIR_EMPTY:
/* exists but empty, fix permissions and use it */ /*
* Directory exists but empty, fix permissions and use it.
*
* Note that at this point the caller might not know the server
* version number, so in this case "set_dir_permissions()" will
* accept 0750 as a valid setting. As this is invalid in Pg10 and
* earlier, the caller should call "set_dir_permissions()" again
* when it has the number.
*
* We need to do the permissions check here in any case to catch
* fatal permissions early.
*/
log_info(_("checking and correcting permissions on existing directory \"%s\""), log_info(_("checking and correcting permissions on existing directory \"%s\""),
path); path);
if (!set_dir_permissions(path)) if (!set_dir_permissions(path, UNKNOWN_SERVER_VERSION_NUM))
{ {
log_error(_("unable to change permissions of directory \"%s\""), path);
log_detail("%s", strerror(errno));
return false; return false;
} }
break; break;

View File

@@ -1,6 +1,6 @@
/* /*
* dirutil.h * dirutil.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -35,7 +35,7 @@ typedef enum
} PgDirState; } PgDirState;
extern int mkdir_p(char *path, mode_t omode); extern int mkdir_p(char *path, mode_t omode);
extern bool set_dir_permissions(const char *path); extern bool set_dir_permissions(const char *path, int server_version_num);
extern DataDirState check_dir(const char *path); extern DataDirState check_dir(const char *path);
extern bool create_dir(const char *path); extern bool create_dir(const char *path);

View File

@@ -95,6 +95,7 @@ clean:
rm -f repmgr.html rm -f repmgr.html
rm -f repmgr-A4.pdf rm -f repmgr-A4.pdf
rm -f repmgr-US.pdf rm -f repmgr-US.pdf
rm -f *.fo
rm -f html/* rm -f html/*
maintainer-clean: maintainer-clean:

View File

@@ -62,7 +62,7 @@
<tip> <tip>
<para> <para>
2ndQuadrant's recommended configuration is to configure Our recommended configuration is to configure
<ulink url="https://www.pgbarman.org/">Barman</ulink> as a fallback <ulink url="https://www.pgbarman.org/">Barman</ulink> as a fallback
source of WAL files, rather than maintain replication slots for source of WAL files, rather than maintain replication slots for
each standby. See also: <link linkend="cloning-from-barman-restore-command">Using Barman as a WAL file source</link>. each standby. See also: <link linkend="cloning-from-barman-restore-command">Using Barman as a WAL file source</link>.
@@ -127,7 +127,7 @@
filesystem layouts. filesystem layouts.
</para> </para>
<para> <para>
Either use PostgreSQL packages provided by the community or 2ndQuadrant; if this Either use PostgreSQL packages provided by the community or EnterpriseDB; if this
is not possible, contact your vendor for assistance. is not possible, contact your vendor for assistance.
</para> </para>
</sect2> </sect2>
@@ -170,7 +170,7 @@
<para> <para>
If different &quot;minor&quot; &repmgr; versions (e.g. 4.1.1 and 4.1.6) are installed, If different &quot;minor&quot; &repmgr; versions (e.g. 4.1.1 and 4.1.6) are installed,
&repmgr; will function, but we strongly recommend always running the same version &repmgr; will function, but we strongly recommend always running the same version
to ensure there are no unexpected suprises, e.g. a newer version behaving slightly to ensure there are no unexpected surprises, e.g. a newer version behaving slightly
differently to the older version. differently to the older version.
</para> </para>
<para> <para>
@@ -212,11 +212,11 @@
</para> </para>
</sect2> </sect2>
<sect2 id="faq-third-party-packages" xreflabel="Compatability with third party vendor packages"> <sect2 id="faq-third-party-packages" xreflabel="Compatibility with third party vendor packages">
<title>Are &repmgr; packages compatible with <literal>$third_party_vendor</literal>'s packages?</title> <title>Are &repmgr; packages compatible with <literal>$third_party_vendor</literal>'s packages?</title>
<para> <para>
&repmgr; packages provided by 2ndQuadrant are compatible with the community-provided PostgreSQL &repmgr; packages provided by EnterpriseDB are compatible with the community-provided PostgreSQL
packages and any software provided by 2ndQuadrant. packages and specified software provided by EnterpriseDB.
</para> </para>
<para> <para>
A number of other vendors provide their own versions of PostgreSQL packages, often with different A number of other vendors provide their own versions of PostgreSQL packages, often with different
@@ -249,16 +249,16 @@
For a standby which has been manually cloned or recovered from an external For a standby which has been manually cloned or recovered from an external
backup manager such as Barman, the command backup manager such as Barman, the command
<command><link linkend="repmgr-standby-clone">repmgr standby clone --replication-conf-only</link></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, 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. <link linkend="repmgr-standby-register">register the node</link> as usual.
</para> </para>
</sect2> </sect2>
<sect2 id="faq-repmgr-recovery-conf" > <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> <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> </para>
</sect2> </sect2>
@@ -311,7 +311,7 @@
</para> </para>
</sect2> </sect2>
<sect2 id="faq-repmgr-shared-preload-libaries-no-repmgrd" xreflabel="shared_preload_libraries without repmgrd"> <sect2 id="faq-repmgr-shared-preload-libraries-no-repmgrd" xreflabel="shared_preload_libraries without repmgrd">
<title>Do I need to include <literal>shared_preload_libraries = 'repmgr'</literal> <title>Do I need to include <literal>shared_preload_libraries = 'repmgr'</literal>
in <filename>postgresql.conf</filename> if I'm not using &repmgrd;?</title> in <filename>postgresql.conf</filename> if I'm not using &repmgrd;?</title>
<para> <para>
@@ -366,11 +366,11 @@
</para> </para>
</sect2> </sect2>
<sect2 id="faq-repmgr-recovery-conf-quoted-values" xreflabel="Quoted values in recovery.conf"> <sect2 id="faq-repmgr-recovery-conf-quoted-values" xreflabel="Quoted values in replication.conf">
<title>Why are some values in <filename>recovery.conf</filename> surrounded by pairs of single quotes?</title> <title>Why are some values in <filename>recovery.conf</filename> (PostgreSQL 11 and earlier) surrounded by pairs of single quotes?</title>
<para> <para>
This is to ensure that user-supplied values which are written as parameter values in <filename>recovery.conf</filename> 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>
<para> <para>
The escaping is performed by an internal PostgreSQL routine, which leaves strings consisting The escaping is performed by an internal PostgreSQL routine, which leaves strings consisting
@@ -419,9 +419,9 @@
<para> <para>
&repmgrd; can monitor delayed standbys - those set up with &repmgrd; can monitor delayed standbys - those set up with
<varname>recovery_min_apply_delay</varname> set to a non-zero value <varname>recovery_min_apply_delay</varname> set to a non-zero value
in <filename>recovery.conf</filename> - but as it's not currently possible in the replication configuration. However &repmgrd; does not currently
to directly examine the value applied to the standby, &repmgrd; consider this setting, and therefore may not be able to properly evaluate
may not be able to properly evaluate the node as a promotion candidate. the node as a promotion candidate.
</para> </para>
<para> <para>
We recommend that delayed standbys are explicitly excluded from promotion We recommend that delayed standbys are explicitly excluded from promotion
@@ -459,7 +459,7 @@
</title> </title>
<para> <para>
<varname>promote_command</varname> or <varname>follow_command</varname> can be user-defined scripts, <varname>promote_command</varname> or <varname>follow_command</varname> can be user-defined scripts,
so &repmgr; will not apply <option>pg_bindir</option> even if excuting &repmgr;. Always provide the full so &repmgr; will not apply <option>pg_bindir</option> even if executing &repmgr;. Always provide the full
path; see <xref linkend="repmgrd-automatic-failover-configuration"/> for more details. path; see <xref linkend="repmgrd-automatic-failover-configuration"/> for more details.
</para> </para>
</sect2> </sect2>
@@ -479,7 +479,7 @@
is out-of-date, which may lead to incorrect failover behaviour. is out-of-date, which may lead to incorrect failover behaviour.
</para> </para>
<para> <para>
The onus is therefore on the adminstrator to manually set the cluster to a stable, healthy state before The onus is therefore on the administrator to manually set the cluster to a stable, healthy state before
starting &repmgrd;. starting &repmgrd;.
</para> </para>
</sect2> </sect2>

View File

@@ -50,19 +50,18 @@
<title>CentOS repositories</title> <title>CentOS repositories</title>
<para> <para>
&repmgr; packages are available from the public 2ndQuadrant repository, and also the &repmgr; packages are available from the public EDB repository, and also the
PostgreSQL community repository. The 2ndQuadrant repository is updated immediately PostgreSQL community repository. The EDB repository is updated immediately
after each after each &repmgr; release.
&repmgr; release.
</para> </para>
<table id="centos-2ndquadrant-repository"> <table id="centos-2ndquadrant-repository">
<title>2ndQuadrant public repository</title> <title>EDB public repository</title>
<tgroup cols="2"> <tgroup cols="2">
<tbody> <tbody>
<row> <row>
<entry>Repository URL:</entry> <entry>Repository URL:</entry>
<entry><ulink url="https://dl.2ndquadrant.com/">https://dl.2ndquadrant.com/</ulink></entry> <entry><ulink url="https://dl.enterprisedb.com/">https://dl.enterprisedb.com/</ulink></entry>
</row> </row>
<row> <row>
<entry>Repository documentation:</entry> <entry>Repository documentation:</entry>
@@ -253,7 +252,7 @@
</indexterm> </indexterm>
<para> <para>
&repmgr; <literal>.deb</literal> packages are provided by 2ndQuadrant as well as the &repmgr; <literal>.deb</literal> packages are provided by EDB as well as the
PostgreSQL Community APT repository, and are available for each community-supported PostgreSQL Community APT repository, and are available for each community-supported
PostgreSQL version, currently supported Debian releases, and currently supported PostgreSQL version, currently supported Debian releases, and currently supported
Ubuntu LTS releases. Ubuntu LTS releases.
@@ -263,12 +262,12 @@
<title>APT repositories</title> <title>APT repositories</title>
<table id="apt-2ndquadrant-repository"> <table id="apt-2ndquadrant-repository">
<title>2ndQuadrant public repository</title> <title>EDB public repository</title>
<tgroup cols="2"> <tgroup cols="2">
<tbody> <tbody>
<row> <row>
<entry>Repository URL:</entry> <entry>Repository URL:</entry>
<entry><ulink url="https://dl.2ndquadrant.com/">https://dl.2ndquadrant.com/</ulink></entry> <entry><ulink url="https://dl.enterprisedb.com/">https://dl.enterprisedb.com/</ulink></entry>
</row> </row>
<row> <row>
<entry>Repository documentation:</entry> <entry>Repository documentation:</entry>
@@ -398,11 +397,11 @@
</indexterm> </indexterm>
<indexterm> <indexterm>
<primary>packages</primary> <primary>packages</primary>
<secondary>snaphots</secondary> <secondary>snapshots</secondary>
</indexterm> </indexterm>
<para> <para>
For testing new features and bug fixes, from time to time 2ndQuadrant provides For testing new features and bug fixes, from time to time EDB provides
so-called &quot;snapshot packages&quot; via its public repository. These packages so-called &quot;snapshot packages&quot; via its public repository. These packages
are built from the &repmgr; source at a particular point in time, and are not formal are built from the &repmgr; source at a particular point in time, and are not formal
releases. releases.
@@ -414,22 +413,22 @@
</para> </para>
</note> </note>
<para> <para>
To install a snapshot package, it's necessary to install the 2ndQuadrant public snapshot repository, To install a snapshot package, it's necessary to install the EDB public snapshot repository,
following the instructions here: <ulink url="https://dl.2ndquadrant.com/default/release/site/">https://dl.2ndquadrant.com/default/release/site/</ulink> but replace <literal>release</literal> with <literal>snapshot</literal> following the instructions here: <ulink url="https://dl.enterprisedb.com/default/release/site/">https://dl.enterprisedb.com/default/release/site/</ulink> but replace <literal>release</literal> with <literal>snapshot</literal>
in the appropriate URL. in the appropriate URL.
</para> </para>
<para> <para>
For example, to install the snapshot RPM repository for PostgreSQL 9.6, execute (as <literal>root</literal>): For example, to install the snapshot RPM repository for PostgreSQL 9.6, execute (as <literal>root</literal>):
<programlisting> <programlisting>
curl https://dl.2ndquadrant.com/default/snapshot/get/9.6/rpm | bash</programlisting> curl https://dl.enterprisedb.com/default/snapshot/get/9.6/rpm | bash</programlisting>
or as a normal user with root sudo access: or as a normal user with root sudo access:
<programlisting> <programlisting>
curl https://dl.2ndquadrant.com/default/snapshot/get/9.6/rpm | sudo bash</programlisting> curl https://dl.enterprisedb.com/default/snapshot/get/9.6/rpm | sudo bash</programlisting>
</para> </para>
<para> <para>
Alternatively you can browse the repository here: Alternatively you can browse the repository here:
<ulink url="https://dl.2ndquadrant.com/default/snapshot/browse/">https://dl.2ndquadrant.com/default/snapshot/browse/</ulink>. <ulink url="https://dl.enterprisedb.com/default/snapshot/browse/">https://dl.enterprisedb.com/default/snapshot/browse/</ulink>.
</para> </para>
<para> <para>
Once the repository is installed, installing or updating &repmgr; will result in the latest snapshot Once the repository is installed, installing or updating &repmgr; will result in the latest snapshot
@@ -439,7 +438,7 @@ curl https://dl.2ndquadrant.com/default/snapshot/get/9.6/rpm | sudo bash</progra
The package name will be formatted like this: The package name will be formatted like this:
<programlisting> <programlisting>
repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting> repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
containg the snapshot build number (here: <literal>320</literal>) and the hash containing the snapshot build number (here: <literal>320</literal>) and the hash
of the <application>git</application> commit it was built from (here: <literal>g5113ab0</literal>). of the <application>git</application> commit it was built from (here: <literal>g5113ab0</literal>).
</para> </para>
@@ -494,32 +493,6 @@ repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
yum install repmgr96-4.0.6-1.rhel6</programlisting> yum install repmgr96-4.0.6-1.rhel6</programlisting>
</para> </para>
<sect3 id="packages-old-versions-rhel-centos-repmgr3">
<title>repmgr 3 packages</title>
<para>
Old &repmgr; 3 RPM packages (<literal>3.2</literal> and later) can be retrieved from the
(deprecated) 2ndQuadrant repository at
<ulink url="http://packages.2ndquadrant.com/repmgr/yum/">http://packages.2ndquadrant.com/repmgr/yum/</ulink>
by installing the appropriate repository RPM:
</para>
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara>
<ulink url="http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-fedora-1.0-1.noarch.rpm">http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-fedora-1.0-1.noarch.rpm</ulink>
</simpara>
</listitem>
<listitem>
<simpara>
<ulink url="http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-rhel-1.0-1.noarch.rpm">http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-rhel-1.0-1.noarch.rpm</ulink>
</simpara>
</listitem>
</itemizedlist>
</sect3>
</sect2> </sect2>
</sect1> </sect1>

View File

@@ -15,10 +15,286 @@
See also: <xref linkend="upgrading-repmgr"/> See also: <xref linkend="upgrading-repmgr"/>
</para> </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>??? ??? ???, 2022</emphasis></para>
<para>
&repmgr; 5.3.2 is a minor release.
</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>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="release-5.3.1">
<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>
<itemizedlist>
<listitem>
<para>
Fix upgrade path from &repmgr; 4.2 and 4.3 to &repmgr; 5.3.
</para>
</listitem>
<listitem>
<para>
&repmgrd;: ensure potentially open connections are closed.
</para>
<para>
In some cases, when recovering from degraded state in local node monitoring,
new connection was opened to the local node without closing
the old one, which will result in memory leakage.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="release-5.3.0">
<title>Release 5.3.0</title>
<para><emphasis>Tue 12 October, 2021</emphasis></para>
<para>
&repmgr; 5.3.0 is a major release.
</para>
<para>
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>
<itemizedlist>
<listitem>
<para>
<link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>:
Improve handling of node rejoin failure on the demotion candidate.
</para>
<para>
Previously &repmgr; did not check whether <command>repmgr node rejoin</command> actually
succeeded on the demotion candidate, and would always wait up to <varname>node_rejoin_timeout</varname>
seconds for it to attach to the promotion candidate, even if this would never happen.
</para>
<para>
This makes it easier to identify unexpected events during a switchover operation, such as
the demotion candidate being unexpectedly restarted by an external process.
</para>
<para>
Note that the output of the <link linkend="repmgr-node-rejoin"><command>repmgr node rejoin</command></link>
operation on the demotion candidate will now be logged to a temporary file on that node;
the location of the file will be reported in the error message, if one is emitted.
</para>
</listitem>
<listitem>
<para>
&repmgrd;: at startup, if node record is marked as "inactive", attempt
to set it to "active".
</para>
<para>
This behaviour can be overridden by setting the configuration parameter
<varname>repmgrd_exit_on_inactive_node</varname> to <literal>true</literal>.
</para>
</listitem>
<listitem>
<para>
<command><link linkend="repmgr-node-rejoin">repmgr node rejoin</link></command>:
emit rejoin target note information as <literal>NOTICE</literal>.
</para>
<para>
This makes it clearer what &repmgr; is trying to do.
</para>
</listitem>
<listitem>
<para>
<link linkend="repmgr-node-check">repmgr node check</link>:
option <option>--repmgrd</option> added to check &repmgrd;
status.
</para>
</listitem>
<listitem>
<para>
Add <literal>%p</literal> <link linkend="event-notifications">event notification parameter</link>
providing the node ID of the former primary for the <literal>repmgrd_failover_promote</literal> event.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
<sect2>
<title>Bug fixes</title>
<para>
<itemizedlist>
<listitem>
<para>
<command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>:
if using <option>--replication-conf-only</option> on a node
which was set up without replication slots, but the &repmgr; configuration
was since changed to <option>use_replication_slots=1</option>,
&repmgr; will now set <varname>slot_name</varname> in the
node record, if it was previously empty.
</para>
</listitem>
<listitem>
<para>
&repmgrd;: rename internal shared library functions to minimize the
risk of clashes with other shared libraries.
</para>
<para>
This does not affect user-facing SQL functions. Howe
</para>
</listitem>
<listitem>
<para>
&repmgrd;: ensure short option <option>-s</option> is accepted.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="release-5.2.1">
<title>Release 5.2.1</title>
<para><emphasis>Mon 7 December, 2020</emphasis></para>
<para>
&repmgr; 5.2.1 is a minor release.
</para>
<sect2>
<title>Improvements</title>
<para>
<itemizedlist>
<listitem>
<para>
<link linkend="repmgr-standby-clone">repmgr standby clone</link>:
option <option>--recovery-min-apply-delay</option> added, overriding any
setting present in <filename>repmgr.conf</filename>.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
<sect2>
<title>Bug fixes</title>
<para>
<itemizedlist>
<listitem>
<para>
Configuration: fix parsing of <option>replication_type</option> configuration parameter. GitHub #672.
</para>
</listitem>
<listitem>
<para>
<link linkend="repmgr-standby-clone">repmgr standby clone</link>:
handle case where <filename>postgresql.auto.conf</filename> is absent on the
source node.
</para>
</listitem>
<listitem>
<para>
<link linkend="repmgr-standby-clone">repmgr standby clone</link>:
in PostgreSQL 11 and later, an existing data directory's permissions
will not be changed to <option>0700</option> if they are already set to
<option>0750</option>.
</para>
</listitem>
<listitem>
<para>
&repmgrd;: prevent termination when local node not available and
<option>standby_disconnect_on_failover</option> is set. GitHub #675.
</para>
</listitem>
<listitem>
<para>
&repmgrd;: ensure <option>reconnect_interval</option> is correctly handled.
GitHub #673.
</para>
</listitem>
<listitem>
<para>
<command>repmgr witness --help</command>: fix <command>witness unregister</command>
description. GitHub #676.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="release-5.2.0"> <sect1 id="release-5.2.0">
<title id="release-current">Release 5.2.0</title> <title>Release 5.2.0</title>
<para><emphasis>Thu 22 October, 2020</emphasis></para> <para><emphasis>Thu 22 October, 2020</emphasis></para>
<para> <para>
@@ -1123,7 +1399,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
</para> </para>
<para> <para>
Possible values are <literal>ping</literal> (default; uses <command>PQping()</command> to Possible values are <literal>ping</literal> (default; uses <command>PQping()</command> to
determine server availability), <literal>connection</literal> (attempst to make a new connection to determine server availability), <literal>connection</literal> (attempts to make a new connection to
the upstream node), and <literal>query</literal> (determines server availability the upstream node), and <literal>query</literal> (determines server availability
by executing an SQL statement on the node via the existing connection). by executing an SQL statement on the node via the existing connection).
</para> </para>

View File

@@ -7,20 +7,20 @@
</indexterm> </indexterm>
<para> <para>
<ulink url="https://2ndquadrant.com/">2ndQuadrant</ulink> provides 24x7 <ulink url="https://www.enterprisedb.com/">EDB</ulink> provides 24x7
production support for &repmgr; and other PostgreSQL production support for &repmgr; and other PostgreSQL
products, including configuration assistance, installation products, including configuration assistance, installation
verification and training for running a robust replication cluster. verification and training for running a robust replication cluster.
</para> </para>
<para> <para>
For further details see: <ulink url="https://2ndquadrant.com/en/support/">https://2ndquadrant.com/en/support/</ulink> For further details see: <ulink url="https://www.enterprisedb.com/support/postgresql-support-overview-get-the-most-out-of-postgresql">Support Center</ulink>
</para> </para>
<para> <para>
A mailing list/forum is provided via Google groups to discuss contributions or issues: <ulink url="https://groups.google.com/group/repmgr">https://groups.google.com/group/repmgr</ulink>. A mailing list/forum is provided via Google groups to discuss contributions or issues: <ulink url="https://groups.google.com/group/repmgr">https://groups.google.com/group/repmgr</ulink>.
</para> </para>
<para> <para>
Please report bugs and other issues to: <ulink url="https://github.com/2ndQuadrant/repmgr">https://github.com/2ndQuadrant/repmgr</ulink>. Please report bugs and other issues to: <ulink url="https://github.com/EnterpriseDB/repmgr">https://github.com/EnterpriseDB/repmgr</ulink>.
</para> </para>
<important> <important>
@@ -64,7 +64,7 @@
<listitem> <listitem>
<simpara> <simpara>
<filename>repmpgr.conf</filename> files (suitably anonymized if necessary) <filename>repmgr.conf</filename> files (suitably anonymized if necessary)
</simpara> </simpara>
</listitem> </listitem>

View File

@@ -15,7 +15,7 @@
<para> <para>
<xref linkend="repmgr-standby-clone"/> can use <xref linkend="repmgr-standby-clone"/> can use
<ulink url="https://www.2ndquadrant.com/">2ndQuadrant</ulink>'s <ulink url="https://www.enterprisedb.com/">EDB</ulink>'s
<ulink url="https://www.pgbarman.org/">Barman</ulink> application <ulink url="https://www.pgbarman.org/">Barman</ulink> application
to clone a standby (and also as a fallback source for WAL files). to clone a standby (and also as a fallback source for WAL files).
</para> </para>
@@ -197,7 +197,7 @@ description = "Main cluster"
<para> <para>
As a fallback in case streaming replication is interrupted, PostgreSQL can optionally 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 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. a valid shell command which can retrieve a specified WAL file from the archive.
</para> </para>
<para> <para>
@@ -299,7 +299,7 @@ description = "Main cluster"
build up indefinitely, possibly leading to server failure. build up indefinitely, possibly leading to server failure.
</simpara> </simpara>
<simpara> <simpara>
As an alternative we recommend using 2ndQuadrant's <ulink url="https://www.pgbarman.org/">Barman</ulink>, As an alternative we recommend using EDB's <ulink url="https://www.pgbarman.org/">Barman</ulink>,
which offloads WAL management to a separate server, removing the requirement to use a replication which offloads WAL management to a separate server, removing the requirement to use a replication
slot for each individual standby to reserve WAL. See section <xref linkend="cloning-from-barman"/> slot for each individual standby to reserve WAL. See section <xref linkend="cloning-from-barman"/>
for more details on using &repmgr; together with Barman. for more details on using &repmgr; together with Barman.
@@ -319,7 +319,7 @@ description = "Main cluster"
Cascading replication, introduced with PostgreSQL 9.2, enables a standby server Cascading replication, introduced with PostgreSQL 9.2, enables a standby server
to replicate from another standby server rather than directly from the primary, to replicate from another standby server rather than directly from the primary,
meaning replication changes "cascade" down through a hierarchy of servers. This meaning replication changes "cascade" down through a hierarchy of servers. This
can be used to reduce load on the primary and minimize bandwith usage between can be used to reduce load on the primary and minimize bandwidth usage between
sites. For more details, see the sites. For more details, see the
<ulink url="https://www.postgresql.org/docs/current/warm-standby.html#CASCADING-REPLICATION"> <ulink url="https://www.postgresql.org/docs/current/warm-standby.html#CASCADING-REPLICATION">
PostgreSQL cascading replication documentation</ulink>. PostgreSQL cascading replication documentation</ulink>.
@@ -328,9 +328,9 @@ description = "Main cluster"
&repmgr; supports cascading replication. When cloning a standby, &repmgr; supports cascading replication. When cloning a standby,
set the command-line parameter <literal>--upstream-node-id</literal> to the 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 <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, 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. point to the primary node.
</para> </para>
<para> <para>
@@ -391,8 +391,8 @@ description = "Main cluster"
cluster, you may wish to clone a downstream standby whose upstream node cluster, you may wish to clone a downstream standby whose upstream node
does not yet exist. In this case you can clone from the primary (or does not yet exist. In this case you can clone from the primary (or
another upstream node); provide the parameter <literal>--upstream-conninfo</literal> another upstream node); provide the parameter <literal>--upstream-conninfo</literal>
to explictly set the upstream's <varname>primary_conninfo</varname> string to explicitly set the upstream's <varname>primary_conninfo</varname> string
in <filename>recovery.conf</filename>. in the replication configuration.
</simpara> </simpara>
</tip> </tip>
</sect1> </sect1>
@@ -491,12 +491,12 @@ description = "Main cluster"
</note> </note>
<para> <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 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> <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> (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> string in the replication configuration. Note that <varname>PGPASSWORD</varname>
will need to be set during any action which causes <filename>recovery.conf</filename> to be will need to be set during any action which causes the replication configuration file to be
rewritten, e.g. <xref linkend="repmgr-standby-follow"/>. rewritten, e.g. <xref linkend="repmgr-standby-follow"/>.
</para> </para>
</sect2> </sect2>
@@ -508,7 +508,7 @@ description = "Main cluster"
user (in addition to the user who manages the &repmgr; metadata). In this case, 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 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 <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> 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 table for each node; it no longer needs to be explicitly specified when
cloning a node or executing <xref linkend="repmgr-standby-follow"/>. cloning a node or executing <xref linkend="repmgr-standby-follow"/>.

View File

@@ -7,6 +7,14 @@
<secondary>optional settings</secondary> <secondary>optional settings</secondary>
</indexterm> </indexterm>
<note>
<simpara>
This section documents a subset of optional configuration settings; for a full
for a full and annotated view of all configuration options see the
see the <ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">sample repmgr.conf file</ulink>
</simpara>
</note>
<variablelist> <variablelist>
@@ -132,5 +140,50 @@ ssh_options='-q -o ConnectTimeout=10'</programlisting>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry id="repmgr-conf-pg-bindir" xreflabel="pg_bindir">
<term><varname>pg_bindir</varname> (<type>string</type>)
<indexterm>
<primary><varname>pg_bindir</varname> configuration file parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Path to the PostgreSQL binary directory (location of <application>pg_ctl</application>,
<application>pg_basebackup</application> etc.). Only required
if these are not in the system <varname>PATH</varname>.
</para>
<tip>
<para>
When &repmgr; is executed via <application>SSH</application> (e.g. when running
<command><link linkend="repmgr-standby-switchover">repmgr standby switchover</link></command>,
<command><link linkend="repmgr-cluster-matrix">repmgr cluster matrix</link></command> or
<command><link linkend="repmgr-cluster-crosscheck">repmgr cluster crosscheck</link></command>,
or if it is executed as cronjob), a login shell will not be used and only the
default system <varname>PATH</varname> will be set. Therefore it's recommended to set
<varname>pg_bindir</varname> so &repmgr; can correctly invoke binaries on a remote
system and avoid potential path issues.
</para>
</tip>
<para>
Debian/Ubuntu users: you will probably need to set this to the directory where
<application>pg_ctl</application> is located, e.g. <filename>/usr/lib/postgresql/9.6/bin/</filename>.
</para>
<para>
<emphasis>NOTE</emphasis>: <varname>pg_bindir</varname> is only used when &repmgr; directly
executes PostgreSQL binaries; any user-defined scripts
<emphasis>must</emphasis> be specified with the full path.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
<tip>
<simpara>
See the <ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">sample repmgr.conf file</ulink>
for a full and annotated view of all configuration options.
</simpara>
</tip>
</sect1> </sect1>

View File

@@ -96,6 +96,9 @@
</variablelist> </variablelist>
</para> </para>
<para>
See <xref linkend="configuration-file-optional-settings"/> for further configuration options.
</para>
</sect1> </sect1>

View File

@@ -27,7 +27,9 @@
<note> <note>
<para> <para>
If using <application>systemd</application>, ensure you have <varname>RemoveIPC</varname> set to <literal>off</literal>. If using <application>systemd</application>, ensure you have <varname>RemoveIPC</varname> set to <literal>off</literal>.
See the <ulink url="https://wiki.postgresql.org/wiki/Systemd">systemd</ulink> See the <ulink url="https://www.postgresql.org/docs/current/index.html">PostgreSQL documentation</ulink> section
<ulink url="https://www.postgresql.org/docs/current/kernel-resources.html#SYSTEMD-REMOVEIPC">systemd RemoveIPC</ulink>
and also the <ulink url="https://wiki.postgresql.org/wiki/Systemd">systemd</ulink>
entry in the <ulink url="https://wiki.postgresql.org/wiki/Main_Page">PostgreSQL wiki</ulink> for details. entry in the <ulink url="https://wiki.postgresql.org/wiki/Main_Page">PostgreSQL wiki</ulink> for details.
</para> </para>
</note> </note>

View File

@@ -164,7 +164,7 @@ conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlistin
</para> </para>
<para> <para>
For a full list of annotated configuration items, see the file For a full list of annotated configuration items, see the file
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>. <ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>.
</para> </para>
<para> <para>
For &repmgrd;-specific settings, see <xref linkend="repmgrd-configuration"/>. For &repmgrd;-specific settings, see <xref linkend="repmgrd-configuration"/>.
@@ -262,7 +262,7 @@ conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlistin
<indexterm> <indexterm>
<primary>repmgr.conf</primary> <primary>repmgr.conf</primary>
<secondary>ostgreSQL major version upgrades</secondary> <secondary>PostgreSQL major version upgrades</secondary>
</indexterm> </indexterm>
<para> <para>

View File

@@ -7,19 +7,186 @@
</indexterm> </indexterm>
<para> <para>
&repmgr; requires that the database defined in the <varname>conninfo</varname> If the &repmgr; database user (the PostgreSQL user defined in the
setting contains the <literal>repmgr</literal> extension. The database user defined in the <varname>conninfo</varname> setting is a superuser, no further user permissions need
<varname>conninfo</varname> setting must be able to access this database and to be granted.
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>
<para> <sect2 id="configuration-permissions-no-superuser" xreflabel="Non-super user permissions">
Alternatively, the extension can be created manually by a superuser <title>repmgr user as a non-superuser</title>
(with &quot;<command>CREATE EXTENSION repmgr</command>&quot;) before executing <para>
<link linkend="repmgr-primary-register">repmgr primary register</link>. In principle the &repmgr; database user does not need to be a superuser.
</para> 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> </sect1>

View File

@@ -95,7 +95,8 @@
</para> </para>
<para> <para>
The following parameters are provided for a subset of event notifications: The following parameters are provided for a subset of event notifications; their meaning may
change according to context:
</para> </para>
<variablelist> <variablelist>
@@ -108,6 +109,9 @@
<para> <para>
node ID of the demoted primary (<xref linkend="repmgr-standby-switchover"/> only) node ID of the demoted primary (<xref linkend="repmgr-standby-switchover"/> only)
</para> </para>
<para>
node ID of the former primary (<literal>repmgrd_failover_promote</literal> only)
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
@@ -133,7 +137,7 @@
<para> <para>
The values provided for <literal>%c</literal> and <literal>%a</literal> The values provided for <literal>%c</literal> and <literal>%a</literal>
will probably contain spaces, so should always be quoted. may contain spaces, so should always be quoted.
</para> </para>
<para> <para>

View File

@@ -22,16 +22,15 @@
<para> <para>
&repmgr; RPM packages for RedHat/CentOS variants and Fedora are available from the &repmgr; RPM packages for RedHat/CentOS variants and Fedora are available from the
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink> <ulink url="https://www.enterprisedb.com">EDB</ulink>
<ulink url="https://dl.2ndquadrant.com/">public repository</ulink>; see following <ulink url="https://dl.enterprisedb.com/">public repository</ulink>; see following
section for details. section for details.
</para> </para>
<note> <note>
<para> <para>
Currently the <ulink url="https://2ndquadrant.com">2ndQuadrant</ulink> Currently the <ulink url="https://www.enterprisedb.com">EDB</ulink>
<ulink url="https://dl.2ndquadrant.com/">public repository</ulink> provides <ulink url="https://dl.enterprisedb.com/">public repository</ulink> provides
support for RedHat/CentOS versions 5, 6 and 7. Support for version 8 is support for RedHat/CentOS versions 6,7 and 8.
available via the PGDG repository; see below for details.
</para> </para>
</note> </note>
<para> <para>
@@ -45,7 +44,7 @@
<note> <note>
<para> <para>
&repmgr; RPM packages are designed to be compatible with the community-provided PostgreSQL packages &repmgr; RPM packages are designed to be compatible with the community-provided PostgreSQL packages
and 2ndQuadrant's <ulink url="https://www.2ndquadrant.com/en/resources/2ndqpostgres/">2ndQPostgres</ulink>. and EDB's PostgreSQL Extended Server (formerly 2ndQPostgres).
They may not work with vendor-specific packages such as those provided by RedHat for RHEL They may not work with vendor-specific packages such as those provided by RedHat for RHEL
customers, as the PostgreSQL filesystem layout may be different to the community RPMs. customers, as the PostgreSQL filesystem layout may be different to the community RPMs.
Please contact your support vendor for assistance. Please contact your support vendor for assistance.
@@ -64,16 +63,16 @@
<sect3 id="installation-packages-redhat-2ndq"> <sect3 id="installation-packages-redhat-2ndq">
<title>2ndQuadrant public RPM yum repository</title> <title>EDB public RPM yum repository</title>
<para> <para>
<ulink url="https://2ndquadrant.com/">2ndQuadrant</ulink> provides a dedicated <literal>yum</literal> <ulink url="https://www.enterprisedb.com/">EDB</ulink> provides a dedicated <literal>yum</literal>
<ulink url="https://dl.2ndquadrant.com/">public repository</ulink> for 2ndQuadrant software, <ulink url="https://dl.enterprisedb.com/">public repository</ulink> for EDB software,
including &repmgr;. We recommend using this for all future &repmgr; releases. including &repmgr;. We recommend using this for all future &repmgr; releases.
</para> </para>
<para> <para>
General instructions for using this repository can be found on its General instructions for using this repository can be found on its
<ulink url="https://dl.2ndquadrant.com/">homepage</ulink>. Specific instructions <ulink url="https://dl.enterprisedb.com/">homepage</ulink>. Specific instructions
for installing &repmgr; follow below. for installing &repmgr; follow below.
</para> </para>
<para> <para>
@@ -83,57 +82,46 @@
<listitem> <listitem>
<para> <para>
Locate the repository RPM for your PostgreSQL version from the list at: Locate the repository RPM for your PostgreSQL version from the list at:
<ulink url="https://dl.2ndquadrant.com/">https://dl.2ndquadrant.com/</ulink> <ulink url="https://dl.enterprisedb.com/">https://dl.enterprisedb.com/</ulink>
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Install the repository definition for your distribution and PostgreSQL version Install the repository definition for your distribution and PostgreSQL version
(this enables the 2ndQuadrant repository as a source of &repmgr; packages). (this enables the EDB repository as a source of &repmgr; packages).
</para> </para>
<para> <para>
For example, for PostgreSQL 11 on CentOS, execute: For example, for PostgreSQL 14 on Rocky Linux 8, execute:
<programlisting> <programlisting>
curl https://dl.2ndquadrant.com/default/release/get/11/rpm | sudo bash</programlisting> curl https://dl.enterprisedb.com/default/release/get/14/rpm | sudo bash</programlisting>
</para> </para>
<para>
For PostgreSQL 9.6 on CentOS, execute:
<programlisting>
curl https://dl.2ndquadrant.com/default/release/get/9.6/rpm | sudo bash</programlisting>
</para>
<para> <para>
Verify that the repository is installed with: Verify that the repository is installed with:
<programlisting> <programlisting>
sudo yum repolist</programlisting> sudo dnf repolist</programlisting>
The output should contain two entries like this: The output should contain two entries like this:
<programlisting> <programlisting>
2ndquadrant-dl-default-release-pg11/7/x86_64 2ndQuadrant packages (PG11) for 7 - x86_64 18 2ndquadrant-dl-default-release-pg14 2ndQuadrant packages (PG14) for 8 - x86_64
2ndquadrant-dl-default-release-pg11-debug/7/x86_64 2ndQuadrant packages (PG11) for 7 - x86_64 - Debug 8</programlisting> 2ndquadrant-dl-default-release-pg14-debug 2ndQuadrant packages (PG14) for 8 - x86_64 - Debug</programlisting>
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <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> <programlisting>
sudo yum install repmgr11</programlisting> sudo dnf install repmgr14</programlisting>
</para> </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> <tip>
<para> <para>
To determine the names of available packages, execute: To determine the names of available packages, execute:
<programlisting> <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> </para>
</tip> </tip>
@@ -145,7 +133,7 @@ yum search repmgr</programlisting>
<emphasis>Compatibility with PGDG Repositories</emphasis> <emphasis>Compatibility with PGDG Repositories</emphasis>
</para> </para>
<para> <para>
The 2ndQuadrant &repmgr; yum repository packages use the same definitions and file system layout as the The EDB &repmgr; yum repository packages use the same definitions and file system layout as the
main PGDG repository. main PGDG repository.
</para> </para>
<para> <para>
@@ -154,36 +142,42 @@ yum search repmgr</programlisting>
the packages are installed from. the packages are installed from.
</para> </para>
<para> <para>
To ensure the 2ndQuadrant repository is always prioritised, install <literal>yum-plugin-priorities</literal> To ensure the EDB repository is always prioritised, set the <literal>priority</literal> option
and set the repository priorities accordingly. in the repository configuration file (e.g. <filename>/etc/yum.repos.d/2ndquadrant-dl-default-release-pg14.repo</filename>
accordingly.
</para> </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> <para>
<emphasis>Installing a specific package version</emphasis> <emphasis>Installing a specific package version</emphasis>
</para> </para>
<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: for the package in question:
<programlisting> <programlisting>
[root@localhost ~]# yum --showduplicates list repmgr11 [root@localhost ~]# dnf --showduplicates list repmgr10
Loaded plugins: fastestmirror Last metadata expiration check: 0:09:15 ago on Fri 11 Mar 2022 01:09:19 AM UTC.
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
Installed Packages 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 Available Packages
repmgr11.x86_64 4.2-1.el7 2ndquadrant-dl-default-release-pg11 repmgr10.x86_64 5.0.0-1.rhel8 pgdg10
repmgr11.x86_64 4.2-2.el7 2ndquadrant-dl-default-release-pg11 repmgr10.x86_64 5.1.0-1.el8 2ndquadrant-dl-default-release-pg10
repmgr11.x86_64 4.3-1.el7 2ndquadrant-dl-default-release-pg11 repmgr10.x86_64 5.1.0-1.rhel8 pgdg10
repmgr11.x86_64 4.4-1.el7 2ndquadrant-dl-default-release-pg11</programlisting> 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.: then append the appropriate version number to the package name with a hyphen, e.g.:
<programlisting> <programlisting>
[root@localhost ~]# yum install repmgr11-4.3-1.el7</programlisting> [root@localhost ~]# dnf install repmgr10-5.3.0-1.el8</programlisting>
</para> </para>
<para> <para>
<emphasis>Installing old packages</emphasis> <emphasis>Installing old packages</emphasis>
</para> </para>
@@ -191,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> See appendix <link linkend="packages-old-versions-rhel-centos">Installing old package versions</link>
for details on how to retrieve older package versions. for details on how to retrieve older package versions.
</para> </para>
</sect3> </sect3>
</sect2> </sect2>
@@ -217,16 +210,16 @@ repmgr11.x86_64 4.4-1.el7 2nd
</para> </para>
<sect3 id="installation-packages-debian-ubuntu-2ndq"> <sect3 id="installation-packages-debian-ubuntu-2ndq">
<title>2ndQuadrant public apt repository for Debian/Ubuntu</title> <title>EDB public apt repository for Debian/Ubuntu</title>
<para> <para>
<ulink url="https://2ndquadrant.com/">2ndQuadrant</ulink> provides a <ulink url="https://www.enterprisedb.com/">EDB</ulink> provides a
<ulink url="https://dl.2ndquadrant.com/">public apt repository</ulink> for 2ndQuadrant software, <ulink url="https://dl.enterprisedb.com/">public apt repository</ulink> for EDB software,
including &repmgr;. including &repmgr;.
</para> </para>
<para> <para>
General instructions for using this repository can be found on its General instructions for using this repository can be found on its
<ulink url="https://dl.2ndquadrant.com/">homepage</ulink>. Specific instructions <ulink url="https://dl.enterprisedb.com/">homepage</ulink>. Specific instructions
for installing &repmgr; follow below. for installing &repmgr; follow below.
</para> </para>
@@ -239,9 +232,9 @@ repmgr11.x86_64 4.4-1.el7 2nd
<listitem> <listitem>
<para> <para>
Install the repository definition for your distribution and PostgreSQL version Install the repository definition for your distribution and PostgreSQL version
(this enables the 2ndQuadrant repository as a source of &repmgr; packages) by executing: (this enables the EDB repository as a source of &repmgr; packages) by executing:
<programlisting> <programlisting>
curl https://dl.2ndquadrant.com/default/release/get/deb | sudo bash</programlisting> curl https://dl.enterprisedb.com/default/release/get/deb | sudo bash</programlisting>
</para> </para>
<note> <note>
<para> <para>

View File

@@ -93,7 +93,7 @@
<table id="repmgr-compatibility-matrix"> <table id="repmgr-compatibility-matrix">
<title>&repmgr; compatibility matrix</title> <title>&repmgr; compatibility matrix</title>
<tgroup cols="3"> <tgroup cols="4">
<thead> <thead>
<row> <row>
<entry> <entry>
@@ -112,10 +112,9 @@
</thead> </thead>
<tbody> <tbody>
<row> <row>
<entry> <entry>
&repmgr; 5.2 &repmgr; 5.3
</entry> </entry>
<entry> <entry>
YES YES
@@ -123,6 +122,21 @@
<entry> <entry>
<link linkend="release-current">&repmgrversion;</link> (&releasedate;) <link linkend="release-current">&repmgrversion;</link> (&releasedate;)
</entry> </entry>
<entry>
9.4, 9.5, 9.6, 10, 11, 12, 13, 14
</entry>
</row>
<row>
<entry>
&repmgr; 5.2
</entry>
<entry>
NO
</entry>
<entry>
<link linkend="release-5.2.1">5.2.1</link> (2020-12-07)
</entry>
<entry> <entry>
9.4, 9.5, 9.6, 10, 11, 12, 13 9.4, 9.5, 9.6, 10, 11, 12, 13
</entry> </entry>

View File

@@ -178,18 +178,18 @@ deb-src https://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlist
<para> <para>
The source for &repmgr; is maintained at The source for &repmgr; is maintained at
<ulink url="https://github.com/2ndQuadrant/repmgr">https://github.com/2ndQuadrant/repmgr</ulink>. <ulink url="https://github.com/EnterpriseDB/repmgr">https://github.com/EnterpriseDB/repmgr</ulink>.
</para> </para>
<para> <para>
There are also tags for each <ulink url="https://github.com/2ndQuadrant/repmgr/releases">&repmgr; release</ulink>, e.g. There are also tags for each <ulink url="https://github.com/EnterpriseDB/repmgr/releases">&repmgr; release</ulink>, e.g.
<literal><ulink url="https://github.com/2ndQuadrant/repmgr/releases/tag/v4.4.0">v4.4.0</ulink></literal>. <literal><ulink url="https://github.com/EnterpriseDB/repmgr/releases/tag/v4.4.0">v4.4.0</ulink></literal>.
</para> </para>
<para> <para>
Clone the source code using <application>git</application>: Clone the source code using <application>git</application>:
<programlisting> <programlisting>
git clone https://github.com/2ndQuadrant/repmgr</programlisting> git clone https://github.com/EnterpriseDB/repmgr</programlisting>
</para> </para>
<para> <para>

View File

@@ -1,18 +1,18 @@
<!-- doc/legal.xml --> <!-- doc/legal.xml -->
<date>2017</date> <date>2022</date>
<copyright> <copyright>
<year>2010-2020</year> <year>2010-2022</year>
<holder>2ndQuadrant, Ltd.</holder> <holder>EDB</holder>
</copyright> </copyright>
<legalnotice id="legalnotice"> <legalnotice id="legalnotice">
<title>Legal Notice</title> <title>Legal Notice</title>
<para> <para>
<productname>repmgr</productname> is Copyright &copy; 2010-2020 <productname>repmgr</productname> is Copyright &copy; 2010-2022
by 2ndQuadrant, Ltd. All rights reserved. by EDB All rights reserved.
</para> </para>
<para> <para>

View File

@@ -284,7 +284,7 @@
<tip> <tip>
<simpara> <simpara>
For Debian-based distributions we recommend explictly setting For Debian-based distributions we recommend explicitly setting
<option>pg_bindir</option> to the directory where <command>pg_ctl</command> and other binaries <option>pg_bindir</option> to the directory where <command>pg_ctl</command> and other binaries
not in the standard path are located. For PostgreSQL 9.6 this would be <filename>/usr/lib/postgresql/9.6/bin/</filename>. not in the standard path are located. For PostgreSQL 9.6 this would be <filename>/usr/lib/postgresql/9.6/bin/</filename>.
</simpara> </simpara>
@@ -302,7 +302,7 @@
<para> <para>
See the file See the file
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink> <ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>
for details of all available configuration parameters. for details of all available configuration parameters.
</para> </para>
@@ -405,9 +405,10 @@
</programlisting> </programlisting>
<para> <para>
This has cloned the PostgreSQL data directory files from the primary <literal>node1</literal> 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> using PostgreSQL's <command>pg_basebackup</command> utility. Replication configuration
file containing the correct parameters to start streaming from this primary server will be created containing the correct parameters to start streaming from this primary server will be
automatically. automatically appended to <filename>postgresql.auto.conf</filename>. (In PostgreSQL 11
and earlier the file <filename>recovery.conf</filename> will be created).
</para> </para>
<note> <note>
<simpara> <simpara>
@@ -481,9 +482,10 @@
sender_port | 5432 sender_port | 5432
conninfo | user=repmgr dbname=replication host=node1 application_name=node2 conninfo | user=repmgr dbname=replication host=node1 application_name=node2
</programlisting> </programlisting>
Note that the <varname>conninfo</varname> value is that generated in <filename>recovery.conf</filename> Note that the <varname>conninfo</varname> value is that generated in <filename>postgresql.auto.conf</filename>
and will differ slightly from the primary's <varname>conninfo</varname> as set in <filename>repmgr.conf</filename> - (PostgreSQL 11 and earlier: <filename>recovery.conf</filename>) and will differ slightly from the primary's
among others it will contain the connecting node's name as <varname>application_name</varname>. <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> </para>
</sect1> </sect1>

View File

@@ -25,7 +25,7 @@
</para> </para>
<para> <para>
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd; By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
started. This behaviour can be overridden by specifying a diffent value using the <option>--wait</option> started. This behaviour can be overridden by specifying a different value using the <option>--wait</option>
option, or disabled altogether with the <option>--no-wait</option> option. option, or disabled altogether with the <option>--no-wait</option> option.
</para> </para>

View File

@@ -26,7 +26,7 @@
<para> <para>
By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd; By default, &repmgr; will wait for up to 15 seconds to confirm that &repmgrd;
stopped. This behaviour can be overridden by specifying a diffent value using the <option>--wait</option> stopped. This behaviour can be overridden by specifying a different value using the <option>--wait</option>
option, or disabled altogether with the <option>--no-wait</option> option. option, or disabled altogether with the <option>--no-wait</option> option.
</para> </para>
<note> <note>

View File

@@ -125,12 +125,29 @@
is correctly configured. is correctly configured.
</simpara> </simpara>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
</para> </para>
</refsect1> </refsect1>
<refsect1>
<title>repmgrd</title>
<para>
A separate check is available to verify whether &repmgrd; is running,
This is not included in the general output, as this does not
per-se constitute a check of the node's replication status.
</para>
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara>
<option>--repmgrd</option>: checks whether &repmgrd; is running.
If &repmgrd; is running but paused, status <literal>1</literal>
(<literal>WARNING</literal>) is returned.
</simpara>
</listitem>
</itemizedlist>
</refsect1>
<refsect1> <refsect1>
<title>Additional checks</title> <title>Additional checks</title>
<para> <para>

View File

@@ -22,6 +22,10 @@
This can optionally use <application>pg_rewind</application> to re-integrate This can optionally use <application>pg_rewind</application> to re-integrate
a node which has diverged from the rest of the cluster, typically a failed primary. a node which has diverged from the rest of the cluster, typically a failed primary.
</para> </para>
<para>
Note that <command>repmgr node rejoin</command> can only be used to attach
a standby to the current primary, not another standby.
</para>
<tip> <tip>
<para> <para>
@@ -281,6 +285,7 @@
<programlisting> <programlisting>
$ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \ $ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \
--force-rewind --config-files=postgresql.local.conf,postgresql.conf --verbose --dry-run --force-rewind --config-files=postgresql.local.conf,postgresql.conf --verbose --dry-run
NOTICE: rejoin target is node "node3" (node ID: 3)
INFO: replication connection to the rejoin target node was successful INFO: replication connection to the rejoin target node was successful
INFO: local and rejoin target system identifiers match INFO: local and rejoin target system identifiers match
DETAIL: system identifier is 6652184002263212600 DETAIL: system identifier is 6652184002263212600
@@ -339,6 +344,7 @@
<programlisting> <programlisting>
$ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \ $ repmgr node rejoin -f /etc/repmgr.conf -d 'host=node3 dbname=repmgr user=repmgr' \
--config-files=postgresql.local.conf,postgresql.conf --verbose --force-rewind --dry-run --config-files=postgresql.local.conf,postgresql.conf --verbose --force-rewind --dry-run
NOTICE: rejoin target is node "node3" (node ID: 3)
INFO: replication connection to the rejoin target node was successful INFO: replication connection to the rejoin target node was successful
INFO: local and rejoin target system identifiers match INFO: local and rejoin target system identifiers match
DETAIL: system identifier is 6652460429293670710 DETAIL: system identifier is 6652460429293670710
@@ -449,15 +455,16 @@
</para> </para>
<para> <para>
Currently it is not possible to resolve this situation using <application>pg_rewind</application>. Currently it is not possible to resolve this situation using <application>pg_rewind</application>.
A <ulink url="https://www.postgresql.org/message-id/flat/CABvVfJU-LDWvoz4-Yow3Ay5LZYTuPD7eSjjE4kGyNZpXC6FrVQ@mail.gmail.com">patch</ulink> A <ulink url="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=2b4f3130382fe2f8705863e4d38589d4d69cd695">patch</ulink>
has been submitted and will hopefully be included in a forthcoming PostgreSQL minor release. has been successfully submitted and will be included the next PostgreSQL minor release round, scheduled for
February 2021.
</para> </para>
<para> <para>
As a workaround, start the primary server the standby was previously attached to, As a workaround, start the primary server the standby was previously attached to,
and ensure the standby can be attached to it. If <application>pg_rewind</application> was actually executed, and ensure the standby can be attached to it. If <application>pg_rewind</application> was actually executed,
it will have copied in the <filename>.history</filename> file from the target primary server; this must it will have copied in the <filename>.history</filename> file from the target primary server; this must
be removed. <command>repmgr node rejoin</command> can then be used to attach the standby to the original be removed. <command>repmgr node rejoin</command> can then be used to attach the standby to the original
primary. Ensure any changes pending on the primary have propogated to the standby. Then shut down the primary primary. Ensure any changes pending on the primary have propagated to the standby. Then shut down the primary
server <emphasis>first</emphasis>, before shutting down the standby. It should then be possible to server <emphasis>first</emphasis>, before shutting down the standby. It should then be possible to
use <command>repmgr node rejoin</command> to attach the standby to the new primary. use <command>repmgr node rejoin</command> to attach the standby to the new primary.
</para> </para>

View File

@@ -260,16 +260,29 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
upstream node if required. upstream node if required.
</para> </para>
<para> <para>
Note that the upstream node must be running. In PostgreSQL 11 and earlier, an existing The upstream node must be running so the correct replication configuration can be obtained.
<filename>recovery.conf</filename> will not be overwritten unless the
<option>-F/--force</option> option is provided.
</para> </para>
<para> <para>
Execute <command>repmgr standby clone --replication-conf-only --dry-run</command> If the standby is running, the replication configuration will not be written unless the
to check the prerequisites for creating the recovery configuration, <option>-F/--force</option> option is provided.
and display the contents of the configuration which would be added without actually
making any changes.
</para> </para>
<tip>
<para>
Execute <command>repmgr standby clone --replication-conf-only --dry-run</command>
to check the prerequisites for creating the recovery configuration,
and display the configuration changes which would be made without actually
making any changes.
</para>
</tip>
<para>
In PostgreSQL 13 and later, the PostgreSQL configuration must be reloaded for replication
configuration changes to take effect.
</para>
<para>
In PostgreSQL 12 and earlier, the PostgreSQL instance must be restarted for replication
configuration changes to take effect.
</para>
</refsect1> </refsect1>
@@ -319,6 +332,12 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
node to the same path on the standby (default) or to the node to the same path on the standby (default) or to the
PostgreSQL data directory. PostgreSQL data directory.
</para> </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> </listitem>
</varlistentry> </varlistentry>
@@ -331,6 +350,25 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--recovery-min-apply-delay</option></term>
<listitem>
<para>
Set PostgreSQL configuration <option>recovery_min_apply_delay</option> parameter
to the provided value.
</para>
<para>
This overrides any <option>recovery_min_apply_delay</option> provided via
<filename>repmgr.conf</filename>.
</para>
<para>
For more details on this parameter, see:
<ulink url="https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-RECOVERY-MIN-APPLY-DELAY">recovery_min_apply_delay</ulink>.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>-R, --remote-user=USERNAME</option></term> <term><option>-R, --remote-user=USERNAME</option></term>
<listitem> <listitem>
@@ -346,14 +384,14 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
<para> <para>
Create recovery configuration for a previously cloned instance. Create recovery configuration for a previously cloned instance.
</para> </para>
<para>
In PostgreSQL 11 and earlier, the replication configuration will be
written to <filename>recovery.conf</filename>.
</para>
<para> <para>
In PostgreSQL 12 and later, the replication configuration will be In PostgreSQL 12 and later, the replication configuration will be
written to <filename>postgresql.auto.conf</filename>. written to <filename>postgresql.auto.conf</filename>.
</para> </para>
<para>
In PostgreSQL 11 and earlier, the replication configuration will be
written to <filename>recovery.conf</filename>.
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@@ -367,11 +405,15 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><option>--superuser</option></term> <term><option>-S</option>/<option>--superuser</option></term>
<listitem> <listitem>
<para> <para>
If the &repmgr; user is not a superuser, the name of a valid superuser must The name of a valid PostgreSQL superuser can be provided with this option.
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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@@ -189,14 +189,14 @@
</listitem> </listitem>
<listitem> <listitem>
<simpara> <simpara>
If the promotion candidate has insufficient free walsenders to accomodate the standbys which will If the promotion candidate has insufficient free walsenders to accommodate the standbys which will
be attached to it, the standby will be promoted anyway. be attached to it, the standby will be promoted anyway.
</simpara> </simpara>
</listitem> </listitem>
<listitem> <listitem>
<simpara> <simpara>
If replication slots are in use but the promotion candidate has insufficient free replication slots If replication slots are in use but the promotion candidate has insufficient free replication slots
to accomodate the standbys which will be attached to it, the standby will be promoted anyway. to accommodate the standbys which will be attached to it, the standby will be promoted anyway.
</simpara> </simpara>
</listitem> </listitem>
</itemizedlist> </itemizedlist>

View File

@@ -64,6 +64,13 @@
<refsect1> <refsect1>
<title>User permission requirements</title> <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><emphasis>CHECKPOINT</emphasis></para>
<para> <para>
&repmgr; executes <command>CHECKPOINT</command> on the demotion candidate as part of the shutdown &repmgr; executes <command>CHECKPOINT</command> on the demotion candidate as part of the shutdown
@@ -72,7 +79,7 @@
<para> <para>
Note that <command>CHECKPOINT</command> requires database superuser permissions to execute. 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 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>
<para> <para>
If &repmgr; is unable to execute the <command>CHECKPOINT</command> command, the switchover If &repmgr; is unable to execute the <command>CHECKPOINT</command> command, the switchover

View File

@@ -18,7 +18,7 @@
<title>repmgr &repmgrversion; Documentation</title> <title>repmgr &repmgrversion; Documentation</title>
<bookinfo> <bookinfo>
<corpauthor>2ndQuadrant Ltd</corpauthor> <corpauthor>EDB</corpauthor>
<productname>repmgr</productname> <productname>repmgr</productname>
<productnumber>&repmgrversion;</productnumber> <productnumber>&repmgrversion;</productnumber>
&legal; &legal;
@@ -26,7 +26,7 @@
<abstract> <abstract>
<para> <para>
This is the official documentation of &repmgr; &repmgrversion; for This is the official documentation of &repmgr; &repmgrversion; for
use with PostgreSQL 9.4 - PostgreSQL 13. use with PostgreSQL 9.4 - PostgreSQL 14.
</para> </para>
<para> <para>
&repmgr; is being continually developed and we strongly recommend using the &repmgr; is being continually developed and we strongly recommend using the
@@ -38,20 +38,19 @@
<para> <para>
&repmgr; is developed by &repmgr; is developed by
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink> <ulink url="https://www.enterprisedb.com/">EDB</ulink>
along with contributions from other individuals and organisations. along with contributions from other individuals and organisations.
Contributions from the community are appreciated and welcome - get Contributions from the community are appreciated and welcome - get
in touch via <ulink url="https://github.com/2ndQuadrant/repmgr">github</ulink> in touch via <ulink url="https://github.com/EnterpriseDB/repmgr">github</ulink>
or <ulink url="https://groups.google.com/group/repmgr">the mailing list/forum</ulink>. or <ulink url="https://groups.google.com/group/repmgr">the mailing list/forum</ulink>.
Multiple 2ndQuadrant customers contribute funding Multiple EDB customers contribute funding to make &repmgr; development possible.
to make repmgr development possible.
</para> </para>
<para> <para>
&repmgr; is fully supported by 2ndQuadrant's &repmgr; is fully supported by EDB's
<ulink url="https://www.2ndquadrant.com/en/support/support-postgresql/">24/7 Production Support</ulink>. <ulink url="https://www.enterprisedb.com/support/postgresql-support-overview-get-the-most-out-of-postgresql">24/7 Production Support</ulink>.
2ndQuadrant, a Major Sponsor of the PostgreSQL project, continues to develop and maintain &repmgr;. EDB, a Major Sponsor of the PostgreSQL project, continues to maintain &repmgr;.
Other organisations as well as individual developers are welcome to participate in the efforts. We welcome participation from other organisations and individual developers.
</para> </para>
</abstract> </abstract>

View File

@@ -81,11 +81,15 @@
</para> </para>
<note> <note>
<simpara> <simpara>
&repmgr; 3.3 and earlier provided a <command>repmgr create witness</command> A PostgreSQL instance can only accommodate a single witness server.
command, which would automatically create a PostgreSQL instance. However </simpara>
this often resulted in an unsatisfactory, hard-to-customise instance. <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> </simpara>
</note> </note>
<para> <para>
The witness server should be configured in the same way as a normal The witness server should be configured in the same way as a normal
&repmgr; node; see section <xref linkend="configuration"/>. &repmgr; node; see section <xref linkend="configuration"/>.
@@ -586,7 +590,7 @@ INFO: node 3 received notification to rerun promotion candidate election
<sect2 id="repmgrd-primary-child-disconnection-caveats"> <sect2 id="repmgrd-primary-child-disconnection-caveats">
<title>Standby disconnections monitoring caveats</title> <title>Standby disconnections monitoring caveats</title>
<para> <para>
The follwing caveats should be considered if you are intending to use this functionality. The following caveats should be considered if you are intending to use this functionality.
</para> </para>
<para> <para>
<itemizedlist mark="bullet"> <itemizedlist mark="bullet">

View File

@@ -89,6 +89,10 @@
<literal>query</literal> - determines server availability <literal>query</literal> - determines server availability
by executing an SQL statement on the node via the existing connection by executing an SQL statement on the node via the existing connection
</simpara> </simpara>
<simpara>
The query is a minimal throwaway query - <command>SELECT 1</command> -
which is used to determine that the server can accept queries.
</simpara>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
@@ -152,7 +156,7 @@
</variablelist> </variablelist>
<para> <para>
See also <filename><ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink></filename> for an annotated sample configuration file. See also <filename><ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink></filename> for an annotated sample configuration file.
</para> </para>
<sect2 id="repmgrd-automatic-failover-configuration"> <sect2 id="repmgrd-automatic-failover-configuration">
@@ -329,7 +333,7 @@
<title>Optional configuration for automatic failover</title> <title>Optional configuration for automatic failover</title>
<para> <para>
The following configuraton options can be use to fine-tune automatic failover: The following configuraton options can be used to fine-tune automatic failover:
</para> </para>
<variablelist> <variablelist>
@@ -481,6 +485,32 @@
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>repmgrd_exit_on_inactive_node</option></term>
<listitem>
<indexterm>
<primary>repmgrd_exit_on_inactive_node</primary>
</indexterm>
<para>
This parameter is available in &repmgr; 5.3 and later.
</para>
<para>
If a node was marked as inactive but is running, and this option is set to
<literal>true</literal>, &repmgrd; will abort on startup.
</para>
<para>
By default, <option>repmgrd_exit_on_inactive_node</option> is set
to <literal>false</literal>, in which case &repmgrd; will set the
node record to active on startup.
</para>
<para>
Setting this parameter to <literal>true</literal> causes &repmgrd;
to behave in the same way it did in &repmgr; 5.2 and earlier.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
<para> <para>
@@ -539,7 +569,7 @@
</indexterm> </indexterm>
<para> <para>
For further details and a reference implementation, see the separate document For further details and a reference implementation, see the separate document
<ulink url="https://github.com/2ndQuadrant/repmgr/blob/master/doc/repmgrd-node-fencing.md">Fencing a failed master node with repmgrd and PgBouncer</ulink>. <ulink url="https://github.com/EnterpriseDB/repmgr/blob/master/doc/repmgrd-node-fencing.md">Fencing a failed master node with repmgrd and PgBouncer</ulink>.
</para> </para>
</sect2> </sect2>
@@ -969,7 +999,7 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
</para> </para>
<para> <para>
If none of the above apply, &repmgrd; will create a PID file If none of the above apply, &repmgrd; will create a PID file
in the operating system's temporary directory (as setermined by the environment variable in the operating system's temporary directory (as determined by the environment variable
<varname>TMPDIR</varname>, or if that is not set, will use <filename>/tmp</filename>). <varname>TMPDIR</varname>, or if that is not set, will use <filename>/tmp</filename>).
</para> </para>
<para> <para>
@@ -1049,6 +1079,29 @@ REPMGRD_OPTS="--daemonize=false"
</para> </para>
</sect2> </sect2>
<sect2 id="repmgrd-daemon-monitoring">
<title>repmgrd daemon monitoring</title>
<indexterm>
<primary>repmgrd</primary>
<secondary>monitoring</secondary>
</indexterm>
<indexterm>
<primary>monitoring</primary>
<secondary>repmgrd</secondary>
</indexterm>
<para>
The command <command><link linkend="repmgr-service-status">repmgr service status</link></command>
provides an overview of the &repmgrd; daemon status (including pause status)
on all nodes in the cluster.
</para>
<para>
From &repmgr; 5.3, <command><link linkend="repmgr-node-check">repmgr node check --repmgrd</link></command>
can be used to check the status of &repmgrd; (including pause status)
on the local node.
</para>
</sect2>
</sect1> </sect1>
<sect1 id="repmgrd-connection-settings"> <sect1 id="repmgrd-connection-settings">

View File

@@ -120,16 +120,19 @@
</important> </important>
<note> <note>
<simpara> <para>
On <literal>systemd</literal> systems we strongly recommend using the appropriate On <literal>systemd</literal> systems we strongly recommend using the appropriate
<command>systemctl</command> commands (typically run via <command>sudo</command>) to ensure <command>systemctl</command> commands (typically run via <command>sudo</command>) to ensure
<literal>systemd</literal> is informed about the status of the PostgreSQL service. <literal>systemd</literal> is informed about the status of the PostgreSQL service.
</simpara> </para>
<simpara> <para>
If using <command>sudo</command> for the <command>systemctl</command> calls, make sure the If using <command>sudo</command> for the <command>systemctl</command> calls, make sure the
<command>sudo</command> specification doesn't require a real tty for the user. If not set <command>sudo</command> specification doesn't require a real tty for the user. If not set
this way, <command>repmgr</command> will fail to stop the primary. this way, <command>repmgr</command> will fail to stop the primary.
</simpara> </para>
<para>
See the <xref linkend="configuration-file-service-commands"/> documentation section for further details.
</para>
</note> </note>
<para> <para>

View File

@@ -482,7 +482,7 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
<simpara> <simpara>
If you don't care about any data from the existing &repmgr; installation, If you don't care about any data from the existing &repmgr; installation,
(e.g. the contents of the <structname>events</structname> and <structname>monitoring</structname> (e.g. the contents of the <structname>events</structname> and <structname>monitoring</structname>
tables), the follwing steps can be skipped; proceed to <xref linkend="upgrade-reregister-nodes"/>. tables), the following steps can be skipped; proceed to <xref linkend="upgrade-reregister-nodes"/>.
</simpara> </simpara>
</tip> </tip>
@@ -497,10 +497,10 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
<itemizedlist spacing="compact" mark="bullet"> <itemizedlist spacing="compact" mark="bullet">
<listitem> <listitem>
<simpara> <simpara>
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/REL3_3_STABLE/sql/repmgr3.0_repmgr3.1.sql">repmgr3.0_repmgr3.1.sql</ulink></simpara> <ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/REL3_3_STABLE/sql/repmgr3.0_repmgr3.1.sql">repmgr3.0_repmgr3.1.sql</ulink></simpara>
</listitem> </listitem>
<listitem> <listitem>
<simpara><ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/REL3_3_STABLE/sql/repmgr3.1.1_repmgr3.1.2.sql">repmgr3.1.1_repmgr3.1.2.sql</ulink></simpara> <simpara><ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/REL3_3_STABLE/sql/repmgr3.1.1_repmgr3.1.2.sql">repmgr3.1.1_repmgr3.1.2.sql</ulink></simpara>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
</para> </para>

View File

@@ -1,6 +1,6 @@
/* /*
* errcode.h * errcode.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

2
log.c
View File

@@ -1,6 +1,6 @@
/* /*
* log.c - Logging methods * log.c - Logging methods
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

2
log.h
View File

@@ -1,6 +1,6 @@
/* /*
* log.h * log.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -1,17 +1,10 @@
-- complain if script is sourced in psql, rather than via CREATE EXTENSION -- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit \echo Use "ALTER EXTENSION repmgr UPDATE" to load this file. \quit
CREATE FUNCTION set_upstream_last_seen() -- This script is intentionally empty and exists to skip the CREATE FUNCTION
RETURNS VOID -- commands contained in the 4.2--4.3 and 4.3--4.4 extension upgrade scripts,
AS 'MODULE_PATHNAME', 'set_upstream_last_seen' -- which reference C functions which no longer exist in 5.3 and later.
LANGUAGE C STRICT; --
-- These functions will be explicitly created in the 5.2--5.3 extension
-- upgrade step with the correct C function references.
CREATE FUNCTION get_upstream_last_seen()
RETURNS INT
AS 'MODULE_PATHNAME', 'get_upstream_last_seen'
LANGUAGE C STRICT;
CREATE FUNCTION get_wal_receiver_pid()
RETURNS INT
AS 'MODULE_PATHNAME', 'get_wal_receiver_pid'
LANGUAGE C STRICT;

View File

@@ -1,19 +1,9 @@
-- complain if script is sourced in psql, rather than via CREATE EXTENSION -- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit \echo Use "ALTER EXTENSION repmgr UPDATE" to load this file. \quit
DROP FUNCTION set_upstream_last_seen(); -- This script is intentionally empty and exists to skip the CREATE FUNCTION
-- commands contained in the 4.3--4.4 extension upgrade script, which reference
CREATE FUNCTION set_upstream_last_seen(INT) -- C functions which no longer exist in 5.3 and later.
RETURNS VOID --
AS 'MODULE_PATHNAME', 'set_upstream_last_seen' -- These functions will be explicitly created in the 5.2--5.3 extension
LANGUAGE C STRICT; -- upgrade step with the correct C function references.
CREATE FUNCTION get_upstream_node_id()
RETURNS INT
AS 'MODULE_PATHNAME', 'get_upstream_node_id'
LANGUAGE C STRICT;
CREATE FUNCTION set_upstream_node_id(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'set_upstream_node_id'
LANGUAGE C STRICT;

64
repmgr--5.2--5.3.sql Normal file
View File

@@ -0,0 +1,64 @@
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
CREATE OR REPLACE FUNCTION set_local_node_id(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_local_node_id'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION repmgr.get_local_node_id()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION standby_set_last_updated()
RETURNS TIMESTAMP WITH TIME ZONE
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION standby_get_last_updated()
RETURNS TIMESTAMP WITH TIME ZONE
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION set_upstream_last_seen(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION get_upstream_last_seen()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION get_upstream_node_id()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION set_upstream_node_id(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
LANGUAGE C STRICT;
/* failover functions */
CREATE OR REPLACE FUNCTION notify_follow_primary(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION get_new_primary()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION reset_voting_status()
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
LANGUAGE C STRICT;
CREATE OR REPLACE FUNCTION get_wal_receiver_pid()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
LANGUAGE C STRICT;

2
repmgr--5.3--5.4.sql Normal file
View File

@@ -0,0 +1,2 @@
-- complain if script is sourced in psql, rather than via CREAT EXTENSION
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit

192
repmgr--5.3.sql Normal file
View File

@@ -0,0 +1,192 @@
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
CREATE TABLE repmgr.nodes (
node_id INTEGER PRIMARY KEY,
upstream_node_id INTEGER NULL REFERENCES nodes (node_id) DEFERRABLE,
active BOOLEAN NOT NULL DEFAULT TRUE,
node_name TEXT NOT NULL,
type TEXT NOT NULL CHECK (type IN('primary','standby','witness','bdr')),
location TEXT NOT NULL DEFAULT 'default',
priority INT NOT NULL DEFAULT 100,
conninfo TEXT NOT NULL,
repluser VARCHAR(63) NOT NULL,
slot_name TEXT NULL,
config_file TEXT NOT NULL
);
SELECT pg_catalog.pg_extension_config_dump('repmgr.nodes', '');
CREATE TABLE repmgr.events (
node_id INTEGER NOT NULL,
event TEXT NOT NULL,
successful BOOLEAN NOT NULL DEFAULT TRUE,
event_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
details TEXT NULL
);
SELECT pg_catalog.pg_extension_config_dump('repmgr.events', '');
CREATE TABLE repmgr.monitoring_history (
primary_node_id INTEGER NOT NULL,
standby_node_id INTEGER NOT NULL,
last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL,
last_apply_time TIMESTAMP WITH TIME ZONE,
last_wal_primary_location PG_LSN NOT NULL,
last_wal_standby_location PG_LSN,
replication_lag BIGINT NOT NULL,
apply_lag BIGINT NOT NULL
);
CREATE INDEX idx_monitoring_history_time
ON repmgr.monitoring_history (last_monitor_time, standby_node_id);
SELECT pg_catalog.pg_extension_config_dump('repmgr.monitoring_history', '');
CREATE VIEW repmgr.show_nodes AS
SELECT n.node_id,
n.node_name,
n.active,
n.upstream_node_id,
un.node_name AS upstream_node_name,
n.type,
n.priority,
n.conninfo
FROM repmgr.nodes n
LEFT JOIN repmgr.nodes un
ON un.node_id = n.upstream_node_id;
CREATE TABLE repmgr.voting_term (
term INT NOT NULL
);
CREATE UNIQUE INDEX voting_term_restrict
ON repmgr.voting_term ((TRUE));
CREATE RULE voting_term_delete AS
ON DELETE TO repmgr.voting_term
DO INSTEAD NOTHING;
/* ================= */
/* repmgrd functions */
/* ================= */
/* monitoring functions */
CREATE FUNCTION set_local_node_id(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_local_node_id'
LANGUAGE C STRICT;
CREATE FUNCTION get_local_node_id()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
LANGUAGE C STRICT;
CREATE FUNCTION standby_set_last_updated()
RETURNS TIMESTAMP WITH TIME ZONE
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
LANGUAGE C STRICT;
CREATE FUNCTION standby_get_last_updated()
RETURNS TIMESTAMP WITH TIME ZONE
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
LANGUAGE C STRICT;
CREATE FUNCTION set_upstream_last_seen(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
LANGUAGE C STRICT;
CREATE FUNCTION get_upstream_last_seen()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
LANGUAGE C STRICT;
CREATE FUNCTION get_upstream_node_id()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
LANGUAGE C STRICT;
CREATE FUNCTION set_upstream_node_id(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
LANGUAGE C STRICT;
/* failover functions */
CREATE FUNCTION notify_follow_primary(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
LANGUAGE C STRICT;
CREATE FUNCTION get_new_primary()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
LANGUAGE C STRICT;
CREATE FUNCTION reset_voting_status()
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
LANGUAGE C STRICT;
CREATE FUNCTION get_repmgrd_pid()
RETURNS INT
AS 'MODULE_PATHNAME', 'get_repmgrd_pid'
LANGUAGE C STRICT;
CREATE FUNCTION get_repmgrd_pidfile()
RETURNS TEXT
AS 'MODULE_PATHNAME', 'get_repmgrd_pidfile'
LANGUAGE C STRICT;
CREATE FUNCTION set_repmgrd_pid(INT, TEXT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'set_repmgrd_pid'
LANGUAGE C CALLED ON NULL INPUT;
CREATE FUNCTION repmgrd_is_running()
RETURNS BOOL
AS 'MODULE_PATHNAME', 'repmgrd_is_running'
LANGUAGE C STRICT;
CREATE FUNCTION repmgrd_pause(BOOL)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgrd_pause'
LANGUAGE C STRICT;
CREATE FUNCTION repmgrd_is_paused()
RETURNS BOOL
AS 'MODULE_PATHNAME', 'repmgrd_is_paused'
LANGUAGE C STRICT;
CREATE FUNCTION get_wal_receiver_pid()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
LANGUAGE C STRICT;
/* views */
CREATE VIEW repmgr.replication_status AS
SELECT m.primary_node_id, m.standby_node_id, n.node_name AS standby_name,
n.type AS node_type, n.active, last_monitor_time,
CASE WHEN n.type='standby' THEN m.last_wal_primary_location ELSE NULL END AS last_wal_primary_location,
m.last_wal_standby_location,
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.replication_lag) ELSE NULL END AS replication_lag,
CASE WHEN n.type='standby' THEN
CASE WHEN replication_lag > 0 THEN age(now(), m.last_apply_time) ELSE '0'::INTERVAL END
ELSE NULL
END AS replication_time_lag,
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.apply_lag) ELSE NULL END AS apply_lag,
AGE(NOW(), CASE WHEN pg_catalog.pg_is_in_recovery() THEN repmgr.standby_get_last_updated() ELSE m.last_monitor_time END) AS communication_time_lag
FROM repmgr.monitoring_history m
JOIN repmgr.nodes n ON m.standby_node_id = n.node_id
WHERE (m.standby_node_id, m.last_monitor_time) IN (
SELECT m1.standby_node_id, MAX(m1.last_monitor_time)
FROM repmgr.monitoring_history m1 GROUP BY 1
);

192
repmgr--5.4.sql Normal file
View File

@@ -0,0 +1,192 @@
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
CREATE TABLE repmgr.nodes (
node_id INTEGER PRIMARY KEY,
upstream_node_id INTEGER NULL REFERENCES nodes (node_id) DEFERRABLE,
active BOOLEAN NOT NULL DEFAULT TRUE,
node_name TEXT NOT NULL,
type TEXT NOT NULL CHECK (type IN('primary','standby','witness','bdr')),
location TEXT NOT NULL DEFAULT 'default',
priority INT NOT NULL DEFAULT 100,
conninfo TEXT NOT NULL,
repluser VARCHAR(63) NOT NULL,
slot_name TEXT NULL,
config_file TEXT NOT NULL
);
SELECT pg_catalog.pg_extension_config_dump('repmgr.nodes', '');
CREATE TABLE repmgr.events (
node_id INTEGER NOT NULL,
event TEXT NOT NULL,
successful BOOLEAN NOT NULL DEFAULT TRUE,
event_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
details TEXT NULL
);
SELECT pg_catalog.pg_extension_config_dump('repmgr.events', '');
CREATE TABLE repmgr.monitoring_history (
primary_node_id INTEGER NOT NULL,
standby_node_id INTEGER NOT NULL,
last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL,
last_apply_time TIMESTAMP WITH TIME ZONE,
last_wal_primary_location PG_LSN NOT NULL,
last_wal_standby_location PG_LSN,
replication_lag BIGINT NOT NULL,
apply_lag BIGINT NOT NULL
);
CREATE INDEX idx_monitoring_history_time
ON repmgr.monitoring_history (last_monitor_time, standby_node_id);
SELECT pg_catalog.pg_extension_config_dump('repmgr.monitoring_history', '');
CREATE VIEW repmgr.show_nodes AS
SELECT n.node_id,
n.node_name,
n.active,
n.upstream_node_id,
un.node_name AS upstream_node_name,
n.type,
n.priority,
n.conninfo
FROM repmgr.nodes n
LEFT JOIN repmgr.nodes un
ON un.node_id = n.upstream_node_id;
CREATE TABLE repmgr.voting_term (
term INT NOT NULL
);
CREATE UNIQUE INDEX voting_term_restrict
ON repmgr.voting_term ((TRUE));
CREATE RULE voting_term_delete AS
ON DELETE TO repmgr.voting_term
DO INSTEAD NOTHING;
/* ================= */
/* repmgrd functions */
/* ================= */
/* monitoring functions */
CREATE FUNCTION set_local_node_id(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_local_node_id'
LANGUAGE C STRICT;
CREATE FUNCTION get_local_node_id()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
LANGUAGE C STRICT;
CREATE FUNCTION standby_set_last_updated()
RETURNS TIMESTAMP WITH TIME ZONE
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
LANGUAGE C STRICT;
CREATE FUNCTION standby_get_last_updated()
RETURNS TIMESTAMP WITH TIME ZONE
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
LANGUAGE C STRICT;
CREATE FUNCTION set_upstream_last_seen(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
LANGUAGE C STRICT;
CREATE FUNCTION get_upstream_last_seen()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
LANGUAGE C STRICT;
CREATE FUNCTION get_upstream_node_id()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
LANGUAGE C STRICT;
CREATE FUNCTION set_upstream_node_id(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
LANGUAGE C STRICT;
/* failover functions */
CREATE FUNCTION notify_follow_primary(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
LANGUAGE C STRICT;
CREATE FUNCTION get_new_primary()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
LANGUAGE C STRICT;
CREATE FUNCTION reset_voting_status()
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
LANGUAGE C STRICT;
CREATE FUNCTION get_repmgrd_pid()
RETURNS INT
AS 'MODULE_PATHNAME', 'get_repmgrd_pid'
LANGUAGE C STRICT;
CREATE FUNCTION get_repmgrd_pidfile()
RETURNS TEXT
AS 'MODULE_PATHNAME', 'get_repmgrd_pidfile'
LANGUAGE C STRICT;
CREATE FUNCTION set_repmgrd_pid(INT, TEXT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'set_repmgrd_pid'
LANGUAGE C CALLED ON NULL INPUT;
CREATE FUNCTION repmgrd_is_running()
RETURNS BOOL
AS 'MODULE_PATHNAME', 'repmgrd_is_running'
LANGUAGE C STRICT;
CREATE FUNCTION repmgrd_pause(BOOL)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgrd_pause'
LANGUAGE C STRICT;
CREATE FUNCTION repmgrd_is_paused()
RETURNS BOOL
AS 'MODULE_PATHNAME', 'repmgrd_is_paused'
LANGUAGE C STRICT;
CREATE FUNCTION get_wal_receiver_pid()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
LANGUAGE C STRICT;
/* views */
CREATE VIEW repmgr.replication_status AS
SELECT m.primary_node_id, m.standby_node_id, n.node_name AS standby_name,
n.type AS node_type, n.active, last_monitor_time,
CASE WHEN n.type='standby' THEN m.last_wal_primary_location ELSE NULL END AS last_wal_primary_location,
m.last_wal_standby_location,
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.replication_lag) ELSE NULL END AS replication_lag,
CASE WHEN n.type='standby' THEN
CASE WHEN replication_lag > 0 THEN age(now(), m.last_apply_time) ELSE '0'::INTERVAL END
ELSE NULL
END AS replication_time_lag,
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.apply_lag) ELSE NULL END AS apply_lag,
AGE(NOW(), CASE WHEN pg_catalog.pg_is_in_recovery() THEN repmgr.standby_get_last_updated() ELSE m.last_monitor_time END) AS communication_time_lag
FROM repmgr.monitoring_history m
JOIN repmgr.nodes n ON m.standby_node_id = n.node_id
WHERE (m.standby_node_id, m.last_monitor_time) IN (
SELECT m1.standby_node_id, MAX(m1.last_monitor_time)
FROM repmgr.monitoring_history m1 GROUP BY 1
);

245
repmgr--unpackaged--5.3.sql Normal file
View File

@@ -0,0 +1,245 @@
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
-- extract the current schema name
-- NOTE: this assumes there will be only one schema matching 'repmgr_%';
-- user is responsible for ensuring this is the case
CREATE TEMPORARY TABLE repmgr_old_schema (schema_name TEXT);
INSERT INTO repmgr_old_schema (schema_name)
SELECT nspname AS schema_name
FROM pg_catalog.pg_namespace
WHERE nspname LIKE 'repmgr_%'
LIMIT 1;
-- move old objects into new schema
DO $repmgr$
DECLARE
old_schema TEXT;
BEGIN
SELECT schema_name FROM repmgr_old_schema
INTO old_schema;
EXECUTE format('ALTER TABLE %I.repl_nodes SET SCHEMA repmgr', old_schema);
EXECUTE format('ALTER TABLE %I.repl_events SET SCHEMA repmgr', old_schema);
EXECUTE format('ALTER TABLE %I.repl_monitor SET SCHEMA repmgr', old_schema);
EXECUTE format('DROP VIEW IF EXISTS %I.repl_show_nodes', old_schema);
EXECUTE format('DROP VIEW IF EXISTS %I.repl_status', old_schema);
END$repmgr$;
-- convert "repmgr_$cluster.repl_nodes" to "repmgr.nodes"
CREATE TABLE repmgr.nodes (
node_id INTEGER PRIMARY KEY,
upstream_node_id INTEGER NULL REFERENCES repmgr.nodes (node_id) DEFERRABLE,
active BOOLEAN NOT NULL DEFAULT TRUE,
node_name TEXT NOT NULL,
type TEXT NOT NULL CHECK (type IN('primary','standby','witness','bdr')),
location TEXT NOT NULL DEFAULT 'default',
priority INT NOT NULL DEFAULT 100,
conninfo TEXT NOT NULL,
repluser VARCHAR(63) NOT NULL,
slot_name TEXT NULL,
config_file TEXT NOT NULL
);
INSERT INTO repmgr.nodes
(node_id, upstream_node_id, active, node_name, type, location, priority, conninfo, repluser, slot_name, config_file)
SELECT id, upstream_node_id, active, name,
CASE WHEN type = 'master' THEN 'primary' ELSE type END,
'default', priority, conninfo, 'unknown', slot_name, 'unknown'
FROM repmgr.repl_nodes
ORDER BY id;
-- convert "repmgr_$cluster.repl_event" to "event"
CREATE TABLE repmgr.events (
node_id INTEGER NOT NULL,
event TEXT NOT NULL,
successful BOOLEAN NOT NULL DEFAULT TRUE,
event_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
details TEXT NULL
);
INSERT INTO repmgr.events
(node_id, event, successful, event_timestamp, details)
SELECT node_id, event, successful, event_timestamp, details
FROM repmgr.repl_events;
-- create new table "repmgr.voting_term"
CREATE TABLE repmgr.voting_term (
term INT NOT NULL
);
CREATE UNIQUE INDEX voting_term_restrict
ON repmgr.voting_term ((TRUE));
CREATE RULE voting_term_delete AS
ON DELETE TO repmgr.voting_term
DO INSTEAD NOTHING;
INSERT INTO repmgr.voting_term (term) VALUES (1);
-- convert "repmgr_$cluster.repl_monitor" to "monitoring_history"
CREATE TABLE repmgr.monitoring_history (
primary_node_id INTEGER NOT NULL,
standby_node_id INTEGER NOT NULL,
last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL,
last_apply_time TIMESTAMP WITH TIME ZONE,
last_wal_primary_location PG_LSN NOT NULL,
last_wal_standby_location PG_LSN,
replication_lag BIGINT NOT NULL,
apply_lag BIGINT NOT NULL
);
INSERT INTO repmgr.monitoring_history
(primary_node_id, standby_node_id, last_monitor_time, last_apply_time, last_wal_primary_location, last_wal_standby_location, replication_lag, apply_lag)
SELECT primary_node, standby_node, last_monitor_time, last_apply_time, last_wal_primary_location::pg_lsn, last_wal_standby_location::pg_lsn, replication_lag, apply_lag
FROM repmgr.repl_monitor;
CREATE INDEX idx_monitoring_history_time
ON repmgr.monitoring_history (last_monitor_time, standby_node_id);
CREATE VIEW repmgr.show_nodes AS
SELECT n.node_id,
n.node_name,
n.active,
n.upstream_node_id,
un.node_name AS upstream_node_name,
n.type,
n.priority,
n.conninfo
FROM repmgr.nodes n
LEFT JOIN repmgr.nodes un
ON un.node_id = n.upstream_node_id;
/* ================= */
/* repmgrd functions */
/* ================= */
/* monitoring functions */
CREATE FUNCTION set_local_node_id(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_local_node_id'
LANGUAGE C STRICT;
CREATE FUNCTION get_local_node_id()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_local_node_id'
LANGUAGE C STRICT;
CREATE FUNCTION standby_set_last_updated()
RETURNS TIMESTAMP WITH TIME ZONE
AS 'MODULE_PATHNAME', 'repmgr_standby_set_last_updated'
LANGUAGE C STRICT;
CREATE FUNCTION standby_get_last_updated()
RETURNS TIMESTAMP WITH TIME ZONE
AS 'MODULE_PATHNAME', 'repmgr_standby_get_last_updated'
LANGUAGE C STRICT;
CREATE FUNCTION set_upstream_last_seen(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_last_seen'
LANGUAGE C STRICT;
CREATE FUNCTION get_upstream_last_seen()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_last_seen'
LANGUAGE C STRICT;
CREATE FUNCTION get_upstream_node_id()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_upstream_node_id'
LANGUAGE C STRICT;
CREATE FUNCTION set_upstream_node_id(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_set_upstream_node_id'
LANGUAGE C STRICT;
/* failover functions */
CREATE FUNCTION notify_follow_primary(INT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_notify_follow_primary'
LANGUAGE C STRICT;
CREATE FUNCTION get_new_primary()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_new_primary'
LANGUAGE C STRICT;
CREATE FUNCTION reset_voting_status()
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgr_reset_voting_status'
LANGUAGE C STRICT;
CREATE FUNCTION get_repmgrd_pid()
RETURNS INT
AS 'MODULE_PATHNAME', 'get_repmgrd_pid'
LANGUAGE C STRICT;
CREATE FUNCTION get_repmgrd_pidfile()
RETURNS TEXT
AS 'MODULE_PATHNAME', 'get_repmgrd_pidfile'
LANGUAGE C STRICT;
CREATE FUNCTION set_repmgrd_pid(INT, TEXT)
RETURNS VOID
AS 'MODULE_PATHNAME', 'set_repmgrd_pid'
LANGUAGE C CALLED ON NULL INPUT;
CREATE FUNCTION repmgrd_is_running()
RETURNS BOOL
AS 'MODULE_PATHNAME', 'repmgrd_is_running'
LANGUAGE C STRICT;
CREATE FUNCTION repmgrd_pause(BOOL)
RETURNS VOID
AS 'MODULE_PATHNAME', 'repmgrd_pause'
LANGUAGE C STRICT;
CREATE FUNCTION repmgrd_is_paused()
RETURNS BOOL
AS 'MODULE_PATHNAME', 'repmgrd_is_paused'
LANGUAGE C STRICT;
CREATE FUNCTION get_wal_receiver_pid()
RETURNS INT
AS 'MODULE_PATHNAME', 'repmgr_get_wal_receiver_pid'
LANGUAGE C STRICT;
/* views */
CREATE VIEW repmgr.replication_status AS
SELECT m.primary_node_id, m.standby_node_id, n.node_name AS standby_name,
n.type AS node_type, n.active, last_monitor_time,
CASE WHEN n.type='standby' THEN m.last_wal_primary_location ELSE NULL END AS last_wal_primary_location,
m.last_wal_standby_location,
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.replication_lag) ELSE NULL END AS replication_lag,
CASE WHEN n.type='standby' THEN
CASE WHEN replication_lag > 0 THEN age(now(), m.last_apply_time) ELSE '0'::INTERVAL END
ELSE NULL
END AS replication_time_lag,
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.apply_lag) ELSE NULL END AS apply_lag,
AGE(NOW(), CASE WHEN pg_catalog.pg_is_in_recovery() THEN repmgr.standby_get_last_updated() ELSE m.last_monitor_time END) AS communication_time_lag
FROM repmgr.monitoring_history m
JOIN repmgr.nodes n ON m.standby_node_id = n.node_id
WHERE (m.standby_node_id, m.last_monitor_time) IN (
SELECT m1.standby_node_id, MAX(m1.last_monitor_time)
FROM repmgr.monitoring_history m1 GROUP BY 1
);
/* drop old tables */
DROP TABLE repmgr.repl_nodes;
DROP TABLE repmgr.repl_monitor;
DROP TABLE repmgr.repl_events;
-- remove temporary table
DROP TABLE repmgr_old_schema;

View File

@@ -3,7 +3,7 @@
* *
* Implements cluster information actions for the repmgr command line utility * Implements cluster information actions for the repmgr command line utility
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/* /*
* repmgr-action-cluster.h * repmgr-action-cluster.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* repmgr-action-daemon.c * repmgr-action-daemon.c
* *
* Implements repmgrd actions for the repmgr command line utility * Implements repmgrd actions for the repmgr command line utility
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/* /*
* repmgr-action-daemon.h * repmgr-action-daemon.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -3,7 +3,7 @@
* *
* Implements actions available for any kind of node * Implements actions available for any kind of node
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -35,6 +35,7 @@
static bool copy_file(const char *src_file, const char *dest_file); static bool copy_file(const char *src_file, const char *dest_file);
static void format_archive_dir(PQExpBufferData *archive_dir); static void format_archive_dir(PQExpBufferData *archive_dir);
static t_server_action parse_server_action(const char *action); static t_server_action parse_server_action(const char *action);
static const char *output_repmgrd_status(CheckStatus status);
static void exit_optformat_error(const char *error, int errcode); static void exit_optformat_error(const char *error, int errcode);
@@ -52,9 +53,11 @@ static CheckStatus do_node_check_role(PGconn *conn, OutputMode mode, t_node_info
static CheckStatus do_node_check_slots(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output); static CheckStatus do_node_check_slots(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
static CheckStatus do_node_check_missing_slots(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output); static CheckStatus do_node_check_missing_slots(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
static CheckStatus do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output); static CheckStatus do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
static CheckStatus do_node_check_repmgrd(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
static CheckStatus do_node_check_replication_config_owner(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output); static CheckStatus do_node_check_replication_config_owner(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output);
static CheckStatus do_node_check_db_connection(PGconn *conn, OutputMode mode); static CheckStatus do_node_check_db_connection(PGconn *conn, OutputMode mode);
/* /*
* NODE STATUS * NODE STATUS
* *
@@ -941,6 +944,16 @@ do_node_check(void)
exit(return_code); exit(return_code);
} }
if (runtime_options.repmgrd == true)
{
return_code = do_node_check_repmgrd(conn,
runtime_options.output_mode,
&node_info,
NULL);
PQfinish(conn);
exit(return_code);
}
if (runtime_options.replication_config_owner == true) if (runtime_options.replication_config_owner == true)
{ {
return_code = do_node_check_replication_config_owner(conn, return_code = do_node_check_replication_config_owner(conn,
@@ -1314,7 +1327,7 @@ do_node_check_downstream(PGconn *conn, OutputMode mode, t_node_info *node_info,
continue; 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++; missing_nodes_count++;
item_list_append_format(&missing_nodes, item_list_append_format(&missing_nodes,
@@ -1382,49 +1395,32 @@ do_node_check_downstream(PGconn *conn, OutputMode mode, t_node_info *node_info,
{ {
case OM_NAGIOS: case OM_NAGIOS:
{ {
printf("REPMGR_DOWNSTREAM_SERVERS %s: %s | ",
output_check_status(status),
details.data);
if (missing_nodes_count) if (missing_nodes_count)
{ {
ItemListCell *missing_cell = NULL; ItemListCell *missing_cell = NULL;
bool first = true; bool first = true;
printf("missing: "); appendPQExpBufferStr(&details, " (missing: ");
for (missing_cell = missing_nodes.head; missing_cell; missing_cell = missing_cell->next) for (missing_cell = missing_nodes.head; missing_cell; missing_cell = missing_cell->next)
{ {
if (first == false) if (first == false)
printf(", "); appendPQExpBufferStr(&details, ", ");
else else
first = false; first = false;
if (first == false) if (first == false)
printf("%s", missing_cell->string); appendPQExpBufferStr(&details, missing_cell->string);
} }
appendPQExpBufferChar(&details, ')');
} }
if (expected_nodes_count - missing_nodes_count) printf("REPMGR_DOWNSTREAM_SERVERS %s: %s | attached=%i, missing=%i\n",
{ output_check_status(status),
ItemListCell *attached_cell = NULL; details.data,
bool first = true; expected_nodes_count - missing_nodes_count,
missing_nodes_count);
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");
} }
break; break;
case OM_CSV: case OM_CSV:
@@ -1522,7 +1518,7 @@ do_node_check_upstream(PGconn *conn, OutputMode mode, t_node_info *node_info, Ch
{ {
case OM_NAGIOS: case OM_NAGIOS:
{ {
printf("REPMGR_UPSTREAM_SERVER %s: %s | ", printf("REPMGR_UPSTREAM_SERVER %s: %s\n",
output_check_status(status), output_check_status(status),
details.data); details.data);
} }
@@ -2024,7 +2020,6 @@ do_node_check_missing_slots(PGconn *conn, OutputMode mode, t_node_info *node_inf
return status; return status;
} }
CheckStatus CheckStatus
do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output) do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output)
{ {
@@ -2159,6 +2154,53 @@ do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_in
return status; return status;
} }
CheckStatus
do_node_check_repmgrd(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckStatusList *list_output)
{
CheckStatus status = CHECK_STATUS_OK;
if (mode == OM_CSV && list_output == NULL)
{
log_error(_("--csv output not provided with --repmgrd option"));
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
status = get_repmgrd_status(conn);
switch (mode)
{
case OM_OPTFORMAT:
printf("--repmgrd=%s\n",
output_check_status(status));
break;
case OM_NAGIOS:
printf("REPMGRD %s: %s\n",
output_check_status(status),
output_repmgrd_status(status));
break;
case OM_CSV:
case OM_TEXT:
if (list_output != NULL)
{
check_status_list_set(list_output,
"repmgrd",
status,
output_repmgrd_status(status));
}
else
{
printf("%s (%s)\n",
output_check_status(status),
output_repmgrd_status(status));
}
default:
break;
}
return status;
}
/* /*
* This is not included in the general list output * This is not included in the general list output
*/ */
@@ -2612,6 +2654,13 @@ do_node_rejoin(void)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
/*
* Emit a notice about the identity of the rejoin target
*/
log_notice(_("rejoin target is node \"%s\" (ID: %i)"),
primary_node_record.node_name,
primary_node_record.node_id);
/* connect to registered primary and check it's not in recovery */ /* connect to registered primary and check it's not in recovery */
primary_conn = establish_db_connection(primary_node_record.conninfo, false); primary_conn = establish_db_connection(primary_node_record.conninfo, false);
@@ -2813,7 +2862,8 @@ do_node_rejoin(void)
log_notice(_("temporarily removing \"standby.signal\"")); log_notice(_("temporarily removing \"standby.signal\""));
log_detail(_("this is required so pg_rewind can fix the unclean shutdown")); log_detail(_("this is required so pg_rewind can fix the unclean shutdown"));
make_standby_signal_path(standby_signal_file_path); make_standby_signal_path(config_file_options.data_directory,
standby_signal_file_path);
if (unlink(standby_signal_file_path) < 0 && errno != ENOENT) if (unlink(standby_signal_file_path) < 0 && errno != ENOENT)
{ {
@@ -2838,7 +2888,7 @@ do_node_rejoin(void)
* of whether the pg_rewind operation failed. * of whether the pg_rewind operation failed.
*/ */
log_notice(_("recreating \"standby.signal\"")); log_notice(_("recreating \"standby.signal\""));
write_standby_signal(); write_standby_signal(config_file_options.data_directory);
} }
if (ret == false) if (ret == false)
@@ -3562,6 +3612,25 @@ copy_file(const char *src_file, const char *dest_file)
} }
static const char *
output_repmgrd_status(CheckStatus status)
{
switch (status)
{
case CHECK_STATUS_OK:
return "repmgrd running";
case CHECK_STATUS_WARNING:
return "repmgrd running but paused";
case CHECK_STATUS_CRITICAL:
return "repmgrd not running";
case CHECK_STATUS_UNKNOWN:
return "repmgrd status unknown";
}
return "UNKNOWN";
}
void void
do_node_help(void) do_node_help(void)
{ {
@@ -3599,11 +3668,12 @@ do_node_help(void)
printf(_(" Following options check an individual status:\n")); printf(_(" Following options check an individual status:\n"));
printf(_(" --archive-ready number of WAL files ready for archiving\n")); printf(_(" --archive-ready number of WAL files ready for archiving\n"));
printf(_(" --downstream whether all downstream nodes are connected\n")); printf(_(" --downstream whether all downstream nodes are connected\n"));
printf(_(" --uptream whether the node is connected to its upstream\n")); printf(_(" --upstream whether the node is connected to its upstream\n"));
printf(_(" --replication-lag replication lag in seconds (standbys only)\n")); printf(_(" --replication-lag replication lag in seconds (standbys only)\n"));
printf(_(" --role check node has expected role\n")); printf(_(" --role check node has expected role\n"));
printf(_(" --slots check for inactive replication slots\n")); printf(_(" --slots check for inactive replication slots\n"));
printf(_(" --missing-slots check for missing replication slots\n")); printf(_(" --missing-slots check for missing replication slots\n"));
printf(_(" --repmgrd check if repmgrd is running\n"));
printf(_(" --data-directory-config check repmgr's data directory configuration\n")); printf(_(" --data-directory-config check repmgr's data directory configuration\n"));
puts(""); puts("");
@@ -3617,7 +3687,7 @@ do_node_help(void)
printf(_(" --dry-run check that the prerequisites are met for rejoining the node\n" \ printf(_(" --dry-run check that the prerequisites are met for rejoining the node\n" \
" (including usability of \"pg_rewind\" if requested)\n")); " (including usability of \"pg_rewind\" if requested)\n"));
printf(_(" --force-rewind[=VALUE] execute \"pg_rewind\" if necessary\n")); printf(_(" --force-rewind[=VALUE] execute \"pg_rewind\" if necessary\n"));
printf(_(" (9.3 and 9.4 - provide full \"pg_rewind\" path)\n")); printf(_(" (PostgreSQL 9.4 - provide full \"pg_rewind\" path)\n"));
printf(_(" --config-files comma-separated list of configuration files to retain\n" \ printf(_(" --config-files comma-separated list of configuration files to retain\n" \
" after executing \"pg_rewind\"\n")); " after executing \"pg_rewind\"\n"));

View File

@@ -1,6 +1,6 @@
/* /*
* repmgr-action-node.h * repmgr-action-node.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -3,7 +3,7 @@
* *
* Implements primary actions for the repmgr command line utility * Implements primary actions for the repmgr command line utility
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/* /*
* repmgr-action-primary.h * repmgr-action-primary.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -2,7 +2,7 @@
* repmgr-action-service.c * repmgr-action-service.c
* *
* Implements repmgrd actions for the repmgr command line utility * Implements repmgrd actions for the repmgr command line utility
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/* /*
* repmgr-action-service.h * repmgr-action-service.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -3,7 +3,7 @@
* *
* Implements standby actions for the repmgr command line utility * Implements standby actions for the repmgr command line utility
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
*/ */
#include <sys/stat.h> #include <sys/stat.h>
#include <time.h>
#include "repmgr.h" #include "repmgr.h"
#include "dirutil.h" #include "dirutil.h"
@@ -94,6 +95,8 @@ static char barman_command_buf[MAXLEN] = "";
* be run and which of the available users, which will be one * be run and which of the available users, which will be one
* of the repmgr user, the replication user (if available) or * of the repmgr user, the replication user (if available) or
* the superuser (if available). * the superuser (if available).
*
* This is determined in check_source_server().
*/ */
static t_user_type SettingsUser = REPMGR_USER; static t_user_type SettingsUser = REPMGR_USER;
@@ -173,21 +176,6 @@ do_standby_clone(void)
initialize_conninfo_params(&recovery_conninfo, false); initialize_conninfo_params(&recovery_conninfo, false);
/*
* --replication-conf-only provided - we'll handle that separately
*/
if (runtime_options.replication_conf_only == true)
{
return _do_create_replication_conf();
}
/*
* conninfo params for the actual upstream node (which might be different
* to the node we're cloning from) to write to recovery.conf
*/
mode = get_standby_clone_mode();
/* /*
* Copy the provided data directory; if a configuration file was provided, * Copy the provided data directory; if a configuration file was provided,
* use the (mandatory) value from that; if -D/--pgdata was provided, use * use the (mandatory) value from that; if -D/--pgdata was provided, use
@@ -215,6 +203,19 @@ do_standby_clone(void)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
/*
* --replication-conf-only provided - we'll handle that separately
*/
if (runtime_options.replication_conf_only == true)
{
return _do_create_replication_conf();
}
/*
* conninfo params for the actual upstream node (which might be different
* to the node we're cloning from) to write to recovery.conf
*/
mode = get_standby_clone_mode();
if (mode == barman) if (mode == barman)
{ {
@@ -670,6 +671,15 @@ do_standby_clone(void)
log_hint(_("consider using the -c/--fast-checkpoint option")); log_hint(_("consider using the -c/--fast-checkpoint option"));
} }
if (mode == pg_basebackup)
{
/*
* In --dry-run mode, this will just output the pg_basebackup command which
* would be executed.
*/
run_basebackup(&local_node_record);
}
PQfinish(source_conn); PQfinish(source_conn);
log_info(_("all prerequisites for \"standby clone\" are met")); log_info(_("all prerequisites for \"standby clone\" are met"));
@@ -733,7 +743,7 @@ do_standby_clone(void)
drop_replication_slot_if_exists(source_conn, UNKNOWN_NODE_ID, local_node_record.slot_name); drop_replication_slot_if_exists(source_conn, UNKNOWN_NODE_ID, local_node_record.slot_name);
} }
log_error(_("unable to take a base backup of the primary server")); log_error(_("unable to take a base backup of the source server"));
log_hint(_("data directory (\"%s\") may need to be cleaned up manually"), log_hint(_("data directory (\"%s\") may need to be cleaned up manually"),
local_data_directory); local_data_directory);
@@ -763,7 +773,7 @@ do_standby_clone(void)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
appendPQExpBufferStr(&command, " "); appendPQExpBufferChar(&command, ' ');
/* Somewhat inconsistent, but pg_verifybackup doesn't accept a -D option */ /* Somewhat inconsistent, but pg_verifybackup doesn't accept a -D option */
appendShellString(&command, appendShellString(&command,
@@ -838,6 +848,16 @@ do_standby_clone(void)
break; break;
} }
/*
* Do a final check on the data directory permissions - if the user
* is cloning into an existing directory set to 0750, and the server
* is Pg10 or earlier, Pg will refuse to start. We might not have
* known the server version when creating the data directory
* (mainly if cloning from Barman with no upstream connection), hence
* the additional check here.
*/
set_dir_permissions(local_data_directory, source_server_version_num);
/* /*
* TODO: It might be nice to provide an option to have repmgr start the * TODO: It might be nice to provide an option to have repmgr start the
* PostgreSQL server automatically * PostgreSQL server automatically
@@ -1290,6 +1310,64 @@ _do_create_replication_conf(void)
PQExpBufferData msg; PQExpBufferData msg;
t_replication_slot slot_info = T_REPLICATION_SLOT_INITIALIZER; t_replication_slot slot_info = T_REPLICATION_SLOT_INITIALIZER;
/*
* Check the node record has slot_name set; if not we'll need to
* update it.
*/
if (local_node_record.slot_name[0] == '\0')
{
PGconn *primary_conn = NULL;
create_slot_name(local_node_record.slot_name, local_node_record.node_id);
/* Check we can connect to the primary so we can update the record */
if (get_recovery_type(upstream_conn) == RECTYPE_PRIMARY)
{
primary_conn = upstream_conn;
}
else
{
primary_conn = establish_primary_db_connection(upstream_conn, false);
if (primary_conn == NULL)
{
log_error(_("unable to connect to primary to update slot name for node \"%s\" (ID: %i)"),
local_node_record.node_name,
local_node_record.node_id);
PQfinish(upstream_conn);
termPQExpBuffer(&msg);
exit(ERR_BAD_CONFIG);
}
}
if (runtime_options.dry_run == true)
{
log_info(_("would set \"slot_name\" for node \"%s\" (ID: %i) to \"%s\""),
local_node_record.node_name,
local_node_record.node_id,
local_node_record.slot_name);
}
else
{
bool success = update_node_record_slot_name(primary_conn,
local_node_record.node_id,
local_node_record.slot_name);
if (primary_conn != upstream_conn)
PQfinish(primary_conn);
if (success == false)
{
log_error(_("unable to update slot name for node \"%s\" (ID: %i)"),
local_node_record.node_name,
local_node_record.node_id);
PQfinish(upstream_conn);
exit(ERR_BAD_CONFIG);
}
}
}
record_status = get_slot_record(upstream_conn, local_node_record.slot_name, &slot_info); record_status = get_slot_record(upstream_conn, local_node_record.slot_name, &slot_info);
/* check if replication slot exists*/ /* check if replication slot exists*/
@@ -1444,7 +1522,18 @@ _do_create_replication_conf(void)
if (node_is_running == true) if (node_is_running == true)
{ {
log_hint(_("node must be restarted for the new file to take effect")); if (PQserverVersion(upstream_conn) >= 130000)
{
log_hint(_("configuration must be reloaded for the configuration changes to take effect"));
}
else if (PQserverVersion(upstream_conn) >= 120000)
{
log_hint(_("node must be restarted for the configuration changes to take effect"));
}
else
{
log_hint(_("node must be restarted for the new file to take effect"));
}
} }
} }
} }
@@ -1459,7 +1548,7 @@ _do_create_replication_conf(void)
} }
else else
{ {
if (write_standby_signal() == false) if (write_standby_signal(local_data_directory) == false)
{ {
log_error(_("unable to write \"standby.signal\" file")); log_error(_("unable to write \"standby.signal\" file"));
} }
@@ -1911,7 +2000,7 @@ do_standby_register(void)
/* /*
* If --upstream-node-id not provided, we're defaulting to the primary as * If --upstream-node-id not provided, we're defaulting to the primary as
* upstream node. If local node is available, double-check that it's attached * upstream node. If local node is available, double-check that it's attached
* to the primary, in case --upstream-node-id was an accidental ommission. * to the primary, in case --upstream-node-id was an accidental omission.
* *
* Currently we'll only do this for newly registered nodes. * Currently we'll only do this for newly registered nodes.
*/ */
@@ -1920,7 +2009,7 @@ do_standby_register(void)
/* only do this if record does not exist */ /* only do this if record does not exist */
if (record_status != RECORD_FOUND) if (record_status != RECORD_FOUND)
{ {
log_warning(_("--upstream-node-id not supplied, assuming upstream node is primary (node ID %i)"), log_warning(_("--upstream-node-id not supplied, assuming upstream node is primary (node ID: %i)"),
primary_node_id); primary_node_id);
/* check our standby is connected */ /* check our standby is connected */
@@ -3259,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); update_node_record_slot_name(primary_conn, config_file_options.node_id, local_node_record.slot_name);
} }
if (create_replication_slot(follow_target_conn, if (create_replication_slot(follow_target_conn,
local_node_record.slot_name, local_node_record.slot_name,
NULL, follow_target_node_record,
output) == false) output) == false)
{ {
log_error("%s", output->data); log_error("%s", output->data);
@@ -3374,7 +3462,7 @@ do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_n
goto cleanup; goto cleanup;
} }
/* In the unlikley event that fails, we'll fall back to a restart */ /* In the unlikely event that fails, we'll fall back to a restart */
log_warning(_("unable to reload server configuration")); log_warning(_("unable to reload server configuration"));
} }
@@ -3565,8 +3653,9 @@ do_standby_switchover(void)
PQExpBufferData remote_command_str; PQExpBufferData remote_command_str;
PQExpBufferData command_output; PQExpBufferData command_output;
PQExpBufferData node_rejoin_options; PQExpBufferData node_rejoin_options;
PQExpBufferData errmsg; PQExpBufferData logmsg;
PQExpBufferData detailmsg; PQExpBufferData detailmsg;
PQExpBufferData event_details;
int r, int r,
i; i;
@@ -3583,6 +3672,9 @@ do_standby_switchover(void)
/* store list of configuration files on the demotion candidate */ /* store list of configuration files on the demotion candidate */
KeyValueList remote_config_files = {NULL, NULL}; KeyValueList remote_config_files = {NULL, NULL};
/* temporary log file for "repmgr node rejoin" on the demotion candidate */
char node_rejoin_log[MAXPGPATH] = "";
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER; NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
SiblingNodeStats sibling_nodes_stats = T_SIBLING_NODES_STATS_INITIALIZER; SiblingNodeStats sibling_nodes_stats = T_SIBLING_NODES_STATS_INITIALIZER;
@@ -3605,7 +3697,7 @@ do_standby_switchover(void)
* SANITY CHECKS * SANITY CHECKS
* *
* We'll be doing a bunch of operations on the remote server (primary to * We'll be doing a bunch of operations on the remote server (primary to
* be demoted) - careful checks needed before proceding. * be demoted) - careful checks needed before proceeding.
*/ */
local_conn = establish_db_connection(config_file_options.conninfo, true); local_conn = establish_db_connection(config_file_options.conninfo, true);
@@ -3725,24 +3817,24 @@ do_standby_switchover(void)
* the demotion candidate as the rejoin will fail if we are unable to to write to that. * the demotion candidate as the rejoin will fail if we are unable to to write to that.
*/ */
initPQExpBuffer(&errmsg); initPQExpBuffer(&logmsg);
initPQExpBuffer(&detailmsg); initPQExpBuffer(&detailmsg);
if (check_replication_config_owner(PQserverVersion(local_conn), if (check_replication_config_owner(PQserverVersion(local_conn),
config_file_options.data_directory, config_file_options.data_directory,
&errmsg, &detailmsg) == false) &logmsg, &detailmsg) == false)
{ {
log_error("%s", errmsg.data); log_error("%s", logmsg.data);
log_detail("%s", detailmsg.data); log_detail("%s", detailmsg.data);
termPQExpBuffer(&errmsg); termPQExpBuffer(&logmsg);
termPQExpBuffer(&detailmsg); termPQExpBuffer(&detailmsg);
PQfinish(local_conn); PQfinish(local_conn);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
termPQExpBuffer(&errmsg); termPQExpBuffer(&logmsg);
termPQExpBuffer(&detailmsg); termPQExpBuffer(&detailmsg);
/* check remote server connection and retrieve its record */ /* check remote server connection and retrieve its record */
@@ -4087,7 +4179,7 @@ do_standby_switchover(void)
if (command_success == false || command_output.data[0] == '0') if (command_success == false || command_output.data[0] == '0')
{ {
log_error(_("expected configuration file not found on the demotion candiate \"%s\" (ID: %i)"), log_error(_("expected configuration file not found on the demotion candidate \"%s\" (ID: %i)"),
remote_node_record.node_name, remote_node_record.node_name,
remote_node_record.node_id); remote_node_record.node_id);
log_detail(_("registered configuration file is \"%s\""), log_detail(_("registered configuration file is \"%s\""),
@@ -4187,7 +4279,7 @@ do_standby_switchover(void)
else if (remote_error == REMOTE_ERROR_CONNINFO_PARSE) else if (remote_error == REMOTE_ERROR_CONNINFO_PARSE)
{ {
/* highly unlikely */ /* highly unlikely */
log_detail(_("an error was encountered when parsing the \"conninfo\" parameter in \"rempgr.conf\" on node \"%s\" (ID: %i)"), log_detail(_("an error was encountered when parsing the \"conninfo\" parameter in \"repmgr.conf\" on node \"%s\" (ID: %i)"),
remote_node_record.node_name, remote_node_record.node_name,
remote_node_record.node_id); remote_node_record.node_id);
} }
@@ -4690,6 +4782,7 @@ do_standby_switchover(void)
repmgrd_info = (RepmgrdInfo **) pg_malloc0(sizeof(RepmgrdInfo *) * all_nodes.node_count); repmgrd_info = (RepmgrdInfo **) pg_malloc0(sizeof(RepmgrdInfo *) * all_nodes.node_count);
log_notice(_("attempting to pause repmgrd on %i nodes"), all_nodes.node_count);
for (cell = all_nodes.head; cell; cell = cell->next) for (cell = all_nodes.head; cell; cell = cell->next)
{ {
repmgrd_info[i] = pg_malloc0(sizeof(RepmgrdInfo)); repmgrd_info[i] = pg_malloc0(sizeof(RepmgrdInfo));
@@ -4718,7 +4811,7 @@ do_standby_switchover(void)
unreachable_node_count++; unreachable_node_count++;
item_list_append_format(&repmgrd_connection_errors, item_list_append_format(&repmgrd_connection_errors,
_("unable to connect to node \"%s\" (ID %i):\n%s"), _("unable to connect to node \"%s\" (ID: %i):\n%s"),
cell->node_info->node_name, cell->node_info->node_name,
cell->node_info->node_id, cell->node_info->node_id,
PQerrorMessage(cell->node_info->conn)); PQerrorMessage(cell->node_info->conn));
@@ -4749,8 +4842,9 @@ do_standby_switchover(void)
initPQExpBuffer(&msg); initPQExpBuffer(&msg);
appendPQExpBuffer(&msg, appendPQExpBuffer(&msg,
_("unable to connect to %i node(s), unable to pause all repmgrd instances"), _("unable to connect to %i of %i node(s), unable to pause all repmgrd instances"),
unreachable_node_count); unreachable_node_count,
all_nodes.node_count);
initPQExpBuffer(&detail); initPQExpBuffer(&detail);
@@ -4801,7 +4895,7 @@ do_standby_switchover(void)
*/ */
if (repmgrd_info[i]->pg_running == false) if (repmgrd_info[i]->pg_running == false)
{ {
log_warning(_("node \"%s\" (ID %i) unreachable, unable to pause repmgrd"), log_warning(_("node \"%s\" (ID: %i) unreachable, unable to pause repmgrd"),
cell->node_info->node_name, cell->node_info->node_name,
cell->node_info->node_id); cell->node_info->node_id);
i++; i++;
@@ -4814,7 +4908,7 @@ do_standby_switchover(void)
*/ */
if (repmgrd_info[i]->running == false) if (repmgrd_info[i]->running == false)
{ {
log_warning(_("repmgrd not running on node \"%s\" (ID %i)"), log_notice(_("repmgrd not running on node \"%s\" (ID: %i), not pausing"),
cell->node_info->node_name, cell->node_info->node_name,
cell->node_info->node_id); cell->node_info->node_id);
i++; i++;
@@ -4835,14 +4929,14 @@ do_standby_switchover(void)
if (runtime_options.dry_run == true) if (runtime_options.dry_run == true)
{ {
log_info(_("would pause repmgrd on node \"%s\" (ID %i)"), log_info(_("would pause repmgrd on node \"%s\" (ID: %i)"),
cell->node_info->node_name, cell->node_info->node_name,
cell->node_info->node_id); cell->node_info->node_id);
} }
else else
{ {
/* XXX check result */ /* XXX check result */
log_debug("pausing repmgrd on node \"%s\" (ID %i)", log_debug("pausing repmgrd on node \"%s\" (ID: %i)",
cell->node_info->node_name, cell->node_info->node_name,
cell->node_info->node_id); cell->node_info->node_id);
@@ -5142,6 +5236,18 @@ do_standby_switchover(void)
format_lsn(replication_info.last_wal_receive_lsn), format_lsn(replication_info.last_wal_receive_lsn),
format_lsn(remote_last_checkpoint_lsn)); format_lsn(remote_last_checkpoint_lsn));
/*
* optionally add a delay before promoting the standby; this is mainly
* useful for testing (e.g. for reappearance of the original primary) and
* is not documented.
*/
if (config_file_options.promote_delay > 0)
{
log_debug("sleeping %i seconds before promoting standby",
config_file_options.promote_delay);
sleep(config_file_options.promote_delay);
}
/* /*
* Promote standby (local node). * Promote standby (local node).
* *
@@ -5267,6 +5373,21 @@ do_standby_switchover(void)
pfree(conninfo_normalized); pfree(conninfo_normalized);
} }
/* */
snprintf(node_rejoin_log, MAXPGPATH,
#if defined(__i386__) || defined(__i386)
"/tmp/node-rejoin.%u.log",
(unsigned)time(NULL)
#else
"/tmp/node-rejoin.%lu.log",
(unsigned long)time(NULL)
#endif
);
appendPQExpBuffer(&remote_command_str,
" > %s 2>&1 && echo \"1\" || echo \"0\"",
node_rejoin_log);
termPQExpBuffer(&node_rejoin_options); termPQExpBuffer(&node_rejoin_options);
log_debug("executing:\n %s", remote_command_str.data); log_debug("executing:\n %s", remote_command_str.data);
@@ -5280,78 +5401,161 @@ do_standby_switchover(void)
termPQExpBuffer(&remote_command_str); termPQExpBuffer(&remote_command_str);
/* TODO: verify this node's record was updated correctly */ initPQExpBuffer(&logmsg);
initPQExpBuffer(&detailmsg);
/* This is failure to execute the ssh command */
if (command_success == false) if (command_success == false)
{ {
log_error(_("rejoin failed with error code %i"), r); log_error(_("rejoin failed with error code %i"), r);
switchover_success = false;
appendPQExpBuffer(&logmsg,
_("unable to execute \"repmgr node rejoin\" on demotion candidate \"%s\" (ID: %i)"),
remote_node_record.node_name,
remote_node_record.node_id);
appendPQExpBufferStr(&detailmsg,
command_output.data);
create_event_notification_extended(local_conn,
&config_file_options,
config_file_options.node_id,
"standby_switchover",
false,
command_output.data,
&event_info);
} }
else else
{ {
PQExpBufferData event_details; standy_join_status join_success = JOIN_UNKNOWN;
standy_join_status join_success = check_standby_join(local_conn,
&local_node_record,
&remote_node_record);
initPQExpBuffer(&event_details); /* "rempgr node rejoin" failed on the demotion candidate */
if (command_output.data[0] == '0')
switch (join_success) {
case JOIN_FAIL_NO_PING:
appendPQExpBuffer(&event_details,
_("node \"%s\" (ID: %i) promoted to primary, but demote node \"%s\" (ID: %i) did not beome available"),
config_file_options.node_name,
config_file_options.node_id,
remote_node_record.node_name,
remote_node_record.node_id);
switchover_success = false;
break;
case JOIN_FAIL_NO_REPLICATION:
appendPQExpBuffer(&event_details,
_("node \"%s\" (ID: %i) promoted to primary, but demote node \"%s\" (ID: %i) did not connect to the new primary"),
config_file_options.node_name,
config_file_options.node_id,
remote_node_record.node_name,
remote_node_record.node_id);
switchover_success = false;
break;
case JOIN_SUCCESS:
appendPQExpBuffer(&event_details,
_("node \"%s\" (ID: %i) promoted to primary, node \"%s\" (ID: %i) demoted to standby"),
config_file_options.node_name,
config_file_options.node_id,
remote_node_record.node_name,
remote_node_record.node_id);
}
create_event_notification_extended(local_conn,
&config_file_options,
config_file_options.node_id,
"standby_switchover",
switchover_success,
event_details.data,
&event_info);
if (switchover_success == true)
{ {
log_notice("%s", event_details.data); appendPQExpBuffer(&logmsg,
_("execution of \"repmgr node rejoin\" on demotion candidate \"%s\" (ID: %i) failed"),
remote_node_record.node_name,
remote_node_record.node_id);
/*
* Speculatively check if the demotion candidate has been restarted, e.g. by
* an external watchdog process which isn't aware a switchover is happening.
* This falls into the category "thing outside of our control which shouldn't
* happen, but if it does, make it easier to find out what happened".
*/
remote_conn = establish_db_connection(remote_node_record.conninfo, false);
if (PQstatus(remote_conn) == CONNECTION_OK)
{
if (get_recovery_type(remote_conn) == RECTYPE_PRIMARY)
{
appendPQExpBuffer(&detailmsg,
_("PostgreSQL instance on demotion candidate \"%s\" (ID: %i) is running as a primary\n"),
remote_node_record.node_name,
remote_node_record.node_id);
log_warning("%s", detailmsg.data);
}
}
PQfinish(remote_conn);
appendPQExpBuffer(&detailmsg,
"check log file \"%s\" on \"%s\" for details",
node_rejoin_log,
remote_node_record.node_name);
switchover_success = false;
join_success = JOIN_COMMAND_FAIL;
} }
else else
{ {
log_error("%s", event_details.data); join_success = check_standby_join(local_conn,
&local_node_record,
&remote_node_record);
switch (join_success) {
case JOIN_FAIL_NO_PING:
appendPQExpBuffer(&logmsg,
_("node \"%s\" (ID: %i) promoted to primary, but demotion candidate \"%s\" (ID: %i) did not become available"),
config_file_options.node_name,
config_file_options.node_id,
remote_node_record.node_name,
remote_node_record.node_id);
switchover_success = false;
break;
case JOIN_FAIL_NO_REPLICATION:
appendPQExpBuffer(&logmsg,
_("node \"%s\" (ID: %i) promoted to primary, but demotion candidate \"%s\" (ID: %i) did not connect to the new primary"),
config_file_options.node_name,
config_file_options.node_id,
remote_node_record.node_name,
remote_node_record.node_id);
switchover_success = false;
break;
case JOIN_SUCCESS:
appendPQExpBuffer(&logmsg,
_("node \"%s\" (ID: %i) promoted to primary, node \"%s\" (ID: %i) demoted to standby"),
config_file_options.node_name,
config_file_options.node_id,
remote_node_record.node_name,
remote_node_record.node_id);
break;
/* check_standby_join() does not return this */
case JOIN_COMMAND_FAIL:
break;
/* should never happen*/
case JOIN_UNKNOWN:
appendPQExpBuffer(&logmsg,
"unable to determine success of node rejoin action for demotion candidate \"%s\" (ID: %i)",
remote_node_record.node_name,
remote_node_record.node_id);
switchover_success = false;
break;
}
if (switchover_success == false)
{
appendPQExpBuffer(&detailmsg,
"check the PostgreSQL log file on demotion candidate \"%s\" (ID: %i)",
remote_node_record.node_name,
remote_node_record.node_id);
}
} }
termPQExpBuffer(&event_details);
} }
if (switchover_success == true)
{
/* TODO: verify demotion candidates's node record was updated correctly */
log_notice("%s", logmsg.data);
}
else
{
log_error("%s", logmsg.data);
}
initPQExpBuffer(&event_details);
appendPQExpBufferStr(&event_details, logmsg.data);
if (detailmsg.data[0] != '\0')
{
log_detail("%s", detailmsg.data);
appendPQExpBuffer(&event_details, "\n%s",
detailmsg.data);
}
create_event_notification_extended(local_conn,
&config_file_options,
config_file_options.node_id,
"standby_switchover",
switchover_success,
event_details.data,
&event_info);
termPQExpBuffer(&event_details);
termPQExpBuffer(&logmsg);
termPQExpBuffer(&detailmsg);
termPQExpBuffer(&command_output); termPQExpBuffer(&command_output);
/* /*
* If --siblings-follow specified, attempt to make them follow the new * If --siblings-follow specified, attempt to make them follow the new
* primary * primary
@@ -5464,7 +5668,7 @@ do_standby_switchover(void)
if (repmgrd_info[i]->paused == true && runtime_options.repmgrd_force_unpause == false) if (repmgrd_info[i]->paused == true && runtime_options.repmgrd_force_unpause == false)
{ {
log_debug("repmgrd on node \"%s\" (ID %i) paused before switchover, --repmgrd-force-unpause not provided, not unpausing", log_debug("repmgrd on node \"%s\" (ID: %i) paused before switchover, --repmgrd-force-unpause not provided, not unpausing",
cell->node_info->node_name, cell->node_info->node_name,
cell->node_info->node_id); cell->node_info->node_id);
@@ -5472,7 +5676,7 @@ do_standby_switchover(void)
continue; continue;
} }
log_debug("unpausing repmgrd on node \"%s\" (ID %i)", log_debug("unpausing repmgrd on node \"%s\" (ID: %i)",
cell->node_info->node_name, cell->node_info->node_name,
cell->node_info->node_id); cell->node_info->node_id);
@@ -5483,7 +5687,7 @@ do_standby_switchover(void)
if (repmgrd_pause(cell->node_info->conn, false) == false) if (repmgrd_pause(cell->node_info->conn, false) == false)
{ {
item_list_append_format(&repmgrd_unpause_errors, item_list_append_format(&repmgrd_unpause_errors,
_("unable to unpause node \"%s\" (ID %i)"), _("unable to unpause node \"%s\" (ID: %i)"),
cell->node_info->node_name, cell->node_info->node_name,
cell->node_info->node_id); cell->node_info->node_id);
error_node_count++; error_node_count++;
@@ -5492,7 +5696,7 @@ do_standby_switchover(void)
else else
{ {
item_list_append_format(&repmgrd_unpause_errors, item_list_append_format(&repmgrd_unpause_errors,
_("unable to connect to node \"%s\" (ID %i):\n%s"), _("unable to connect to node \"%s\" (ID: %i):\n%s"),
cell->node_info->node_name, cell->node_info->node_name,
cell->node_info->node_id, cell->node_info->node_id,
PQerrorMessage(cell->node_info->conn)); PQerrorMessage(cell->node_info->conn));
@@ -5580,20 +5784,18 @@ check_source_server()
} }
/* /*
* If a connection was established, perform some sanity checks on the * The server version check will also serve as a sanity-check that we can
* provided upstream connection. * actually execute queries on this connection.
*/ */
source_server_version_num = check_server_version(source_conn, "primary", true, NULL); 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 * The cluster size is nice to have, but not essential to know, so only display
* we can actually run a query before going any further. * something if the user has sufficient permissions to retrieve the size of
* all databases.
*/ */
if (get_cluster_size(source_conn, cluster_size) == false) if (get_cluster_size(source_conn, cluster_size) == true)
exit(ERR_DB_QUERY); log_detail(_("current installation size is %s"),
log_detail(_("current installation size is %s"),
cluster_size); cluster_size);
/* /*
@@ -6776,6 +6978,13 @@ run_basebackup(t_node_info *node_record)
termPQExpBuffer(&params); termPQExpBuffer(&params);
if (runtime_options.dry_run == true)
{
log_info(_("would execute:\n %s"), script.data);
termPQExpBuffer(&script);
return SUCCESS;
}
log_info(_("executing:\n %s"), script.data); log_info(_("executing:\n %s"), script.data);
/* /*
@@ -7509,7 +7718,7 @@ stop_backup:
if (record_status == RECORD_FOUND) if (record_status == RECORD_FOUND)
{ {
log_verbose(LOG_INFO, log_verbose(LOG_INFO,
_("replication slot \"%s\" aleady exists on upstream node %i"), _("replication slot \"%s\" already exists on upstream node %i"),
local_node_record->slot_name, local_node_record->slot_name,
upstream_node_id); upstream_node_id);
} }
@@ -7762,7 +7971,9 @@ static void
tablespace_data_append(TablespaceDataList *list, const char *name, const char *oid, const char *location) tablespace_data_append(TablespaceDataList *list, const char *name, const char *oid, const char *location)
{ {
TablespaceDataListCell *cell = NULL; TablespaceDataListCell *cell = NULL;
int oid_len = strlen(oid);
int name_len = strlen(name);
int location_len = strlen(location);
cell = (TablespaceDataListCell *) pg_malloc0(sizeof(TablespaceDataListCell)); cell = (TablespaceDataListCell *) pg_malloc0(sizeof(TablespaceDataListCell));
if (cell == NULL) if (cell == NULL)
@@ -7771,13 +7982,13 @@ tablespace_data_append(TablespaceDataList *list, const char *name, const char *o
exit(ERR_OUT_OF_MEMORY); exit(ERR_OUT_OF_MEMORY);
} }
cell->oid = pg_malloc(1 + strlen(oid)); cell->oid = pg_malloc0(1 + oid_len);
cell->name = pg_malloc(1 + strlen(name)); cell->name = pg_malloc0(1 + name_len);
cell->location = pg_malloc(1 + strlen(location)); cell->location = pg_malloc0(1 + location_len);
strncpy(cell->oid, oid, 1 + strlen(oid)); strncpy(cell->oid, oid, oid_len);
strncpy(cell->name, name, 1 + strlen(name)); strncpy(cell->name, name, name_len);
strncpy(cell->location, location, 1 + strlen(location)); strncpy(cell->location, location, location_len);
if (list->tail) if (list->tail)
list->tail->next = cell; list->tail->next = cell;
@@ -7937,9 +8148,9 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *primary_co
free(escaped); free(escaped);
} }
/*
* Caller requests the generated file to be written into a buffer
*/
if (as_file == false) if (as_file == false)
{ {
/* create file in buffer */ /* create file in buffer */
@@ -7959,20 +8170,17 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *primary_co
return true; return true;
} }
/* /*
* PostgreSQL 12 and later: modify postgresql.auto.conf * PostgreSQL 12 and later: modify postgresql.auto.conf
*
*/ */
if (server_version_num >= 120000) if (server_version_num >= 120000)
{ {
if (modify_auto_conf(dest, &recovery_config) == false) if (modify_auto_conf(dest, &recovery_config) == false)
{ {
return false; return false;
} }
if (write_standby_signal() == false) if (write_standby_signal(dest) == false)
{ {
return false; return false;
} }
@@ -8911,6 +9119,8 @@ do_standby_help(void)
#endif #endif
printf(_(" --without-barman do not clone from Barman even if configured\n")); printf(_(" --without-barman do not clone from Barman even if configured\n"));
printf(_(" --replication-conf-only generate replication configuration for a previously cloned instance\n")); printf(_(" --replication-conf-only generate replication configuration for a previously cloned instance\n"));
printf(_(" --recovery-min-apply-delay set PostgreSQL configuration parameter \"recovery_min_apply_delay\"\n" \
" (overrides any setting in repmgr.conf)\n"));
puts(""); puts("");
@@ -8963,7 +9173,7 @@ do_standby_help(void)
printf(_(" --dry-run perform checks etc. but don't actually execute switchover\n")); printf(_(" --dry-run perform checks etc. but don't actually execute switchover\n"));
printf(_(" -F, --force ignore warnings and continue anyway\n")); printf(_(" -F, --force ignore warnings and continue anyway\n"));
printf(_(" --force-rewind[=VALUE] use \"pg_rewind\" to reintegrate the old primary if necessary\n")); printf(_(" --force-rewind[=VALUE] use \"pg_rewind\" to reintegrate the old primary if necessary\n"));
printf(_(" (9.3 and 9.4 - provide \"pg_rewind\" path)\n")); printf(_(" (PostgreSQL 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(_(" -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(_(" -S, --superuser=USERNAME superuser to use, if repmgr user is not superuser\n"));

View File

@@ -1,6 +1,6 @@
/* /*
* repmgr-action-standby.h * repmgr-action-standby.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -3,7 +3,7 @@
* *
* Implements witness actions for the repmgr command line utility * Implements witness actions for the repmgr command line utility
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -560,7 +560,7 @@ void do_witness_help(void)
printf(_("WITNESS UNREGISTER\n")); printf(_("WITNESS UNREGISTER\n"));
puts(""); puts("");
printf(_(" \"witness register\" unregisters a witness node.\n")); printf(_(" \"witness unregister\" unregisters a witness node.\n"));
puts(""); puts("");
printf(_(" --dry-run check prerequisites but don't make any changes\n")); printf(_(" --dry-run check prerequisites but don't make any changes\n"));
printf(_(" -F, --force unregister when witness node not running\n")); printf(_(" -F, --force unregister when witness node not running\n"));

View File

@@ -1,6 +1,6 @@
/* /*
* repmgr-action-witness.h * repmgr-action-witness.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/* /*
* repmgr-client-global.h * repmgr-client-global.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -84,7 +84,7 @@ typedef struct
bool fast_checkpoint; bool fast_checkpoint;
bool rsync_only; bool rsync_only;
bool no_upstream_connection; bool no_upstream_connection;
char recovery_min_apply_delay[MAXLEN]; char recovery_min_apply_delay[MAXLEN]; /* overrides setting in repmgr.conf */
char replication_user[MAXLEN]; char replication_user[MAXLEN];
char upstream_conninfo[MAXLEN]; char upstream_conninfo[MAXLEN];
bool without_barman; bool without_barman;
@@ -120,6 +120,7 @@ typedef struct
bool missing_slots; bool missing_slots;
bool has_passfile; bool has_passfile;
bool replication_connection; bool replication_connection;
bool repmgrd;
bool data_directory_config; bool data_directory_config;
bool replication_config_owner; bool replication_config_owner;
bool db_connection; bool db_connection;
@@ -175,7 +176,7 @@ typedef struct
/* "node status" options */ \ /* "node status" options */ \
false, \ false, \
/* "node check" options */ \ /* "node check" options */ \
false, false, false, false, false, false, false, false, false, false, false, false, \ false, false, false, false, false, false, false, false, false, false, false, false, false, \
/* "node rejoin" options */ \ /* "node rejoin" options */ \
"", \ "", \
/* "node service" options */ \ /* "node service" options */ \
@@ -219,7 +220,9 @@ typedef enum
typedef enum typedef enum
{ {
JOIN_UNKNOWN = -1,
JOIN_SUCCESS, JOIN_SUCCESS,
JOIN_COMMAND_FAIL,
JOIN_FAIL_NO_PING, JOIN_FAIL_NO_PING,
JOIN_FAIL_NO_REPLICATION JOIN_FAIL_NO_REPLICATION
} standy_join_status; } standy_join_status;
@@ -282,8 +285,8 @@ extern void get_node_config_directory(char *config_dir_buf);
extern void get_node_data_directory(char *data_dir_buf); extern void get_node_data_directory(char *data_dir_buf);
extern void init_node_record(t_node_info *node_record); extern void init_node_record(t_node_info *node_record);
extern bool can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *reason); extern bool can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *reason);
extern void make_standby_signal_path(char *buf); extern void make_standby_signal_path(const char *data_dir, char *buf);
extern bool write_standby_signal(void); extern bool write_standby_signal(const char *data_dir);
extern bool create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_node_record, PQExpBufferData *error_msg); extern bool create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_node_record, PQExpBufferData *error_msg);
extern bool drop_replication_slot_if_exists(PGconn *conn, int node_id, char *slot_name); extern bool drop_replication_slot_if_exists(PGconn *conn, int node_id, char *slot_name);

View File

@@ -1,7 +1,7 @@
/* /*
* repmgr-client.c - Command interpreter for the repmgr package * repmgr-client.c - Command interpreter for the repmgr package
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This module is a command-line utility to easily setup a cluster of * This module is a command-line utility to easily setup a cluster of
* hot standby servers for an HA environment * hot standby servers for an HA environment
@@ -51,6 +51,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <pwd.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <signal.h> #include <signal.h>
@@ -89,17 +90,22 @@ char pg_bindir[MAXPGPATH] = "";
*/ */
t_node_info target_node_info = T_NODE_INFO_INITIALIZER; 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; static t_user_type ReplicationSlotUser = USER_TYPE_UNKNOWN;
/* Collate command line errors and warnings here for friendlier reporting */ /* Collate command line errors and warnings here for friendlier reporting */
static ItemList cli_errors = {NULL, NULL}; static ItemList cli_errors = {NULL, NULL};
static ItemList cli_warnings = {NULL, NULL}; static ItemList cli_warnings = {NULL, NULL};
static void _determine_replication_slot_user(PGconn *conn, static void _determine_replication_slot_user(PGconn *conn,
t_node_info *upstream_node_record, t_node_info *upstream_node_record,
char **replication_user); char **replication_user);
static PGconn *_get_replication_slot_connection(PGconn *conn,
char *replication_user,
bool *use_replication_protocol);
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@@ -122,7 +128,7 @@ main(int argc, char **argv)
/* /*
* Tell the logger we're a command-line program - this will ensure any * Tell the logger we're a command-line program - this will ensure any
* output logged before the logger is initialized will be formatted * output logged before the logger is initialized will be formatted
* correctly. Can be overriden with "--log-to-file". * correctly. Can be overridden with "--log-to-file".
*/ */
logger_output_mode = OM_COMMAND_LINE; logger_output_mode = OM_COMMAND_LINE;
@@ -438,6 +444,11 @@ main(int argc, char **argv)
runtime_options.replication_conf_only = true; runtime_options.replication_conf_only = true;
break; break;
/* --recovery-min-apply-delay */
case OPT_RECOVERY_MIN_APPLY_DELAY:
strncpy(runtime_options.recovery_min_apply_delay, optarg, sizeof(runtime_options.recovery_min_apply_delay));
break;
/* --verify-backup */ /* --verify-backup */
case OPT_VERIFY_BACKUP: case OPT_VERIFY_BACKUP:
runtime_options.verify_backup = true; runtime_options.verify_backup = true;
@@ -544,6 +555,10 @@ main(int argc, char **argv)
runtime_options.data_directory_config = true; runtime_options.data_directory_config = true;
break; break;
case OPT_REPMGRD:
runtime_options.repmgrd = true;
break;
case OPT_REPLICATION_CONFIG_OWNER: case OPT_REPLICATION_CONFIG_OWNER:
runtime_options.replication_config_owner = true; runtime_options.replication_config_owner = true;
break; break;
@@ -1105,10 +1120,25 @@ main(int argc, char **argv)
exit(SUCCESS); exit(SUCCESS);
} }
check_cli_parameters(action); check_cli_parameters(action);
/*
* Command-line parameter --recovery-min-apply-delay overrides the equivalent
* setting in the config file. Note we'll need to parse it here to handle
* any formatting errors.
*/
if (*runtime_options.recovery_min_apply_delay != '\0')
{
parse_time_unit_parameter("--recovery-min-apply-delay",
runtime_options.recovery_min_apply_delay,
config_file_options.recovery_min_apply_delay,
&cli_errors);
config_file_options.recovery_min_apply_delay_provided = true;
}
/* /*
* Sanity checks for command line parameters completed by now; any further * Sanity checks for command line parameters completed by now; any further
* errors will be runtime ones * errors will be runtime ones
@@ -1169,7 +1199,7 @@ main(int argc, char **argv)
} }
/* /*
* Check for configuration file items which can be overriden by runtime * Check for configuration file items which can be overridden by runtime
* options * options
* ===================================================================== * =====================================================================
*/ */
@@ -2715,7 +2745,7 @@ do_help(void)
* *
* Note: * Note:
* This is one of two places where superuser rights are required. * This is one of two places where superuser rights are required.
* We should also consider possible scenarious where a non-superuser * We should also consider possible scenarios where a non-superuser
* has sufficient privileges to install the extension. * has sufficient privileges to install the extension.
*/ */
@@ -2750,7 +2780,7 @@ create_repmgr_extension(PGconn *conn)
log_detail(_("version %s is installed but newer version %s is available"), log_detail(_("version %s is installed but newer version %s is available"),
extversions.installed_version, extversions.installed_version,
extversions.default_version); extversions.default_version);
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\"")); log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\" in the repmgr database"));
return false; return false;
case REPMGR_INSTALLED: case REPMGR_INSTALLED:
@@ -2916,7 +2946,7 @@ check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *
* PostgreSQL from a particular PostgreSQL release onwards (e.g. 4.4 with PostgreSQL * PostgreSQL from a particular PostgreSQL release onwards (e.g. 4.4 with PostgreSQL
* 12 and later due to recovery.conf removal), set MAX_UNSUPPORTED_VERSION and * 12 and later due to recovery.conf removal), set MAX_UNSUPPORTED_VERSION and
* MAX_UNSUPPORTED_VERSION_NUM in "repmgr.h" to define the first PostgreSQL * MAX_UNSUPPORTED_VERSION_NUM in "repmgr.h" to define the first PostgreSQL
* version which can't be suppored. * version which can't be supported.
*/ */
#ifdef MAX_UNSUPPORTED_VERSION_NUM #ifdef MAX_UNSUPPORTED_VERSION_NUM
if (conn_server_version_num >= MAX_UNSUPPORTED_VERSION_NUM) if (conn_server_version_num >= MAX_UNSUPPORTED_VERSION_NUM)
@@ -3162,6 +3192,11 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
" --exclude=pg_xlog/* --exclude=pg_log/*"); " --exclude=pg_xlog/* --exclude=pg_log/*");
} }
/*
* From PostgreSQL 15, the core server no longer uses pg_stat_tmp,
* but some extensions (e.g. pg_stat_statements) may still do, so
* keep excluding it.
*/
appendPQExpBufferStr(&rsync_flags, appendPQExpBufferStr(&rsync_flags,
" --exclude=pg_stat_tmp/*"); " --exclude=pg_stat_tmp/*");
@@ -3641,11 +3676,11 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
void void
make_standby_signal_path(char *buf) make_standby_signal_path(const char *data_dir, char *buf)
{ {
snprintf(buf, MAXPGPATH, snprintf(buf, MAXPGPATH,
"%s/%s", "%s/%s",
config_file_options.data_directory, data_dir,
STANDBY_SIGNAL_FILE); STANDBY_SIGNAL_FILE);
} }
@@ -3653,13 +3688,15 @@ make_standby_signal_path(char *buf)
* create standby.signal (PostgreSQL 12 and later) * create standby.signal (PostgreSQL 12 and later)
*/ */
bool bool
write_standby_signal(void) write_standby_signal(const char *data_dir)
{ {
char standby_signal_file_path[MAXPGPATH] = ""; char standby_signal_file_path[MAXPGPATH] = "";
FILE *file; FILE *file;
mode_t um; mode_t um;
make_standby_signal_path(standby_signal_file_path); Assert(data_dir != NULL);
make_standby_signal_path(data_dir, standby_signal_file_path);
/* Set umask to 0600 */ /* Set umask to 0600 */
um = umask((~(S_IRUSR | S_IWUSR)) & (S_IRWXG | S_IRWXO)); um = umask((~(S_IRUSR | S_IWUSR)) & (S_IRWXG | S_IRWXO));
@@ -3707,6 +3744,7 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
char *replication_user = NULL; char *replication_user = NULL;
_determine_replication_slot_user(conn, upstream_node_record, &replication_user); _determine_replication_slot_user(conn, upstream_node_record, &replication_user);
/* /*
* If called in --dry-run context, if the replication slot user is not the * If called in --dry-run context, if the replication slot user is not the
* repmgr user, attempt to validate the connection. * repmgr user, attempt to validate the connection.
@@ -3718,7 +3756,7 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
case USER_TYPE_UNKNOWN: case USER_TYPE_UNKNOWN:
log_error("unable to determine user for replication slot creation"); log_error("unable to determine user for replication slot creation");
return false; return false;
case REPMGR_USER: case REPMGR_USER:
log_info(_("replication slots will be created by user \"%s\""), log_info(_("replication slots will be created by user \"%s\""),
PQuser(conn)); PQuser(conn));
return true; return true;
@@ -3764,65 +3802,12 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
PQfinish(superuser_conn); PQfinish(superuser_conn);
} }
} }
} }
/* slot_conn = _get_replication_slot_connection(conn, replication_user, &use_replication_protocol);
* 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;
case REPLICATION_USER_NODE: if (slot_conn == NULL)
case REPLICATION_USER_OPT: return false;
{
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 (use_replication_protocol == true) if (use_replication_protocol == true)
{ {
@@ -3865,34 +3850,55 @@ drop_replication_slot_if_exists(PGconn *conn, int node_id, char *slot_name)
if (record_status != RECORD_FOUND) if (record_status != RECORD_FOUND)
{ {
/* this is not a bad good thing */ /* no slot, no problem */
log_verbose(LOG_INFO, log_verbose(LOG_INFO,
_("slot \"%s\" does not exist on node %i, nothing to remove"), _("slot \"%s\" does not exist on node %i, nothing to remove"),
slot_name, node_id); slot_name, node_id);
return true; 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 = NULL;
slot_conn = _get_replication_slot_connection(conn,
replication_user,
&use_replication_protocol);
if (use_replication_protocol == true)
{
success = drop_replication_slot_replprot(conn, slot_name);
}
else
{
success = drop_replication_slot_sql(conn, slot_name);
}
if (success == true)
{ {
log_notice(_("replication slot \"%s\" deleted on node %i"), slot_name, node_id); log_notice(_("replication slot \"%s\" deleted on node %i"), slot_name, node_id);
} }
else else
{ {
log_error(_("unable to delete replication slot \"%s\" on node %i"), slot_name, node_id); log_error(_("unable to delete replication slot \"%s\" on node %i"), slot_name, node_id);
success = false;
} }
}
/* if (slot_conn != conn)
* If an active replication slot exists, call Houston as we have a PQfinish(slot_conn);
* problem.
*/
else
{
log_warning(_("replication slot \"%s\" is still active on node %i"), slot_name, node_id);
success = false;
} }
return success; return success;
@@ -3954,10 +3960,84 @@ _determine_replication_slot_user(PGconn *conn, t_node_info *upstream_node_record
ReplicationSlotUser = REPLICATION_USER_NODE; ReplicationSlotUser = REPLICATION_USER_NODE;
*replication_user = upstream_node_record->repluser; *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 replication slot creation");
return NULL;
case REPMGR_USER:
slot_conn = conn;
log_info(_("creating 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 create replication connection as user \"%s\""),
runtime_options.replication_user);
log_detail("%s", PQerrorMessage(slot_conn));
PQfinish(slot_conn);
return NULL;
}
*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 NULL;
}
log_info(_("creating replication slot as superuser \"%s\""),
runtime_options.superuser);
}
break;
}
return slot_conn;
}
bool bool
check_replication_slots_available(int node_id, PGconn* conn) check_replication_slots_available(int node_id, PGconn* conn)
{ {
@@ -4066,7 +4146,7 @@ check_standby_join(PGconn *upstream_conn, t_node_info *upstream_node_record, t_n
if (node_attached == NODE_NOT_ATTACHED) if (node_attached == NODE_NOT_ATTACHED)
{ {
log_detail(_("node \"%s\" (ID: %i) is currrently attached to its upstream node in state \"%s\""), log_detail(_("node \"%s\" (ID: %i) is currently attached to its upstream node in state \"%s\""),
upstream_node_record->node_name, upstream_node_record->node_name,
standby_node_record->node_id, standby_node_record->node_id,
node_state); node_state);

View File

@@ -1,6 +1,6 @@
/* /*
* repmgr-client.h * repmgr-client.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -99,6 +99,8 @@
#define OPT_REPLICATION_CONFIG_OWNER 1046 #define OPT_REPLICATION_CONFIG_OWNER 1046
#define OPT_DB_CONNECTION 1047 #define OPT_DB_CONNECTION 1047
#define OPT_VERIFY_BACKUP 1048 #define OPT_VERIFY_BACKUP 1048
#define OPT_RECOVERY_MIN_APPLY_DELAY 1049
#define OPT_REPMGRD 1050
/* These options are for internal use only */ /* These options are for internal use only */
#define OPT_CONFIG_ARCHIVE_DIR 2001 #define OPT_CONFIG_ARCHIVE_DIR 2001
@@ -164,6 +166,7 @@ static struct option long_options[] =
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN}, {"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
{"replication-conf-only", no_argument, NULL, OPT_REPLICATION_CONF_ONLY}, {"replication-conf-only", no_argument, NULL, OPT_REPLICATION_CONF_ONLY},
{"verify-backup", no_argument, NULL, OPT_VERIFY_BACKUP }, {"verify-backup", no_argument, NULL, OPT_VERIFY_BACKUP },
{"recovery-min-apply-delay", required_argument, NULL, OPT_RECOVERY_MIN_APPLY_DELAY },
/* deprecate this once Pg11 and earlier are unsupported */ /* deprecate this once Pg11 and earlier are unsupported */
{"recovery-conf-only", no_argument, NULL, OPT_REPLICATION_CONF_ONLY}, {"recovery-conf-only", no_argument, NULL, OPT_REPLICATION_CONF_ONLY},
@@ -191,6 +194,7 @@ static struct option long_options[] =
{"role", no_argument, NULL, OPT_ROLE}, {"role", no_argument, NULL, OPT_ROLE},
{"slots", no_argument, NULL, OPT_SLOTS}, {"slots", no_argument, NULL, OPT_SLOTS},
{"missing-slots", no_argument, NULL, OPT_MISSING_SLOTS}, {"missing-slots", no_argument, NULL, OPT_MISSING_SLOTS},
{"repmgrd", no_argument, NULL, OPT_REPMGRD},
{"has-passfile", no_argument, NULL, OPT_HAS_PASSFILE}, {"has-passfile", no_argument, NULL, OPT_HAS_PASSFILE},
{"replication-connection", no_argument, NULL, OPT_REPL_CONN}, {"replication-connection", no_argument, NULL, OPT_REPL_CONN},
{"data-directory-config", no_argument, NULL, OPT_DATA_DIRECTORY_CONFIG}, {"data-directory-config", no_argument, NULL, OPT_DATA_DIRECTORY_CONFIG},

123
repmgr.c
View File

@@ -1,7 +1,7 @@
/* /*
* repmgr.c - repmgr extension * repmgr.c - repmgr extension
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This is the actual extension code; see repmgr-client.c for the code which * This is the actual extension code; see repmgr-client.c for the code which
* generates the repmgr binary * generates the repmgr binary
@@ -80,67 +80,37 @@ typedef struct repmgrdSharedState
static repmgrdSharedState *shared_state = NULL; static repmgrdSharedState *shared_state = NULL;
#if (PG_VERSION_NUM >= 150000)
static shmem_request_hook_type prev_shmem_request_hook = NULL;
#endif
static shmem_startup_hook_type prev_shmem_startup_hook = NULL; static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
void _PG_init(void); void _PG_init(void);
void _PG_fini(void); void _PG_fini(void);
#if (PG_VERSION_NUM >= 150000)
static void repmgr_shmem_request(void);
#endif
static void repmgr_shmem_startup(void); static void repmgr_shmem_startup(void);
Datum set_local_node_id(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(repmgr_set_local_node_id);
PG_FUNCTION_INFO_V1(set_local_node_id); PG_FUNCTION_INFO_V1(repmgr_get_local_node_id);
PG_FUNCTION_INFO_V1(repmgr_standby_set_last_updated);
Datum get_local_node_id(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(repmgr_standby_get_last_updated);
PG_FUNCTION_INFO_V1(get_local_node_id); PG_FUNCTION_INFO_V1(repmgr_set_upstream_last_seen);
PG_FUNCTION_INFO_V1(repmgr_get_upstream_last_seen);
Datum standby_set_last_updated(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(repmgr_get_upstream_node_id);
PG_FUNCTION_INFO_V1(standby_set_last_updated); PG_FUNCTION_INFO_V1(repmgr_set_upstream_node_id);
PG_FUNCTION_INFO_V1(repmgr_notify_follow_primary);
Datum standby_get_last_updated(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(repmgr_get_new_primary);
PG_FUNCTION_INFO_V1(standby_get_last_updated); PG_FUNCTION_INFO_V1(repmgr_reset_voting_status);
Datum set_upstream_last_seen(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(set_upstream_last_seen);
Datum get_upstream_last_seen(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(get_upstream_last_seen);
Datum get_upstream_node_id(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(get_upstream_node_id);
Datum set_upstream_node_id(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(set_upstream_node_id);
Datum notify_follow_primary(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(notify_follow_primary);
Datum get_new_primary(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(get_new_primary);
Datum reset_voting_status(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(reset_voting_status);
Datum set_repmgrd_pid(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(set_repmgrd_pid); PG_FUNCTION_INFO_V1(set_repmgrd_pid);
Datum get_repmgrd_pid(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(get_repmgrd_pid); PG_FUNCTION_INFO_V1(get_repmgrd_pid);
Datum get_repmgrd_pidfile(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(get_repmgrd_pidfile); PG_FUNCTION_INFO_V1(get_repmgrd_pidfile);
Datum repmgrd_is_running(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(repmgrd_is_running); PG_FUNCTION_INFO_V1(repmgrd_is_running);
Datum repmgrd_pause(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(repmgrd_pause); PG_FUNCTION_INFO_V1(repmgrd_pause);
Datum repmgrd_is_paused(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(repmgrd_is_paused); PG_FUNCTION_INFO_V1(repmgrd_is_paused);
PG_FUNCTION_INFO_V1(repmgr_get_wal_receiver_pid);
Datum get_wal_receiver_pid(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(get_wal_receiver_pid);
/* /*
@@ -152,19 +122,27 @@ _PG_init(void)
if (!process_shared_preload_libraries_in_progress) if (!process_shared_preload_libraries_in_progress)
return; return;
#if (PG_VERSION_NUM < 150000)
RequestAddinShmemSpace(MAXALIGN(sizeof(repmgrdSharedState))); RequestAddinShmemSpace(MAXALIGN(sizeof(repmgrdSharedState)));
#if (PG_VERSION_NUM >= 90600) #if (PG_VERSION_NUM >= 90600)
RequestNamedLWLockTranche(TRANCHE_NAME, 1); RequestNamedLWLockTranche(TRANCHE_NAME, 1);
#else #else
RequestAddinLWLocks(1); RequestAddinLWLocks(1);
#endif
#endif #endif
/* /*
* Install hooks. * Install hooks.
*/ */
#if (PG_VERSION_NUM >= 150000)
prev_shmem_request_hook = shmem_request_hook;
shmem_request_hook = repmgr_shmem_request;
#endif
prev_shmem_startup_hook = shmem_startup_hook; prev_shmem_startup_hook = shmem_startup_hook;
shmem_startup_hook = repmgr_shmem_startup; shmem_startup_hook = repmgr_shmem_startup;
} }
@@ -175,12 +153,31 @@ void
_PG_fini(void) _PG_fini(void)
{ {
/* Uninstall hook */ /* Uninstall hook */
#if (PG_VERSION_NUM >= 150000)
shmem_request_hook = prev_shmem_request_hook;
#endif
shmem_startup_hook = prev_shmem_startup_hook; shmem_startup_hook = prev_shmem_startup_hook;
} }
#if (PG_VERSION_NUM >= 150000)
/*
* shmem_requst_hook: request shared memory
*/
static void
repmgr_shmem_request(void)
{
if (prev_shmem_request_hook)
prev_shmem_request_hook();
RequestAddinShmemSpace(MAXALIGN(sizeof(repmgrdSharedState)));
RequestNamedLWLockTranche(TRANCHE_NAME, 1);
}
#endif
/* /*
* shmem_startup hook: allocate or attach to shared memory, * shmem_ hook: allocate or attach to shared memory,
*/ */
static void static void
repmgr_shmem_startup(void) repmgr_shmem_startup(void)
@@ -194,7 +191,7 @@ repmgr_shmem_startup(void)
shared_state = NULL; shared_state = NULL;
/* /*
* Create or attach to the shared memory state, including hash table * Create or attach to the shared memory state
*/ */
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
@@ -233,7 +230,7 @@ repmgr_shmem_startup(void)
/* ==================== */ /* ==================== */
Datum Datum
set_local_node_id(PG_FUNCTION_ARGS) repmgr_set_local_node_id(PG_FUNCTION_ARGS)
{ {
int local_node_id = UNKNOWN_NODE_ID; int local_node_id = UNKNOWN_NODE_ID;
int stored_node_id = UNKNOWN_NODE_ID; int stored_node_id = UNKNOWN_NODE_ID;
@@ -303,7 +300,7 @@ set_local_node_id(PG_FUNCTION_ARGS)
Datum Datum
get_local_node_id(PG_FUNCTION_ARGS) repmgr_get_local_node_id(PG_FUNCTION_ARGS)
{ {
int local_node_id = UNKNOWN_NODE_ID; int local_node_id = UNKNOWN_NODE_ID;
@@ -320,7 +317,7 @@ get_local_node_id(PG_FUNCTION_ARGS)
/* update and return last updated with current timestamp */ /* update and return last updated with current timestamp */
Datum Datum
standby_set_last_updated(PG_FUNCTION_ARGS) repmgr_standby_set_last_updated(PG_FUNCTION_ARGS)
{ {
TimestampTz last_updated = GetCurrentTimestamp(); TimestampTz last_updated = GetCurrentTimestamp();
@@ -337,7 +334,7 @@ standby_set_last_updated(PG_FUNCTION_ARGS)
/* get last updated timestamp */ /* get last updated timestamp */
Datum Datum
standby_get_last_updated(PG_FUNCTION_ARGS) repmgr_standby_get_last_updated(PG_FUNCTION_ARGS)
{ {
TimestampTz last_updated; TimestampTz last_updated;
@@ -354,7 +351,7 @@ standby_get_last_updated(PG_FUNCTION_ARGS)
Datum Datum
set_upstream_last_seen(PG_FUNCTION_ARGS) repmgr_set_upstream_last_seen(PG_FUNCTION_ARGS)
{ {
int upstream_node_id = UNKNOWN_NODE_ID; int upstream_node_id = UNKNOWN_NODE_ID;
@@ -377,7 +374,7 @@ set_upstream_last_seen(PG_FUNCTION_ARGS)
Datum Datum
get_upstream_last_seen(PG_FUNCTION_ARGS) repmgr_get_upstream_last_seen(PG_FUNCTION_ARGS)
{ {
long secs; long secs;
int microsecs; int microsecs;
@@ -411,7 +408,7 @@ get_upstream_last_seen(PG_FUNCTION_ARGS)
Datum Datum
get_upstream_node_id(PG_FUNCTION_ARGS) repmgr_get_upstream_node_id(PG_FUNCTION_ARGS)
{ {
int upstream_node_id = UNKNOWN_NODE_ID; int upstream_node_id = UNKNOWN_NODE_ID;
@@ -426,7 +423,7 @@ get_upstream_node_id(PG_FUNCTION_ARGS)
} }
Datum Datum
set_upstream_node_id(PG_FUNCTION_ARGS) repmgr_set_upstream_node_id(PG_FUNCTION_ARGS)
{ {
int upstream_node_id = UNKNOWN_NODE_ID; int upstream_node_id = UNKNOWN_NODE_ID;
int local_node_id = UNKNOWN_NODE_ID; int local_node_id = UNKNOWN_NODE_ID;
@@ -462,7 +459,7 @@ set_upstream_node_id(PG_FUNCTION_ARGS)
Datum Datum
notify_follow_primary(PG_FUNCTION_ARGS) repmgr_notify_follow_primary(PG_FUNCTION_ARGS)
{ {
int primary_node_id = UNKNOWN_NODE_ID; int primary_node_id = UNKNOWN_NODE_ID;
@@ -505,7 +502,7 @@ notify_follow_primary(PG_FUNCTION_ARGS)
Datum Datum
get_new_primary(PG_FUNCTION_ARGS) repmgr_get_new_primary(PG_FUNCTION_ARGS)
{ {
int new_primary_node_id = UNKNOWN_NODE_ID; int new_primary_node_id = UNKNOWN_NODE_ID;
@@ -527,7 +524,7 @@ get_new_primary(PG_FUNCTION_ARGS)
Datum Datum
reset_voting_status(PG_FUNCTION_ARGS) repmgr_reset_voting_status(PG_FUNCTION_ARGS)
{ {
if (!shared_state) if (!shared_state)
PG_RETURN_NULL(); PG_RETURN_NULL();
@@ -735,7 +732,7 @@ repmgrd_is_paused(PG_FUNCTION_ARGS)
Datum Datum
get_wal_receiver_pid(PG_FUNCTION_ARGS) repmgr_get_wal_receiver_pid(PG_FUNCTION_ARGS)
{ {
int wal_receiver_pid; int wal_receiver_pid;

View File

@@ -69,7 +69,7 @@
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
#replication_user='repmgr' # User to make replication connections with, if not set #replication_user='repmgr' # User to make replication connections with, if not set
# defaults to the user defined in "conninfo". # defaults to the user defined in "conninfo".
#replication_type='physical' # Must "physical" (the default). #replication_type='physical' # Must "physical" (the default).
@@ -238,7 +238,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
#primary_follow_timeout=60 # The max length of time (in seconds) to wait #primary_follow_timeout=60 # The max length of time (in seconds) to wait
# for the new primary to become available # for the new primary to become available
#standby_follow_timeout=15 # The max length of time (in seconds) to wait #standby_follow_timeout=30 # The max length of time (in seconds) to wait
# for the standby to connect to the primary # for the standby to connect to the primary
#standby_follow_restart=false # Restart the standby instead of sending a SIGHUP #standby_follow_restart=false # Restart the standby instead of sending a SIGHUP
# (only for PostgreSQL 13 and later) # (only for PostgreSQL 13 and later)
@@ -301,7 +301,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
#connection_check_type=ping # How to check availability of the upstream node; valid options: #connection_check_type=ping # How to check availability of the upstream node; valid options:
# 'ping': use PQping() to check if the node is accepting connections # 'ping': use PQping() to check if the node is accepting connections
# 'connection': execute a throwaway query on the current connection # 'connection': attempt to make a new connection to the node
# 'query': execute an SQL statement on the node via the existing connection # 'query': execute an SQL statement on the node via the existing connection
#reconnect_attempts=6 # Number of attempts which will be made to reconnect to an unreachable #reconnect_attempts=6 # Number of attempts which will be made to reconnect to an unreachable
# primary (or other upstream node) # primary (or other upstream node)
@@ -314,7 +314,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
#follow_command='' # command repmgrd executes when instructing a standby to follow a new primary; #follow_command='' # command repmgrd executes when instructing a standby to follow a new primary;
# use something like: # use something like:
# #
# repmgr standby follow -f /etc/repmgr.conf -W --upstream-node-id=%n # repmgr standby follow -f /etc/repmgr.conf --upstream-node-id=%n
# #
#primary_notification_timeout=60 # Interval (in seconds) which repmgrd on a standby #primary_notification_timeout=60 # Interval (in seconds) which repmgrd on a standby
# will wait for a notification from the new primary, # will wait for a notification from the new primary,
@@ -323,7 +323,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
# for the the local node to restart and become ready to accept connections after # for the the local node to restart and become ready to accept connections after
# executing "follow_command" (defaults to the value set in "standby_reconnect_timeout") # executing "follow_command" (defaults to the value set in "standby_reconnect_timeout")
#monitoring_history=no # Whether to write monitoring data to the "montoring_history" table #monitoring_history=no # Whether to write monitoring data to the "monitoring_history" table
#monitor_interval_secs=2 # Interval (in seconds) at which to write monitoring data #monitor_interval_secs=2 # Interval (in seconds) at which to write monitoring data
#degraded_monitoring_timeout=-1 # Interval (in seconds) after which repmgrd will terminate if the #degraded_monitoring_timeout=-1 # Interval (in seconds) after which repmgrd will terminate if the
# server(s) being monitored are no longer available. -1 (default) # server(s) being monitored are no longer available. -1 (default)
@@ -337,6 +337,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
# "--no-pid-file" will force PID file creation to be skipped. # "--no-pid-file" will force PID file creation to be skipped.
# Note: there is normally no need to set this, particularly if # Note: there is normally no need to set this, particularly if
# repmgr was installed from packages. # repmgr was installed from packages.
#repmgrd_exit_on_inactive_node=false # If "true", and the node record is marked as "inactive", abort repmgrd startup
#standby_disconnect_on_failover=false # If "true", in a failover situation wait for all standbys to #standby_disconnect_on_failover=false # If "true", in a failover situation wait for all standbys to
# disconnect their WAL receivers before electing a new primary # disconnect their WAL receivers before electing a new primary
# (PostgreSQL 9.5 and later only; repmgr user must be a superuser for this) # (PostgreSQL 9.5 and later only; repmgr user must be a superuser for this)
@@ -397,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. # 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_start_command = ''
#service_stop_command = '' #service_stop_command = ''

View File

@@ -1,8 +1,7 @@
# repmgr extension # repmgr extension
comment = 'Replication manager for PostgreSQL' comment = 'Replication manager for PostgreSQL'
default_version = '5.2' default_version = '5.4'
module_pathname = '$libdir/repmgr' module_pathname = '$libdir/repmgr'
relocatable = false relocatable = false
schema = repmgr schema = repmgr

View File

@@ -1,6 +1,6 @@
/* /*
* repmgr.h * repmgr.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -77,8 +77,6 @@
#define MIN_SUPPORTED_VERSION "9.4" #define MIN_SUPPORTED_VERSION "9.4"
#define MIN_SUPPORTED_VERSION_NUM 90400 #define MIN_SUPPORTED_VERSION_NUM 90400
#define REPLICATION_TYPE_PHYSICAL 1
#define UNKNOWN_SERVER_VERSION_NUM -1 #define UNKNOWN_SERVER_VERSION_NUM -1
#define UNKNOWN_REPMGR_VERSION_NUM -1 #define UNKNOWN_REPMGR_VERSION_NUM -1
@@ -122,6 +120,7 @@
#define DEFAULT_NODE_REJOIN_TIMEOUT 60 /* seconds */ #define DEFAULT_NODE_REJOIN_TIMEOUT 60 /* seconds */
#define DEFAULT_ARCHIVE_READY_WARNING 16 /* WAL files */ #define DEFAULT_ARCHIVE_READY_WARNING 16 /* WAL files */
#define DEFAULT_ARCHIVE_READY_CRITICAL 128 /* WAL files */ #define DEFAULT_ARCHIVE_READY_CRITICAL 128 /* WAL files */
#define DEFAULT_REPLICATION_TYPE REPLICATION_TYPE_PHYSICAL
#define DEFAULT_REPLICATION_LAG_WARNING 300 /* seconds */ #define DEFAULT_REPLICATION_LAG_WARNING 300 /* seconds */
#define DEFAULT_REPLICATION_LAG_CRITICAL 600 /* seconds */ #define DEFAULT_REPLICATION_LAG_CRITICAL 600 /* seconds */
#define DEFAULT_WITNESS_SYNC_INTERVAL 15 /* seconds */ #define DEFAULT_WITNESS_SYNC_INTERVAL 15 /* seconds */
@@ -136,6 +135,7 @@
#define DEFAULT_ASYNC_QUERY_TIMEOUT 60 /* seconds */ #define DEFAULT_ASYNC_QUERY_TIMEOUT 60 /* seconds */
#define DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT 60 /* seconds */ #define DEFAULT_PRIMARY_NOTIFICATION_TIMEOUT 60 /* seconds */
#define DEFAULT_REPMGRD_STANDBY_STARTUP_TIMEOUT -1 /*seconds */ #define DEFAULT_REPMGRD_STANDBY_STARTUP_TIMEOUT -1 /*seconds */
#define DEFAULT_REPMGRD_EXIT_ON_INACTIVE_NODE false,
#define DEFAULT_STANDBY_DISCONNECT_ON_FAILOVER false #define DEFAULT_STANDBY_DISCONNECT_ON_FAILOVER false
#define DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT 30 /* seconds */ #define DEFAULT_SIBLING_NODES_DISCONNECT_TIMEOUT 30 /* seconds */
#define DEFAULT_CONNECTION_CHECK_TYPE CHECK_PING #define DEFAULT_CONNECTION_CHECK_TYPE CHECK_PING

View File

@@ -1,5 +1,7 @@
#define REPMGR_VERSION_DATE "" #define REPMGR_VERSION_DATE ""
#define REPMGR_VERSION "5.2.0" #define REPMGR_VERSION "5.4dev"
#define REPMGR_VERSION_NUM 50200 #define REPMGR_VERSION_NUM 50400
#define REPMGR_RELEASE_DATE "2020-10-22" #define REPMGR_EXTENSION_VERSION "5.4"
#define REPMGR_EXTENSION_NUM 50400
#define REPMGR_RELEASE_DATE "2022-XX-XX"
#define PG_ACTUAL_VERSION_NUM #define PG_ACTUAL_VERSION_NUM

View File

@@ -1,7 +1,7 @@
/* /*
* repmgrd-physical.c - physical (streaming) replication functionality for repmgrd * repmgrd-physical.c - physical (streaming) replication functionality for repmgrd
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -169,45 +169,126 @@ handle_sigint_physical(SIGNAL_ARGS)
/* perform some sanity checks on the node's configuration */ /* perform some sanity checks on the node's configuration */
void void
do_physical_node_check(void) do_physical_node_check(PGconn *conn)
{ {
/* /*
* Check if node record is active - if not, and `failover=automatic`, the * If node record is "inactive"; if not, attempt to set it to "active".
* node won't be considered as a promotion candidate; this often happens
* when a failed primary is recloned and the node was not re-registered,
* giving the impression failover capability is there when it's not. In
* this case abort with an error and a hint about registering.
* *
* If `failover=manual`, repmgrd can continue to passively monitor the * Usually it will have become inactive due to e.g. a standby being shut down
* node, but we should nevertheless issue a warning and the same hint. * while repmgrd was running in an unpaused state. In this case it's
* perfectly reasonable to automatically mark the node as "active".
*/ */
if (local_node_info.active == false) if (local_node_info.active == false)
{ {
char *hint = "Check that \"repmgr (primary|standby) register\" was executed for this node"; char *hint = "Check that \"repmgr (primary|standby) register\" was executed for this node";
RecoveryType recovery_type = get_recovery_type(conn);
switch (config_file_options.failover) /*
* If the local node's recovery status is incompatible with its registered
* status, e.g. registered as primary but running as a standby, refuse to start.
*
* This typically happens when a failed primary is recloned but the node was not
* re-registered, leaving the cluster in a potentially ambiguous state. In
* this case it would not be possible or desirable to attempt to set the
* node to active; the user should ensure the cluster is in the correct state.
*/
if (recovery_type != RECTYPE_UNKNOWN && local_node_info.type != UNKNOWN)
{ {
/* "failover" is an enum, all values should be covered here */ bool require_reregister = false;
PQExpBufferData event_details;
initPQExpBuffer(&event_details);
case FAILOVER_AUTOMATIC: if (recovery_type == RECTYPE_STANDBY && local_node_info.type != STANDBY)
log_error(_("this node is marked as inactive and cannot be used as a failover target")); {
appendPQExpBuffer(&event_details,
_("node is registered as a %s but running as a standby"),
get_node_type_string(local_node_info.type));
require_reregister = true;
}
else if (recovery_type == RECTYPE_PRIMARY && local_node_info.type == STANDBY)
{
log_error(_("node is registered as a standby but running as a %s"), get_node_type_string(local_node_info.type));
require_reregister = true;
}
if (require_reregister == true)
{
log_error("%s", event_details.data);
log_hint(_("%s"), hint); log_hint(_("%s"), hint);
create_event_notification(NULL, create_event_notification(NULL,
&config_file_options, &config_file_options,
config_file_options.node_id, config_file_options.node_id,
"repmgrd_shutdown", "repmgrd_start",
false, false,
"node is inactive and cannot be used as a failover target"); event_details.data);
termPQExpBuffer(&event_details);
terminate(ERR_BAD_CONFIG); terminate(ERR_BAD_CONFIG);
break; }
case FAILOVER_MANUAL: termPQExpBuffer(&event_details);
log_warning(_("this node is marked as inactive and will be passively monitored only")); }
log_hint(_("%s"), hint);
break; /*
* Attempt to set node record active (unless explicitly configured not to)
*/
log_notice(_("setting node record for node \"%s\" (ID: %i) to \"active\""),
local_node_info.node_name,
local_node_info.node_id);
if (config_file_options.repmgrd_exit_on_inactive_node == false)
{
PGconn *primary_conn = get_primary_connection(conn, NULL, NULL);
bool success = true;
if (PQstatus(primary_conn) != CONNECTION_OK)
{
log_error(_("unable to connect to the primary node to activate the node record"));
success = false;
}
else
{
success = update_node_record_set_active(primary_conn, local_node_info.node_id, true);
PQfinish(primary_conn);
}
if (success == true)
{
local_node_info.active = true;
}
}
/*
* Corner-case where it was not possible to set the node to "active"
*/
if (local_node_info.active == false)
{
switch (config_file_options.failover)
{
/* "failover" is an enum, all values should be covered here */
case FAILOVER_AUTOMATIC:
log_error(_("this node is marked as inactive and cannot be used as a failover target"));
log_hint(_("%s"), hint);
create_event_notification(NULL,
&config_file_options,
config_file_options.node_id,
"repmgrd_start",
false,
"node is inactive and cannot be used as a failover target");
terminate(ERR_BAD_CONFIG);
break;
case FAILOVER_MANUAL:
log_warning(_("this node is marked as inactive and will be passively monitored only"));
log_hint(_("%s"), hint);
break;
}
} }
} }
@@ -504,6 +585,7 @@ monitor_streaming_primary(void)
if (is_server_available(local_node_info.conninfo) == true) if (is_server_available(local_node_info.conninfo) == true)
{ {
close_connection(&local_conn);
local_conn = establish_db_connection(local_node_info.conninfo, false); local_conn = establish_db_connection(local_node_info.conninfo, false);
if (PQstatus(local_conn) != CONNECTION_OK) if (PQstatus(local_conn) != CONNECTION_OK)
@@ -737,7 +819,7 @@ check_primary_status(int degraded_monitoring_elapsed)
/* refresh our copy of the node record from the primary */ /* refresh our copy of the node record from the primary */
record_status = get_node_record(new_primary_conn, config_file_options.node_id, &local_node_info); record_status = get_node_record(new_primary_conn, config_file_options.node_id, &local_node_info);
/* this is unlikley to happen */ /* this is unlikely to happen */
if (record_status != RECORD_FOUND) if (record_status != RECORD_FOUND)
{ {
log_warning(_("unable to retrieve local node record from primary node %i"), primary_node_id); log_warning(_("unable to retrieve local node record from primary node %i"), primary_node_id);
@@ -1111,7 +1193,7 @@ execute_child_nodes_disconnect_command(NodeInfoList *db_child_node_records, t_ch
/* calculate number of connected child nodes */ /* calculate number of connected child nodes */
for (cell = db_child_node_records->head; cell; cell = cell->next) for (cell = db_child_node_records->head; cell; cell = cell->next)
{ {
/* exclude witness server from total, if necessay */ /* exclude witness server from total, if necessary */
if (config_file_options.child_nodes_connected_include_witness == false && if (config_file_options.child_nodes_connected_include_witness == false &&
cell->node_info->type == WITNESS) cell->node_info->type == WITNESS)
continue; continue;
@@ -1149,7 +1231,7 @@ execute_child_nodes_disconnect_command(NodeInfoList *db_child_node_records, t_ch
instr_time current_time = current_time_base; instr_time current_time = current_time_base;
int seconds_since_detached; int seconds_since_detached;
/* exclude witness server from calculatin if neccessary */ /* exclude witness server from calculation, if requested */
if (config_file_options.child_nodes_connected_include_witness == false && if (config_file_options.child_nodes_connected_include_witness == false &&
child_node_rec->type == WITNESS) child_node_rec->type == WITNESS)
continue; continue;
@@ -1732,7 +1814,10 @@ monitor_streaming_standby(void)
if (upstream_check_result == true) if (upstream_check_result == true)
{ {
if (config_file_options.connection_check_type != CHECK_QUERY) if (config_file_options.connection_check_type != CHECK_QUERY)
{
close_connection(&upstream_conn);
upstream_conn = establish_db_connection(upstream_node_info.conninfo, false); upstream_conn = establish_db_connection(upstream_node_info.conninfo, false);
}
if (PQstatus(upstream_conn) == CONNECTION_OK) if (PQstatus(upstream_conn) == CONNECTION_OK)
{ {
@@ -1813,6 +1898,7 @@ monitor_streaming_standby(void)
int former_upstream_node_id = local_node_info.upstream_node_id; int former_upstream_node_id = local_node_info.upstream_node_id;
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER; NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
PQExpBufferData event_details; PQExpBufferData event_details;
t_event_info event_info = T_EVENT_INFO_INITIALIZER;
update_node_record_set_primary(local_conn, local_node_info.node_id); update_node_record_set_primary(local_conn, local_node_info.node_id);
record_status = get_node_record(local_conn, local_node_info.node_id, &local_node_info); record_status = get_node_record(local_conn, local_node_info.node_id, &local_node_info);
@@ -1825,12 +1911,16 @@ monitor_streaming_standby(void)
initPQExpBuffer(&event_details); initPQExpBuffer(&event_details);
appendPQExpBufferStr(&event_details, appendPQExpBufferStr(&event_details,
_("promotion command failed but promotion completed successfully")); _("promotion command failed but promotion completed successfully"));
create_event_notification(local_conn,
&config_file_options, event_info.node_id = former_upstream_node_id;
local_node_info.node_id,
"repmgrd_failover_promote", create_event_notification_extended(local_conn,
true, &config_file_options,
event_details.data); local_node_info.node_id,
"repmgrd_failover_promote",
true,
event_details.data,
&event_info);
termPQExpBuffer(&event_details); termPQExpBuffer(&event_details);
@@ -2292,6 +2382,18 @@ monitor_streaming_witness(void)
log_warning(_("unable to retrieve node record from primary")); 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); initPQExpBuffer(&event_details);
appendPQExpBuffer(&event_details, appendPQExpBuffer(&event_details,
@@ -2460,8 +2562,10 @@ monitor_streaming_witness(void)
if (check_upstream_connection(&primary_conn, upstream_node_info.conninfo, NULL) == true) if (check_upstream_connection(&primary_conn, upstream_node_info.conninfo, NULL) == true)
{ {
if (config_file_options.connection_check_type != CHECK_QUERY) if (config_file_options.connection_check_type != CHECK_QUERY)
{
close_connection(&primary_conn);
primary_conn = establish_db_connection(upstream_node_info.conninfo, false); primary_conn = establish_db_connection(upstream_node_info.conninfo, false);
}
if (PQstatus(primary_conn) == CONNECTION_OK) if (PQstatus(primary_conn) == CONNECTION_OK)
{ {
PQExpBufferData event_details; PQExpBufferData event_details;
@@ -2758,6 +2862,7 @@ do_primary_failover(void)
bool final_result = false; bool final_result = false;
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER; NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
int new_primary_id = UNKNOWN_NODE_ID; int new_primary_id = UNKNOWN_NODE_ID;
bool standby_disconnect_on_failover = false;
/* /*
* Double-check status of the local connection * Double-check status of the local connection
@@ -2770,20 +2875,20 @@ do_primary_failover(void)
*/ */
if (config_file_options.standby_disconnect_on_failover == true) if (config_file_options.standby_disconnect_on_failover == true)
{ {
NodeInfoListCell *cell = NULL; /*
NodeInfoList check_sibling_nodes = T_NODE_INFO_LIST_INITIALIZER; * Determine whether we can actually disable the walsender; this depends
int i; * 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); disable_wal_receiver(local_conn);
/* /*
@@ -2867,7 +2972,7 @@ do_primary_failover(void)
log_debug("election result: %s", _print_election_result(election_result)); log_debug("election result: %s", _print_election_result(election_result));
/* Reenable WAL receiver, if disabled */ /* 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 */ /* adjust "wal_retrieve_retry_interval" but don't wait for WAL receiver to start */
enable_wal_receiver(local_conn, false); enable_wal_receiver(local_conn, false);
@@ -2975,7 +3080,6 @@ do_primary_failover(void)
t_node_info new_primary = T_NODE_INFO_INITIALIZER; t_node_info new_primary = T_NODE_INFO_INITIALIZER;
RecordStatus record_status = RECORD_NOT_FOUND; RecordStatus record_status = RECORD_NOT_FOUND;
PGconn *new_primary_conn;
record_status = get_node_record(local_conn, new_primary_id, &new_primary); record_status = get_node_record(local_conn, new_primary_id, &new_primary);
@@ -2987,6 +3091,7 @@ do_primary_failover(void)
else else
{ {
PQExpBufferData event_details; PQExpBufferData event_details;
PGconn *new_primary_conn;
initPQExpBuffer(&event_details); initPQExpBuffer(&event_details);
appendPQExpBuffer(&event_details, appendPQExpBuffer(&event_details,
@@ -3007,7 +3112,6 @@ do_primary_failover(void)
event_details.data); event_details.data);
close_connection(&new_primary_conn); close_connection(&new_primary_conn);
termPQExpBuffer(&event_details); termPQExpBuffer(&event_details);
} }
failover_state = FAILOVER_STATE_REQUIRES_MANUAL_FAILOVER; failover_state = FAILOVER_STATE_REQUIRES_MANUAL_FAILOVER;
} }
@@ -3254,7 +3358,7 @@ update_monitoring_history(void)
* *
* Attach cascaded standby to another node, currently the primary. * Attach cascaded standby to another node, currently the primary.
* *
* Note that in contrast to a primary failover, where one of the downstrean * Note that in contrast to a primary failover, where one of the downstream
* standby nodes will become a primary, a cascaded standby failover (where the * standby nodes will become a primary, a cascaded standby failover (where the
* upstream standby has gone away) is "just" a case of attaching the standby to * upstream standby has gone away) is "just" a case of attaching the standby to
* another node. * another node.
@@ -3674,6 +3778,7 @@ promote_self(void)
{ {
PQExpBufferData event_details; PQExpBufferData event_details;
t_event_info event_info = T_EVENT_INFO_INITIALIZER;
/* update own internal node record */ /* update own internal node record */
record_status = get_node_record(local_conn, local_node_info.node_id, &local_node_info); record_status = get_node_record(local_conn, local_node_info.node_id, &local_node_info);
@@ -3690,13 +3795,16 @@ promote_self(void)
failed_primary.node_name, failed_primary.node_name,
failed_primary.node_id); failed_primary.node_id);
event_info.node_id = failed_primary.node_id;
/* local_conn is now the primary connection */ /* local_conn is now the primary connection */
create_event_notification(local_conn, create_event_notification_extended(local_conn,
&config_file_options, &config_file_options,
local_node_info.node_id, local_node_info.node_id,
"repmgrd_failover_promote", "repmgrd_failover_promote",
true, true,
event_details.data); event_details.data,
&event_info);
termPQExpBuffer(&event_details); termPQExpBuffer(&event_details);
} }
@@ -3921,6 +4029,7 @@ follow_new_primary(int new_primary_id)
termPQExpBuffer(&event_details); termPQExpBuffer(&event_details);
close_connection(&upstream_conn);
close_connection(&old_primary_conn); close_connection(&old_primary_conn);
return FAILOVER_STATE_PRIMARY_REAPPEARED; return FAILOVER_STATE_PRIMARY_REAPPEARED;
@@ -3931,6 +4040,8 @@ follow_new_primary(int new_primary_id)
close_connection(&old_primary_conn); close_connection(&old_primary_conn);
} }
close_connection(&upstream_conn);
return FAILOVER_STATE_FOLLOW_FAIL; return FAILOVER_STATE_FOLLOW_FAIL;
} }
@@ -5381,7 +5492,7 @@ try_primary_reconnect(PGconn **conn, PGconn *local_conn, t_node_info *node_info)
time_t started_at = time(NULL); time_t started_at = time(NULL);
int up_to; int up_to;
bool sleep_now = false; bool sleep_now = false;
bool max_sleep_seconds; int max_sleep_seconds;
log_info(_("checking state of node \"%s\" (ID: %i), %i of %i attempts"), log_info(_("checking state of node \"%s\" (ID: %i), %i of %i attempts"),
node_info->node_name, node_info->node_name,

View File

@@ -1,6 +1,6 @@
/* /*
* repmgrd-physical.h * repmgrd-physical.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
#ifndef _REPMGRD_PHYSICAL_H_ #ifndef _REPMGRD_PHYSICAL_H_
#define _REPMGRD_PHYSICAL_H_ #define _REPMGRD_PHYSICAL_H_
void do_physical_node_check(void); void do_physical_node_check(PGconn *conn);
void monitor_streaming_primary(void); void monitor_streaming_primary(void);
void monitor_streaming_standby(void); void monitor_streaming_standby(void);

View File

@@ -1,7 +1,7 @@
/* /*
* repmgrd.c - Replication manager daemon * repmgrd.c - Replication manager daemon
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -131,7 +131,7 @@ main(int argc, char **argv)
memset(pid_file, 0, MAXPGPATH); memset(pid_file, 0, MAXPGPATH);
while ((c = getopt_long(argc, argv, "?Vf:L:vdp:m", long_options, &optindex)) != -1) while ((c = getopt_long(argc, argv, "?Vf:L:vdp:sm", long_options, &optindex)) != -1)
{ {
switch (c) switch (c)
{ {
@@ -249,7 +249,7 @@ main(int argc, char **argv)
/* /*
* Parse the configuration file, if provided (if no configuration file was * Parse the configuration file, if provided (if no configuration file was
* provided, an attempt will be made to find one in one of the default * provided, an attempt will be made to find one in one of the default
* locations). If no conifguration file is available, or it can't be parsed * locations). If no configuration file is available, or it can't be parsed
* parse_config() will abort anyway, with an appropriate message. * parse_config() will abort anyway, with an appropriate message.
*/ */
load_config(config_file, verbose, false, argv[0]); load_config(config_file, verbose, false, argv[0]);
@@ -307,7 +307,7 @@ main(int argc, char **argv)
} }
/* Some configuration file items can be overriden by command line options */ /* Some configuration file items can be overridden by command line options */
/* /*
* Command-line parameter -L/--log-level overrides any setting in config * Command-line parameter -L/--log-level overrides any setting in config
@@ -396,13 +396,14 @@ main(int argc, char **argv)
* extension is the latest available according to "pg_available_extensions" - * extension is the latest available according to "pg_available_extensions" -
* - does our (major) version match that? * - does our (major) version match that?
*/ */
log_verbose(LOG_DEBUG, "binary version: %i; extension version: %i", log_verbose(LOG_DEBUG, "expected extension version: %i; extension version: %i",
REPMGR_VERSION_NUM, extversions.installed_version_num); REPMGR_EXTENSION_NUM, extversions.installed_version_num);
if ((REPMGR_VERSION_NUM/100) < (extversions.installed_version_num / 100)) if ((REPMGR_EXTENSION_NUM/100) < (extversions.installed_version_num / 100))
{ {
log_error(_("this \"repmgr\" version is older than the installed \"repmgr\" extension version")); log_error(_("this \"repmgr\" version is older than the installed \"repmgr\" extension version"));
log_detail(_("\"repmgr\" version %s is installed but extension is version %s"), log_detail(_("\"repmgr\" version %s providing extension version %s is installed but extension is version %s"),
REPMGR_VERSION, REPMGR_VERSION,
REPMGR_EXTENSION_VERSION,
extversions.installed_version); extversions.installed_version);
log_hint(_("update the repmgr binaries to match the installed extension version")); log_hint(_("update the repmgr binaries to match the installed extension version"));
@@ -410,13 +411,14 @@ main(int argc, char **argv)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
if ((REPMGR_VERSION_NUM/100) > (extversions.installed_version_num / 100)) if ((REPMGR_EXTENSION_NUM/100) > (extversions.installed_version_num / 100))
{ {
log_error(_("this \"repmgr\" version is newer than the installed \"repmgr\" extension version")); log_error(_("this \"repmgr\" version is newer than the installed \"repmgr\" extension version"));
log_detail(_("\"repmgr\" version %s is installed but extension is version %s"), log_detail(_("\"repmgr\" version %s providing extension version %s is installed but extension is version %s"),
REPMGR_VERSION, REPMGR_VERSION,
REPMGR_EXTENSION_VERSION,
extversions.installed_version); extversions.installed_version);
log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\"")); log_hint(_("update the installed extension version by executing \"ALTER EXTENSION repmgr UPDATE\" in the repmgr database"));
close_connection(&local_conn); close_connection(&local_conn);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
@@ -477,7 +479,7 @@ main(int argc, char **argv)
switch (config_file_options.replication_type) switch (config_file_options.replication_type)
{ {
case REPLICATION_TYPE_PHYSICAL: 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; break;
} }
@@ -510,7 +512,7 @@ main(int argc, char **argv)
log_debug("node id is %i, upstream node id is %i", log_debug("node id is %i, upstream node id is %i",
local_node_info.node_id, local_node_info.node_id,
local_node_info.upstream_node_id); local_node_info.upstream_node_id);
do_physical_node_check(); do_physical_node_check(local_conn);
} }
if (daemonize == true) if (daemonize == true)

View File

@@ -1,6 +1,6 @@
/* /*
* repmgrd.h * repmgrd.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
*/ */

View File

@@ -1,7 +1,7 @@
/* /*
* strutil.c * strutil.c
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -369,7 +369,6 @@ check_status_list_free(CheckStatusList *list)
} }
const char * const char *
output_check_status(CheckStatus status) output_check_status(CheckStatus status)
{ {

View File

@@ -1,6 +1,6 @@
/* /*
* strutil.h * strutil.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -3,7 +3,7 @@
* *
* Functions which need to be executed on the local system. * Functions which need to be executed on the local system.
* *
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -289,10 +289,19 @@ disable_wal_receiver(PGconn *conn)
if (wal_retrieve_retry_interval < WALRECEIVER_DISABLE_TIMEOUT_VALUE) if (wal_retrieve_retry_interval < WALRECEIVER_DISABLE_TIMEOUT_VALUE)
{ {
bool success;
log_notice(_("setting \"wal_retrieve_retry_interval\" to %i milliseconds"), log_notice(_("setting \"wal_retrieve_retry_interval\" to %i milliseconds"),
new_wal_retrieve_retry_interval); new_wal_retrieve_retry_interval);
alter_system_int(conn, "wal_retrieve_retry_interval", new_wal_retrieve_retry_interval); alter_system_int(conn, "wal_retrieve_retry_interval", new_wal_retrieve_retry_interval);
pg_reload_conf(conn);
success = pg_reload_conf(conn);
if (success == false)
{
log_warning(_("unable to reload configuration"));
return UNKNOWN_PID;
}
} }
/* /*
@@ -354,6 +363,12 @@ enable_wal_receiver(PGconn *conn, bool wait_startup)
/* make timeout configurable */ /* make timeout configurable */
int i, timeout = 30; int i, timeout = 30;
if (PQstatus(conn) != CONNECTION_OK)
{
log_error(_("database connection not available"));
return UNKNOWN_PID;
}
if (is_superuser_connection(conn, NULL) == false) if (is_superuser_connection(conn, NULL) == false)
{ {
log_error(_("superuser connection required")); log_error(_("superuser connection required"));
@@ -394,7 +409,13 @@ enable_wal_receiver(PGconn *conn, bool wait_startup)
return UNKNOWN_PID; return UNKNOWN_PID;
} }
pg_reload_conf(conn); success = pg_reload_conf(conn);
if (success == false)
{
log_warning(_("unable to reload configuration"));
return UNKNOWN_PID;
}
} }
else else
{ {

View File

@@ -1,6 +1,6 @@
/* /*
* sysutils.h * sysutils.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/* /*
* voting.h * voting.h
* Copyright (c) 2ndQuadrant, 2010-2020 * Copyright (c) EnterpriseDB Corporation, 2010-2021
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by