Compare commits

...

33 Commits

Author SHA1 Message Date
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
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
30 changed files with 771 additions and 253 deletions

View File

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

View File

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

12
HISTORY
View File

@@ -1,7 +1,15 @@
5.3.2 2022-??-??
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)
@@ -66,7 +74,7 @@
"standby clone" (Ian)
repmgr: add --upstream option to "node check"
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: improve "standby switchover" completion checks (Ian)
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
export GIT_DIR
export GIT_WORK_TREE
PG_LDFLAGS=-lcurl -ljson-c
include $(PGXS)
-include ${repmgr_abs_srcdir}/Makefile.custom

View File

@@ -66,7 +66,7 @@ REPMGR_CLIENT_OBJS = repmgr-client.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 \
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 \
dbutils.o strutil.o controldata.o compat.o sysutils.o
@@ -81,10 +81,10 @@ configfile-scan.c: configfile-scan.l
$(REPMGR_CLIENT_OBJS): repmgr-client.h repmgr_version.h
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)
$(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)
$(REPMGRD_OBJS): $(HEADERS)

View File

@@ -7,8 +7,8 @@ replication capabilities with utilities to set up standby servers, monitor
replication, and perform administrative tasks such as failover or switchover
operations.
The most recent `repmgr` version (5.2.1) supports all PostgreSQL versions from
9.5 to 13. PostgreSQL 9.4 is also supported, with some restrictions.
The most recent `repmgr` version (5.3.2) supports all PostgreSQL versions from
9.5 to 14. PostgreSQL 9.4 is also supported, with some restrictions.
`repmgr` is distributed under the GNU GPL 3 and maintained by EnterpriseDB.
@@ -19,14 +19,6 @@ The full `repmgr` documentation is available here:
> [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
--------
@@ -48,7 +40,6 @@ Directories
- `contrib/`: additional utilities
- `doc/`: DocBook-based documentation files
- `expected/`: expected regression test output
- `scripts/`: example scripts
- `sql/`: regression test input
@@ -78,7 +69,6 @@ news are always welcome.
Thanks from the repmgr core team.
* Ian Barwick
* Jaime Casanova
* Abhijit Menon-Sen
* 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

View File

@@ -164,6 +164,10 @@ typedef struct
char archive_cleanup_command[MAXLEN];
bool use_primary_conninfo_password;
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 */
int promote_check_timeout;

View File

@@ -60,6 +60,7 @@ AC_SUBST(vpath_build)
AC_CHECK_PROG(HAVE_GNUSED,gnused,yes,no)
AC_CHECK_PROG(HAVE_GSED,gsed,yes,no)
AC_CHECK_PROG(HAVE_SED,sed,yes,no)
AC_CHECK_PROG(HAVE_FLEX,flex,yes,no)
if test "$HAVE_GNUSED" = yes; then
SED=gnused
@@ -72,6 +73,25 @@ else
fi
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.global])

View File

@@ -1888,6 +1888,42 @@ can_execute_pg_promote(PGconn *conn)
}
/*
* Determine if the user associated with the current connection
* has sufficient permissions to disable the walsender
*/
bool
can_disable_walsender(PGconn *conn)
{
/*
* Requires PostgreSQL 9.5 or later, because ALTER SYSTEM
*/
if (PQserverVersion(conn) < 90500)
{
log_warning(_("\"standby_disconnect_on_failover\" specified, but not available for this PostgreSQL version"));
/* TODO: format server version */
log_detail(_("available from PostgreSQL 9.5; this PostgreSQL version is %i"), PQserverVersion(conn));
return false;
}
/*
* Superusers can do anything
*/
if (is_superuser_connection(conn, NULL) == true)
return true;
/*
* As of PostgreSQL 14, it is not possible for a non-superuser
* to execute ALTER SYSTEM, so further checks are superfluous.
* This will need modifying for PostgreSQL 15.
*/
log_warning(_("\"standby_disconnect_on_failover\" specified, but repmgr user is not a superuser"));
log_detail(_("superuser permission required to disable standbys on failover"));
return false;
}
/*
* Determine if the user associated with the current connection is
* a member of the "pg_monitor" default role, or optionally one
@@ -4580,17 +4616,17 @@ drop_replication_slot_replprot(PGconn *repl_conn, char *slot_name)
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
"DROP_REPLICATION_SLOT %s",
"DROP_REPLICATION_SLOT %s;",
slot_name);
log_verbose(LOG_DEBUG, "drop_replication_slot_replprot():\n %s", query.data);
res = PQexec(repl_conn, query.data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
if (PQresultStatus(res) != PGRES_TUPLES_OK || !PQntuples(res))
{
log_db_error(repl_conn, query.data,
_("drop_replication_slot_sql(): unable to drop replication slot \"%s\""),
_("drop_replication_slot_replprot(): unable to drop replication slot \"%s\""),
slot_name);
success = false;

View File

@@ -454,6 +454,7 @@ pid_t get_wal_receiver_pid(PGconn *conn);
/* user/role information functions */
bool can_execute_pg_promote(PGconn *conn);
bool can_disable_walsender(PGconn *conn);
bool connection_has_pg_monitor_role(PGconn *conn, const char *subrole);
bool is_replication_role(PGconn *conn, char *rolname);
bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo);

View File

@@ -14,12 +14,47 @@
<para>
See also: <xref linkend="upgrading-repmgr"/>
</para>
<!-- remember to update the release date in ../repmgr_version.h.in -->
<sect1 id="release-5.3.3">
<title id="release-current">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 id="release-current">Release 5.3.2</title>
<para><emphasis>??? ??? ???, 2022</emphasis></para>
<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>
@@ -53,12 +88,24 @@
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>
<!-- remember to update the release date in ../repmgr_version.h.in -->
<sect1 id="release-5.3.1">
<title>Release 5.3.1</title>
<para><emphasis>Tue 15 February, 2022</emphasis></para>

View File

@@ -108,10 +108,31 @@
<entry>
Supported PostgreSQL versions
</entry>
<entry>
Notes
</entry>
</row>
</thead>
<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>
<entry>
&repmgr; 5.3
@@ -123,7 +144,10 @@
<link linkend="release-current">&repmgrversion;</link> (&releasedate;)
</entry>
<entry>
9.4, 9.5, 9.6, 10, 11, 12, 13, 14
9.4, 9.5, 9.6, 10, 11, 12, 13, 14, 15
</entry>
<entry>
PostgreSQL 15 supported from &repmgr; 5.3.3
</entry>
</row>
@@ -140,6 +164,9 @@
<entry>
9.4, 9.5, 9.6, 10, 11, 12, 13
</entry>
<entry>
&nbsp;
</entry>
</row>
<row>
@@ -155,6 +182,9 @@
<entry>
9.3, 9.4, 9.5, 9.6, 10, 11, 12
</entry>
<entry>
&nbsp;
</entry>
</row>
<row>
@@ -170,6 +200,9 @@
<entry>
9.3, 9.4, 9.5, 9.6, 10, 11, 12
</entry>
<entry>
&nbsp;
</entry>
</row>
@@ -186,6 +219,9 @@
<entry>
9.3, 9.4, 9.5, 9.6, 10, 11
</entry>
<entry>
&nbsp;
</entry>
</row>
<row>
@@ -201,6 +237,9 @@
<entry>
9.3, 9.4, 9.5, 9.6
</entry>
<entry>
&nbsp;
</entry>
</row>
<row>
@@ -216,6 +255,9 @@
<entry>
9.0, 9.1, 9.2, 9.3, 9.4
</entry>
<entry>
&nbsp;
</entry>
</row>
</tbody>

View File

@@ -73,16 +73,16 @@
</varlistentry>
<varlistentry>
<term><option>--force-rewind[=/path/to/pg_rewind]</option></term>
<term><option>--force-rewind</option></term>
<listitem>
<para>
Execute <application>pg_rewind</application>.
</para>
<para>
It is only necessary to provide the <application>pg_rewind</application> path
if using PostgreSQL 9.4, and <application>pg_rewind</application>
is not installed in the PostgreSQL <filename>bin</filename> directory.
See <xref linkend="repmgr-node-rejoin-pg-rewind"/> for more details on using
<application>pg_rewind</application>.
</para>
</listitem>
</varlistentry>
@@ -261,8 +261,6 @@
<para>
<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.
<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>
<note>
<para>
@@ -271,6 +269,10 @@
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.
</para>
<para>
Additionally, <varname>full_page_writes</varname> must be enabled; this is the default and
normally should never be disabled.
</para>
</note>
<para>
@@ -382,6 +384,29 @@
DETAIL: node 2 is now attached to node 3</programlisting>
</para>
</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 id="repmgr-node-rejoin-caveats" xreflabel="Caveats">
@@ -426,7 +451,7 @@
<warning>
<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.
</para>
<para>
@@ -456,8 +481,7 @@
<para>
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>
has been successfully submitted and will be included the next PostgreSQL minor release round, scheduled for
February 2021.
was submitted and is included in all PostgreSQL versions released in February 2021 or later.
</para>
<para>
As a workaround, start the primary server the standby was previously attached to,
@@ -475,7 +499,7 @@
<refsect1>
<title>See also</title>
<para>
<xref linkend="repmgr-standby-follow"/>
<xref linkend="repmgr-standby-follow"/>, <xref linkend="repmgr-standby-switchover"/>
</para>
</refsect1>
</refentry>

View File

@@ -154,9 +154,12 @@
<para>
Use <application>pg_rewind</application> to reintegrate the old primary if necessary
(and the prerequisites for using <application>pg_rewind</application> are met).
</para>
<para>
If using PostgreSQL 9.4, and the <application>pg_rewind</application>
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>
</listitem>
</varlistentry>

View File

@@ -26,7 +26,7 @@
<abstract>
<para>
This is the official documentation of &repmgr; &repmgrversion; for
use with PostgreSQL 9.4 - PostgreSQL 14.
use with PostgreSQL 9.4 - PostgreSQL 15.
</para>
<para>
&repmgr; is being continually developed and we strongly recommend using the

View File

@@ -345,14 +345,18 @@
</indexterm>
<para>
Indicates a preferred priority (default: <literal>100</literal>) for promoting nodes;
a value of zero prevents the node being promoted to primary.
Indicates a preferred priority (default: <literal>100</literal>) for promoting nodes.
</para>
<para>
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
higher priority is selected.
</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>
</varlistentry>

View File

@@ -29,7 +29,7 @@
<listitem>
<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
</simpara>
</listitem>

View File

@@ -242,21 +242,12 @@
</simpara>
</note>
<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>.
</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>

View File

@@ -71,6 +71,12 @@
<secondary>minor release</secondary>
</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>
The process for installing minor version upgrades is quite straightforward:
@@ -105,15 +111,17 @@
</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>
<note>
<para>
The same &repmgr; &quot;major version&quot; (e.g. <literal>4.2</literal>) must be
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,
we strongly recommend updating all nodes to the latest minor version.
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
&repmgr; &quot;minor versions&quot; (e.g. <literal>5.3.1</literal> and <literal>5.3.2</literal>)
on different nodes, we strongly recommend updating all nodes to the latest minor version.
</para>
</note>

View File

@@ -49,5 +49,6 @@
#define ERR_NODE_STATUS 25
#define ERR_REPMGRD_PAUSE 26
#define ERR_REPMGRD_SERVICE 27
#define ERR_PGBACKUPAPI_SERVICE 28
#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

@@ -21,6 +21,7 @@
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "repmgr.h"
#include "dirutil.h"
@@ -29,7 +30,7 @@
#include "repmgr-client-global.h"
#include "repmgr-action-standby.h"
#include "pgbackupapi.h"
typedef struct TablespaceDataListCell
{
@@ -113,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 int run_basebackup(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);
@@ -687,19 +689,18 @@ do_standby_clone(void)
exit(SUCCESS);
}
if (mode != barman)
{
initialise_direct_clone(&local_node_record, &upstream_node_record);
}
switch (mode)
{
case pg_basebackup:
initialise_direct_clone(&local_node_record, &upstream_node_record);
log_notice(_("starting backup (using pg_basebackup)..."));
break;
case barman:
log_notice(_("retrieving backup from Barman..."));
break;
case pg_backupapi:
log_notice(_("starting backup (using pg_backupapi)..."));
break;
default:
/* should never reach here */
log_error(_("unknown clone mode"));
@@ -721,6 +722,9 @@ do_standby_clone(void)
case barman:
r = run_file_backup(&local_node_record);
break;
case pg_backupapi:
r = run_pg_backupapi(&local_node_record);
break;
default:
/* should never reach here */
log_error(_("unknown clone mode"));
@@ -814,7 +818,6 @@ do_standby_clone(void)
}
/* Write the recovery.conf file */
if (create_recovery_file(&local_node_record,
&recovery_conninfo,
source_server_version_num,
@@ -846,6 +849,9 @@ do_standby_clone(void)
case barman:
log_notice(_("standby clone (from Barman) complete"));
break;
case pg_backupapi:
log_notice(_("standby clone (from pg_backupapi) complete"));
break;
}
/*
@@ -937,6 +943,9 @@ do_standby_clone(void)
case barman:
appendPQExpBufferStr(&event_details, "barman");
break;
case pg_backupapi:
appendPQExpBufferStr(&event_details, "pg_backupapi");
break;
}
appendPQExpBuffer(&event_details,
@@ -3348,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);
}
if (create_replication_slot(follow_target_conn,
local_node_record.slot_name,
NULL,
follow_target_node_record,
output) == false)
{
log_error("%s", output->data);
@@ -7771,6 +7779,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 *
make_barman_ssh_command(char *buf)
{

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);
void check_pg_backupapi_standby_clone_options(void);
#endif /* _REPMGR_ACTION_STANDBY_H_ */

View File

@@ -193,7 +193,8 @@ typedef struct
typedef enum
{
barman,
pg_basebackup
pg_basebackup,
pg_backupapi
} standy_clone_mode;
typedef enum

View File

@@ -90,17 +90,22 @@ char pg_bindir[MAXPGPATH] = "";
*/
t_node_info target_node_info = T_NODE_INFO_INITIALIZER;
/* used by create_replication_slot() */
/* set by the first call to _determine_replication_slot_user() */
static t_user_type ReplicationSlotUser = USER_TYPE_UNKNOWN;
/* Collate command line errors and warnings here for friendlier reporting */
static ItemList cli_errors = {NULL, NULL};
static ItemList cli_warnings = {NULL, NULL};
static void _determine_replication_slot_user(PGconn *conn,
t_node_info *upstream_node_record,
char **replication_user);
static PGconn *_get_replication_slot_connection(PGconn *conn,
char *replication_user,
bool *use_replication_protocol);
int
main(int argc, char **argv)
{
@@ -3091,9 +3096,14 @@ get_standby_clone_mode(void)
if (*config_file_options.barman_host != '\0' && runtime_options.without_barman == false)
mode = barman;
else
mode = pg_basebackup;
else {
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;
}
@@ -3629,8 +3639,8 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
/* "full_page_writes" must be on in any case */
if (guc_set(conn, "full_page_writes", "=", "off"))
{
appendPQExpBuffer(reason,
_("\"full_page_writes\" must be set to \"on\""));
appendPQExpBufferStr(reason,
_("\"full_page_writes\" must be set to \"on\""));
can_use = false;
}
@@ -3648,18 +3658,18 @@ can_use_pg_rewind(PGconn *conn, const char *data_directory, PQExpBufferData *rea
if (data_checksum_version == UNKNOWN_DATA_CHECKSUM_VERSION)
{
if (can_use == false)
appendPQExpBuffer(reason, "; ");
appendPQExpBufferStr(reason, "; ");
appendPQExpBuffer(reason,
_("\"wal_log_hints\" is set to \"off\" but unable to determine data checksum version"));
appendPQExpBufferStr(reason,
_("\"wal_log_hints\" is set to \"off\" but unable to determine data checksum version"));
can_use = false;
}
else if (data_checksum_version == 0)
{
if (can_use == false)
appendPQExpBuffer(reason, "; ");
appendPQExpBufferStr(reason, "; ");
appendPQExpBuffer(reason,
appendPQExpBufferStr(reason,
_("\"wal_log_hints\" is set to \"off\" and data checksums are disabled"));
can_use = false;
@@ -3739,6 +3749,7 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
char *replication_user = NULL;
_determine_replication_slot_user(conn, upstream_node_record, &replication_user);
/*
* If called in --dry-run context, if the replication slot user is not the
* repmgr user, attempt to validate the connection.
@@ -3750,7 +3761,7 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
case USER_TYPE_UNKNOWN:
log_error("unable to determine user for replication slot creation");
return false;
case REPMGR_USER:
case REPMGR_USER:
log_info(_("replication slots will be created by user \"%s\""),
PQuser(conn));
return true;
@@ -3796,65 +3807,12 @@ create_replication_slot(PGconn *conn, char *slot_name, t_node_info *upstream_nod
PQfinish(superuser_conn);
}
}
}
/*
* If we can't create a replication slot with the connection provided to
* the function, create an connection with appropriate permissions.
*/
switch (ReplicationSlotUser)
{
case USER_TYPE_UNKNOWN:
log_error("unable to determine user for replication slot creation");
return false;
case REPMGR_USER:
slot_conn = conn;
log_info(_("creating replication slot as user \"%s\""),
PQuser(conn));
break;
slot_conn = _get_replication_slot_connection(conn, replication_user, &use_replication_protocol);
case REPLICATION_USER_NODE:
case REPLICATION_USER_OPT:
{
slot_conn = duplicate_connection(conn,
replication_user,
true);
if (slot_conn == NULL || PQstatus(slot_conn) != CONNECTION_OK)
{
log_error(_("unable to create replication connection as user \"%s\""),
runtime_options.replication_user);
log_detail("%s", PQerrorMessage(slot_conn));
PQfinish(slot_conn);
return false;
}
use_replication_protocol = true;
log_info(_("creating replication slot as replication user \"%s\""),
replication_user);
}
break;
case SUPERUSER:
{
slot_conn = duplicate_connection(conn,
runtime_options.superuser,
false);
if (slot_conn == NULL || PQstatus(slot_conn )!= CONNECTION_OK)
{
log_error(_("unable to create super connection as user \"%s\""),
runtime_options.superuser);
log_detail("%s", PQerrorMessage(slot_conn));
PQfinish(slot_conn);
return false;
}
log_info(_("creating replication slot as superuser \"%s\""),
runtime_options.superuser);
}
break;
}
if (slot_conn == NULL)
return false;
if (use_replication_protocol == true)
{
@@ -3897,34 +3855,53 @@ drop_replication_slot_if_exists(PGconn *conn, int node_id, char *slot_name)
if (record_status != RECORD_FOUND)
{
/* this is not a bad good thing */
/* no slot, no problem */
log_verbose(LOG_INFO,
_("slot \"%s\" does not exist on node %i, nothing to remove"),
slot_name, node_id);
return true;
}
if (slot_info.active == false)
if (slot_info.active == true)
{
if (drop_replication_slot_sql(conn, slot_name) == true)
/*
* If an active replication slot exists, bail out as we have a problem
* we can't solve here.
*/
log_warning(_("replication slot \"%s\" is still active on node %i"), slot_name, node_id);
success = false;
}
else
{
/*
* Create the appropriate connection with which to drop the slot
*/
bool use_replication_protocol = false;
PGconn *slot_conn = _get_replication_slot_connection(conn,
replication_user,
&use_replication_protocol);
if (use_replication_protocol == true)
{
success = drop_replication_slot_replprot(slot_conn, slot_name);
}
else
{
success = drop_replication_slot_sql(slot_conn, slot_name);
}
if (success == true)
{
log_notice(_("replication slot \"%s\" deleted on node %i"), slot_name, node_id);
}
else
{
log_error(_("unable to delete replication slot \"%s\" on node %i"), slot_name, node_id);
success = false;
}
}
/*
* If an active replication slot exists, call Houston as we have a
* problem.
*/
else
{
log_warning(_("replication slot \"%s\" is still active on node %i"), slot_name, node_id);
success = false;
if (slot_conn != conn)
PQfinish(slot_conn);
}
return success;
@@ -3986,10 +3963,88 @@ _determine_replication_slot_user(PGconn *conn, t_node_info *upstream_node_record
ReplicationSlotUser = REPLICATION_USER_NODE;
*replication_user = upstream_node_record->repluser;
}
else
{
/* This should never happen */
log_error("unable to determine replication slot user");
if (upstream_node_record != NULL)
{
log_debug("%i %s %s", upstream_node_record->node_id, upstream_node_record->repluser, PQuser(conn));
}
else
{
log_debug("upstream_node_record not provided");
}
}
}
}
static PGconn *
_get_replication_slot_connection(PGconn *conn, char *replication_user, bool *use_replication_protocol)
{
PGconn *slot_conn = NULL;
/*
* If we can't create a replication slot with the connection provided to
* the function, create an connection with appropriate permissions.
*/
switch (ReplicationSlotUser)
{
case USER_TYPE_UNKNOWN:
log_error("unable to determine user for managing replication slots");
return NULL;
case REPMGR_USER:
slot_conn = conn;
log_verbose(LOG_INFO, _("managing replication slot as user \"%s\""),
PQuser(conn));
break;
case REPLICATION_USER_NODE:
case REPLICATION_USER_OPT:
{
slot_conn = duplicate_connection(conn,
replication_user,
true);
if (slot_conn == NULL || PQstatus(slot_conn) != CONNECTION_OK)
{
log_error(_("unable to manage replication connection as replication user \"%s\""),
runtime_options.replication_user);
log_detail("%s", PQerrorMessage(slot_conn));
PQfinish(slot_conn);
return NULL;
}
*use_replication_protocol = true;
log_verbose(LOG_INFO, _("managing replication slot as replication user \"%s\""),
replication_user);
}
break;
case SUPERUSER:
{
slot_conn = duplicate_connection(conn,
runtime_options.superuser,
false);
if (slot_conn == NULL || PQstatus(slot_conn )!= CONNECTION_OK)
{
log_error(_("unable to create superuser connection as user \"%s\""),
runtime_options.superuser);
log_detail("%s", PQerrorMessage(slot_conn));
PQfinish(slot_conn);
return NULL;
}
log_verbose(LOG_INFO, _("creating replication slot as superuser \"%s\""),
runtime_options.superuser);
}
break;
}
return slot_conn;
}
bool
check_replication_slots_available(int node_id, PGconn* conn)
{

View File

@@ -86,7 +86,6 @@ static shmem_request_hook_type prev_shmem_request_hook = NULL;
static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
void _PG_init(void);
void _PG_fini(void);
#if (PG_VERSION_NUM >= 150000)
static void repmgr_shmem_request(void);
@@ -145,21 +144,6 @@ _PG_init(void)
}
/*
* Module unload callback
*/
void
_PG_fini(void)
{
/* Uninstall hook */
#if (PG_VERSION_NUM >= 150000)
shmem_request_hook = prev_shmem_request_hook;
#endif
shmem_startup_hook = prev_shmem_startup_hook;
}
#if (PG_VERSION_NUM >= 150000)
/*
* shmem_requst_hook: request shared memory
@@ -177,7 +161,7 @@ repmgr_shmem_request(void)
#endif
/*
* shmem_ hook: allocate or attach to shared memory,
* shmem_startup hook: allocate or attach to shared memory
*/
static void
repmgr_shmem_startup(void)

View File

@@ -116,6 +116,7 @@
#define DEFAULT_STANDBY_FOLLOW_TIMEOUT 30 /* seconds */
#define DEFAULT_STANDBY_FOLLOW_RESTART false
#define DEFAULT_SHUTDOWN_CHECK_TIMEOUT 60 /* seconds */
#define DEFAULT_STANDBY_PG_BACKUPAPI_OP_TYPE "recovery"
#define DEFAULT_STANDBY_RECONNECT_TIMEOUT 60 /* seconds */
#define DEFAULT_NODE_REJOIN_TIMEOUT 60 /* seconds */
#define DEFAULT_ARCHIVE_READY_WARNING 16 /* WAL files */

View File

@@ -1587,22 +1587,22 @@ monitor_streaming_standby(void)
/* TODO: possibly add pre-action event here */
if (upstream_node_info.type == STANDBY)
{
create_event_record(primary_conn,
&config_file_options,
config_file_options.node_id,
"repmgrd_upstream_disconnect",
true,
event_details.data);
create_event_notification(primary_conn,
&config_file_options,
config_file_options.node_id,
"repmgrd_upstream_disconnect",
true,
event_details.data);
}
else
{
/* primary connection lost - script notification only */
create_event_record(NULL,
&config_file_options,
config_file_options.node_id,
"repmgrd_upstream_disconnect",
true,
event_details.data);
create_event_notification(NULL,
&config_file_options,
config_file_options.node_id,
"repmgrd_upstream_disconnect",
true,
event_details.data);
}
log_warning("%s", event_details.data);
@@ -2482,12 +2482,12 @@ monitor_streaming_witness(void)
_("unable to connect to primary node \"%s\" (ID: %i)"),
upstream_node_info.node_name, upstream_node_info.node_id);
create_event_record(NULL,
&config_file_options,
config_file_options.node_id,
"repmgrd_upstream_disconnect",
true,
event_details.data);
create_event_notification(NULL,
&config_file_options,
config_file_options.node_id,
"repmgrd_upstream_disconnect",
true,
event_details.data);
termPQExpBuffer(&event_details);
}
@@ -2862,6 +2862,7 @@ do_primary_failover(void)
bool final_result = false;
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
int new_primary_id = UNKNOWN_NODE_ID;
bool standby_disconnect_on_failover = false;
/*
* Double-check status of the local connection
@@ -2874,20 +2875,20 @@ do_primary_failover(void)
*/
if (config_file_options.standby_disconnect_on_failover == true)
{
NodeInfoListCell *cell = NULL;
NodeInfoList check_sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
int i;
/*
* Determine whether we can actually disable the walsender; this depends
* on PostgreSQL version and user permissions.
*/
standby_disconnect_on_failover = can_disable_walsender(local_conn);
bool sibling_node_wal_receiver_connected = false;
if (standby_disconnect_on_failover == true)
{
NodeInfoListCell *cell = NULL;
NodeInfoList check_sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
int i;
bool sibling_node_wal_receiver_connected = false;
if (PQserverVersion(local_conn) < 90500)
{
log_warning(_("\"standby_disconnect_on_failover\" specified, but not available for this PostgreSQL version"));
/* TODO: format server version */
log_detail(_("available from PostgreSQL 9.5, this PostgreSQL version is %i"), PQserverVersion(local_conn));
}
else
{
disable_wal_receiver(local_conn);
/*
@@ -2971,7 +2972,7 @@ do_primary_failover(void)
log_debug("election result: %s", _print_election_result(election_result));
/* Reenable WAL receiver, if disabled */
if (config_file_options.standby_disconnect_on_failover == true)
if (standby_disconnect_on_failover == true)
{
/* adjust "wal_retrieve_retry_interval" but don't wait for WAL receiver to start */
enable_wal_receiver(local_conn, false);