Compare commits

...

115 Commits

Author SHA1 Message Date
Mario Gonzalez
99bbf207b5 Update HISTORY and appendix for v5.5.0
References: HL-38
2024-11-21 12:23:18 -03:00
Mario Gonzalez
836894c965 Bump repmgr.control to 5.5
References: HL-38
2024-11-21 14:42:50 +01:00
Mario Gonzalez
7f3a26f0d9 Add primary_node_info inline function
When a t_node_info struct must be re initilised, it was re-declared
only. Moreover, a macro was user for any var creation of this type
impeding use the same to reset the values later if needed.

This new function allows to re initilise again a t_node_info typed
variable without the need to redeclare it to create other varibles for
the same purpose, and also shadowing is now avoided from pg16.

Macros seems to be replaced by `static inline` functions in upstream
postgres, credits to  Alvaro Herrera <alvherre@alvh.no-ip.org> for this
idea.

References: HL-40
2024-11-18 09:46:14 -03:00
Mario Gonzalez
a469221e28 Fix shadowed declaration
Since b5934bfd6071 in postgresql.git the flag
`-Wshadow=compatible-local` is activated. This commit fixes any
duplicated declaration made in the same function.

References: HL-40
2024-11-18 09:46:14 -03:00
Mario Gonzalez
c6d9f38458 Bump repmgr version 5.5.0 2024-11-15 10:51:12 -03:00
Francisco Miguel Biete Banon
5abdbb0d39 Definition moved to a different header 2024-10-28 09:37:30 -03:00
Martín Marqués
8f27e3bc5d Fix wrong reference to connection from commit f69485c0
Commit f69485c0 introduced a change in how we check if the repmgr
user can run checkpoints on PG15 and newer.

There was a regression in the messages where the conn passed
was not declared. That is because the pointer we were using was
called local_conn instead of conn.

Signed-off-by: Martín Marqués <martin.marques@enterprisedb.com>
Co-authored-by: Mario Gonzalez <mario.gonzalez@enterprisedb.com>
2024-10-22 15:40:56 -03:00
RealGreenDragon
b92d43d136 Fixed repmgr.conf.sample 2024-10-14 14:46:27 +02:00
RealGreenDragon
4a28c57bc7 Check for USAGE (instead of MEMBER) privilege in all pg_has_role occurrences 2024-09-11 20:17:32 +02:00
RealGreenDragon
f69485c0ba Added check for pg_checkpoint role presence (#807)
* Added check for pg_checkpoint role presence

This commit provides the needed infrastructure in `repmgr` so if the `repmgr` database
user is a member of the `pg_checkpoint` role, and inherits its privileges, there is no 
need for such a user to be a superuser.

Co-authored-by: Martín Marqués <martin.marques@enterprisedb.com>
2024-09-11 15:13:44 -03:00
Martín Marqués
b4a0938081 Update Authors and version on README
Signed-off-by: Martín Marqués <martin.marques@enterprisedb.com>
2024-09-09 18:00:42 +02:00
Martín Marqués
569f906003 Add CODEOWNERS to the repmgr repo
Signed-off-by: Martín Marqués <martin.marques@enterprisedb.com>
2024-09-09 16:30:50 +02:00
RealGreenDragon
94b21ae8ac Fixed standby_disconnect_on_failover description in repmgr.conf 2024-09-09 15:29:48 +02:00
RealGreenDragon
4c9cca64d0 Fixed standby_disconnect_on_failover docs 2024-09-09 15:29:48 +02:00
RealGreenDragon
82e2fd66e1 Fixed can_disable_walsender indentation and warning message 2024-09-09 15:29:48 +02:00
RealGreenDragon
90fe1b8135 Fixed indentation 2024-09-09 15:29:48 +02:00
RealGreenDragon
1cd168360e Added ALTER SYSTEM permission in docs 2024-09-09 15:29:48 +02:00
RealGreenDragon
e8aa3aced7 Added check for ALTER SYSTEM permission presence 2024-09-09 15:29:48 +02:00
Martín Marqués
d3b1ff45b0 Merge pull request #782 from EnterpriseDB/Fixed-reported-phrase
Update configuration-file-optional-settings.xml
2023-07-04 09:04:04 -03:00
Martín Marqués
450786ec29 Typo in the documentation
Signed-off-by: Martín Marqués <martin.marques@enterprisedb.com>
2023-07-04 14:02:08 +02:00
Ian Barwick
70b34308cc repmgrd: ensure witness node metadata is updated
If the primary changed while the witness repmgrd was not running,
ensure the witness's upstream node ID is updated when the witness
repmgrd is restarted.
2023-06-08 16:35:56 +09:00
Martín Marqués
19c92a7092 Merge pull request #803 from Nyantechnolog/patch-1
Update README.md
2023-04-17 12:57:51 -03:00
Sidorov Pavel
520ff25ef3 Update README.md
upd upper version according to https://repmgr.org
2023-04-04 11:54:59 +03:00
Martín Marqués
8e81c04b4a Add release notes for repmgr release 5.4.0
This release added support for pg-backup-api. Here we add the
release notes which expose the new feature.

Signed-off-by: Martín Marqués <martin.marques@enterprisedb.com>
2023-03-24 15:05:03 +00:00
Martín Marqués
aad988c292 Merge pull request #800 from EnterpriseDB/update-docs-for-pg-backupapi-mode
Adding new mode to clone standbys.
2023-03-16 07:14:33 -03:00
Martín Marqués
43b8a5f65f Various improvements and fixes to the pg-backup-api restore section on the docs
I added a paragraph at the beginning of the section on where to look for
instructions on how to install the pg-backup-api rest API.

Fixed typos and some gramatical changes. Also reworded the first paragraph
(which is now the second one).

Signed-off-by: Martín Marqués <martin.marques@enterprisedb.com>
2023-03-14 11:39:22 +01:00
Martín Marqués
26cfb56170 New sect2 block has to be inside the sect1. The closing tag has to go at the end.
Signed-off-by: Martín Marqués <martin.marques@enterprisedb.com>
2023-03-14 10:14:16 +01:00
Mario Gonzalez
f0cc225de0 Adding new mode to clone standbys.
repmgr v5.4.0 supports this new mode called `pg_backupapi` which is
enabled by defining `pg_backupapi_host` in repmgr.conf.
2023-03-13 11:03:02 -03:00
Martín Marqués
02d8e0c808 Merge pull request #799 from EnterpriseDB/validate-repmgr-options
Validate repmgr options
2023-03-08 07:13:45 -03:00
Mario Gonzalez
167d166ae8 Validate options when using pg_backupapi mode.
When `pg_backupapi` is enabled, we should validate if the remote ssh
command, node name and backup_id are also defined.
2023-03-07 16:51:25 -03:00
Mario Gonzalez
03c2ae1bd8 Connecting to default pg-backup-api port: 7480/TCP 2023-03-07 16:50:02 -03:00
Martín Marqués
4021037d38 Merge pull request #797 from EnterpriseDB/connect-to-pg-backup-api
Connect to pg backup api
2023-03-07 14:34:54 -03:00
Ian Barwick
7cd7566409 doc: update README
Remove reference to non-existent "scripts/" directory.
2023-03-07 08:36:00 +09:00
Mario Gonzalez
81c3200ef2 Integration of pgbackupapi 2023-02-27 12:23:57 -03:00
Mario Gonzalez
c6366db6f9 Library to connect to a pg-backup-api server.
Module to provide communication with a server in order to send new
tasks and query them.

pg-backup-api is a REST api that at the moment, is integrated with
barman only, and can provide a communication interface in order to
perform remote recoveries through background tasks. There are cases
where instead of writing a new repmgr module of some feature that
exists in backup tools already, like barman, pg-backup-api can
provide that integration.
2023-02-27 12:23:57 -03:00
Martín Marqués
078a47e182 Merge pull request #791 from EnterpriseDB/adding-flex-and-libs-as-deps
Adding flex and libs as deps
2023-01-27 06:32:59 -03:00
Mario Gonzalez
ed2c0aaf0b Checking for required libraries before compiling.
This commit ensures all the different libraries are installed before
starting to compile.
2023-01-25 15:51:55 -03:00
Martín Marqués
6249027a03 Merge pull request #792 from EnterpriseDB/dev/remove-sonarqube
Dev/remove sonarqube
2023-01-24 17:03:11 -03:00
Martín Marqués
b36fca17d9 Remove Sonarqube
Sonarqube has been failing for some time (seems like a user/credential
problem).

There will be discussion on how we'll resolve this, but that will be
sometime in the future. For now we are just removing the action.

Signed-off-by: Martín Marqués <martin.marques@enterprisedb.com>
2023-01-24 13:00:35 -03:00
Mario Gonzalez
a3b919d599 Checking if flex is installed before compiling.
We are checking for sed amd other external tools inside configure script,
now is turn of flex.

In systems without flex you will have this error:

gcc -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement
[...]
postgresql/internal  -Wdate-time -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -I/usr/include/libxml2   -c -o configfile.o configfile.c
flex  -o'configfile-scan.c' configfile-scan.l
make: flex: No such file or directory
make: *** [Makefile.global:40: configfile-scan.c] Error 127
2023-01-20 18:48:51 -03:00
Dee Dee Rothery
4c95d8d75e Update configuration-file-optional-settings.xml 2022-12-08 06:26:52 -05:00
Martín Marqués
c21d452076 Fix typo in documentation
Fixed a mising closing quote and closing parenthesis in the repmgrd overview
section of the documentation.

Signed-off-by: Martín Marqués <martin.marques@enterprisedb.com>
2022-11-16 13:55:36 -03:00
Ian Barwick
3b89731899 doc: update release notes 2022-10-18 10:26:44 +09:00
Ian Barwick
138bee98e9 doc: update compatibility matrix
Additional "Notes" column added.
2022-10-17 10:05:48 +09:00
Ian Barwick
83ffe84ff5 doc: update compatibility matrix for repmgr 5.3 / PostgreSQL 15 2022-10-17 10:05:26 +09:00
Ian Barwick
bb3206a2bf doc: clarify failover behaviour when node priority is zero
Make it clear the node will not be promoted under any circumstances.
2022-09-20 09:35:19 +09:00
Ian Barwick
49dfaea471 repmgrd: ensure notification script is called for "repmgrd_upstream_disconnect"
GitHUb #760.
2022-09-02 17:20:39 +09:00
Ian Barwick
8edc64f64e doc: update note about pg_rewind corner-case bug
Sadly it's likely there are still installations running PostgreSQL
versions released prior to February 2021, so keep the note there
for now.
2022-07-14 10:11:01 +09:00
Ian Barwick
3ce646f960 doc: mention full_page_writes as prerequisite for pg_rewind
Anyone disabling it needs to examine their life choices, but as
we check for it anyway, might as well explicitly mention it for
completeness.
2022-07-14 09:45:33 +09:00
Ian Barwick
dc0e89e234 doc: consolidate PostgreSQL 9.4 pg_rewind references
Anyone still using PostgreSQL 9.4 should re-examine their life choices
at this point, but as it is not yet de-supported by repmgr, consolidate
the references to it whenever pg_rewind is mentioned to a single
section.
2022-07-14 09:33:12 +09:00
Ian Barwick
41b6194580 Replace some appendPQExpBuffer occurrences with appendPQExpBufferStr 2022-07-14 09:14:56 +09:00
Ian Barwick
d501781a5f repmgr: update README
- update current version
- remove reference to upgrading from 3.x
2022-07-06 09:39:31 +09:00
Ian Barwick
de5265f594 Update Makefile
Re-add $(LIBS), previously removed in 9d7eebef.

While not required for internal builds, per GitHub #755 this may be
required in some environments.
2022-06-03 10:30:18 +09:00
Ian Barwick
66ac4183b4 doc: clarifications for upgrade process 2022-05-26 10:18:05 +09:00
Ian Barwick
59e5bc1500 doc: update compatibility matrix for repmgr 5.4 / PostgreSQL 15 2022-05-25 14:05:04 +09:00
Ian Barwick
8164914598 Add 5.3.2 release date 2022-05-25 14:04:19 +09:00
Ian Barwick
eb867516ff doc: update release notes 2022-05-25 14:03:39 +09:00
Ian Barwick
6b961ab6a7 doc: update release notes 2022-05-25 14:03:36 +09:00
Ian Barwick
7e2d14d225 shared library: remove redundant code
This has never actually served any purpose; see core commit ab02d702ef.
2022-05-17 20:00:12 +09:00
Ian Barwick
a90d1cf3dd Ensure replication slots can be dropped by a replication-only user
If the repmgr user is a non-superuser, and a replication-only user exists,
ensure redundant replication slots are dropped correctly.
2022-05-16 16:37:25 +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
60 changed files with 2728 additions and 641 deletions

7
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,7 @@
# Each line is a file pattern followed by one or more owners.
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
# @global-owner1 and @global-owner2 will be requested for
# review when someone opens a pull request.
* @EnterpriseDB/repmgr-dev

34
HISTORY
View File

@@ -1,11 +1,37 @@
5.3.0 2021-??-?? 5.5.0 2024-11-20
Support for PostgreSQL 17 added
Fix warnings detected by the -Wshadow=compatible-local
added in PostgreSQL 16
5.4.1 2023-07-04
repmgrd: ensure witness node metadata is updated (Ian)
5.4.0 2023-03-16
Support cloning replicas using pg-backup-api
5.3.3 2022-10-17
Support for PostgreSQL added
repmgrd: ensure event notification script is called for event
"repmgrd_upstream_disconnect"; GitHub #760 (Ian)
5.3.2 2022-05-25
standby clone: don't error out if unable to determine cluster size (Ian)
node check: fix --downstream --nagios output; GitHub #749 (Ian)
repmgrd: ensure witness node marked active (hslightdb)
repmgrd: improve walsender disable check (Ian)
general: ensure replication slots can be dropped by a
replication-only user (Ian)
5.3.1 2022-02-15
repmgrd: fixes for potential connection leaks (hslightdb)
repmgr: fix upgrade path from repmgr 4.2 and 4.3 to repmgr 5.3 (Ian)
5.3.0 2021-10-12
standby switchover: improve handling of node rejoin failure (Ian) standby switchover: improve handling of node rejoin failure (Ian)
repmgrd: prefix all shared library functions with "repmgr_" to repmgrd: prefix all shared library functions with "repmgr_" to
minimize the risk of clashes with other shared libraries (Ian) minimize the risk of clashes with other shared libraries (Ian)
repmgrd: at startup, if node record is marked as "inactive", attempt repmgrd: at startup, if node record is marked as "inactive", attempt
to set it to "active" (Ian) to set it to "active" (Ian)
5.2.2. 2021-??-??
standby clone: set "slot_name" in node record if required (Ian) standby clone: set "slot_name" in node record if required (Ian)
node rejoin: emit rejoin target note information as NOTICE (Ian) node rejoin: emit rejoin target note information as NOTICE (Ian)
repmgrd: ensure short option "-s" is accepted (Ian) repmgrd: ensure short option "-s" is accepted (Ian)
@@ -59,7 +85,7 @@
"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
0 replication slot (Ian) replication slot (Ian)
repmgr: ensure "node rejoin" checks for available replication slots (Ian) repmgr: ensure "node rejoin" checks for available replication slots (Ian)
repmgr: improve "standby switchover" completion checks (Ian) repmgr: improve "standby switchover" completion checks (Ian)
repmgr: add replication configuration file ownership check to repmgr: add replication configuration file ownership check to

View File

@@ -22,7 +22,7 @@ GIT_WORK_TREE=${repmgr_abs_srcdir}
GIT_DIR=${repmgr_abs_srcdir}/.git GIT_DIR=${repmgr_abs_srcdir}/.git
export GIT_DIR export GIT_DIR
export GIT_WORK_TREE export GIT_WORK_TREE
PG_LDFLAGS=-lcurl -ljson-c
include $(PGXS) include $(PGXS)
-include ${repmgr_abs_srcdir}/Makefile.custom -include ${repmgr_abs_srcdir}/Makefile.custom

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 \
@@ -29,7 +30,11 @@ DATA = \
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.2--5.3.sql \
repmgr--5.3.sql repmgr--5.3.sql \
repmgr--5.3--5.4.sql \
repmgr--5.4.sql \
repmgr--5.4--5.5.sql \
repmgr--5.5.sql
REGRESS = repmgr_extension REGRESS = repmgr_extension
@@ -63,7 +68,7 @@ REPMGR_CLIENT_OBJS = repmgr-client.o \
repmgr-action-primary.o repmgr-action-standby.o repmgr-action-witness.o \ repmgr-action-primary.o repmgr-action-standby.o repmgr-action-witness.o \
repmgr-action-cluster.o repmgr-action-node.o repmgr-action-service.o repmgr-action-daemon.o \ repmgr-action-cluster.o repmgr-action-node.o repmgr-action-service.o repmgr-action-daemon.o \
configdata.o configfile.o configfile-scan.o log.o strutil.o controldata.o dirutil.o compat.o \ configdata.o configfile.o configfile-scan.o log.o strutil.o controldata.o dirutil.o compat.o \
dbutils.o sysutils.o dbutils.o sysutils.o pgbackupapi.o
REPMGRD_OBJS = repmgrd.o repmgrd-physical.o configdata.o configfile.o configfile-scan.o log.o \ REPMGRD_OBJS = repmgrd.o repmgrd-physical.o configdata.o configfile.o configfile-scan.o log.o \
dbutils.o strutil.o controldata.o compat.o sysutils.o dbutils.o strutil.o controldata.o compat.o sysutils.o
@@ -78,10 +83,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) -o $@$(X) $(CC) $(CFLAGS) $(REPMGR_CLIENT_OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
repmgrd: $(REPMGRD_OBJS) repmgrd: $(REPMGRD_OBJS)
$(CC) $(CFLAGS) $(REPMGRD_OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) -o $@$(X) $(CC) $(CFLAGS) $(REPMGRD_OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
$(REPMGR_CLIENT_OBJS): $(HEADERS) $(REPMGR_CLIENT_OBJS): $(HEADERS)
$(REPMGRD_OBJS): $(HEADERS) $(REPMGRD_OBJS): $(HEADERS)

View File

@@ -7,8 +7,9 @@ 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.
The most recent `repmgr` version (5.2.1) supports all PostgreSQL versions from The most recent `repmgr` version (5.5.x) supports all PostgreSQL versions from
9.5 to 13. PostgreSQL 9.4 is also supported, with some restrictions. 13 to 17. Despite it could be used with some older ones, some features might not
be available, however, it's strongly recommended to use the latest version.
`repmgr` is distributed under the GNU GPL 3 and maintained by EnterpriseDB. `repmgr` is distributed under the GNU GPL 3 and maintained by EnterpriseDB.
@@ -19,14 +20,6 @@ The full `repmgr` documentation is available here:
> [repmgr documentation](https://repmgr.org/docs/current/index.html) > [repmgr documentation](https://repmgr.org/docs/current/index.html)
The old `README` file for `repmgr` 3.x is available here:
> 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;
please upgrade to the [current repmgr version](https://repmgr.org/docs/current/appendix-release-notes.html)
as soon as possible.
Versions Versions
-------- --------
@@ -48,7 +41,6 @@ Directories
- `contrib/`: additional utilities - `contrib/`: additional utilities
- `doc/`: DocBook-based documentation files - `doc/`: DocBook-based documentation files
- `expected/`: expected regression test output - `expected/`: expected regression test output
- `scripts/`: example scripts
- `sql/`: regression test input - `sql/`: regression test input
@@ -65,8 +57,6 @@ There is a mailing list/forum to discuss contributions or issues:
* https://groups.google.com/group/repmgr * https://groups.google.com/group/repmgr
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/EnterpriseDB/repmgr * https://github.com/EnterpriseDB/repmgr
@@ -79,6 +69,13 @@ news are always welcome.
Thanks from the repmgr core team. Thanks from the repmgr core team.
* Ian Barwick * Ian Barwick
* Israel Barth
* Mario González
* Martín Marqués
* Gianni Ciolli
Past contributors:
* Jaime Casanova * Jaime Casanova
* Abhijit Menon-Sen * Abhijit Menon-Sen
* Simon Riggs * Simon Riggs

View File

@@ -291,6 +291,46 @@ struct ConfigFileSetting config_file_settings[] =
{}, {},
{} {}
}, },
/* pg_backupapi_backup_id*/
{
"pg_backupapi_backup_id",
CONFIG_STRING,
{ .strptr = config_file_options.pg_backupapi_backup_id },
{ .strdefault = "" },
{},
{ .strmaxlen = sizeof(config_file_options.pg_backupapi_backup_id) },
{}
},
/* pg_backupapi_host*/
{
"pg_backupapi_host",
CONFIG_STRING,
{ .strptr = config_file_options.pg_backupapi_host },
{ .strdefault = "" },
{},
{ .strmaxlen = sizeof(config_file_options.pg_backupapi_host) },
{}
},
/* pg_backupapi_node_name */
{
"pg_backupapi_node_name",
CONFIG_STRING,
{ .strptr = config_file_options.pg_backupapi_node_name },
{ .strdefault = "" },
{},
{ .strmaxlen = sizeof(config_file_options.pg_backupapi_node_name) },
{}
},
/* pg_backupapi_remote_ssh_command */
{
"pg_backupapi_remote_ssh_command",
CONFIG_STRING,
{ .strptr = config_file_options.pg_backupapi_remote_ssh_command },
{ .strdefault = "" },
{},
{ .strmaxlen = sizeof(config_file_options.pg_backupapi_remote_ssh_command) },
{}
},
/* ======================= /* =======================
* standby follow settings * standby follow settings

View File

@@ -164,6 +164,10 @@ typedef struct
char archive_cleanup_command[MAXLEN]; char archive_cleanup_command[MAXLEN];
bool use_primary_conninfo_password; bool use_primary_conninfo_password;
char passfile[MAXPGPATH]; char passfile[MAXPGPATH];
char pg_backupapi_backup_id[NAMEDATALEN];
char pg_backupapi_host[NAMEDATALEN];
char pg_backupapi_node_name[NAMEDATALEN];
char pg_backupapi_remote_ssh_command[MAXLEN];
/* standby promote settings */ /* standby promote settings */
int promote_check_timeout; int promote_check_timeout;

18
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.3.0. # Generated by GNU Autoconf 2.69 for repmgr 5.4.0.
# #
# Report bugs to <repmgr@googlegroups.com>. # Report bugs to <repmgr@googlegroups.com>.
# #
@@ -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.3.0' PACKAGE_VERSION='5.4.0'
PACKAGE_STRING='repmgr 5.3.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.3.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.3.0:";; short | recursive ) echo "Configuration of repmgr 5.4.0:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@@ -1316,7 +1316,7 @@ 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.3.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.
@@ -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.3.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 $@
@@ -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.3.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.3.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.3.0], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/]) AC_INIT([repmgr], [5.5.0], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
AC_COPYRIGHT([Copyright (c) 2010-2021, EnterpriseDB Corporation]) AC_COPYRIGHT([Copyright (c) 2010-2024, EnterpriseDB Corporation])
AC_CONFIG_HEADER(config.h) AC_CONFIG_HEADER(config.h)
@@ -60,6 +60,7 @@ AC_SUBST(vpath_build)
AC_CHECK_PROG(HAVE_GNUSED,gnused,yes,no) AC_CHECK_PROG(HAVE_GNUSED,gnused,yes,no)
AC_CHECK_PROG(HAVE_GSED,gsed,yes,no) AC_CHECK_PROG(HAVE_GSED,gsed,yes,no)
AC_CHECK_PROG(HAVE_SED,sed,yes,no) AC_CHECK_PROG(HAVE_SED,sed,yes,no)
AC_CHECK_PROG(HAVE_FLEX,flex,yes,no)
if test "$HAVE_GNUSED" = yes; then if test "$HAVE_GNUSED" = yes; then
SED=gnused SED=gnused
@@ -72,6 +73,25 @@ else
fi fi
AC_SUBST(SED) AC_SUBST(SED)
AS_IF([test x"$HAVE_FLEX" != x"yes"], AC_MSG_ERROR([flex should be installed first]))
#Checking libraries
GENERIC_LIB_FAILED_MSG="library should be installed"
AC_CHECK_LIB(selinux, is_selinux_enabled, [],
[AC_MSG_ERROR(['selinux' $GENERIC_LIB_FAILED_MSG])])
AC_CHECK_LIB(lz4, LZ4_compress_default, [],
[AC_MSG_ERROR(['Z4' $GENERIC_LIB_FAILED_MSG])])
AC_CHECK_LIB(xslt, xsltCleanupGlobals, [],
[AC_MSG_ERROR(['xslt' $GENERIC_LIB_FAILED_MSG])])
AC_CHECK_LIB(pam, pam_start, [],
[AC_MSG_ERROR(['pam' $GENERIC_LIB_FAILED_MSG])])
AC_CHECK_LIB(gssapi_krb5, gss_init_sec_context, [],
[AC_MSG_ERROR([gssapi_krb5 $GENERIC_LIB_FAILED_MSG])])
AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([Makefile.global]) AC_CONFIG_FILES([Makefile.global])

269
dbutils.c
View File

@@ -61,6 +61,8 @@ static ReplSlotStatus _verify_replication_slot(PGconn *conn, char *slot_name, PQ
static bool _create_event(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details, t_event_info *event_info, bool send_notification); static 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;
@@ -1289,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);
@@ -1627,7 +1624,7 @@ get_ready_archive_files(PGconn *conn, const char *data_directory)
while ((arcdir_ent = readdir(arcdir)) != NULL) while ((arcdir_ent = readdir(arcdir)) != NULL)
{ {
struct stat statbuf; struct stat local_statbuf;
char file_path[MAXPGPATH + sizeof(arcdir_ent->d_name)]; char file_path[MAXPGPATH + sizeof(arcdir_ent->d_name)];
int basenamelen = 0; int basenamelen = 0;
@@ -1637,7 +1634,7 @@ get_ready_archive_files(PGconn *conn, const char *data_directory)
arcdir_ent->d_name); arcdir_ent->d_name);
/* skip non-files */ /* skip non-files */
if (stat(file_path, &statbuf) == 0 && !S_ISREG(statbuf.st_mode)) if (stat(file_path, &local_statbuf) == 0 && !S_ISREG(local_statbuf.st_mode))
{ {
continue; continue;
} }
@@ -1826,11 +1823,80 @@ 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 */
/* =============================== */ /* =============================== */
/*
* Determine if the user associated with the current connection can execute CHECKPOINT command.
* User must be a supersuer or a member of the pg_checkpoint default role (available from PostgreSQL 15).
*/
bool
can_execute_checkpoint(PGconn *conn)
{
PQExpBufferData query;
PGresult *res;
bool has_pg_checkpoint_role = false;
/* superusers can do anything, no role check needed */
if (is_superuser_connection(conn, NULL) == true)
return true;
/* pg_checkpoint available from PostgreSQL 15 */
if (PQserverVersion(conn) < 150000)
return false;
initPQExpBuffer(&query);
appendPQExpBufferStr(&query,
" SELECT pg_catalog.pg_has_role('pg_checkpoint','USAGE') ");
res = PQexec(conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, query.data,
_("can_execute_checkpoint(): unable to query user roles"));
}
else
{
has_pg_checkpoint_role = atobool(PQgetvalue(res, 0, 0));
}
termPQExpBuffer(&query);
PQclear(res);
return has_pg_checkpoint_role;
}
/*
* Determine if the user associated with the current connection
* has sufficient permissions to use pg_promote function
*/
bool bool
can_execute_pg_promote(PGconn *conn) can_execute_pg_promote(PGconn *conn)
{ {
@@ -1867,6 +1933,74 @@ 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;
PQExpBufferData query;
PGresult *res;
bool has_alter_system_priv = false;
/* GRANT ALTER SYSTEM available from PostgreSQL 15 */
if (PQserverVersion(conn) >= 150000)
{
initPQExpBuffer(&query);
appendPQExpBufferStr(&query,
" SELECT pg_catalog.has_parameter_privilege('wal_retrieve_retry_interval', 'ALTER SYSTEM') ");
res = PQexec(conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_db_error(conn, query.data,
_("can_disable_walsender(): unable to query user parameter privileges"));
}
else
{
has_alter_system_priv = atobool(PQgetvalue(res, 0, 0));
}
termPQExpBuffer(&query);
PQclear(res);
}
if (has_alter_system_priv == false)
{
log_warning(_("\"standby_disconnect_on_failover\" specified, but repmgr user is not authorized to perform ALTER SYSTEM wal_retrieve_retry_interval"));
if (PQserverVersion(conn) >= 150000)
{
log_detail(_("superuser or ALTER SYSTEM wal_retrieve_retry_interval permission required to disable standbys on failover"));
}
else
{
log_detail(_("superuser permission required to disable standbys on failover"));
}
}
return has_alter_system_priv;
}
/* /*
* 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
@@ -1890,13 +2024,13 @@ connection_has_pg_monitor_role(PGconn *conn, const char *subrole)
initPQExpBuffer(&query); initPQExpBuffer(&query);
appendPQExpBufferStr(&query, appendPQExpBufferStr(&query,
" SELECT CASE " " SELECT CASE "
" WHEN pg_catalog.pg_has_role('pg_monitor','MEMBER') " " WHEN pg_catalog.pg_has_role('pg_monitor','USAGE') "
" THEN TRUE "); " THEN TRUE ");
if (subrole != NULL) if (subrole != NULL)
{ {
appendPQExpBuffer(&query, appendPQExpBuffer(&query,
" WHEN pg_catalog.pg_has_role('%s','MEMBER') " " WHEN pg_catalog.pg_has_role('%s','USAGE') "
" THEN TRUE ", " THEN TRUE ",
subrole); subrole);
} }
@@ -2082,7 +2216,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)
{ {
@@ -2246,29 +2386,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)
@@ -2420,7 +2537,10 @@ get_repmgr_extension_status(PGconn *conn, t_extension_versions *extversions)
/* node management functions */ /* node management functions */
/* ========================= */ /* ========================= */
/* assumes superuser connection */ /*
* Assumes the connection can execute CHECKPOINT command.
* A check can be executed via 'can_execute_checkpoint' function.
*/
void void
checkpoint(PGconn *conn) checkpoint(PGconn *conn)
{ {
@@ -4242,7 +4362,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)
{ {
@@ -4576,17 +4696,17 @@ drop_replication_slot_replprot(PGconn *repl_conn, char *slot_name)
initPQExpBuffer(&query); initPQExpBuffer(&query);
appendPQExpBuffer(&query, appendPQExpBuffer(&query,
"DROP_REPLICATION_SLOT %s", "DROP_REPLICATION_SLOT %s;",
slot_name); slot_name);
log_verbose(LOG_DEBUG, "drop_replication_slot_replprot():\n %s", query.data); log_verbose(LOG_DEBUG, "drop_replication_slot_replprot():\n %s", query.data);
res = PQexec(repl_conn, query.data); res = PQexec(repl_conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK) if (PQresultStatus(res) != PGRES_TUPLES_OK || !PQntuples(res))
{ {
log_db_error(repl_conn, query.data, log_db_error(repl_conn, query.data,
_("drop_replication_slot_sql(): unable to drop replication slot \"%s\""), _("drop_replication_slot_replprot(): unable to drop replication slot \"%s\""),
slot_name); slot_name);
success = false; success = false;
@@ -5704,7 +5824,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)
{ {
@@ -5792,6 +5912,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;
@@ -5826,9 +5959,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);
@@ -5837,7 +5973,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);
@@ -5863,9 +6000,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);
@@ -6008,6 +6146,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

@@ -450,9 +450,12 @@ 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_checkpoint(PGconn *conn);
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 +470,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 +599,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

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

View File

@@ -50,18 +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 &repmgr; release. after each &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>
@@ -252,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.
@@ -262,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>
@@ -401,7 +401,7 @@
</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.
@@ -413,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
@@ -493,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,17 +15,199 @@
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.5.0">
<title>Release 5.5.0</title>
<para><emphasis>Wed 20 November, 2024</emphasis></para>
<para>
&repmgr; 5.5.0 is a major release.
</para>
<para>
This release adds support for PostgreSQL 17
</para>
<para>
Fixes warnings detected by the -Wshadow gcc flag added in PostgreSQL 16.
</para>
</sect1>
<sect1 id="release-5.4.1">
<title id="release-current">Release 5.4.1</title>
<para><emphasis>Tue 04 Jul, 2023</emphasis></para>
<para>
&repmgr; 5.4.1 is a minor release providing ...
</para>
<sect2>
<title>Bug fixes</title>
<para>
<itemizedlist>
<listitem>
<para>
&repmgrd;: ensure witness node metadata is updated if the primary
node changed while the witness &repmgrd; was not running.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="release-5.4.0">
<title>Release 5.4.0</title>
<para><emphasis>Thu 15 March, 2023</emphasis></para>
<para>
&repmgr; 5.4.0 is a major release.
</para>
<para>
This release provides support for cloning standbys using backups taken with <ulink url="http://www.pgbarman.org">barman</ulink>
with the use of <ulink url="https://github.com/EnterpriseDB/pg-backup-api">pg-backup-api</ulink>.
</para>
<para>
Minor fixes to the documentation.
</para>
</sect1>
<sect1 id="release-5.3.3">
<title>Release 5.3.3</title>
<para><emphasis>Mon 17 October, 2022</emphasis></para>
<para>
&repmgr; 5.3.3 is a minor release providing support for
<ulink url="https://www.postgresql.org/docs/15/release-15.html">PostgreSQL 15</ulink>
and a &repmgrd; bug fix.
</para>
<para>
If upgrading from an earlier &repmgr; version, any running &repmgrd; instances should be restarted.
</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>
&repmgrd;: ensure <link linkend="event-notifications">event notification</link> script is called for event
<literal>repmgrd_upstream_disconnect</literal>. GitHub #760.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="release-5.3.2">
<title>Release 5.3.2</title>
<para><emphasis>Wed 25 May, 2022</emphasis></para>
<para>
&repmgr; 5.3.2 is a minor release.
</para>
<para>
Any running &repmgrd; instances should be restarted following this upgrade.
</para>
<para>
If upgrading from &repmgr; 5.2.1 or earlier, a PostgreSQL restart <emphasis>is</emphasis> required.
</para>
<sect2>
<title>Bug fixes</title>
<para>
<itemizedlist>
<listitem>
<para>
<command><link linkend="repmgr-node-status">repmgr node status</link></command>:
fix output with <option>--downstream</option> <option>--nagios</option> option combination.
GitHub #749.
</para>
</listitem>
<listitem>
<para>
<command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>:
don't treat inability to determine the cluster size as a fatal error.
</para>
<para>
The cluster size is displayed for informational purposes and is not essential
for execution of the clone operation. As the &repmgr; user may not have permissions
for all databases in the cluster, ignore the cluster size query if it fails.
</para>
</listitem>
<listitem>
<para>
&repmgrd;: ensure the witness node record on the primary is always marked
as <literal>active</literal> if previously marked <literal>inactive</literal>.
GitHub #754.
</para>
</listitem>
<listitem>
<para>
&repmgrd;: if <varname>standby_disconnect_on_failover</varname> is set, verify
&repmgr; is a superuser before attempting to disable the WAL receiver.
</para>
</listitem>
<listitem>
<para>
If the &repmgr; user is a non-superuser, and a replication-only user exists,
ensure redundant replication slots are dropped correctly even
if the <option>-S/--superuser</option> option is not provided.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="release-5.3.1">
<title>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"> <sect1 id="release-5.3.0">
<title id="release-current">Release 5.3.0</title> <title>Release 5.3.0</title>
<para><emphasis>??? ? ???, 2021</emphasis></para> <para><emphasis>Tue 12 October, 2021</emphasis></para>
<para> <para>
&repmgr; 5.3.0 is a major release. &repmgr; 5.3.0 is a major release.
</para> </para>
<para> <para>
This release provides support for <ulink url="https://www.postgresql.org/docs/14/release-14.html">PostgreSQL 14</ulink>, This release provides support for <ulink url="https://www.postgresql.org/docs/14/release-14.html">PostgreSQL 14</ulink>,
to be released later in 2021. released in September 2021.
</para> </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> <sect2>
<title>Improvements</title> <title>Improvements</title>
<para> <para>
@@ -44,6 +226,11 @@
This makes it easier to identify unexpected events during a switchover operation, such as This makes it easier to identify unexpected events during a switchover operation, such as
the demotion candidate being unexpectedly restarted by an external process. the demotion candidate being unexpectedly restarted by an external process.
</para> </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>
<listitem> <listitem>
<para> <para>
@@ -55,7 +242,33 @@
<varname>repmgrd_exit_on_inactive_node</varname> to <literal>true</literal>. <varname>repmgrd_exit_on_inactive_node</varname> to <literal>true</literal>.
</para> </para>
</listitem> </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> </itemizedlist>
</para> </para>
</sect2> </sect2>
@@ -63,31 +276,6 @@
<title>Bug fixes</title> <title>Bug fixes</title>
<para> <para>
<itemizedlist> <itemizedlist>
<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.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="release-5.2.2">
<title>Release 5.2.2</title>
<para><emphasis>??? ? ???, 2021</emphasis></para>
<para>
&repmgr; 5.2.2 is a minor release.
</para>
<sect2>
<title>Bug fixes</title>
<para>
<itemizedlist>
<listitem> <listitem>
<para> <para>
<command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>: <command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>:
@@ -99,23 +287,23 @@
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<command><link linkend="repmgr-node-rejoin">repmgr node rejoin</link></command>: &repmgrd;: rename internal shared library functions to minimize the
emit rejoin target note information as <literal>NOTICE</literal>. risk of clashes with other shared libraries.
</para> </para>
<para> <para>
This makes it clearer what &repmgr; is trying to do. This does not affect user-facing SQL functions. Howe
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
&repmgrd;: ensure short option <option>-s</option> is accepted. &repmgrd;: ensure short option <option>-s</option> is accepted.
</para> </para>
</listitem> </listitem>
</itemizedlist>
</itemizedlist>
</para> </para>
</sect2> </sect2>
</sect1> </sect1>

View File

@@ -7,13 +7,13 @@
</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>

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>
@@ -225,6 +225,109 @@ description = "Main cluster"
</note> </note>
</sect2> </sect2>
<sect2 id="cloning-from-barman-pg_backupapi-mode" xreflabel="Using Barman through its API (pg-backup-api)">
<title>Using Barman through its API (pg-backup-api)</title>
<indexterm>
<primary>cloning</primary>
<secondary>pg-backup-api</secondary>
</indexterm>
<para>
You can find information on how to install and setup pg-backup-api in
<ulink url="https://www.enterprisedb.com/docs/supported-open-source/barman/pg-backup-api/">the pg-backup-api
documentation</ulink>.
</para>
<para>
This mode (`pg-backupapi`) was introduced in v5.4.0 as a way to further integrate with Barman letting Barman
handle the restore. This also reduces the ssh keys that need to share between the backup and postgres nodes.
As long as you have access to the API service by HTTP calls, you could perform recoveries right away.
You just need to instruct Barman through the API which backup you need and on which node the backup needs to
to be restored on.
</para>
<para>
In order to enable <literal>pg_backupapi mode</literal> support for <command>repmgr standby clone</command>,
you need the following lines in repmgr.conf:
<itemizedlist spacing="compact" mark="bullet">
<listitem><para>pg_backupapi_host: Where pg-backup-api is hosted</para></listitem>
<listitem><para>pg_backupapi_node_name: Name of the server as understood by Barman</para></listitem>
<listitem><para>pg_backupapi_remote_ssh_command: How Barman will be connecting as to the node</para></listitem>
<listitem><para>pg_backupapi_backup_id: ID of the existing backup you need to restore</para></listitem>
</itemizedlist>
This is an example of how repmgr.conf would look like:
<programlisting>
pg_backupapi_host = '192.168.122.154'
pg_backupapi_node_name = 'burrito'
pg_backupapi_remote_ssh_command = 'ssh john_doe@192.168.122.1'
pg_backupapi_backup_id = '20230223T093201'
</programlisting>
</para>
<para>
<literal>pg_backupapi_host</literal> is the variable name that enables this mode, and when you set it,
all the rest of the above variables are required. Also, remember that this service is just an interface
between Barman and repmgr, hence if something fails during a recovery, you should check Barman's logs upon
why the process couldn't finish properly.
</para>
<note>
<simpara>
Despite in Barman you can define shortcuts like "lastest" or "oldest", they are not supported for the
time being in pg-backup-api. These shortcuts will be supported in a future release.
</simpara>
</note>
<para>
This is a real example of repmgr's output cloning with the API. Note that during this operation, we stopped
the service for a little while and repmgr had to retry but that doesn't affect the final outcome. The primary
is listening on localhost's port 6001:
<programlisting>
$ repmgr -f ~/nodes/node_3/repmgr.conf standby clone -U repmgr -p 6001 -h localhost
NOTICE: destination directory "/home/mario/nodes/node_3/data" provided
INFO: Attempting to use `pg_backupapi` new restore mode
INFO: connecting to source node
DETAIL: connection string is: user=repmgr port=6001 host=localhost
DETAIL: current installation size is 8541 MB
DEBUG: 1 node records returned by source node
DEBUG: connecting to: "user=repmgr dbname=repmgr host=localhost port=6001 connect_timeout=2 fallback_application_name=repmgr options=-csearch_path="
DEBUG: upstream_node_id determined as 1
INFO: Attempting to use `pg_backupapi` new restore mode
INFO: replication slot usage not requested; no replication slot will be set up for this standby
NOTICE: starting backup (using pg_backupapi)...
INFO: Success creating the task: operation id '20230309T150647'
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
Incorrect reply received for that operation ID.
INFO: Retrying...
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status IN_PROGRESS
INFO: status DONE
NOTICE: standby clone (from pg_backupapi) complete
NOTICE: you can now start your PostgreSQL server
HINT: for example: pg_ctl -D /home/mario/nodes/node_3/data start
HINT: after starting the server, you need to register this standby with "repmgr standby register"
</programlisting>
</para>
</sect2> <!--END cloning-from-barman-pg_backupapi-mode !-->
</sect1> </sect1>
<sect1 id="cloning-replication-slots" xreflabel="Cloning and replication slots"> <sect1 id="cloning-replication-slots" xreflabel="Cloning and replication slots">
@@ -299,7 +402,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.
@@ -328,9 +431,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>
@@ -392,7 +495,7 @@ description = "Main cluster"
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 explicitly 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 +594,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 +611,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

@@ -10,8 +10,8 @@
<note> <note>
<simpara> <simpara>
This section documents a subset of optional configuration settings; for a full This section documents a subset of optional configuration settings; for a full
for a full and annotated view of all configuration options see the 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> <ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">sample repmgr.conf file</ulink>
</simpara> </simpara>
</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,194 @@
</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>
PostgreSQL 15 introduced the <varname>pg_checkpoint</varname> predefined role which allows a
non-superuser &repmgr; database user to perform a CHECKPOINT command.
</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.
From PostgreSQL 15 the <varname>pg_checkpoint</varname> predefined role removes the need of
superuser permissions to perform <command>CHECKPOINT</command> command.
</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>. Until PostgreSQL 14 <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.
From PostgreSQL 15 a specific ALTER SYSTEM privilege can be granted with e.g.
<command>GRANT ALTER SYSTEM ON PARAMETER wal_retrieve_retry_interval TO repmgr</command>.
</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

@@ -108,14 +108,34 @@
<entry> <entry>
Supported PostgreSQL versions Supported PostgreSQL versions
</entry> </entry>
<entry>
Notes
</entry>
</row> </row>
</thead> </thead>
<tbody> <tbody>
<row>
<entry>
&repmgr; 5.4
</entry>
<entry>
(dev)
</entry>
<entry>
<link linkend="release-current">&repmgrversion;</link> (&releasedate;)
</entry>
<entry>
9.4, 9.5, 9.6, 10, 11, 12, 13, 15
</entry>
<entry>
&nbsp;
</entry>
</row>
<row> <row>
<entry> <entry>
&repmgr; 5.2 &repmgr; 5.3
</entry> </entry>
<entry> <entry>
YES YES
@@ -123,9 +143,30 @@
<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, 15
</entry>
<entry>
PostgreSQL 15 supported from &repmgr; 5.3.3
</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>
<entry>
&nbsp;
</entry>
</row> </row>
<row> <row>
@@ -141,6 +182,9 @@
<entry> <entry>
9.3, 9.4, 9.5, 9.6, 10, 11, 12 9.3, 9.4, 9.5, 9.6, 10, 11, 12
</entry> </entry>
<entry>
&nbsp;
</entry>
</row> </row>
<row> <row>
@@ -156,6 +200,9 @@
<entry> <entry>
9.3, 9.4, 9.5, 9.6, 10, 11, 12 9.3, 9.4, 9.5, 9.6, 10, 11, 12
</entry> </entry>
<entry>
&nbsp;
</entry>
</row> </row>
@@ -172,6 +219,9 @@
<entry> <entry>
9.3, 9.4, 9.5, 9.6, 10, 11 9.3, 9.4, 9.5, 9.6, 10, 11
</entry> </entry>
<entry>
&nbsp;
</entry>
</row> </row>
<row> <row>
@@ -187,6 +237,9 @@
<entry> <entry>
9.3, 9.4, 9.5, 9.6 9.3, 9.4, 9.5, 9.6
</entry> </entry>
<entry>
&nbsp;
</entry>
</row> </row>
<row> <row>
@@ -202,6 +255,9 @@
<entry> <entry>
9.0, 9.1, 9.2, 9.3, 9.4 9.0, 9.1, 9.2, 9.3, 9.4
</entry> </entry>
<entry>
&nbsp;
</entry>
</row> </row>
</tbody> </tbody>

View File

@@ -1,18 +1,18 @@
<!-- doc/legal.xml --> <!-- doc/legal.xml -->
<date>2017</date> <date>2022</date>
<copyright> <copyright>
<year>2010-2021</year> <year>2010-2022</year>
<holder>EnterpriseDB Corporation</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-2021 <productname>repmgr</productname> is Copyright &copy; 2010-2022
by EnterpriseDB Corporation All rights reserved. by EDB All rights reserved.
</para> </para>
<para> <para>

View File

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

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

@@ -73,16 +73,16 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><option>--force-rewind[=/path/to/pg_rewind]</option></term> <term><option>--force-rewind</option></term>
<listitem> <listitem>
<para> <para>
Execute <application>pg_rewind</application>. Execute <application>pg_rewind</application>.
</para> </para>
<para> <para>
It is only necessary to provide the <application>pg_rewind</application> path See <xref linkend="repmgr-node-rejoin-pg-rewind"/> for more details on using
if using PostgreSQL 9.4, and <application>pg_rewind</application> <application>pg_rewind</application>.
is not installed in the PostgreSQL <filename>bin</filename> directory.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@@ -261,8 +261,6 @@
<para> <para>
<command>repmgr node rejoin</command> can optionally use <command>pg_rewind</command> to re-integrate a <command>repmgr node rejoin</command> can optionally use <command>pg_rewind</command> to re-integrate a
node which has diverged from the rest of the cluster, typically a failed primary. node which has diverged from the rest of the cluster, typically a failed primary.
<command>pg_rewind</command> is available in PostgreSQL 9.5 and later as part of the core distribution,
and can be installed from external sources for PostgreSQL 9.4.
</para> </para>
<note> <note>
<para> <para>
@@ -271,6 +269,10 @@
data checksums were enabled when the cluster was initialized. See the data checksums were enabled when the cluster was initialized. See the
<ulink url="https://www.postgresql.org/docs/current/app-pgrewind.html"><command>pg_rewind</command> documentation</ulink> for details. <ulink url="https://www.postgresql.org/docs/current/app-pgrewind.html"><command>pg_rewind</command> documentation</ulink> for details.
</para> </para>
<para>
Additionally, <varname>full_page_writes</varname> must be enabled; this is the default and
normally should never be disabled.
</para>
</note> </note>
<para> <para>
@@ -382,6 +384,29 @@
DETAIL: node 2 is now attached to node 3</programlisting> DETAIL: node 2 is now attached to node 3</programlisting>
</para> </para>
</refsect2> </refsect2>
<refsect2 id="repmgr-node-rejoin-postgresql-94" xreflabel="pg_rewind and PostgreSQL 9.4">
<title><command>pg_rewind</command> and PostgreSQL 9.4</title>
<indexterm>
<primary>pg_rewind</primary>
<secondary>PostgreSQL 9.4</secondary>
</indexterm>
<para>
<application>pg_rewind</application> is available in PostgreSQL 9.5 and later as part of the core distribution.
Users of PostgreSQL 9.4 will need to manually install it; the source code is available here:
<ulink url="https://github.com/vmware/pg_rewind">https://github.com/vmware/pg_rewind</ulink>.
If the <application>pg_rewind</application>
binary is not installed in the PostgreSQL <filename>bin</filename> directory, provide
its full path on the demotion candidate with <option>--force-rewind</option>.
</para>
<para>
Note that building the 9.4 version of <application>pg_rewind</application> requires the PostgreSQL
source code.
</para>
</refsect2>
</refsect1> </refsect1>
<refsect1 id="repmgr-node-rejoin-caveats" xreflabel="Caveats"> <refsect1 id="repmgr-node-rejoin-caveats" xreflabel="Caveats">
@@ -426,7 +451,7 @@
<warning> <warning>
<para> <para>
In all current PostgreSQL versions (as of September 2020), <application>pg_rewind</application> In all PostgreSQL released before February 2021, <application>pg_rewind</application>
contains a corner-case bug which affects standbys in a very specific situation. contains a corner-case bug which affects standbys in a very specific situation.
</para> </para>
<para> <para>
@@ -456,8 +481,7 @@
<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://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=2b4f3130382fe2f8705863e4d38589d4d69cd695">patch</ulink> A <ulink url="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=2b4f3130382fe2f8705863e4d38589d4d69cd695">patch</ulink>
has been successfully submitted and will be included the next PostgreSQL minor release round, scheduled for was submitted and is included in all PostgreSQL versions released in February 2021 or later.
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,
@@ -475,7 +499,7 @@
<refsect1> <refsect1>
<title>See also</title> <title>See also</title>
<para> <para>
<xref linkend="repmgr-standby-follow"/> <xref linkend="repmgr-standby-follow"/>, <xref linkend="repmgr-standby-switchover"/>
</para> </para>
</refsect1> </refsect1>
</refentry> </refentry>

View File

@@ -77,7 +77,8 @@
</para> </para>
<para> <para>
Note that a superuser connection is required to be able to execute the Note that a superuser connection is required to be able to execute the
<command>CHECKPOINT</command> command. <command>CHECKPOINT</command> command. From PostgreSQL 15 the <varname>pg_checkpoint</varname>
predefined role removes the need for superuser permissions to perform <command>CHECKPOINT</command> command.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@@ -332,6 +332,12 @@ pg_basebackup_options='--waldir=/path/to/wal-directory'</programlisting>
node to the same path on the standby (default) or to the 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>
@@ -399,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

@@ -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,8 @@
<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. From PostgreSQL 15 the <varname>pg_checkpoint</varname>
predefined role removes the need for superuser permissions to perform <command>CHECKPOINT</command> command.
</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
@@ -147,9 +155,12 @@
<para> <para>
Use <application>pg_rewind</application> to reintegrate the old primary if necessary Use <application>pg_rewind</application> to reintegrate the old primary if necessary
(and the prerequisites for using <application>pg_rewind</application> are met). (and the prerequisites for using <application>pg_rewind</application> are met).
</para>
<para>
If using PostgreSQL 9.4, and the <application>pg_rewind</application> If using PostgreSQL 9.4, and the <application>pg_rewind</application>
binary is not installed in the PostgreSQL <filename>bin</filename> directory, binary is not installed in the PostgreSQL <filename>bin</filename> directory,
provide its full path. For more details see also <xref linkend="switchover-pg-rewind"/>. provide its full path. For more details see also <xref linkend="switchover-pg-rewind"/>
and <xref linkend="repmgr-node-rejoin-pg-rewind"/>.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@@ -18,7 +18,7 @@
<title>repmgr &repmgrversion; Documentation</title> <title>repmgr &repmgrversion; Documentation</title>
<bookinfo> <bookinfo>
<corpauthor>EnterpriseDB Corporation</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 14. use with PostgreSQL 12 - PostgreSQL 17.
</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,19 +38,18 @@
<para> <para>
&repmgr; is developed by &repmgr; is developed by
<ulink url="https://2ndquadrant.com">2ndQuadrant (EDB)</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/EnterpriseDB/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 (EDB) 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 (EDB)'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>.
EnterpriseDB Corporation, a Major Sponsor of the PostgreSQL project, continues to maintain &repmgr;. EDB, a Major Sponsor of the PostgreSQL project, continues to maintain &repmgr;.
We welcome participation from other organisations and individual developers. 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"/>.
@@ -275,7 +279,9 @@
<note> <note>
<para> <para>
<option>standby_disconnect_on_failover</option> is available with PostgreSQL 9.5 and later. <option>standby_disconnect_on_failover</option> is available with PostgreSQL 9.5 and later.
Additionally this requires that the <literal>repmgr</literal> database user is a superuser. Until PostgreSQL 14 this requires that the <literal>repmgr</literal> database user is a superuser.
From PostgreSQL 15 a specific ALTER SYSTEM privilege can be granted to the <literal>repmgr</literal> database
user with e.g. <command>GRANT ALTER SYSTEM ON PARAMETER wal_retrieve_retry_interval TO repmgr</command>.
</para> </para>
</note> </note>
<para> <para>

View File

@@ -345,14 +345,18 @@
</indexterm> </indexterm>
<para> <para>
Indicates a preferred priority (default: <literal>100</literal>) for promoting nodes; Indicates a preferred priority (default: <literal>100</literal>) for promoting nodes.
a value of zero prevents the node being promoted to primary.
</para> </para>
<para> <para>
Note that the priority setting is only applied if two or more nodes are Note that the priority setting is only applied if two or more nodes are
determined as promotion candidates; in that case the node with the determined as promotion candidates; in that case the node with the
higher priority is selected. higher priority is selected.
</para> </para>
<para>
A value of zero will always prevent the node being promoted to primary, even if there
is no other promotion candidate.
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@@ -1079,6 +1083,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

@@ -29,7 +29,7 @@
<listitem> <listitem>
<simpara> <simpara>
option to execute custom scripts (&quot;<link linkend="event-notifications">event notifications</link> option to execute custom scripts (&quot;<link linkend="event-notifications">event notifications</link>&quot;)
at different points in the failover sequence at different points in the failover sequence
</simpara> </simpara>
</listitem> </listitem>

View File

@@ -242,21 +242,12 @@
</simpara> </simpara>
</note> </note>
<para> <para>
For more details on <application>pg_rewind</application>, see: For more details on <application>pg_rewind</application>, see section <xref linkend="repmgr-node-rejoin-pg-rewind"/>
in the <link linkend="repmgr-node-rejoin"><command>repmgr node rejoin</command></link> documentation and
the PostgreSQL documentation at
<ulink url="https://www.postgresql.org/docs/current/app-pgrewind.html">https://www.postgresql.org/docs/current/app-pgrewind.html</ulink>. <ulink url="https://www.postgresql.org/docs/current/app-pgrewind.html">https://www.postgresql.org/docs/current/app-pgrewind.html</ulink>.
</para> </para>
<para>
<application>pg_rewind</application> has been part of the core PostgreSQL distribution since
version 9.5. Users of PostgreSQL 9.4 will need to manually install it; the source code is available here:
<ulink url="https://github.com/vmware/pg_rewind">https://github.com/vmware/pg_rewind</ulink>.
If the <application>pg_rewind</application>
binary is not installed in the PostgreSQL <filename>bin</filename> directory, provide
its full path on the demotion candidate with <option>--force-rewind</option>.
</para>
<para>
Note that building the 9.4 version of <application>pg_rewind</application> requires the PostgreSQL
source code.
</para>
</sect2> </sect2>

View File

@@ -71,6 +71,12 @@
<secondary>minor release</secondary> <secondary>minor release</secondary>
</indexterm> </indexterm>
<para>
A minor release upgrade involves updating &repmgr; from one minor release to another
minor release within the same major release (e.g. <literal>5.3.1</literal> to <literal>5.3.2</literal>).
An upgrade between minor releases of differing major releases (e.g. <literal>5.2.1</literal> to <literal>5.3.2</literal>)
is a <link linkend="upgrading-major-version">major upgrade</link>.
</para>
<para> <para>
The process for installing minor version upgrades is quite straightforward: The process for installing minor version upgrades is quite straightforward:
@@ -105,15 +111,17 @@
</para> </para>
<para> <para>
A PostgreSQL restart is <emphasis>not</emphasis> required for minor version upgrades. A PostgreSQL restart is usually <emphasis>not</emphasis> required for minor version upgrades
within the same major version (e.g. <literal>5.3.1</literal> to <literal>5.3.2</literal>).
Be sure to check the <link linkend="appendix-release-notes">release notes</link>.
</para> </para>
<note> <note>
<para> <para>
The same &repmgr; &quot;major version&quot; (e.g. <literal>4.2</literal>) must be The same &repmgr; &quot;major version&quot; (e.g. <literal>5.3</literal>) must be
installed on all nodes in the replication cluster. While it's possible to have differing installed on all nodes in the replication cluster. While it's possible to have differing
&repmgr; &quot;minor versions&quot; (e.g. <literal>4.2.1</literal>) on different nodes, &repmgr; &quot;minor versions&quot; (e.g. <literal>5.3.1</literal> and <literal>5.3.2</literal>)
we strongly recommend updating all nodes to the latest minor version. on different nodes, we strongly recommend updating all nodes to the latest minor version.
</para> </para>
</note> </note>

View File

@@ -49,5 +49,6 @@
#define ERR_NODE_STATUS 25 #define ERR_NODE_STATUS 25
#define ERR_REPMGRD_PAUSE 26 #define ERR_REPMGRD_PAUSE 26
#define ERR_REPMGRD_SERVICE 27 #define ERR_REPMGRD_SERVICE 27
#define ERR_PGBACKUPAPI_SERVICE 28
#endif /* _ERRCODE_H_ */ #endif /* _ERRCODE_H_ */

147
pgbackupapi.c Normal file
View File

@@ -0,0 +1,147 @@
/*
* pgbackupapi.c
* Copyright (c) EnterpriseDB Corporation, 2010-2021
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <curl/curl.h>
#include <json-c/json.h>
#include "repmgr.h"
#include "pgbackupapi.h"
size_t receive_operations_cb(void *content, size_t size, size_t nmemb, char *buffer) {
short int max_chars_to_copy = MAX_BUFFER_LENGTH -2;
short int i = 0;
int operation_length = 0;
json_object *value;
json_object *root = json_tokener_parse(content);
json_object *operations = json_object_object_get(root, "operations");
operation_length = strlen(json_object_get_string(operations));
if (operation_length < max_chars_to_copy) {
max_chars_to_copy = operation_length;
}
strncpy(buffer, json_object_get_string(operations), max_chars_to_copy);
fprintf(stdout, "Success! The following operations were found\n");
for (i=0; i<json_object_array_length(operations); i++) {
value = json_object_array_get_idx(operations, i);
printf("%s\n", json_object_get_string(value));
}
return size * nmemb;
}
char * define_base_url(operation_task *task) {
char *format = "http://%s:7480/servers/%s/operations";
char *url = malloc(MAX_BUFFER_LENGTH);
snprintf(url, MAX_BUFFER_LENGTH-1, format, task->host, task->node_name);
//`url` is freed on the function that called this
return url;
}
CURLcode get_operations_on_server(CURL *curl, operation_task *task) {
char buffer[MAX_BUFFER_LENGTH];
char *url = define_base_url(task);
CURLcode ret;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receive_operations_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
curl_easy_setopt(curl, CURLOPT_URL, url);
ret = curl_easy_perform(curl);
free(url);
return ret;
}
size_t receive_operation_id(void *content, size_t size, size_t nmemb, char *buffer) {
json_object *root = json_tokener_parse(content);
json_object *operation = json_object_object_get(root, "operation_id");
if (operation != NULL) {
strncpy(buffer, json_object_get_string(operation), MAX_BUFFER_LENGTH-2);
}
return size * nmemb;
}
CURLcode create_new_task(CURL *curl, operation_task *task) {
PQExpBufferData payload;
char *url = define_base_url(task);
CURLcode ret;
json_object *root = json_object_new_object();
struct curl_slist *chunk = NULL;
json_object_object_add(root, "operation_type", json_object_new_string(task->operation_type));
json_object_object_add(root, "backup_id", json_object_new_string(task->backup_id));
json_object_object_add(root, "remote_ssh_command", json_object_new_string(task->remote_ssh_command));
json_object_object_add(root, "destination_directory", json_object_new_string(task->destination_directory));
initPQExpBuffer(&payload);
appendPQExpBufferStr(&payload, json_object_to_json_string(root));
chunk = curl_slist_append(chunk, "Content-type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.data);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receive_operation_id);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, task->operation_id);
ret = curl_easy_perform(curl);
free(url);
termPQExpBuffer(&payload);
return ret;
}
size_t receive_operation_status(void *content, size_t size, size_t nmemb, char *buffer) {
json_object *root = json_tokener_parse(content);
json_object *status = json_object_object_get(root, "status");
if (status != NULL) {
strncpy(buffer, json_object_get_string(status), MAX_BUFFER_LENGTH-2);
}
else {
fprintf(stderr, "Incorrect reply received for that operation ID.\n");
strcpy(buffer, "\0");
}
return size * nmemb;
}
CURLcode get_status_of_operation(CURL *curl, operation_task *task) {
CURLcode ret;
char *url = define_base_url(task);
strcat(url, "/");
strcat(url, task->operation_id);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receive_operation_status);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, task->operation_status);
ret = curl_easy_perform(curl);
free(url);
return ret;
}

46
pgbackupapi.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* pgbackupapi.h
* Copyright (c) EnterpriseDB Corporation, 2010-2021
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <curl/curl.h>
#include <json-c/json.h>
typedef struct operation_task {
char *backup_id;
char *destination_directory;
char *operation_type;
char *operation_id;
char *operation_status;
char *remote_ssh_command;
char *host;
char *node_name;
} operation_task;
//Default simplebuffer size in most of operations
#define MAX_BUFFER_LENGTH 72
//Callbacks to send/receive data from pg-backup-api endpoints
size_t receive_operations_cb(void *content, size_t size, size_t nmemb, char *buffer);
size_t receive_operation_id(void *content, size_t size, size_t nmemb, char *buffer);
size_t receive_operation_status(void *content, size_t size, size_t nmemb, char *buffer);
//Functions that implement the logic and know what to do and how to comunnicate wuth the API
CURLcode get_operations_on_server(CURL *curl, operation_task *task);
CURLcode create_new_task(CURL *curl, operation_task *task);
CURLcode get_status_of_operation(CURL *curl, operation_task *task);
//Helper to make simpler to read the handler where we set the URL
char * define_base_url(operation_task *task);

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;

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

2
repmgr--5.4--5.5.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.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
);

191
repmgr--5.5.sql Normal file
View File

@@ -0,0 +1,191 @@
-- 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

@@ -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
* *
@@ -391,7 +394,6 @@ do_node_status(void)
if (node_info.inactive_replication_slots > 0) if (node_info.inactive_replication_slots > 0)
{ {
KeyValueList inactive_replication_slots = {NULL, NULL}; KeyValueList inactive_replication_slots = {NULL, NULL};
KeyValueListCell *cell = NULL;
(void) get_inactive_replication_slots(conn, &inactive_replication_slots); (void) get_inactive_replication_slots(conn, &inactive_replication_slots);
@@ -521,8 +523,6 @@ do_node_status(void)
if (node_info.inactive_replication_slots) if (node_info.inactive_replication_slots)
{ {
KeyValueList inactive_replication_slots = {NULL, NULL}; KeyValueList inactive_replication_slots = {NULL, NULL};
KeyValueListCell *cell = NULL;
(void) get_inactive_replication_slots(conn, &inactive_replication_slots); (void) get_inactive_replication_slots(conn, &inactive_replication_slots);
for (cell = inactive_replication_slots.head; cell; cell = cell->next) for (cell = inactive_replication_slots.head; cell; cell = cell->next)
{ {
@@ -941,6 +941,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 +1324,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 +1392,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 +1515,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 +2017,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 +2151,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
*/ */
@@ -2323,18 +2362,25 @@ do_node_service(void)
conn = establish_db_connection_by_params(&source_conninfo, true); conn = establish_db_connection_by_params(&source_conninfo, true);
} }
if (is_superuser_connection(conn, NULL) == false) if (can_execute_checkpoint(conn) == false)
{ {
if (runtime_options.dry_run == true) if (runtime_options.dry_run == true)
{ {
log_warning(_("a CHECKPOINT would be issued here but no superuser connection is available")); log_warning(_("a CHECKPOINT would be issued here but no authorized connection is available"));
} }
else else
{ {
log_warning(_("a superuser connection is required to issue a CHECKPOINT")); log_warning(_("an authorized connection is required to issue a CHECKPOINT"));
} }
log_hint(_("provide a superuser with -S/--superuser")); if (PQserverVersion(conn) >= 150000)
{
log_hint(_("provide a superuser with -S/--superuser or grant pg_checkpoint role to repmgr user"));
}
else
{
log_hint(_("provide a superuser with -S/--superuser"));
}
} }
else else
{ {
@@ -2497,6 +2543,7 @@ do_node_rejoin(void)
int server_version_num = UNKNOWN_SERVER_VERSION_NUM; int server_version_num = UNKNOWN_SERVER_VERSION_NUM;
bool hide_standby_signal = false; bool hide_standby_signal = false;
KeyValueListCell *cell = NULL;
PQExpBufferData command; PQExpBufferData command;
PQExpBufferData command_output; PQExpBufferData command_output;
PQExpBufferData follow_output; PQExpBufferData follow_output;
@@ -2916,7 +2963,7 @@ do_node_rejoin(void)
else else
{ {
while ((slotdir_ent = readdir(slotdir)) != NULL) { while ((slotdir_ent = readdir(slotdir)) != NULL) {
struct stat statbuf; struct stat local_statbuf;
PQExpBufferData slotdir_ent_path; PQExpBufferData slotdir_ent_path;
if (strcmp(slotdir_ent->d_name, ".") == 0 || strcmp(slotdir_ent->d_name, "..") == 0) if (strcmp(slotdir_ent->d_name, ".") == 0 || strcmp(slotdir_ent->d_name, "..") == 0)
@@ -2929,7 +2976,7 @@ do_node_rejoin(void)
slotdir_path.data, slotdir_path.data,
slotdir_ent->d_name); slotdir_ent->d_name);
if (stat(slotdir_ent_path.data, &statbuf) == 0 && !S_ISDIR(statbuf.st_mode)) if (stat(slotdir_ent_path.data, &local_statbuf) == 0 && !S_ISDIR(local_statbuf.st_mode))
{ {
termPQExpBuffer(&slotdir_ent_path); termPQExpBuffer(&slotdir_ent_path);
continue; continue;
@@ -3060,7 +3107,6 @@ do_node_rejoin(void)
else else
{ {
KeyValueList inactive_replication_slots = {NULL, NULL}; KeyValueList inactive_replication_slots = {NULL, NULL};
KeyValueListCell *cell = NULL;
int inactive_count = 0; int inactive_count = 0;
PQExpBufferData slotinfo; PQExpBufferData slotinfo;
@@ -3570,6 +3616,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)
{ {
@@ -3612,6 +3677,7 @@ do_node_help(void)
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("");

View File

@@ -235,6 +235,38 @@ do_primary_register(void)
return; return;
} }
static inline void reset_node_info(t_node_info *info)
{
info->node_id = NODE_NOT_FOUND;
info->upstream_node_id = NO_UPSTREAM_NODE;
info->type = UNKNOWN;
info->node_name[0] = '\0';
info->upstream_node_name[0] = '\0';
info->conninfo[0] = '\0';
info->repluser[0] = '\0';
info->priority = DEFAULT_PRIORITY;
info->active = true;
info->slot_name[0] = '\0';
info->config_file[0] = '\0';
info->last_wal_receive_lsn = InvalidXLogRecPtr;
info->node_status = NODE_STATUS_UNKNOWN;
info->recovery_type = RECTYPE_UNKNOWN;
info->monitoring_state = MS_NORMAL;
info->conn = NULL;
info->details[0] = '\0';
info->reachable = true;
info->attached = true;
/* various statistics */
info->max_wal_senders = -1;
info->attached_wal_receivers = -1;
info->max_replication_slots = -1;
info->total_replication_slots = -1;
info->active_replication_slots = -1;
info->inactive_replication_slots = -1;
info->replication_info = NULL;
strlcpy(info->location, DEFAULT_LOCATION, sizeof(info->location));
}
/* /*
* do_primary_unregister() * do_primary_unregister()
@@ -436,7 +468,7 @@ do_primary_unregister(void)
} }
else if (recovery_type == RECTYPE_PRIMARY) else if (recovery_type == RECTYPE_PRIMARY)
{ {
t_node_info primary_node_info = T_NODE_INFO_INITIALIZER; reset_node_info(&primary_node_info);
bool primary_record_found = false; bool primary_record_found = false;
primary_record_found = get_primary_node_record(primary_conn, &primary_node_info); primary_record_found = get_primary_node_record(primary_conn, &primary_node_info);

View File

@@ -21,6 +21,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <time.h> #include <time.h>
#include <unistd.h>
#include "repmgr.h" #include "repmgr.h"
#include "dirutil.h" #include "dirutil.h"
@@ -29,7 +30,7 @@
#include "repmgr-client-global.h" #include "repmgr-client-global.h"
#include "repmgr-action-standby.h" #include "repmgr-action-standby.h"
#include "pgbackupapi.h"
typedef struct TablespaceDataListCell typedef struct TablespaceDataListCell
{ {
@@ -95,6 +96,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;
@@ -111,6 +114,7 @@ static void check_recovery_type(PGconn *conn);
static void initialise_direct_clone(t_node_info *local_node_record, t_node_info *upstream_node_record); static void initialise_direct_clone(t_node_info *local_node_record, t_node_info *upstream_node_record);
static int run_basebackup(t_node_info *node_record); static int run_basebackup(t_node_info *node_record);
static int run_file_backup(t_node_info *node_record); static int run_file_backup(t_node_info *node_record);
static int run_pg_backupapi(t_node_info *node_record);
static void copy_configuration_files(bool delete_after_copy); static void copy_configuration_files(bool delete_after_copy);
@@ -531,7 +535,7 @@ do_standby_clone(void)
if (external_config_files == true) if (external_config_files == true)
{ {
int r; r = 0;
PQExpBufferData msg; PQExpBufferData msg;
initPQExpBuffer(&msg); initPQExpBuffer(&msg);
@@ -685,19 +689,18 @@ do_standby_clone(void)
exit(SUCCESS); exit(SUCCESS);
} }
if (mode != barman)
{
initialise_direct_clone(&local_node_record, &upstream_node_record);
}
switch (mode) switch (mode)
{ {
case pg_basebackup: case pg_basebackup:
initialise_direct_clone(&local_node_record, &upstream_node_record);
log_notice(_("starting backup (using pg_basebackup)...")); log_notice(_("starting backup (using pg_basebackup)..."));
break; break;
case barman: case barman:
log_notice(_("retrieving backup from Barman...")); log_notice(_("retrieving backup from Barman..."));
break; break;
case pg_backupapi:
log_notice(_("starting backup (using pg_backupapi)..."));
break;
default: default:
/* should never reach here */ /* should never reach here */
log_error(_("unknown clone mode")); log_error(_("unknown clone mode"));
@@ -719,6 +722,9 @@ do_standby_clone(void)
case barman: case barman:
r = run_file_backup(&local_node_record); r = run_file_backup(&local_node_record);
break; break;
case pg_backupapi:
r = run_pg_backupapi(&local_node_record);
break;
default: default:
/* should never reach here */ /* should never reach here */
log_error(_("unknown clone mode")); log_error(_("unknown clone mode"));
@@ -756,7 +762,7 @@ do_standby_clone(void)
if (mode == pg_basebackup && runtime_options.verify_backup == true) if (mode == pg_basebackup && runtime_options.verify_backup == true)
{ {
PQExpBufferData command; PQExpBufferData command;
int r; r = 0;
struct stat st; struct stat st;
initPQExpBuffer(&command); initPQExpBuffer(&command);
@@ -812,7 +818,6 @@ do_standby_clone(void)
} }
/* Write the recovery.conf file */ /* Write the recovery.conf file */
if (create_recovery_file(&local_node_record, if (create_recovery_file(&local_node_record,
&recovery_conninfo, &recovery_conninfo,
source_server_version_num, source_server_version_num,
@@ -844,6 +849,9 @@ do_standby_clone(void)
case barman: case barman:
log_notice(_("standby clone (from Barman) complete")); log_notice(_("standby clone (from Barman) complete"));
break; break;
case pg_backupapi:
log_notice(_("standby clone (from pg_backupapi) complete"));
break;
} }
/* /*
@@ -935,6 +943,9 @@ do_standby_clone(void)
case barman: case barman:
appendPQExpBufferStr(&event_details, "barman"); appendPQExpBufferStr(&event_details, "barman");
break; break;
case pg_backupapi:
appendPQExpBufferStr(&event_details, "pg_backupapi");
break;
} }
appendPQExpBuffer(&event_details, appendPQExpBuffer(&event_details,
@@ -3346,10 +3357,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);
@@ -3917,7 +3927,6 @@ do_standby_switchover(void)
if (PQserverVersion(local_conn) < 130000 && is_wal_replay_paused(local_conn, false) == true) if (PQserverVersion(local_conn) < 130000 && is_wal_replay_paused(local_conn, false) == true)
{ {
ReplInfo replication_info;
init_replication_info(&replication_info); init_replication_info(&replication_info);
if (get_replication_info(local_conn, STANDBY, &replication_info) == false) if (get_replication_info(local_conn, STANDBY, &replication_info) == false)
@@ -4774,7 +4783,7 @@ do_standby_switchover(void)
{ {
NodeInfoListCell *cell = NULL; NodeInfoListCell *cell = NULL;
ItemList repmgrd_connection_errors = {NULL, NULL}; ItemList repmgrd_connection_errors = {NULL, NULL};
int i = 0; i = 0;
int unreachable_node_count = 0; int unreachable_node_count = 0;
get_all_node_records(local_conn, &all_nodes); get_all_node_records(local_conn, &all_nodes);
@@ -5089,8 +5098,6 @@ do_standby_switchover(void)
/* database server could not be contacted */ /* database server could not be contacted */
if (ping_res == PQPING_NO_RESPONSE || ping_res == PQPING_NO_ATTEMPT) if (ping_res == PQPING_NO_RESPONSE || ping_res == PQPING_NO_ATTEMPT)
{ {
bool command_success;
/* /*
* remote server can't be contacted at protocol level - that * remote server can't be contacted at protocol level - that
* doesn't necessarily mean it's shut down, so we'll ask its * doesn't necessarily mean it's shut down, so we'll ask its
@@ -5278,7 +5285,7 @@ do_standby_switchover(void)
checkpoint_conn = superuser_conn; checkpoint_conn = superuser_conn;
} }
if (is_superuser_connection(checkpoint_conn, NULL) == true) if (can_execute_checkpoint(checkpoint_conn) == true)
{ {
log_notice(_("issuing CHECKPOINT on node \"%s\" (ID: %i) "), log_notice(_("issuing CHECKPOINT on node \"%s\" (ID: %i) "),
config_file_options.node_name, config_file_options.node_name,
@@ -5287,7 +5294,16 @@ do_standby_switchover(void)
} }
else else
{ {
log_warning(_("no superuser connection available, unable to issue CHECKPOINT")); log_warning(_("no authorized connection available, unable to issue CHECKPOINT"));
if (PQserverVersion(local_conn) >= 150000)
{
log_hint(_("provide a superuser with -S/--superuser or grant pg_checkpoint role to repmgr user"));
}
else
{
log_hint(_("provide a superuser with -S/--superuser"));
}
} }
} }
@@ -5659,7 +5675,7 @@ do_standby_switchover(void)
{ {
ItemList repmgrd_unpause_errors = {NULL, NULL}; ItemList repmgrd_unpause_errors = {NULL, NULL};
NodeInfoListCell *cell = NULL; NodeInfoListCell *cell = NULL;
int i = 0; i = 0;
int error_node_count = 0; int error_node_count = 0;
for (cell = all_nodes.head; cell; cell = cell->next) for (cell = all_nodes.head; cell; cell = cell->next)
@@ -5783,20 +5799,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);
/* /*
@@ -6496,12 +6510,12 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea
if (mode == pg_basebackup) if (mode == pg_basebackup)
{ {
PGconn **connections; PGconn **connections;
int i; int available_wal_senders;
int available_wal_senders; int min_replication_connections = 1;
int min_replication_connections = 1; int possible_replication_connections = 0;
int possible_replication_connections = 0; i = 0;
t_conninfo_param_list repl_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER; t_conninfo_param_list repl_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER;
/* /*
@@ -7771,6 +7785,117 @@ stop_backup:
} }
/*
* Perform a call to pg_backupapi endpoint to ask barman to write the backup
* for us. This will ensure that no matter the format on-disk of new backups,
* barman will always find a way how to read and write them.
* From repmgr 4 this is only used for Barman backups.
*/
static int
run_pg_backupapi(t_node_info *local_node_record)
{
int r = ERR_PGBACKUPAPI_SERVICE;
long http_return_code = 0;
short seconds_to_sleep = 3;
operation_task *task = malloc(sizeof(operation_task));
CURL *curl = curl_easy_init();
CURLcode ret;
check_pg_backupapi_standby_clone_options();
task->host = malloc(strlen(config_file_options.pg_backupapi_host)+1);
task->remote_ssh_command = malloc(strlen(config_file_options.pg_backupapi_remote_ssh_command)+1);
task->node_name = malloc(strlen(config_file_options.pg_backupapi_node_name)+1);
task->operation_type = malloc(strlen(DEFAULT_STANDBY_PG_BACKUPAPI_OP_TYPE)+1);
task->backup_id = malloc(strlen(config_file_options.pg_backupapi_backup_id)+1);
task->destination_directory = malloc(strlen(local_data_directory)+1);
task->operation_id = malloc(MAX_BUFFER_LENGTH);
task->operation_status = malloc(MAX_BUFFER_LENGTH);
strcpy(task->host, config_file_options.pg_backupapi_host);
strcpy(task->remote_ssh_command, config_file_options.pg_backupapi_remote_ssh_command);
strcpy(task->node_name, config_file_options.pg_backupapi_node_name);
strcpy(task->operation_type, DEFAULT_STANDBY_PG_BACKUPAPI_OP_TYPE);
strcpy(task->backup_id, config_file_options.pg_backupapi_backup_id);
strcpy(task->destination_directory, local_data_directory);
strcpy(task->operation_id, "\0");
ret = create_new_task(curl, task);
if ((ret != CURLE_OK) || (strlen(task->operation_id) == 0)) {
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_return_code);
if (499 > http_return_code && http_return_code >= 400) {
log_error("Cannot find backup '%s' for node '%s'.", task->backup_id, task->node_name);
} else {
log_error("whilst reaching out pg_backup service: %s\n", curl_easy_strerror(ret));
}
}
else
{
log_info("Success creating the task: operation id '%s'", task->operation_id);
//We call init again because previous call included POST calls
curl_easy_cleanup(curl);
curl = curl_easy_init();
while (true)
{
ret = get_status_of_operation(curl, task);
if (strlen(task->operation_status) == 0) {
log_info("Retrying...");
}
else
{
log_info("status %s", task->operation_status);
}
if (strcmp(task->operation_status, "FAILED") == 0) {
break;
}
if (strcmp(task->operation_status, "DONE") == 0) {
r = SUCCESS;
break;
}
sleep(seconds_to_sleep);
}
}
curl_easy_cleanup(curl);
free(task);
return r;
}
/*
* pg_backupapi mode is enabled when config_file_options.pg_backupapi_host is set hence, we
* should also check the other required variables too.
*/
void check_pg_backupapi_standby_clone_options() {
bool error = false;
if (*config_file_options.pg_backupapi_remote_ssh_command == '\0') {
log_hint("Check config: remote ssh command is required");
error = true;
}
if (*config_file_options.pg_backupapi_node_name == '\0') {
log_hint("Check config: node name is required");
error = true;
}
if (*config_file_options.pg_backupapi_backup_id == '\0') {
log_hint("Check config: backup_id is required");
error = true;
}
if (error == true) {
log_error("Please fix the errors and try again");
exit(ERR_BAD_CONFIG);
}
}
static char * static char *
make_barman_ssh_command(char *buf) make_barman_ssh_command(char *buf)
{ {
@@ -8352,7 +8477,6 @@ check_sibling_nodes(NodeInfoList *sibling_nodes, SiblingNodeStats *sibling_nodes
if (sibling_nodes->node_count > 0) if (sibling_nodes->node_count > 0)
{ {
PQExpBufferData nodes; PQExpBufferData nodes;
NodeInfoListCell *cell;
initPQExpBuffer(&nodes); initPQExpBuffer(&nodes);

View File

@@ -30,6 +30,6 @@ extern void do_standby_help(void);
extern bool do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_node_info *follow_target_node_record, PQExpBufferData *output, int general_error_code, int *error_code); extern bool do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_node_info *follow_target_node_record, PQExpBufferData *output, int general_error_code, int *error_code);
void check_pg_backupapi_standby_clone_options(void);
#endif /* _REPMGR_ACTION_STANDBY_H_ */ #endif /* _REPMGR_ACTION_STANDBY_H_ */

View File

@@ -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 */ \
@@ -192,7 +193,8 @@ typedef struct
typedef enum typedef enum
{ {
barman, barman,
pg_basebackup pg_basebackup,
pg_backupapi
} standy_clone_mode; } standy_clone_mode;
typedef enum typedef enum

View File

@@ -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>
@@ -69,7 +70,11 @@
#include "repmgr-action-service.h" #include "repmgr-action-service.h"
#include "repmgr-action-daemon.h" #include "repmgr-action-daemon.h"
#if (PG_VERSION_NUM >= 170000)
#include <common/file_utils.h> /* for PG_TEMP_FILE_PREFIX */
#else
#include <storage/fd.h> /* for PG_TEMP_FILE_PREFIX */ #include <storage/fd.h> /* for PG_TEMP_FILE_PREFIX */
#endif
/* globally available variables * /* globally available variables *
* ============================ */ * ============================ */
@@ -89,17 +94,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)
{ {
@@ -549,6 +559,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;
@@ -3086,9 +3100,14 @@ get_standby_clone_mode(void)
if (*config_file_options.barman_host != '\0' && runtime_options.without_barman == false) if (*config_file_options.barman_host != '\0' && runtime_options.without_barman == false)
mode = barman; mode = barman;
else else {
mode = pg_basebackup; if (*config_file_options.pg_backupapi_host != '\0') {
log_info("Attempting to use `pg_backupapi` new restore mode");
mode = pg_backupapi;
}
else
mode = pg_basebackup;
}
return mode; return mode;
} }
@@ -3182,6 +3201,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/*");
@@ -3619,8 +3643,8 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
/* "full_page_writes" must be on in any case */ /* "full_page_writes" must be on in any case */
if (guc_set(conn, "full_page_writes", "=", "off")) if (guc_set(conn, "full_page_writes", "=", "off"))
{ {
appendPQExpBuffer(reason, appendPQExpBufferStr(reason,
_("\"full_page_writes\" must be set to \"on\"")); _("\"full_page_writes\" must be set to \"on\""));
can_use = false; can_use = false;
} }
@@ -3638,18 +3662,18 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
if (data_checksum_version == UNKNOWN_DATA_CHECKSUM_VERSION) if (data_checksum_version == UNKNOWN_DATA_CHECKSUM_VERSION)
{ {
if (can_use == false) if (can_use == false)
appendPQExpBuffer(reason, "; "); appendPQExpBufferStr(reason, "; ");
appendPQExpBuffer(reason, appendPQExpBufferStr(reason,
_("\"wal_log_hints\" is set to \"off\" but unable to determine data checksum version")); _("\"wal_log_hints\" is set to \"off\" but unable to determine data checksum version"));
can_use = false; can_use = false;
} }
else if (data_checksum_version == 0) else if (data_checksum_version == 0)
{ {
if (can_use == false) if (can_use == false)
appendPQExpBuffer(reason, "; "); appendPQExpBufferStr(reason, "; ");
appendPQExpBuffer(reason, appendPQExpBufferStr(reason,
_("\"wal_log_hints\" is set to \"off\" and data checksums are disabled")); _("\"wal_log_hints\" is set to \"off\" and data checksums are disabled"));
can_use = false; can_use = false;
@@ -3729,6 +3753,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.
@@ -3740,7 +3765,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;
@@ -3786,65 +3811,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)
{ {
@@ -3887,34 +3859,53 @@ 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 = _get_replication_slot_connection(conn,
replication_user,
&use_replication_protocol);
if (use_replication_protocol == true)
{
success = drop_replication_slot_replprot(slot_conn, slot_name);
}
else
{
success = drop_replication_slot_sql(slot_conn, slot_name);
}
if (success == true)
{ {
log_notice(_("replication slot \"%s\" deleted on node %i"), slot_name, node_id); 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;
@@ -3976,10 +3967,88 @@ _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 managing replication slots");
return NULL;
case REPMGR_USER:
slot_conn = conn;
log_verbose(LOG_INFO, _("managing replication slot as user \"%s\""),
PQuser(conn));
break;
case REPLICATION_USER_NODE:
case REPLICATION_USER_OPT:
{
slot_conn = duplicate_connection(conn,
replication_user,
true);
if (slot_conn == NULL || PQstatus(slot_conn) != CONNECTION_OK)
{
log_error(_("unable to manage replication connection as replication user \"%s\""),
runtime_options.replication_user);
log_detail("%s", PQerrorMessage(slot_conn));
PQfinish(slot_conn);
return NULL;
}
*use_replication_protocol = true;
log_verbose(LOG_INFO, _("managing replication slot as replication user \"%s\""),
replication_user);
}
break;
case SUPERUSER:
{
slot_conn = duplicate_connection(conn,
runtime_options.superuser,
false);
if (slot_conn == NULL || PQstatus(slot_conn )!= CONNECTION_OK)
{
log_error(_("unable to create superuser connection as user \"%s\""),
runtime_options.superuser);
log_detail("%s", PQerrorMessage(slot_conn));
PQfinish(slot_conn);
return NULL;
}
log_verbose(LOG_INFO, _("creating replication slot as superuser \"%s\""),
runtime_options.superuser);
}
break;
}
return slot_conn;
}
bool bool
check_replication_slots_available(int node_id, PGconn* conn) check_replication_slots_available(int node_id, PGconn* conn)
{ {

View File

@@ -100,6 +100,7 @@
#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_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
@@ -193,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},

View File

@@ -80,12 +80,16 @@ 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);
#if (PG_VERSION_NUM >= 150000)
static void repmgr_shmem_request(void);
#endif
static void repmgr_shmem_startup(void); static void repmgr_shmem_startup(void);
PG_FUNCTION_INFO_V1(repmgr_set_local_node_id); PG_FUNCTION_INFO_V1(repmgr_set_local_node_id);
@@ -117,35 +121,47 @@ _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;
} }
#if (PG_VERSION_NUM >= 150000)
/* /*
* Module unload callback * shmem_requst_hook: request shared memory
*/ */
void static void
_PG_fini(void) repmgr_shmem_request(void)
{ {
/* Uninstall hook */ if (prev_shmem_request_hook)
shmem_startup_hook = prev_shmem_startup_hook; prev_shmem_request_hook();
}
RequestAddinShmemSpace(MAXALIGN(sizeof(repmgrdSharedState)));
RequestNamedLWLockTranche(TRANCHE_NAME, 1);
}
#endif
/* /*
* shmem_startup hook: allocate or attach to shared memory, * shmem_startup hook: allocate or attach to shared memory
*/ */
static void static void
repmgr_shmem_startup(void) repmgr_shmem_startup(void)

View File

@@ -12,7 +12,7 @@
# #
# For details on the configuration file format see the documentation at: # For details on the configuration file format see the documentation at:
# #
# https://repmgr.org/docs/current/configuration-file.html#CONFIGURATION-FILE-FORMAT # https://repmgr.org/docs/current/configuration-file.html#CONFIGURATION-FILE-FORMAT
# #
# ============================================================================= # =============================================================================
# Required configuration items # Required configuration items
@@ -69,14 +69,14 @@
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
#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).
#location='default' # An arbitrary string defining the location of the node; this #location='default' # An arbitrary string defining the location of the node; this
# is used during failover to check visibility of the # is used during failover to check visibility of the
# current primary node. For further details see: # current primary node. For further details see:
# https://repmgr.org/docs/current/repmgrd-network-split.html # https://repmgr.org/docs/current/repmgrd-network-split.html
#use_replication_slots=no # whether to use physical replication slots #use_replication_slots=no # whether to use physical replication slots
# NOTE: when using replication slots, # NOTE: when using replication slots,
@@ -181,8 +181,8 @@
#pg_ctl_options='' # Options to append to "pg_ctl" #pg_ctl_options='' # Options to append to "pg_ctl"
#pg_basebackup_options='' # Options to append to "pg_basebackup" #pg_basebackup_options='' # Options to append to "pg_basebackup"
# (Note: when cloning from Barman, repmgr will honour any # (Note: when cloning from Barman, repmgr will honour any
# --waldir/--xlogdir setting present in "pg_basebackup_options" # --waldir/--xlogdir setting present in "pg_basebackup_options"
#rsync_options='' # Options to append to "rsync" #rsync_options='' # Options to append to "rsync"
ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh" ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
@@ -212,8 +212,8 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
#recovery_min_apply_delay= # If provided, "recovery_min_apply_delay" will be set to #recovery_min_apply_delay= # If provided, "recovery_min_apply_delay" will be set to
# this value (PostgreSQL 9.4 and later). Value can be # this value (PostgreSQL 9.4 and later). Value can be
# an integer representing milliseconds, or a string # an integer representing milliseconds, or a string
# representing a period of time (e.g. '5 min'). # representing a period of time (e.g. '5 min').
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
@@ -299,7 +299,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
# a value of zero prevents the node being promoted to primary # a value of zero prevents the node being promoted to primary
# (default: 100) # (default: 100)
#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': attempt to make a new connection to the node # '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
@@ -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,
@@ -340,22 +340,31 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
#repmgrd_exit_on_inactive_node=false # If "true", and the node record is marked as "inactive", abort repmgrd startup #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) # Can be true in PostgreSQL 9.5 and later only. Until PostgreSQL 14 repmgr user must be a superuser to use this.
# From PostgreSQL 15 repmgr must be a superuser or have 'ALTER SYSTEM wal_retrieve_retry_interval' privilege.
# (see: https://repmgr.org/docs/current/repmgrd-standby-disconnection-on-failover.html )
#sibling_nodes_disconnect_timeout=30 # If "standby_disconnect_on_failover" is true, the maximum length of time #sibling_nodes_disconnect_timeout=30 # If "standby_disconnect_on_failover" is true, the maximum length of time
# (in seconds) to wait for other standbys to confirm they have disconnected their # (in seconds) to wait for other standbys to confirm they have disconnected their
# WAL receivers # WAL receivers
#primary_visibility_consensus=false # If "true", only continue with failover if no standbys have seen #primary_visibility_consensus=false # If "true", only continue with failover if no standbys have seen
# the primary node recently. *Must* be the same on all nodes. # the primary node recently. *Must* be the same on all nodes.
#always_promote=false # Always promote a node, even if repmgr metadata is outdated #always_promote=false # Always promote a node, even if repmgr metadata is outdated
#failover_validation_command='' # Script to execute for an external mechanism to validate the failover #failover_validation_command='' # Script to execute for an external mechanism to validate the failover
# decision made by repmgrd. One or both of the following parameter placeholders # decision made by repmgrd. Each of the following parameter placeholders
# should be provided, which will be replaced by repmgrd with the appropriate # should be provided, which will be replaced by repmgrd with the appropriate value:
# value: %n (node_id), %a (node_name). *Must* be the same on all nodes. # %n (node_id)
# %a (node_name)
# %v (number of visible nodes)
# %u (number of shared upstream nodes)
# %t (total number of nodes)
# *Must* be the same on all nodes.
#election_rerun_interval=15 # if "failover_validation_command" is set, and the command returns #election_rerun_interval=15 # if "failover_validation_command" is set, and the command returns
# an error, pause the specified amount of seconds before rerunning the election. # an error, pause the specified amount of seconds before rerunning the election.
#
# The following items are relevant for repmgrd running on the primary, # The following items are relevant for repmgrd running on the primary,
# and will be ignored on non-primary nodes # and will be ignored on non-primary nodes.
# (see: https://repmgr.org/docs/current/repmgrd-primary-child-disconnection.html )
#child_nodes_check_interval=5 # Interval (in seconds) to check for attached child nodes (standbys) #child_nodes_check_interval=5 # Interval (in seconds) to check for attached child nodes (standbys)
#child_nodes_connected_min_count=-1 # Minimum number of child nodes which must remain connected, otherwise #child_nodes_connected_min_count=-1 # Minimum number of child nodes which must remain connected, otherwise
# disconnection command will be triggered # disconnection command will be triggered
@@ -363,6 +372,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
# (ignored if "child_nodes_connected_min_count" set) # (ignored if "child_nodes_connected_min_count" set)
#child_nodes_disconnect_timeout=30 # Interval between child node disconnection and disconnection command execution #child_nodes_disconnect_timeout=30 # Interval between child node disconnection and disconnection command execution
#child_nodes_disconnect_command='' # Command to execute if child node disconnection detected #child_nodes_disconnect_command='' # Command to execute if child node disconnection detected
#child_nodes_connected_include_witness=false # Whether to count the witness node (if in use) as a child node when determining whether to execute child_nodes_disconnect_command.
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# service control commands # service control commands
@@ -385,20 +395,20 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
# #
# For example, to use systemd, you can set # For example, to use systemd, you can set
# #
# service_start_command = 'sudo systemctl start postgresql-9.6' # service_start_command = 'sudo systemctl start postgresql-16'
# (...) # (...)
# #
# and then use the following sudoers configuration: # and then use the following sudoers configuration:
# #
# # this is required when running sudo over ssh without -t: # # this is required when running sudo over ssh without -t:
# Defaults:postgres !requiretty # Defaults:postgres !requiretty
# postgres ALL = NOPASSWD: /usr/bin/systemctl stop postgresql-9.6, \ # postgres ALL = NOPASSWD: /usr/bin/systemctl stop postgresql-16, \
# /usr/bin/systemctl start postgresql-9.6, \ # /usr/bin/systemctl start postgresql-16, \
# /usr/bin/systemctl restart postgresql-9.6 # /usr/bin/systemctl restart postgresql-16
# #
# 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 further details, see: https://repmgr.org/docs/current/configuration-file-service-commands.html
#service_start_command = '' #service_start_command = ''
#service_stop_command = '' #service_stop_command = ''
@@ -441,4 +451,3 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
# "repmgr standby switchover" to warn about potential # "repmgr standby switchover" to warn about potential
# issues with shutting down the demotion candidate. # issues with shutting down the demotion candidate.

View File

@@ -1,6 +1,6 @@
# repmgr extension # repmgr extension
comment = 'Replication manager for PostgreSQL' comment = 'Replication manager for PostgreSQL'
default_version = '5.3' default_version = '5.5'
module_pathname = '$libdir/repmgr' module_pathname = '$libdir/repmgr'
relocatable = false relocatable = false
schema = repmgr schema = repmgr

View File

@@ -116,6 +116,7 @@
#define DEFAULT_STANDBY_FOLLOW_TIMEOUT 30 /* seconds */ #define DEFAULT_STANDBY_FOLLOW_TIMEOUT 30 /* seconds */
#define DEFAULT_STANDBY_FOLLOW_RESTART false #define DEFAULT_STANDBY_FOLLOW_RESTART false
#define DEFAULT_SHUTDOWN_CHECK_TIMEOUT 60 /* seconds */ #define DEFAULT_SHUTDOWN_CHECK_TIMEOUT 60 /* seconds */
#define DEFAULT_STANDBY_PG_BACKUPAPI_OP_TYPE "recovery"
#define DEFAULT_STANDBY_RECONNECT_TIMEOUT 60 /* seconds */ #define DEFAULT_STANDBY_RECONNECT_TIMEOUT 60 /* seconds */
#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 */

View File

@@ -1,7 +1,7 @@
#define REPMGR_VERSION_DATE "" #define REPMGR_VERSION_DATE "2024-11-20"
#define REPMGR_VERSION "5.3dev" #define REPMGR_VERSION "5.5.0"
#define REPMGR_VERSION_NUM 50300 #define REPMGR_VERSION_NUM 50500
#define REPMGR_EXTENSION_VERSION "5.3" #define REPMGR_EXTENSION_VERSION "5.5.0"
#define REPMGR_EXTENSION_NUM 50300 #define REPMGR_EXTENSION_NUM 50500
#define REPMGR_RELEASE_DATE "2021-XX-XX" #define REPMGR_RELEASE_DATE "2024-XX-XX"
#define PG_ACTUAL_VERSION_NUM #define PG_ACTUAL_VERSION_NUM

View File

@@ -172,37 +172,85 @@ void
do_physical_node_check(PGconn *conn) 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);
/*
* 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)
{
bool require_reregister = false;
PQExpBufferData event_details;
initPQExpBuffer(&event_details);
if (recovery_type == RECTYPE_STANDBY && local_node_info.type != STANDBY)
{
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);
create_event_notification(NULL,
&config_file_options,
config_file_options.node_id,
"repmgrd_start",
false,
event_details.data);
termPQExpBuffer(&event_details);
terminate(ERR_BAD_CONFIG);
}
termPQExpBuffer(&event_details);
}
/* /*
* Attempt to set node record active (unless explicitly configured not to) * 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) if (config_file_options.repmgrd_exit_on_inactive_node == false)
{ {
PGconn *primary_conn = get_primary_connection_quiet(conn, NULL, NULL); PGconn *primary_conn = get_primary_connection(conn, NULL, NULL);
bool success = true; bool success = true;
if (PQstatus(primary_conn) != CONNECTION_OK) if (PQstatus(primary_conn) != CONNECTION_OK)
{ {
log_error(_("unable to connect to the primary node to activate the node record"));
success = false; success = false;
} }
else else
{ {
log_notice(_("setting node record for node \"%s\" (ID: %i) to \"active\""),
local_node_info.node_name,
local_node_info.node_id);
success = update_node_record_set_active(primary_conn, local_node_info.node_id, true); success = update_node_record_set_active(primary_conn, local_node_info.node_id, true);
PQfinish(primary_conn); PQfinish(primary_conn);
} }
@@ -210,33 +258,37 @@ do_physical_node_check(PGconn *conn)
if (success == true) if (success == true)
{ {
local_node_info.active = true; local_node_info.active = true;
return;
} }
} }
switch (config_file_options.failover) /*
* 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 */
/* "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);
case FAILOVER_AUTOMATIC: create_event_notification(NULL,
log_error(_("this node is marked as inactive and cannot be used as a failover target")); &config_file_options,
log_hint(_("%s"), hint); config_file_options.node_id,
"repmgrd_start",
false,
"node is inactive and cannot be used as a failover target");
create_event_notification(NULL, terminate(ERR_BAD_CONFIG);
&config_file_options, break;
config_file_options.node_id,
"repmgrd_shutdown",
false,
"node is inactive and cannot be used as a failover target");
terminate(ERR_BAD_CONFIG); case FAILOVER_MANUAL:
break; log_warning(_("this node is marked as inactive and will be passively monitored only"));
log_hint(_("%s"), hint);
case FAILOVER_MANUAL: break;
log_warning(_("this node is marked as inactive and will be passively monitored only")); }
log_hint(_("%s"), hint);
break;
} }
} }
@@ -533,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)
@@ -1306,6 +1359,8 @@ monitor_streaming_standby(void)
MonitoringState local_monitoring_state = MS_NORMAL; MonitoringState local_monitoring_state = MS_NORMAL;
instr_time local_degraded_monitoring_start; instr_time local_degraded_monitoring_start;
bool upstream_check_result;
int degraded_monitoring_elapsed;
int last_known_upstream_node_id = UNKNOWN_NODE_ID; int last_known_upstream_node_id = UNKNOWN_NODE_ID;
log_debug("monitor_streaming_standby()"); log_debug("monitor_streaming_standby()");
@@ -1494,7 +1549,6 @@ monitor_streaming_standby(void)
while (true) while (true)
{ {
bool upstream_check_result;
log_verbose(LOG_DEBUG, "checking %s", upstream_node_info.conninfo); log_verbose(LOG_DEBUG, "checking %s", upstream_node_info.conninfo);
@@ -1534,22 +1588,22 @@ monitor_streaming_standby(void)
/* TODO: possibly add pre-action event here */ /* TODO: possibly add pre-action event here */
if (upstream_node_info.type == STANDBY) if (upstream_node_info.type == STANDBY)
{ {
create_event_record(primary_conn, create_event_notification(primary_conn,
&config_file_options, &config_file_options,
config_file_options.node_id, config_file_options.node_id,
"repmgrd_upstream_disconnect", "repmgrd_upstream_disconnect",
true, true,
event_details.data); event_details.data);
} }
else else
{ {
/* primary connection lost - script notification only */ /* primary connection lost - script notification only */
create_event_record(NULL, create_event_notification(NULL,
&config_file_options, &config_file_options,
config_file_options.node_id, config_file_options.node_id,
"repmgrd_upstream_disconnect", "repmgrd_upstream_disconnect",
true, true,
event_details.data); event_details.data);
} }
log_warning("%s", event_details.data); log_warning("%s", event_details.data);
@@ -1717,8 +1771,7 @@ monitor_streaming_standby(void)
if (monitoring_state == MS_DEGRADED) if (monitoring_state == MS_DEGRADED)
{ {
int degraded_monitoring_elapsed = calculate_elapsed(degraded_monitoring_start); degraded_monitoring_elapsed = calculate_elapsed(degraded_monitoring_start);
bool upstream_check_result;
if (config_file_options.degraded_monitoring_timeout > 0 if (config_file_options.degraded_monitoring_timeout > 0
&& degraded_monitoring_elapsed > config_file_options.degraded_monitoring_timeout) && degraded_monitoring_elapsed > config_file_options.degraded_monitoring_timeout)
@@ -1761,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)
{ {
@@ -1838,10 +1894,10 @@ monitor_streaming_standby(void)
*/ */
if (failover_state == FAILOVER_STATE_PROMOTION_FAILED) if (failover_state == FAILOVER_STATE_PROMOTION_FAILED)
{ {
int degraded_monitoring_elapsed;
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);
@@ -1854,12 +1910,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);
@@ -1892,7 +1952,7 @@ monitor_streaming_standby(void)
if (local_node_info.type == PRIMARY) if (local_node_info.type == PRIMARY)
{ {
int degraded_monitoring_elapsed = calculate_elapsed(degraded_monitoring_start); degraded_monitoring_elapsed = calculate_elapsed(degraded_monitoring_start);
log_notice(_("resuming monitoring as primary node after %i seconds"), log_notice(_("resuming monitoring as primary node after %i seconds"),
degraded_monitoring_elapsed); degraded_monitoring_elapsed);
@@ -2321,6 +2381,29 @@ 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);
}
/*
* It's possible that the primary changed while the witness repmgrd was not
* running. This does not affect the functionality of the witness repmgrd, but
* does mean outdated node metadata will be displayed, so update that.
*/
if (local_node_info.upstream_node_id != primary_node_id)
{
update_node_record_set_upstream(primary_conn, local_node_info.node_id, primary_node_id);
local_node_info.upstream_node_id = primary_node_id;
}
initPQExpBuffer(&event_details); initPQExpBuffer(&event_details);
appendPQExpBuffer(&event_details, appendPQExpBuffer(&event_details,
@@ -2409,12 +2492,12 @@ monitor_streaming_witness(void)
_("unable to connect to primary node \"%s\" (ID: %i)"), _("unable to connect to primary node \"%s\" (ID: %i)"),
upstream_node_info.node_name, upstream_node_info.node_id); upstream_node_info.node_name, upstream_node_info.node_id);
create_event_record(NULL, create_event_notification(NULL,
&config_file_options, &config_file_options,
config_file_options.node_id, config_file_options.node_id,
"repmgrd_upstream_disconnect", "repmgrd_upstream_disconnect",
true, true,
event_details.data); event_details.data);
termPQExpBuffer(&event_details); termPQExpBuffer(&event_details);
} }
@@ -2489,8 +2572,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;
@@ -2787,6 +2872,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
@@ -2799,20 +2885,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);
/* /*
@@ -2896,7 +2982,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);
@@ -3004,7 +3090,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);
@@ -3016,6 +3101,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,
@@ -3036,7 +3122,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;
} }
@@ -3703,6 +3788,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);
@@ -3719,13 +3805,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);
} }

View File

@@ -479,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;
} }

View File

@@ -369,7 +369,6 @@ check_status_list_free(CheckStatusList *list)
} }
const char * const char *
output_check_status(CheckStatus status) output_check_status(CheckStatus status)
{ {