mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-23 15:16:29 +00:00
Compare commits
1 Commits
fix-local-
...
dev/gianni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d52b045113 |
7
.github/CODEOWNERS
vendored
7
.github/CODEOWNERS
vendored
@@ -1,7 +0,0 @@
|
|||||||
# 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
|
|
||||||
37
.github/workflows/sonarqube-scan.yml
vendored
Normal file
37
.github/workflows/sonarqube-scan.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
name: SonarQube Scan
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
workflow_dispatch:
|
||||||
|
jobs:
|
||||||
|
sonarQube:
|
||||||
|
name: SonarQube-Job
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout source repo
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
with:
|
||||||
|
ref: '${{ github.head_ref }}'
|
||||||
|
|
||||||
|
- name: Checkout GitHub Action Repo
|
||||||
|
uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
repository: EnterpriseDB/edb-github-actions.git
|
||||||
|
ref: master
|
||||||
|
token: ${{ secrets.GH_SLONIK }}
|
||||||
|
path: .github/actions/edb-github-actions
|
||||||
|
|
||||||
|
- name: SonarQube Scan
|
||||||
|
uses: ./.github/actions/edb-github-actions/sonarqube
|
||||||
|
with:
|
||||||
|
REPO_NAME: '${{github.event.repository.name}}'
|
||||||
|
SONAR_PROJECT_KEY: EnterpriseDB_repmgr
|
||||||
|
SONAR_URL: '${{secrets.SONARQUBE_URL}}'
|
||||||
|
SONAR_LOGIN: '${{secrets.SONARQUBE_LOGIN}}'
|
||||||
|
PULL_REQUEST_KEY: '${{github.event.number}}'
|
||||||
|
PULL_REQUEST_BRANCH: '${{github.head_ref}}'
|
||||||
|
PULL_REQUEST_BASE_BRANCH: '${{github.base_ref}}'
|
||||||
|
REPO_DEFAULT_BRANCH: '${{github.event.repository.default_branch}}'
|
||||||
|
REPO_EXCLUDE_FILES: '*properties*,**/src/test/**/*,**/*.sql,**/docs/**/*,**/*/*.java'
|
||||||
18
.github/workflows/sonarqube/configure-env.sh
vendored
Executable file
18
.github/workflows/sonarqube/configure-env.sh
vendored
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DEBIAN_FRONTEND=noninteractive sudo apt-get -y install debhelper curl autoconf zlib1g-dev \
|
||||||
|
libedit-dev libxml2-dev libxslt1-dev libkrb5-dev libssl-dev libpam0g-dev systemtap-sdt-dev \
|
||||||
|
libselinux1-dev build-essential bison apt-utils lsb-release devscripts \
|
||||||
|
software-properties-common git shellcheck flex
|
||||||
|
|
||||||
|
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||||
|
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||||
|
sudo apt-get update
|
||||||
|
|
||||||
|
sudo apt-get -y install libpq-dev postgresql-13 postgresql-server-dev-13
|
||||||
|
|
||||||
|
./configure
|
||||||
|
|
||||||
|
export PG_CONFIG=/usr/bin/pg_config
|
||||||
|
|
||||||
|
/home/buildfarm/sonar/depends/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir build_wrapper_output_directory make
|
||||||
6
HISTORY
6
HISTORY
@@ -1,9 +1,3 @@
|
|||||||
5.4.1 2023-??-??
|
|
||||||
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
|
5.3.3 2022-10-17
|
||||||
Support for PostgreSQL added
|
Support for PostgreSQL added
|
||||||
repmgrd: ensure event notification script is called for event
|
repmgrd: ensure event notification script is called for event
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -66,7 +66,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 pgbackupapi.o
|
dbutils.o sysutils.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
|
||||||
|
|
||||||
|
|||||||
14
README.md
14
README.md
@@ -7,8 +7,8 @@ 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.4.1) supports all PostgreSQL versions from
|
The most recent `repmgr` version (5.3.2) supports all PostgreSQL versions from
|
||||||
10 to 16.
|
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.
|
`repmgr` is distributed under the GNU GPL 3 and maintained by EnterpriseDB.
|
||||||
|
|
||||||
@@ -40,6 +40,7 @@ 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
|
||||||
|
|
||||||
|
|
||||||
@@ -56,6 +57,8 @@ 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
|
||||||
@@ -68,13 +71,6 @@ 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
|
||||||
|
|||||||
40
configdata.c
40
configdata.c
@@ -291,46 +291,6 @@ 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
|
||||||
|
|||||||
@@ -164,10 +164,6 @@ 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;
|
||||||
|
|||||||
20
configure.in
20
configure.in
@@ -60,7 +60,6 @@ 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
|
||||||
@@ -73,25 +72,6 @@ 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])
|
||||||
|
|||||||
102
dbutils.c
102
dbutils.c
@@ -1852,51 +1852,6 @@ get_wal_receiver_pid(PGconn *conn)
|
|||||||
/* =============================== */
|
/* =============================== */
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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)
|
||||||
{
|
{
|
||||||
@@ -1958,47 +1913,15 @@ can_disable_walsender(PGconn *conn)
|
|||||||
if (is_superuser_connection(conn, NULL) == true)
|
if (is_superuser_connection(conn, NULL) == true)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
PQExpBufferData query;
|
/*
|
||||||
PGresult *res;
|
* As of PostgreSQL 14, it is not possible for a non-superuser
|
||||||
bool has_alter_system_priv = false;
|
* 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"));
|
||||||
|
|
||||||
/* GRANT ALTER SYSTEM available from PostgreSQL 15 */
|
return false;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2024,13 +1947,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','USAGE') "
|
" WHEN pg_catalog.pg_has_role('pg_monitor','MEMBER') "
|
||||||
" THEN TRUE ");
|
" THEN TRUE ");
|
||||||
|
|
||||||
if (subrole != NULL)
|
if (subrole != NULL)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(&query,
|
appendPQExpBuffer(&query,
|
||||||
" WHEN pg_catalog.pg_has_role('%s','USAGE') "
|
" WHEN pg_catalog.pg_has_role('%s','MEMBER') "
|
||||||
" THEN TRUE ",
|
" THEN TRUE ",
|
||||||
subrole);
|
subrole);
|
||||||
}
|
}
|
||||||
@@ -2537,10 +2460,7 @@ 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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -453,7 +453,6 @@ TimeLineHistoryEntry *get_timeline_history(PGconn *repl_conn, TimeLineID tli);
|
|||||||
pid_t get_wal_receiver_pid(PGconn *conn);
|
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 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);
|
||||||
|
|||||||
@@ -16,44 +16,8 @@
|
|||||||
</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.4.1">
|
|
||||||
<title id="release-current">Release 5.4.1</title>
|
|
||||||
<para><emphasis>??? ?? ??????, 202?</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">
|
<sect1 id="release-5.3.3">
|
||||||
<title>Release 5.3.3</title>
|
<title id="release-current">Release 5.3.3</title>
|
||||||
<para><emphasis>Mon 17 October, 2022</emphasis></para>
|
<para><emphasis>Mon 17 October, 2022</emphasis></para>
|
||||||
<para>
|
<para>
|
||||||
&repmgr; 5.3.3 is a minor release providing support for
|
&repmgr; 5.3.3 is a minor release providing support for
|
||||||
|
|||||||
@@ -225,109 +225,6 @@ 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">
|
||||||
|
|||||||
@@ -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
|
||||||
and annotated view of all configuration options see the
|
for a full and annotated view of all configuration options see the
|
||||||
<ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">sample repmgr.conf file</ulink>
|
see the <ulink url="https://raw.githubusercontent.com/EnterpriseDB/repmgr/master/repmgr.conf.sample">sample repmgr.conf file</ulink>
|
||||||
</simpara>
|
</simpara>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
|
|||||||
@@ -79,10 +79,6 @@
|
|||||||
Alternatively the meta-role <varname>pg_monitor</varname> can be granted, which includes membership
|
Alternatively the meta-role <varname>pg_monitor</varname> can be granted, which includes membership
|
||||||
of the above predefined roles.
|
of the above predefined roles.
|
||||||
</para>
|
</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>
|
<para>
|
||||||
Membership of these roles can be granted with e.g. <command>GRANT pg_read_all_stats TO repmgr</command>.
|
Membership of these roles can be granted with e.g. <command>GRANT pg_read_all_stats TO repmgr</command>.
|
||||||
</para>
|
</para>
|
||||||
@@ -152,8 +148,6 @@
|
|||||||
<link linkend="repmgr-standby-switchover">repmgr standby switchover</link>. This can only
|
<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,
|
be executed by a superuser; if the &repmgr; user is not a superuser,
|
||||||
the <option>-S</option>/<option>--superuser</option> should be used.
|
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>
|
||||||
<simpara>
|
<simpara>
|
||||||
If &repmgr; is not able to execute <command>CHECKPOINT</command>,
|
If &repmgr; is not able to execute <command>CHECKPOINT</command>,
|
||||||
@@ -165,10 +159,8 @@
|
|||||||
<simpara>
|
<simpara>
|
||||||
The <command>ALTER SYSTEM</command> is executed by &repmgrd; if
|
The <command>ALTER SYSTEM</command> is executed by &repmgrd; if
|
||||||
<varname>standby_disconnect_on_failover</varname> is set to <literal>true</literal> in
|
<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
|
<filename>repmgr.conf</filename>. <command>ALTER SYSTEM</command> can only be executed by
|
||||||
a superuser; if the &repmgr; user is not a superuser, this functionality will not be available.
|
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>
|
</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|||||||
@@ -77,8 +77,7 @@
|
|||||||
</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. From PostgreSQL 15 the <varname>pg_checkpoint</varname>
|
<command>CHECKPOINT</command> command.
|
||||||
predefined role removes the need for superuser permissions to perform <command>CHECKPOINT</command> command.
|
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|||||||
@@ -79,8 +79,7 @@
|
|||||||
<para>
|
<para>
|
||||||
Note that <command>CHECKPOINT</command> requires database superuser permissions to execute.
|
Note that <command>CHECKPOINT</command> requires database superuser permissions to execute.
|
||||||
If the <literal>repmgr</literal> user is not a superuser, the name of a superuser should be
|
If the <literal>repmgr</literal> user is not a superuser, the name of a superuser should be
|
||||||
provided with the <option>-S</option>/<option>--superuser</option> option. From PostgreSQL 15 the <varname>pg_checkpoint</varname>
|
provided with the <option>-S</option>/<option>--superuser</option> option.
|
||||||
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
|
||||||
|
|||||||
@@ -279,9 +279,7 @@
|
|||||||
<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.
|
||||||
Until PostgreSQL 14 this requires that the <literal>repmgr</literal> database user is a superuser.
|
Additionally 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>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara>
|
<simpara>
|
||||||
option to execute custom scripts ("<link linkend="event-notifications">event notifications</link>")
|
option to execute custom scripts ("<link linkend="event-notifications">event notifications</link>
|
||||||
at different points in the failover sequence
|
at different points in the failover sequence
|
||||||
</simpara>
|
</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|||||||
@@ -49,6 +49,5 @@
|
|||||||
#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
147
pgbackupapi.c
@@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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);
|
|
||||||
@@ -2365,25 +2365,18 @@ do_node_service(void)
|
|||||||
conn = establish_db_connection_by_params(&source_conninfo, true);
|
conn = establish_db_connection_by_params(&source_conninfo, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (can_execute_checkpoint(conn) == false)
|
if (is_superuser_connection(conn, NULL) == false)
|
||||||
{
|
{
|
||||||
if (runtime_options.dry_run == true)
|
if (runtime_options.dry_run == true)
|
||||||
{
|
{
|
||||||
log_warning(_("a CHECKPOINT would be issued here but no authorized connection is available"));
|
log_warning(_("a CHECKPOINT would be issued here but no superuser connection is available"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_warning(_("an authorized connection is required to issue a CHECKPOINT"));
|
log_warning(_("a superuser connection is required to issue a CHECKPOINT"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PQserverVersion(conn) >= 150000)
|
log_hint(_("provide a superuser with -S/--superuser"));
|
||||||
{
|
|
||||||
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
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,77 @@
|
|||||||
#ifndef _REPMGR_ACTION_STANDBY_H_
|
#ifndef _REPMGR_ACTION_STANDBY_H_
|
||||||
#define _REPMGR_ACTION_STANDBY_H_
|
#define _REPMGR_ACTION_STANDBY_H_
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int reachable_sibling_node_count;
|
||||||
|
int reachable_sibling_nodes_with_slot_count;
|
||||||
|
int unreachable_sibling_node_count;
|
||||||
|
int min_required_wal_senders;
|
||||||
|
int min_required_free_slots;
|
||||||
|
} SiblingNodeStats;
|
||||||
|
|
||||||
|
#define T_SIBLING_NODES_STATS_INITIALIZER { \
|
||||||
|
0, \
|
||||||
|
0, \
|
||||||
|
0, \
|
||||||
|
0, \
|
||||||
|
0 \
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
RepmgrdInfo **repmgrd_info;
|
||||||
|
int repmgrd_running_count;
|
||||||
|
|
||||||
|
bool dry_run_success;
|
||||||
|
|
||||||
|
/* store list of configuration files on the demotion candidate */
|
||||||
|
KeyValueList remote_config_files;
|
||||||
|
|
||||||
|
/* used for handling repmgrd pause/unpause */
|
||||||
|
NodeInfoList all_nodes;
|
||||||
|
|
||||||
|
NodeInfoList sibling_nodes;
|
||||||
|
SiblingNodeStats sibling_nodes_stats;
|
||||||
|
|
||||||
|
t_event_info event_info;
|
||||||
|
int remote_node_id;
|
||||||
|
t_node_info remote_node_record;
|
||||||
|
t_node_info local_node_record;
|
||||||
|
char remote_conninfo[MAXCONNINFO];
|
||||||
|
bool switchover_success;
|
||||||
|
RecoveryType recovery_type;
|
||||||
|
PGconn *superuser_conn;
|
||||||
|
|
||||||
|
/* the remote server is the primary to be demoted */
|
||||||
|
char remote_host[MAXLEN];
|
||||||
|
int remote_repmgr_version;
|
||||||
|
PGconn *remote_conn;
|
||||||
|
PGconn *local_conn;
|
||||||
|
} t_standby_switchover_rec;
|
||||||
|
|
||||||
|
#define T_STANDBY_SWITCHOVER_INITIALIZER { \
|
||||||
|
NULL, \
|
||||||
|
true, \
|
||||||
|
{NULL, NULL}, \
|
||||||
|
T_NODE_INFO_LIST_INITIALIZER, \
|
||||||
|
T_NODE_INFO_LIST_INITIALIZER, \
|
||||||
|
T_SIBLING_NODES_STATS_INITIALIZER, \
|
||||||
|
T_EVENT_INFO_INITIALIZER, \
|
||||||
|
UNKNOWN_NODE_ID, \
|
||||||
|
T_NODE_INFO_INITIALIZER, \
|
||||||
|
T_NODE_INFO_INITIALIZER, \
|
||||||
|
"", \
|
||||||
|
true, \
|
||||||
|
RECTYPE_UNKNOWN, \
|
||||||
|
NULL, \
|
||||||
|
"", \
|
||||||
|
UNKNOWN_REPMGR_VERSION_NUM, \
|
||||||
|
NULL, \
|
||||||
|
NULL \
|
||||||
|
}
|
||||||
|
|
||||||
extern void do_standby_clone(void);
|
extern void do_standby_clone(void);
|
||||||
extern void do_standby_register(void);
|
extern void do_standby_register(void);
|
||||||
extern void do_standby_unregister(void);
|
extern void do_standby_unregister(void);
|
||||||
@@ -30,6 +101,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_ */
|
||||||
|
|||||||
@@ -193,8 +193,7 @@ typedef struct
|
|||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
barman,
|
barman,
|
||||||
pg_basebackup,
|
pg_basebackup
|
||||||
pg_backupapi
|
|
||||||
} standy_clone_mode;
|
} standy_clone_mode;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
|||||||
@@ -3096,14 +3096,9 @@ 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
|
||||||
if (*config_file_options.pg_backupapi_host != '\0') {
|
mode = pg_basebackup;
|
||||||
log_info("Attempting to use `pg_backupapi` new restore mode");
|
|
||||||
mode = pg_backupapi;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mode = pg_basebackup;
|
|
||||||
}
|
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
#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
|
||||||
@@ -340,31 +340,22 @@ 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
|
||||||
# Can be true in PostgreSQL 9.5 and later only. Until PostgreSQL 14 repmgr user must be a superuser to use this.
|
# (PostgreSQL 9.5 and later only; repmgr user must be a superuser for 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. Each of the following parameter placeholders
|
# decision made by repmgrd. One or both of the following parameter placeholders
|
||||||
# should be provided, which will be replaced by repmgrd with the appropriate value:
|
# should be provided, which will be replaced by repmgrd with the appropriate
|
||||||
# %n (node_id)
|
# value: %n (node_id), %a (node_name). *Must* be the same on all nodes.
|
||||||
# %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
|
||||||
@@ -372,7 +363,6 @@ 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
|
||||||
@@ -395,20 +385,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-16'
|
# service_start_command = 'sudo systemctl start postgresql-9.6'
|
||||||
# (...)
|
# (...)
|
||||||
#
|
#
|
||||||
# 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-16, \
|
# postgres ALL = NOPASSWD: /usr/bin/systemctl stop postgresql-9.6, \
|
||||||
# /usr/bin/systemctl start postgresql-16, \
|
# /usr/bin/systemctl start postgresql-9.6, \
|
||||||
# /usr/bin/systemctl restart postgresql-16
|
# /usr/bin/systemctl restart postgresql-9.6
|
||||||
#
|
#
|
||||||
# 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 further details, see: https://repmgr.org/docs/current/configuration-file-service-commands.html
|
# For more details, see: https://repmgr.org/docs/current/configuration-file-service-commands.html
|
||||||
|
|
||||||
#service_start_command = ''
|
#service_start_command = ''
|
||||||
#service_stop_command = ''
|
#service_stop_command = ''
|
||||||
@@ -451,3 +441,4 @@ 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.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
1
repmgr.h
1
repmgr.h
@@ -116,7 +116,6 @@
|
|||||||
#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 */
|
||||||
|
|||||||
@@ -2394,17 +2394,6 @@ monitor_streaming_witness(void)
|
|||||||
terminate(ERR_BAD_CONFIG);
|
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,
|
||||||
|
|||||||
Reference in New Issue
Block a user