mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-23 15:16:29 +00:00
Compare commits
18 Commits
REL5_0_STA
...
v4.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40b6c92129 | ||
|
|
761d65526c | ||
|
|
a13a1232e9 | ||
|
|
65965b3ba4 | ||
|
|
629d2b8f85 | ||
|
|
23c285b73b | ||
|
|
915fb7d617 | ||
|
|
ae141b9d32 | ||
|
|
d035550723 | ||
|
|
c7692b5d84 | ||
|
|
08b7f1294b | ||
|
|
81d01bf0e8 | ||
|
|
089c778e49 | ||
|
|
b4b5681762 | ||
|
|
e5ef549aa7 | ||
|
|
cfc41392c3 | ||
|
|
55dc4f7a5f | ||
|
|
6616712346 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -53,6 +53,3 @@ repmgr
|
|||||||
repmgrd
|
repmgrd
|
||||||
repmgr4
|
repmgr4
|
||||||
repmgrd4
|
repmgrd4
|
||||||
|
|
||||||
# generated files
|
|
||||||
configfile-scan.c
|
|
||||||
|
|||||||
13
HISTORY
13
HISTORY
@@ -1,16 +1,3 @@
|
|||||||
5.0.1 20??-??-??
|
|
||||||
repmgr: ensure an existing replication slot is not deleted if the
|
|
||||||
follow target is the node's current upstream (Ian)
|
|
||||||
|
|
||||||
5.0 2019-10-15
|
|
||||||
general: add PostgreSQL 12 support (Ian)
|
|
||||||
general: parse configuration file using flex (Ian)
|
|
||||||
repmgr: rename "repmgr daemon ..." commands to "repmgr service ..." (Ian)
|
|
||||||
repmgr: improve data directory check (Ian)
|
|
||||||
repmgr: improve extension check during "standby clone" (Ian)
|
|
||||||
repmgr: pass provided log level when executing repmgr remotely (Ian)
|
|
||||||
repmgrd: fix handling of upstream node change check (Ian)
|
|
||||||
|
|
||||||
4.4 2019-06-27
|
4.4 2019-06-27
|
||||||
repmgr: improve "daemon status" output (Ian)
|
repmgr: improve "daemon status" output (Ian)
|
||||||
repmgr: add "--siblings-follow" option to "standby promote" (Ian)
|
repmgr: add "--siblings-follow" option to "standby promote" (Ian)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
# Makefile.global.in
|
# Makefile.global.in
|
||||||
# @configure_input@
|
# @configure_input@
|
||||||
|
|
||||||
|
|
||||||
# Can only be built using pgxs
|
# Can only be built using pgxs
|
||||||
USE_PGXS=1
|
USE_PGXS=1
|
||||||
|
|
||||||
@@ -15,9 +14,6 @@ ifeq ($(vpath_build),yes)
|
|||||||
VPATH := $(repmgr_abs_srcdir)/$(repmgr_subdir)
|
VPATH := $(repmgr_abs_srcdir)/$(repmgr_subdir)
|
||||||
USE_VPATH :=$(VPATH)
|
USE_VPATH :=$(VPATH)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SED=@SED@
|
|
||||||
|
|
||||||
GIT_WORK_TREE=${repmgr_abs_srcdir}
|
GIT_WORK_TREE=${repmgr_abs_srcdir}
|
||||||
GIT_DIR=${repmgr_abs_srcdir}/.git
|
GIT_DIR=${repmgr_abs_srcdir}/.git
|
||||||
export GIT_DIR
|
export GIT_DIR
|
||||||
@@ -28,13 +24,4 @@ include $(PGXS)
|
|||||||
-include ${repmgr_abs_srcdir}/Makefile.custom
|
-include ${repmgr_abs_srcdir}/Makefile.custom
|
||||||
|
|
||||||
REPMGR_VERSION=$(shell awk '/^\#define REPMGR_VERSION / { print $3; }' ${repmgr_abs_srcdir}/repmgr_version.h.in | cut -d '"' -f 2)
|
REPMGR_VERSION=$(shell awk '/^\#define REPMGR_VERSION / { print $3; }' ${repmgr_abs_srcdir}/repmgr_version.h.in | cut -d '"' -f 2)
|
||||||
REPMGR_RELEASE_DATE=$(shell awk '/^\#define REPMGR_RELEASE_DATE / { print $3; }' ${repmgr_abs_srcdir}/repmgr_version.h.in | cut -d '"' -f 2)
|
|
||||||
|
|
||||||
FLEX = flex
|
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
#
|
|
||||||
# Global targets and rules
|
|
||||||
|
|
||||||
%.c: %.l
|
|
||||||
$(FLEX) $(FLEXFLAGS) -o'$@' $<
|
|
||||||
|
|||||||
16
Makefile.in
16
Makefile.in
@@ -19,9 +19,7 @@ DATA = \
|
|||||||
repmgr--4.2--4.3.sql \
|
repmgr--4.2--4.3.sql \
|
||||||
repmgr--4.3.sql \
|
repmgr--4.3.sql \
|
||||||
repmgr--4.3--4.4.sql \
|
repmgr--4.3--4.4.sql \
|
||||||
repmgr--4.4.sql \
|
repmgr--4.4.sql
|
||||||
repmgr--4.4--5.0.sql \
|
|
||||||
repmgr--5.0.sql
|
|
||||||
|
|
||||||
REGRESS = repmgr_extension
|
REGRESS = repmgr_extension
|
||||||
|
|
||||||
@@ -53,16 +51,13 @@ $(info Building against PostgreSQL $(MAJORVERSION))
|
|||||||
|
|
||||||
REPMGR_CLIENT_OBJS = repmgr-client.o \
|
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-bdr.o repmgr-action-cluster.o repmgr-action-node.o repmgr-action-service.o repmgr-action-daemon.o \
|
repmgr-action-bdr.o repmgr-action-cluster.o repmgr-action-node.o repmgr-action-daemon.o \
|
||||||
configfile.o configfile-scan.o log.o strutil.o controldata.o dirutil.o compat.o dbutils.o sysutils.o
|
configfile.o log.o strutil.o controldata.o dirutil.o compat.o dbutils.o sysutils.o
|
||||||
REPMGRD_OBJS = repmgrd.o repmgrd-physical.o repmgrd-bdr.o configfile.o configfile-scan.o log.o dbutils.o strutil.o controldata.o compat.o sysutils.o
|
REPMGRD_OBJS = repmgrd.o repmgrd-physical.o repmgrd-bdr.o configfile.o log.o dbutils.o strutil.o controldata.o compat.o sysutils.o
|
||||||
DATE=$(shell date "+%Y-%m-%d")
|
DATE=$(shell date "+%Y-%m-%d")
|
||||||
|
|
||||||
repmgr_version.h: repmgr_version.h.in
|
repmgr_version.h: repmgr_version.h.in
|
||||||
$(SED) -E 's/REPMGR_VERSION_DATE.*""/REPMGR_VERSION_DATE "$(DATE)"/' $< >$@; \
|
sed '0,/REPMGR_VERSION_DATE/s,\(REPMGR_VERSION_DATE\).*,\1 "$(DATE)",' $< >$@
|
||||||
$(SED) -i -E 's/PG_ACTUAL_VERSION_NUM/PG_ACTUAL_VERSION_NUM $(VERSION_NUM)/' $@
|
|
||||||
|
|
||||||
configfile-scan.c: configfile-scan.l
|
|
||||||
|
|
||||||
$(REPMGR_CLIENT_OBJS): repmgr-client.h repmgr_version.h
|
$(REPMGR_CLIENT_OBJS): repmgr-client.h repmgr_version.h
|
||||||
|
|
||||||
@@ -103,7 +98,6 @@ maintainer-clean: additional-maintainer-clean
|
|||||||
|
|
||||||
additional-clean:
|
additional-clean:
|
||||||
rm -f *.o
|
rm -f *.o
|
||||||
rm -f repmgr_version.h
|
|
||||||
$(MAKE) -C doc clean
|
$(MAKE) -C doc clean
|
||||||
|
|
||||||
additional-maintainer-clean: clean
|
additional-maintainer-clean: clean
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -7,30 +7,32 @@ replication capabilities with utilities to set up standby servers, monitor
|
|||||||
replication, and perform administrative tasks such as failover or switchover
|
replication, and perform administrative tasks such as failover or switchover
|
||||||
operations.
|
operations.
|
||||||
|
|
||||||
PostgreSQL 12, 11, 10, 9.6 and 9.5 are fully supported.
|
`repmgr 4` is a complete rewrite of the existing `repmgr` codebase, allowing
|
||||||
|
the use of all of the latest features in PostgreSQL replication.
|
||||||
|
|
||||||
|
PostgreSQL 11, 10, 9.6 and 9.5 are fully supported.
|
||||||
PostgreSQL 9.4 and 9.3 are supported, with some restrictions.
|
PostgreSQL 9.4 and 9.3 are supported, with some restrictions.
|
||||||
|
|
||||||
`repmgr` is distributed under the GNU GPL 3 and maintained by 2ndQuadrant.
|
`repmgr` is distributed under the GNU GPL 3 and maintained by 2ndQuadrant.
|
||||||
|
|
||||||
|
### BDR support
|
||||||
|
|
||||||
|
`repmgr 4` supports monitoring of a two-node BDR 2.0 cluster on PostgreSQL 9.6
|
||||||
|
only. Note that BDR 2.0 is not publicly available; please contact 2ndQuadrant
|
||||||
|
for details.
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The full `repmgr` documentation is available here:
|
The main `repmgr` documentation is available here:
|
||||||
|
|
||||||
> [repmgr documentation](https://repmgr.org/docs/current/index.html)
|
> [repmgr documentation](https://repmgr.org/docs/current/index.html)
|
||||||
|
|
||||||
The old `README` file for `repmgr` 3.x is available here:
|
The `README` file for `repmgr` 3.x is available here:
|
||||||
|
|
||||||
> https://github.com/2ndQuadrant/repmgr/blob/REL3_3_STABLE/README.md
|
> https://github.com/2ndQuadrant/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 as soon as possible.
|
|
||||||
|
|
||||||
Versions
|
|
||||||
--------
|
|
||||||
|
|
||||||
For an overview of `repmgr` versions and PostgreSQL compatibility, see the
|
|
||||||
[repmgr compatibility matrix](https://repmgr.org/docs/current/install-requirements.html#INSTALL-COMPATIBILITY-MATRIX).
|
|
||||||
|
|
||||||
Files
|
Files
|
||||||
------
|
------
|
||||||
@@ -70,8 +72,6 @@ Please report bugs and other issues to:
|
|||||||
|
|
||||||
* https://github.com/2ndQuadrant/repmgr
|
* https://github.com/2ndQuadrant/repmgr
|
||||||
|
|
||||||
See
|
|
||||||
|
|
||||||
Further information is available at https://repmgr.org/
|
Further information is available at https://repmgr.org/
|
||||||
|
|
||||||
We'd love to hear from you about how you use repmgr. Case studies and
|
We'd love to hear from you about how you use repmgr. Case studies and
|
||||||
@@ -98,8 +98,6 @@ Further reading
|
|||||||
---------------
|
---------------
|
||||||
|
|
||||||
* [repmgr documentation](https://repmgr.org/docs/current/index.html)
|
* [repmgr documentation](https://repmgr.org/docs/current/index.html)
|
||||||
* [How to Automate PostgreSQL 12 Replication and Failover with repmgr - Part 1](https://www.2ndquadrant.com/en/blog/how-to-automate-postgresql-12-replication-and-failover-with-repmgr-part-1/)
|
|
||||||
* [How to Automate PostgreSQL 12 Replication and Failover with repmgr - Part 2](https://www.2ndquadrant.com/en/blog/how-to-automate-postgresql-12-replication-and-failover-with-repmgr-part-2/)
|
|
||||||
* https://blog.2ndquadrant.com/repmgr-3-2-is-here-barman-support-brand-new-high-availability-features/
|
* https://blog.2ndquadrant.com/repmgr-3-2-is-here-barman-support-brand-new-high-availability-features/
|
||||||
* https://blog.2ndquadrant.com/improvements-in-repmgr-3-1-4/
|
* https://blog.2ndquadrant.com/improvements-in-repmgr-3-1-4/
|
||||||
* https://blog.2ndquadrant.com/managing-useful-clusters-repmgr/
|
* https://blog.2ndquadrant.com/managing-useful-clusters-repmgr/
|
||||||
|
|||||||
@@ -1,366 +0,0 @@
|
|||||||
/*
|
|
||||||
* Scanner for the configuration file
|
|
||||||
*/
|
|
||||||
|
|
||||||
%{
|
|
||||||
|
|
||||||
#include <setjmp.h>
|
|
||||||
|
|
||||||
#include "repmgr.h"
|
|
||||||
#include "configfile.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* flex emits a yy_fatal_error() function that it calls in response to
|
|
||||||
* critical errors like malloc failure, file I/O errors, and detection of
|
|
||||||
* internal inconsistency. That function prints a message and calls exit().
|
|
||||||
* Mutate it to instead call our handler, which jumps out of the parser.
|
|
||||||
*/
|
|
||||||
#undef fprintf
|
|
||||||
#define fprintf(file, fmt, msg) CONF_flex_fatal(msg)
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
CONF_ID = 1,
|
|
||||||
CONF_STRING = 2,
|
|
||||||
CONF_INTEGER = 3,
|
|
||||||
CONF_REAL = 4,
|
|
||||||
CONF_EQUALS = 5,
|
|
||||||
CONF_UNQUOTED_STRING = 6,
|
|
||||||
CONF_QUALIFIED_ID = 7,
|
|
||||||
CONF_EOL = 99,
|
|
||||||
CONF_ERROR = 100
|
|
||||||
};
|
|
||||||
|
|
||||||
static unsigned int ConfigFileLineno;
|
|
||||||
static const char *CONF_flex_fatal_errmsg;
|
|
||||||
static sigjmp_buf *CONF_flex_fatal_jmp;
|
|
||||||
|
|
||||||
static char *CONF_scanstr(const char *s);
|
|
||||||
static int CONF_flex_fatal(const char *msg);
|
|
||||||
|
|
||||||
static bool ProcessConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
|
|
||||||
|
|
||||||
%}
|
|
||||||
|
|
||||||
%option 8bit
|
|
||||||
%option never-interactive
|
|
||||||
%option nodefault
|
|
||||||
%option noinput
|
|
||||||
%option nounput
|
|
||||||
%option noyywrap
|
|
||||||
%option warn
|
|
||||||
%option prefix="CONF_yy"
|
|
||||||
|
|
||||||
|
|
||||||
SIGN ("-"|"+")
|
|
||||||
DIGIT [0-9]
|
|
||||||
HEXDIGIT [0-9a-fA-F]
|
|
||||||
|
|
||||||
UNIT_LETTER [a-zA-Z]
|
|
||||||
|
|
||||||
INTEGER {SIGN}?({DIGIT}+|0x{HEXDIGIT}+){UNIT_LETTER}*
|
|
||||||
|
|
||||||
EXPONENT [Ee]{SIGN}?{DIGIT}+
|
|
||||||
REAL {SIGN}?{DIGIT}*"."{DIGIT}*{EXPONENT}?
|
|
||||||
|
|
||||||
LETTER [A-Za-z_\200-\377]
|
|
||||||
LETTER_OR_DIGIT [A-Za-z_0-9\200-\377]
|
|
||||||
|
|
||||||
ID {LETTER}{LETTER_OR_DIGIT}*
|
|
||||||
QUALIFIED_ID {ID}"."{ID}
|
|
||||||
|
|
||||||
UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])*
|
|
||||||
STRING \'([^'\\\n]|\\.|\'\')*\'
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
\n ConfigFileLineno++; return CONF_EOL;
|
|
||||||
[ \t\r]+ /* eat whitespace */
|
|
||||||
#.* /* eat comment (.* matches anything until newline) */
|
|
||||||
|
|
||||||
{ID} return CONF_ID;
|
|
||||||
{QUALIFIED_ID} return CONF_QUALIFIED_ID;
|
|
||||||
{STRING} return CONF_STRING;
|
|
||||||
{UNQUOTED_STRING} return CONF_UNQUOTED_STRING;
|
|
||||||
{INTEGER} return CONF_INTEGER;
|
|
||||||
{REAL} return CONF_REAL;
|
|
||||||
= return CONF_EQUALS;
|
|
||||||
|
|
||||||
. return CONF_ERROR;
|
|
||||||
|
|
||||||
%%
|
|
||||||
|
|
||||||
extern bool
|
|
||||||
ProcessRepmgrConfigFile(FILE *fp, const char *config_file, t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
|
|
||||||
{
|
|
||||||
return ProcessConfigFile(fp, config_file, NULL, options, error_list, warning_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern bool
|
|
||||||
ProcessPostgresConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, ItemList *error_list, ItemList *warning_list)
|
|
||||||
{
|
|
||||||
return ProcessConfigFile(fp, config_file, contents, NULL, error_list, warning_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ProcessConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
|
|
||||||
{
|
|
||||||
volatile bool OK = true;
|
|
||||||
volatile YY_BUFFER_STATE lex_buffer = NULL;
|
|
||||||
sigjmp_buf flex_fatal_jmp;
|
|
||||||
int errorcount;
|
|
||||||
int token;
|
|
||||||
|
|
||||||
if (sigsetjmp(flex_fatal_jmp, 1) == 0)
|
|
||||||
{
|
|
||||||
CONF_flex_fatal_jmp = &flex_fatal_jmp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Regain control after a fatal, internal flex error. It may have
|
|
||||||
* corrupted parser state. Consequently, abandon the file, but trust
|
|
||||||
* that the state remains sane enough for yy_delete_buffer().
|
|
||||||
*/
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
"%s at file \"%s\" line %u",
|
|
||||||
CONF_flex_fatal_errmsg, config_file, ConfigFileLineno);
|
|
||||||
OK = false;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse
|
|
||||||
*/
|
|
||||||
ConfigFileLineno = 1;
|
|
||||||
errorcount = 0;
|
|
||||||
|
|
||||||
lex_buffer = yy_create_buffer(fp, YY_BUF_SIZE);
|
|
||||||
yy_switch_to_buffer(lex_buffer);
|
|
||||||
|
|
||||||
/* This loop iterates once per logical line */
|
|
||||||
while ((token = yylex()))
|
|
||||||
{
|
|
||||||
char *opt_name = NULL;
|
|
||||||
char *opt_value = NULL;
|
|
||||||
|
|
||||||
if (token == CONF_EOL) /* empty or comment line */
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* first token on line is option name */
|
|
||||||
if (token != CONF_ID && token != CONF_QUALIFIED_ID)
|
|
||||||
goto parse_error;
|
|
||||||
opt_name = pstrdup(yytext);
|
|
||||||
|
|
||||||
/* next we have an optional equal sign; discard if present */
|
|
||||||
token = yylex();
|
|
||||||
if (token == CONF_EQUALS)
|
|
||||||
token = yylex();
|
|
||||||
|
|
||||||
/* now we must have the option value */
|
|
||||||
if (token != CONF_ID &&
|
|
||||||
token != CONF_STRING &&
|
|
||||||
token != CONF_INTEGER &&
|
|
||||||
token != CONF_REAL &&
|
|
||||||
token != CONF_UNQUOTED_STRING)
|
|
||||||
goto parse_error;
|
|
||||||
if (token == CONF_STRING) /* strip quotes and escapes */
|
|
||||||
opt_value = CONF_scanstr(yytext);
|
|
||||||
else
|
|
||||||
opt_value = pstrdup(yytext);
|
|
||||||
|
|
||||||
/* now we'd like an end of line, or possibly EOF */
|
|
||||||
token = yylex();
|
|
||||||
if (token != CONF_EOL)
|
|
||||||
{
|
|
||||||
if (token != 0)
|
|
||||||
goto parse_error;
|
|
||||||
/* treat EOF like \n for line numbering purposes, cf bug 4752 */
|
|
||||||
ConfigFileLineno++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* OK, process the option name and value */
|
|
||||||
if (contents != NULL)
|
|
||||||
{
|
|
||||||
key_value_list_replace_or_set(contents,
|
|
||||||
opt_name,
|
|
||||||
opt_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options != NULL)
|
|
||||||
{
|
|
||||||
parse_configuration_item(options,
|
|
||||||
error_list,
|
|
||||||
warning_list,
|
|
||||||
opt_name,
|
|
||||||
opt_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* break out of loop if read EOF, else loop for next line */
|
|
||||||
if (token == 0)
|
|
||||||
break;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
parse_error:
|
|
||||||
/* release storage if we allocated any on this line */
|
|
||||||
if (opt_name)
|
|
||||||
pfree(opt_name);
|
|
||||||
if (opt_value)
|
|
||||||
pfree(opt_value);
|
|
||||||
|
|
||||||
/* report the error */
|
|
||||||
if (token == CONF_EOL || token == 0)
|
|
||||||
{
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
_("syntax error in file \"%s\" line %u, near end of line"),
|
|
||||||
config_file, ConfigFileLineno - 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
_("syntax error in file \"%s\" line %u, near token \"%s\""),
|
|
||||||
config_file, ConfigFileLineno, yytext);
|
|
||||||
}
|
|
||||||
OK = false;
|
|
||||||
errorcount++;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To avoid producing too much noise when fed a totally bogus file,
|
|
||||||
* give up after 100 syntax errors per file (an arbitrary number).
|
|
||||||
* Also, if we're only logging the errors at DEBUG level anyway, might
|
|
||||||
* as well give up immediately. (This prevents postmaster children
|
|
||||||
* from bloating the logs with duplicate complaints.)
|
|
||||||
*/
|
|
||||||
if (errorcount >= 100)
|
|
||||||
{
|
|
||||||
fprintf(stderr,
|
|
||||||
_("too many syntax errors found, abandoning file \"%s\"\n"),
|
|
||||||
config_file);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* resync to next end-of-line or EOF */
|
|
||||||
while (token != CONF_EOL && token != 0)
|
|
||||||
token = yylex();
|
|
||||||
/* break out of loop on EOF */
|
|
||||||
if (token == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
yy_delete_buffer(lex_buffer);
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* scanstr
|
|
||||||
*
|
|
||||||
* Strip the quotes surrounding the given string, and collapse any embedded
|
|
||||||
* '' sequences and backslash escapes.
|
|
||||||
*
|
|
||||||
* the string returned is palloc'd and should eventually be pfree'd by the
|
|
||||||
* caller.
|
|
||||||
*/
|
|
||||||
static char *
|
|
||||||
CONF_scanstr(const char *s)
|
|
||||||
{
|
|
||||||
char *newStr;
|
|
||||||
int len,
|
|
||||||
i,
|
|
||||||
j;
|
|
||||||
|
|
||||||
Assert(s != NULL && s[0] == '\'');
|
|
||||||
len = strlen(s);
|
|
||||||
Assert(s != NULL);
|
|
||||||
|
|
||||||
Assert(len >= 2);
|
|
||||||
Assert(s[len - 1] == '\'');
|
|
||||||
|
|
||||||
/* Skip the leading quote; we'll handle the trailing quote below */
|
|
||||||
s++, len--;
|
|
||||||
|
|
||||||
/* Since len still includes trailing quote, this is enough space */
|
|
||||||
newStr = palloc(len);
|
|
||||||
|
|
||||||
for (i = 0, j = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
if (s[i] == '\\')
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
switch (s[i])
|
|
||||||
{
|
|
||||||
case 'b':
|
|
||||||
newStr[j] = '\b';
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
newStr[j] = '\f';
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
newStr[j] = '\n';
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
newStr[j] = '\r';
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
newStr[j] = '\t';
|
|
||||||
break;
|
|
||||||
case '0':
|
|
||||||
case '1':
|
|
||||||
case '2':
|
|
||||||
case '3':
|
|
||||||
case '4':
|
|
||||||
case '5':
|
|
||||||
case '6':
|
|
||||||
case '7':
|
|
||||||
{
|
|
||||||
int k;
|
|
||||||
long octVal = 0;
|
|
||||||
|
|
||||||
for (k = 0;
|
|
||||||
s[i + k] >= '0' && s[i + k] <= '7' && k < 3;
|
|
||||||
k++)
|
|
||||||
octVal = (octVal << 3) + (s[i + k] - '0');
|
|
||||||
i += k - 1;
|
|
||||||
newStr[j] = ((char) octVal);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
newStr[j] = s[i];
|
|
||||||
break;
|
|
||||||
} /* switch */
|
|
||||||
}
|
|
||||||
else if (s[i] == '\'' && s[i + 1] == '\'')
|
|
||||||
{
|
|
||||||
/* doubled quote becomes just one quote */
|
|
||||||
newStr[j] = s[++i];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
newStr[j] = s[i];
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We copied the ending quote to newStr, so replace with \0 */
|
|
||||||
Assert(j > 0 && j <= len);
|
|
||||||
newStr[--j] = '\0';
|
|
||||||
|
|
||||||
return newStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Flex fatal errors bring us here. Stash the error message and jump back to
|
|
||||||
* ParseConfigFp(). Assume all msg arguments point to string constants; this
|
|
||||||
* holds for flex 2.5.31 (earliest we support) and flex 2.5.35 (latest as of
|
|
||||||
* this writing). Otherwise, we would need to copy the message.
|
|
||||||
*
|
|
||||||
* We return "int" since this takes the place of calls to fprintf().
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
CONF_flex_fatal(const char *msg)
|
|
||||||
{
|
|
||||||
CONF_flex_fatal_errmsg = msg;
|
|
||||||
siglongjmp(*CONF_flex_fatal_jmp, 1);
|
|
||||||
return 0; /* keep compiler quiet */
|
|
||||||
}
|
|
||||||
833
configfile.c
833
configfile.c
@@ -23,12 +23,6 @@
|
|||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#include <utils/elog.h>
|
|
||||||
|
|
||||||
#if (PG_ACTUAL_VERSION_NUM >= 100000)
|
|
||||||
#include <storage/fd.h> /* for durable_rename() */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const static char *_progname = NULL;
|
const static char *_progname = NULL;
|
||||||
char config_file_path[MAXPGPATH] = "";
|
char config_file_path[MAXPGPATH] = "";
|
||||||
static bool config_file_provided = false;
|
static bool config_file_provided = false;
|
||||||
@@ -272,6 +266,12 @@ static void
|
|||||||
_parse_config(t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
|
_parse_config(t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
char *s = NULL,
|
||||||
|
buf[MAXLINELENGTH] = "";
|
||||||
|
char name[MAXLEN] = "";
|
||||||
|
char value[MAXLEN] = "";
|
||||||
|
|
||||||
|
bool node_id_found = false;
|
||||||
|
|
||||||
/* Initialize configuration options with sensible defaults */
|
/* Initialize configuration options with sensible defaults */
|
||||||
|
|
||||||
@@ -468,12 +468,365 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) ProcessRepmgrConfigFile(fp, config_file_path, options, error_list, warning_list);
|
/* Read file */
|
||||||
|
while ((s = fgets(buf, sizeof buf, fp)) != NULL)
|
||||||
|
{
|
||||||
|
bool known_parameter = true;
|
||||||
|
|
||||||
|
/* Parse name/value pair from line */
|
||||||
|
_parse_line(buf, name, value);
|
||||||
|
|
||||||
|
/* Skip blank lines */
|
||||||
|
if (!strlen(name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Skip comments */
|
||||||
|
if (name[0] == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Copy into correct entry in parameters struct */
|
||||||
|
if (strcmp(name, "node_id") == 0)
|
||||||
|
{
|
||||||
|
options->node_id = repmgr_atoi(value, name, error_list, MIN_NODE_ID);
|
||||||
|
node_id_found = true;
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "node_name") == 0)
|
||||||
|
{
|
||||||
|
if (strlen(value) < sizeof(options->node_name))
|
||||||
|
strncpy(options->node_name, value, sizeof(options->node_name));
|
||||||
|
else
|
||||||
|
item_list_append_format(error_list,
|
||||||
|
_("value for \"node_name\" must contain fewer than %lu characters"),
|
||||||
|
sizeof(options->node_name));
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "conninfo") == 0)
|
||||||
|
strncpy(options->conninfo, value, MAXLEN);
|
||||||
|
else if (strcmp(name, "data_directory") == 0)
|
||||||
|
{
|
||||||
|
strncpy(options->data_directory, value, MAXPGPATH);
|
||||||
|
canonicalize_path(options->data_directory);
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "config_directory") == 0)
|
||||||
|
{
|
||||||
|
strncpy(options->config_directory, value, MAXPGPATH);
|
||||||
|
canonicalize_path(options->config_directory);
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "replication_user") == 0)
|
||||||
|
{
|
||||||
|
if (strlen(value) < sizeof(options->replication_user))
|
||||||
|
strncpy(options->replication_user, value, sizeof(options->replication_user));
|
||||||
|
else
|
||||||
|
item_list_append_format(error_list,
|
||||||
|
_("value for \"replication_user\" must contain fewer than %lu characters"),
|
||||||
|
sizeof(options->replication_user));
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "pg_bindir") == 0)
|
||||||
|
strncpy(options->pg_bindir, value, MAXPGPATH);
|
||||||
|
else if (strcmp(name, "repmgr_bindir") == 0)
|
||||||
|
strncpy(options->repmgr_bindir, value, MAXPGPATH);
|
||||||
|
|
||||||
|
else if (strcmp(name, "replication_type") == 0)
|
||||||
|
{
|
||||||
|
if (strcmp(value, "physical") == 0)
|
||||||
|
options->replication_type = REPLICATION_TYPE_PHYSICAL;
|
||||||
|
else if (strcmp(value, "bdr") == 0)
|
||||||
|
options->replication_type = REPLICATION_TYPE_BDR;
|
||||||
|
else
|
||||||
|
item_list_append(error_list, _("value for \"replication_type\" must be \"physical\" or \"bdr\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* log settings */
|
||||||
|
else if (strcmp(name, "log_file") == 0)
|
||||||
|
strncpy(options->log_file, value, MAXLEN);
|
||||||
|
else if (strcmp(name, "log_level") == 0)
|
||||||
|
strncpy(options->log_level, value, MAXLEN);
|
||||||
|
else if (strcmp(name, "log_facility") == 0)
|
||||||
|
strncpy(options->log_facility, value, MAXLEN);
|
||||||
|
else if (strcmp(name, "log_status_interval") == 0)
|
||||||
|
options->log_status_interval = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
|
||||||
|
/* standby clone settings */
|
||||||
|
else if (strcmp(name, "use_replication_slots") == 0)
|
||||||
|
options->use_replication_slots = parse_bool(value, name, error_list);
|
||||||
|
else if (strcmp(name, "pg_basebackup_options") == 0)
|
||||||
|
strncpy(options->pg_basebackup_options, value, MAXLEN);
|
||||||
|
else if (strcmp(name, "tablespace_mapping") == 0)
|
||||||
|
tablespace_list_append(options, value);
|
||||||
|
else if (strcmp(name, "restore_command") == 0)
|
||||||
|
strncpy(options->restore_command, value, MAXLEN);
|
||||||
|
else if (strcmp(name, "recovery_min_apply_delay") == 0)
|
||||||
|
{
|
||||||
|
parse_time_unit_parameter(name, value, options->recovery_min_apply_delay, error_list);
|
||||||
|
options->recovery_min_apply_delay_provided = true;
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "archive_cleanup_command") == 0)
|
||||||
|
strncpy(options->archive_cleanup_command, value, MAXLEN);
|
||||||
|
else if (strcmp(name, "use_primary_conninfo_password") == 0)
|
||||||
|
options->use_primary_conninfo_password = parse_bool(value, name, error_list);
|
||||||
|
else if (strcmp(name, "passfile") == 0)
|
||||||
|
strncpy(options->passfile, value, sizeof(options->passfile));
|
||||||
|
|
||||||
|
/* standby promote settings */
|
||||||
|
else if (strcmp(name, "promote_check_timeout") == 0)
|
||||||
|
options->promote_check_timeout = repmgr_atoi(value, name, error_list, 1);
|
||||||
|
|
||||||
|
else if (strcmp(name, "promote_check_interval") == 0)
|
||||||
|
options->promote_check_interval = repmgr_atoi(value, name, error_list, 1);
|
||||||
|
|
||||||
|
/* standby follow settings */
|
||||||
|
else if (strcmp(name, "primary_follow_timeout") == 0)
|
||||||
|
options->primary_follow_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
else if (strcmp(name, "standby_follow_timeout") == 0)
|
||||||
|
options->standby_follow_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
|
||||||
|
/* standby switchover settings */
|
||||||
|
else if (strcmp(name, "shutdown_check_timeout") == 0)
|
||||||
|
options->shutdown_check_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
else if (strcmp(name, "standby_reconnect_timeout") == 0)
|
||||||
|
options->standby_reconnect_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
else if (strcmp(name, "wal_receive_check_timeout") == 0)
|
||||||
|
options->wal_receive_check_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
|
||||||
|
/* node rejoin settings */
|
||||||
|
else if (strcmp(name, "node_rejoin_timeout") == 0)
|
||||||
|
options->node_rejoin_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
|
||||||
|
/* node check settings */
|
||||||
|
else if (strcmp(name, "archive_ready_warning") == 0)
|
||||||
|
options->archive_ready_warning = repmgr_atoi(value, name, error_list, 1);
|
||||||
|
else if (strcmp(name, "archive_ready_critical") == 0)
|
||||||
|
options->archive_ready_critical = repmgr_atoi(value, name, error_list, 1);
|
||||||
|
else if (strcmp(name, "replication_lag_warning") == 0)
|
||||||
|
options->replication_lag_warning = repmgr_atoi(value, name, error_list, 1);
|
||||||
|
else if (strcmp(name, "replication_lag_critical") == 0)
|
||||||
|
options->replication_lag_critical = repmgr_atoi(value, name, error_list, 1);
|
||||||
|
|
||||||
|
/* repmgrd settings */
|
||||||
|
else if (strcmp(name, "failover") == 0)
|
||||||
|
{
|
||||||
|
if (strcmp(value, "manual") == 0)
|
||||||
|
{
|
||||||
|
options->failover = FAILOVER_MANUAL;
|
||||||
|
}
|
||||||
|
else if (strcmp(value, "automatic") == 0)
|
||||||
|
{
|
||||||
|
options->failover = FAILOVER_AUTOMATIC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item_list_append(error_list,
|
||||||
|
_("value for \"failover\" must be \"automatic\" or \"manual\"\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "priority") == 0)
|
||||||
|
options->priority = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
else if (strcmp(name, "location") == 0)
|
||||||
|
strncpy(options->location, value, sizeof(options->location));
|
||||||
|
else if (strcmp(name, "promote_command") == 0)
|
||||||
|
strncpy(options->promote_command, value, sizeof(options->promote_command));
|
||||||
|
else if (strcmp(name, "follow_command") == 0)
|
||||||
|
strncpy(options->follow_command, value, sizeof(options->follow_command));
|
||||||
|
else if (strcmp(name, "reconnect_attempts") == 0)
|
||||||
|
options->reconnect_attempts = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
else if (strcmp(name, "reconnect_interval") == 0)
|
||||||
|
options->reconnect_interval = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
else if (strcmp(name, "monitor_interval_secs") == 0)
|
||||||
|
options->monitor_interval_secs = repmgr_atoi(value, name, error_list, 1);
|
||||||
|
else if (strcmp(name, "monitoring_history") == 0)
|
||||||
|
options->monitoring_history = parse_bool(value, name, error_list);
|
||||||
|
else if (strcmp(name, "degraded_monitoring_timeout") == 0)
|
||||||
|
options->degraded_monitoring_timeout = repmgr_atoi(value, name, error_list, -1);
|
||||||
|
else if (strcmp(name, "async_query_timeout") == 0)
|
||||||
|
options->async_query_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
else if (strcmp(name, "primary_notification_timeout") == 0)
|
||||||
|
options->primary_notification_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
else if (strcmp(name, "repmgrd_standby_startup_timeout") == 0)
|
||||||
|
options->repmgrd_standby_startup_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
else if (strcmp(name, "repmgrd_pid_file") == 0)
|
||||||
|
strncpy(options->repmgrd_pid_file, value, MAXPGPATH);
|
||||||
|
else if (strcmp(name, "standby_disconnect_on_failover") == 0)
|
||||||
|
options->standby_disconnect_on_failover = parse_bool(value, name, error_list);
|
||||||
|
else if (strcmp(name, "sibling_nodes_disconnect_timeout") == 0)
|
||||||
|
options->sibling_nodes_disconnect_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
else if (strcmp(name, "connection_check_type") == 0)
|
||||||
|
{
|
||||||
|
if (strcasecmp(value, "ping") == 0)
|
||||||
|
{
|
||||||
|
options->connection_check_type = CHECK_PING;
|
||||||
|
}
|
||||||
|
else if (strcasecmp(value, "connection") == 0)
|
||||||
|
{
|
||||||
|
options->connection_check_type = CHECK_CONNECTION;
|
||||||
|
}
|
||||||
|
else if (strcasecmp(value, "query") == 0)
|
||||||
|
{
|
||||||
|
options->connection_check_type = CHECK_QUERY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item_list_append(error_list,
|
||||||
|
_("value for \"connection_check_type\" must be \"ping\", \"connection\" or \"query\"\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "primary_visibility_consensus") == 0)
|
||||||
|
options->primary_visibility_consensus = parse_bool(value, name, error_list);
|
||||||
|
else if (strcmp(name, "failover_validation_command") == 0)
|
||||||
|
strncpy(options->failover_validation_command, value, sizeof(options->failover_validation_command));
|
||||||
|
else if (strcmp(name, "election_rerun_interval") == 0)
|
||||||
|
options->election_rerun_interval = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
else if (strcmp(name, "child_nodes_check_interval") == 0)
|
||||||
|
options->child_nodes_check_interval = repmgr_atoi(value, name, error_list, 1);
|
||||||
|
else if (strcmp(name, "child_nodes_disconnect_command") == 0)
|
||||||
|
snprintf(options->child_nodes_disconnect_command, sizeof(options->child_nodes_disconnect_command), "%s", value);
|
||||||
|
else if (strcmp(name, "child_nodes_disconnect_min_count") == 0)
|
||||||
|
options->child_nodes_disconnect_min_count = repmgr_atoi(value, name, error_list, -1);
|
||||||
|
else if (strcmp(name, "child_nodes_connected_min_count") == 0)
|
||||||
|
options->child_nodes_connected_min_count = repmgr_atoi(value, name, error_list, -1);
|
||||||
|
else if (strcmp(name, "child_nodes_connected_include_witness") == 0)
|
||||||
|
options->child_nodes_connected_include_witness = parse_bool(value, name, error_list);
|
||||||
|
else if (strcmp(name, "child_nodes_disconnect_timeout") == 0)
|
||||||
|
options->child_nodes_disconnect_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
|
||||||
|
/* witness settings */
|
||||||
|
else if (strcmp(name, "witness_sync_interval") == 0)
|
||||||
|
options->witness_sync_interval = repmgr_atoi(value, name, error_list, 1);
|
||||||
|
|
||||||
|
/* BDR settings */
|
||||||
|
else if (strcmp(name, "bdr_local_monitoring_only") == 0)
|
||||||
|
options->bdr_local_monitoring_only = parse_bool(value, name, error_list);
|
||||||
|
else if (strcmp(name, "bdr_recovery_timeout") == 0)
|
||||||
|
options->bdr_recovery_timeout = repmgr_atoi(value, name, error_list, 0);
|
||||||
|
|
||||||
|
/* service settings */
|
||||||
|
else if (strcmp(name, "pg_ctl_options") == 0)
|
||||||
|
strncpy(options->pg_ctl_options, value, sizeof(options->pg_ctl_options));
|
||||||
|
else if (strcmp(name, "service_start_command") == 0)
|
||||||
|
strncpy(options->service_start_command, value, sizeof(options->service_start_command));
|
||||||
|
else if (strcmp(name, "service_stop_command") == 0)
|
||||||
|
strncpy(options->service_stop_command, value, sizeof(options->service_stop_command));
|
||||||
|
else if (strcmp(name, "service_restart_command") == 0)
|
||||||
|
strncpy(options->service_restart_command, value, sizeof(options->service_restart_command));
|
||||||
|
else if (strcmp(name, "service_reload_command") == 0)
|
||||||
|
strncpy(options->service_reload_command, value, sizeof(options->service_reload_command));
|
||||||
|
else if (strcmp(name, "service_promote_command") == 0)
|
||||||
|
strncpy(options->service_promote_command, value, sizeof(options->service_promote_command));
|
||||||
|
|
||||||
|
/* repmgrd service settings */
|
||||||
|
else if (strcmp(name, "repmgrd_service_start_command") == 0)
|
||||||
|
strncpy(options->repmgrd_service_start_command, value, sizeof(options->repmgrd_service_start_command));
|
||||||
|
else if (strcmp(name, "repmgrd_service_stop_command") == 0)
|
||||||
|
strncpy(options->repmgrd_service_stop_command, value, sizeof(options->repmgrd_service_stop_command));
|
||||||
|
|
||||||
|
|
||||||
|
/* event notification settings */
|
||||||
|
else if (strcmp(name, "event_notification_command") == 0)
|
||||||
|
strncpy(options->event_notification_command, value, sizeof(options->event_notification_command));
|
||||||
|
else if (strcmp(name, "event_notifications") == 0)
|
||||||
|
{
|
||||||
|
/* store unparsed value for comparison when reloading config */
|
||||||
|
strncpy(options->event_notifications_orig, value, sizeof(options->event_notifications_orig));
|
||||||
|
parse_event_notifications_list(options, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* barman settings */
|
||||||
|
else if (strcmp(name, "barman_host") == 0)
|
||||||
|
strncpy(options->barman_host, value, sizeof(options->barman_host));
|
||||||
|
else if (strcmp(name, "barman_server") == 0)
|
||||||
|
strncpy(options->barman_server, value, sizeof(options->barman_server));
|
||||||
|
else if (strcmp(name, "barman_config") == 0)
|
||||||
|
strncpy(options->barman_config, value, sizeof(options->barman_config));
|
||||||
|
|
||||||
|
/* rsync/ssh settings */
|
||||||
|
else if (strcmp(name, "rsync_options") == 0)
|
||||||
|
strncpy(options->rsync_options, value, sizeof(options->rsync_options));
|
||||||
|
else if (strcmp(name, "ssh_options") == 0)
|
||||||
|
strncpy(options->ssh_options, value, sizeof(options->ssh_options));
|
||||||
|
|
||||||
|
/* undocumented settings for testing */
|
||||||
|
else if (strcmp(name, "promote_delay") == 0)
|
||||||
|
options->promote_delay = repmgr_atoi(value, name, error_list, 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Following parameters have been deprecated or renamed from 3.x -
|
||||||
|
* issue a warning
|
||||||
|
*/
|
||||||
|
else if (strcmp(name, "cluster") == 0)
|
||||||
|
{
|
||||||
|
item_list_append(warning_list,
|
||||||
|
_("parameter \"cluster\" is deprecated and will be ignored"));
|
||||||
|
known_parameter = false;
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "node") == 0)
|
||||||
|
{
|
||||||
|
item_list_append(warning_list,
|
||||||
|
_("parameter \"node\" has been renamed to \"node_id\""));
|
||||||
|
known_parameter = false;
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "upstream_node") == 0)
|
||||||
|
{
|
||||||
|
item_list_append(warning_list,
|
||||||
|
_("parameter \"upstream_node\" has been removed; use \"--upstream-node-id\" when cloning a standby"));
|
||||||
|
known_parameter = false;
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "loglevel") == 0)
|
||||||
|
{
|
||||||
|
item_list_append(warning_list,
|
||||||
|
_("parameter \"loglevel\" has been renamed to \"log_level\""));
|
||||||
|
known_parameter = false;
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "logfacility") == 0)
|
||||||
|
{
|
||||||
|
item_list_append(warning_list,
|
||||||
|
_("parameter \"logfacility\" has been renamed to \"log_facility\""));
|
||||||
|
known_parameter = false;
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "logfile") == 0)
|
||||||
|
{
|
||||||
|
item_list_append(warning_list,
|
||||||
|
_("parameter \"logfile\" has been renamed to \"log_file\""));
|
||||||
|
known_parameter = false;
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "master_reponse_timeout") == 0)
|
||||||
|
{
|
||||||
|
item_list_append(warning_list,
|
||||||
|
_("parameter \"master_reponse_timeout\" has been removed; use \"async_query_timeout\" instead"));
|
||||||
|
known_parameter = false;
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "retry_promote_interval_secs") == 0)
|
||||||
|
{
|
||||||
|
item_list_append(warning_list,
|
||||||
|
_("parameter \"retry_promote_interval_secs\" has been removed; use \"primary_notification_timeout\" instead"));
|
||||||
|
known_parameter = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
known_parameter = false;
|
||||||
|
log_warning(_("%s/%s: unknown name/value pair provided; ignoring"), name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Raise an error if a known parameter is provided with an empty
|
||||||
|
* value. Currently there's no reason why empty parameters are needed;
|
||||||
|
* if we want to accept those, we'd need to add stricter default
|
||||||
|
* checking, as currently e.g. an empty `node_id` value will be converted
|
||||||
|
* to '0'.
|
||||||
|
*/
|
||||||
|
if (known_parameter == true && !strlen(value))
|
||||||
|
{
|
||||||
|
char error_message_buf[MAXLEN] = "";
|
||||||
|
|
||||||
|
maxlen_snprintf(error_message_buf,
|
||||||
|
_("\"%s\": no value provided"),
|
||||||
|
name);
|
||||||
|
|
||||||
|
item_list_append(error_list, error_message_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
/* check required parameters */
|
/* check required parameters */
|
||||||
if (options->node_id == UNKNOWN_NODE_ID)
|
if (node_id_found == false)
|
||||||
{
|
{
|
||||||
item_list_append(error_list, _("\"node_id\": required parameter was not found"));
|
item_list_append(error_list, _("\"node_id\": required parameter was not found"));
|
||||||
}
|
}
|
||||||
@@ -566,349 +919,6 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
parse_configuration_item(t_configuration_options *options, ItemList *error_list, ItemList *warning_list, const char *name, const char *value)
|
|
||||||
{
|
|
||||||
bool known_parameter = true;
|
|
||||||
|
|
||||||
if (strcmp(name, "node_id") == 0)
|
|
||||||
{
|
|
||||||
options->node_id = repmgr_atoi(value, name, error_list, MIN_NODE_ID);
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "node_name") == 0)
|
|
||||||
{
|
|
||||||
if (strlen(value) < sizeof(options->node_name))
|
|
||||||
strncpy(options->node_name, value, sizeof(options->node_name));
|
|
||||||
else
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
_("value for \"node_name\" must contain fewer than %lu characters"),
|
|
||||||
sizeof(options->node_name));
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "conninfo") == 0)
|
|
||||||
{
|
|
||||||
strncpy(options->conninfo, value, MAXLEN);
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "data_directory") == 0)
|
|
||||||
{
|
|
||||||
strncpy(options->data_directory, value, MAXPGPATH);
|
|
||||||
canonicalize_path(options->data_directory);
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "config_directory") == 0)
|
|
||||||
{
|
|
||||||
strncpy(options->config_directory, value, MAXPGPATH);
|
|
||||||
canonicalize_path(options->config_directory);
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "replication_user") == 0)
|
|
||||||
{
|
|
||||||
if (strlen(value) < sizeof(options->replication_user))
|
|
||||||
strncpy(options->replication_user, value, sizeof(options->replication_user));
|
|
||||||
else
|
|
||||||
item_list_append_format(error_list,
|
|
||||||
_("value for \"replication_user\" must contain fewer than %lu characters"),
|
|
||||||
sizeof(options->replication_user));
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "pg_bindir") == 0)
|
|
||||||
strncpy(options->pg_bindir, value, MAXPGPATH);
|
|
||||||
else if (strcmp(name, "repmgr_bindir") == 0)
|
|
||||||
strncpy(options->repmgr_bindir, value, MAXPGPATH);
|
|
||||||
|
|
||||||
else if (strcmp(name, "replication_type") == 0)
|
|
||||||
{
|
|
||||||
if (strcmp(value, "physical") == 0)
|
|
||||||
options->replication_type = REPLICATION_TYPE_PHYSICAL;
|
|
||||||
else if (strcmp(value, "bdr") == 0)
|
|
||||||
options->replication_type = REPLICATION_TYPE_BDR;
|
|
||||||
else
|
|
||||||
item_list_append(error_list, _("value for \"replication_type\" must be \"physical\" or \"bdr\""));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* log settings */
|
|
||||||
else if (strcmp(name, "log_file") == 0)
|
|
||||||
strncpy(options->log_file, value, MAXLEN);
|
|
||||||
else if (strcmp(name, "log_level") == 0)
|
|
||||||
strncpy(options->log_level, value, MAXLEN);
|
|
||||||
else if (strcmp(name, "log_facility") == 0)
|
|
||||||
strncpy(options->log_facility, value, MAXLEN);
|
|
||||||
else if (strcmp(name, "log_status_interval") == 0)
|
|
||||||
options->log_status_interval = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
|
|
||||||
/* standby clone settings */
|
|
||||||
else if (strcmp(name, "use_replication_slots") == 0)
|
|
||||||
options->use_replication_slots = parse_bool(value, name, error_list);
|
|
||||||
else if (strcmp(name, "pg_basebackup_options") == 0)
|
|
||||||
strncpy(options->pg_basebackup_options, value, MAXLEN);
|
|
||||||
else if (strcmp(name, "tablespace_mapping") == 0)
|
|
||||||
tablespace_list_append(options, value);
|
|
||||||
else if (strcmp(name, "restore_command") == 0)
|
|
||||||
strncpy(options->restore_command, value, MAXLEN);
|
|
||||||
else if (strcmp(name, "recovery_min_apply_delay") == 0)
|
|
||||||
{
|
|
||||||
parse_time_unit_parameter(name, value, options->recovery_min_apply_delay, error_list);
|
|
||||||
options->recovery_min_apply_delay_provided = true;
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "archive_cleanup_command") == 0)
|
|
||||||
strncpy(options->archive_cleanup_command, value, MAXLEN);
|
|
||||||
else if (strcmp(name, "use_primary_conninfo_password") == 0)
|
|
||||||
options->use_primary_conninfo_password = parse_bool(value, name, error_list);
|
|
||||||
else if (strcmp(name, "passfile") == 0)
|
|
||||||
strncpy(options->passfile, value, sizeof(options->passfile));
|
|
||||||
|
|
||||||
/* standby promote settings */
|
|
||||||
else if (strcmp(name, "promote_check_timeout") == 0)
|
|
||||||
options->promote_check_timeout = repmgr_atoi(value, name, error_list, 1);
|
|
||||||
|
|
||||||
else if (strcmp(name, "promote_check_interval") == 0)
|
|
||||||
options->promote_check_interval = repmgr_atoi(value, name, error_list, 1);
|
|
||||||
|
|
||||||
/* standby follow settings */
|
|
||||||
else if (strcmp(name, "primary_follow_timeout") == 0)
|
|
||||||
options->primary_follow_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
else if (strcmp(name, "standby_follow_timeout") == 0)
|
|
||||||
options->standby_follow_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
|
|
||||||
/* standby switchover settings */
|
|
||||||
else if (strcmp(name, "shutdown_check_timeout") == 0)
|
|
||||||
options->shutdown_check_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
else if (strcmp(name, "standby_reconnect_timeout") == 0)
|
|
||||||
options->standby_reconnect_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
else if (strcmp(name, "wal_receive_check_timeout") == 0)
|
|
||||||
options->wal_receive_check_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
|
|
||||||
/* node rejoin settings */
|
|
||||||
else if (strcmp(name, "node_rejoin_timeout") == 0)
|
|
||||||
options->node_rejoin_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
|
|
||||||
/* node check settings */
|
|
||||||
else if (strcmp(name, "archive_ready_warning") == 0)
|
|
||||||
options->archive_ready_warning = repmgr_atoi(value, name, error_list, 1);
|
|
||||||
else if (strcmp(name, "archive_ready_critical") == 0)
|
|
||||||
options->archive_ready_critical = repmgr_atoi(value, name, error_list, 1);
|
|
||||||
else if (strcmp(name, "replication_lag_warning") == 0)
|
|
||||||
options->replication_lag_warning = repmgr_atoi(value, name, error_list, 1);
|
|
||||||
else if (strcmp(name, "replication_lag_critical") == 0)
|
|
||||||
options->replication_lag_critical = repmgr_atoi(value, name, error_list, 1);
|
|
||||||
|
|
||||||
/* repmgrd settings */
|
|
||||||
else if (strcmp(name, "failover") == 0)
|
|
||||||
{
|
|
||||||
if (strcmp(value, "manual") == 0)
|
|
||||||
{
|
|
||||||
options->failover = FAILOVER_MANUAL;
|
|
||||||
}
|
|
||||||
else if (strcmp(value, "automatic") == 0)
|
|
||||||
{
|
|
||||||
options->failover = FAILOVER_AUTOMATIC;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item_list_append(error_list,
|
|
||||||
_("value for \"failover\" must be \"automatic\" or \"manual\"\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "priority") == 0)
|
|
||||||
options->priority = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
else if (strcmp(name, "location") == 0)
|
|
||||||
strncpy(options->location, value, sizeof(options->location));
|
|
||||||
else if (strcmp(name, "promote_command") == 0)
|
|
||||||
strncpy(options->promote_command, value, sizeof(options->promote_command));
|
|
||||||
else if (strcmp(name, "follow_command") == 0)
|
|
||||||
strncpy(options->follow_command, value, sizeof(options->follow_command));
|
|
||||||
else if (strcmp(name, "reconnect_attempts") == 0)
|
|
||||||
options->reconnect_attempts = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
else if (strcmp(name, "reconnect_interval") == 0)
|
|
||||||
options->reconnect_interval = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
else if (strcmp(name, "monitor_interval_secs") == 0)
|
|
||||||
options->monitor_interval_secs = repmgr_atoi(value, name, error_list, 1);
|
|
||||||
else if (strcmp(name, "monitoring_history") == 0)
|
|
||||||
options->monitoring_history = parse_bool(value, name, error_list);
|
|
||||||
else if (strcmp(name, "degraded_monitoring_timeout") == 0)
|
|
||||||
options->degraded_monitoring_timeout = repmgr_atoi(value, name, error_list, -1);
|
|
||||||
else if (strcmp(name, "async_query_timeout") == 0)
|
|
||||||
options->async_query_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
else if (strcmp(name, "primary_notification_timeout") == 0)
|
|
||||||
options->primary_notification_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
else if (strcmp(name, "repmgrd_standby_startup_timeout") == 0)
|
|
||||||
options->repmgrd_standby_startup_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
else if (strcmp(name, "repmgrd_pid_file") == 0)
|
|
||||||
strncpy(options->repmgrd_pid_file, value, MAXPGPATH);
|
|
||||||
else if (strcmp(name, "standby_disconnect_on_failover") == 0)
|
|
||||||
options->standby_disconnect_on_failover = parse_bool(value, name, error_list);
|
|
||||||
else if (strcmp(name, "sibling_nodes_disconnect_timeout") == 0)
|
|
||||||
options->sibling_nodes_disconnect_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
else if (strcmp(name, "connection_check_type") == 0)
|
|
||||||
{
|
|
||||||
if (strcasecmp(value, "ping") == 0)
|
|
||||||
{
|
|
||||||
options->connection_check_type = CHECK_PING;
|
|
||||||
}
|
|
||||||
else if (strcasecmp(value, "connection") == 0)
|
|
||||||
{
|
|
||||||
options->connection_check_type = CHECK_CONNECTION;
|
|
||||||
}
|
|
||||||
else if (strcasecmp(value, "query") == 0)
|
|
||||||
{
|
|
||||||
options->connection_check_type = CHECK_QUERY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item_list_append(error_list,
|
|
||||||
_("value for \"connection_check_type\" must be \"ping\", \"connection\" or \"query\"\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "primary_visibility_consensus") == 0)
|
|
||||||
options->primary_visibility_consensus = parse_bool(value, name, error_list);
|
|
||||||
else if (strcmp(name, "failover_validation_command") == 0)
|
|
||||||
strncpy(options->failover_validation_command, value, sizeof(options->failover_validation_command));
|
|
||||||
else if (strcmp(name, "election_rerun_interval") == 0)
|
|
||||||
options->election_rerun_interval = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
else if (strcmp(name, "child_nodes_check_interval") == 0)
|
|
||||||
options->child_nodes_check_interval = repmgr_atoi(value, name, error_list, 1);
|
|
||||||
else if (strcmp(name, "child_nodes_disconnect_command") == 0)
|
|
||||||
snprintf(options->child_nodes_disconnect_command, sizeof(options->child_nodes_disconnect_command), "%s", value);
|
|
||||||
else if (strcmp(name, "child_nodes_disconnect_min_count") == 0)
|
|
||||||
options->child_nodes_disconnect_min_count = repmgr_atoi(value, name, error_list, -1);
|
|
||||||
else if (strcmp(name, "child_nodes_connected_min_count") == 0)
|
|
||||||
options->child_nodes_connected_min_count = repmgr_atoi(value, name, error_list, -1);
|
|
||||||
else if (strcmp(name, "child_nodes_connected_include_witness") == 0)
|
|
||||||
options->child_nodes_connected_include_witness = parse_bool(value, name, error_list);
|
|
||||||
else if (strcmp(name, "child_nodes_disconnect_timeout") == 0)
|
|
||||||
options->child_nodes_disconnect_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
|
|
||||||
/* witness settings */
|
|
||||||
else if (strcmp(name, "witness_sync_interval") == 0)
|
|
||||||
options->witness_sync_interval = repmgr_atoi(value, name, error_list, 1);
|
|
||||||
|
|
||||||
/* BDR settings */
|
|
||||||
else if (strcmp(name, "bdr_local_monitoring_only") == 0)
|
|
||||||
options->bdr_local_monitoring_only = parse_bool(value, name, error_list);
|
|
||||||
else if (strcmp(name, "bdr_recovery_timeout") == 0)
|
|
||||||
options->bdr_recovery_timeout = repmgr_atoi(value, name, error_list, 0);
|
|
||||||
|
|
||||||
/* service settings */
|
|
||||||
else if (strcmp(name, "pg_ctl_options") == 0)
|
|
||||||
strncpy(options->pg_ctl_options, value, sizeof(options->pg_ctl_options));
|
|
||||||
else if (strcmp(name, "service_start_command") == 0)
|
|
||||||
strncpy(options->service_start_command, value, sizeof(options->service_start_command));
|
|
||||||
else if (strcmp(name, "service_stop_command") == 0)
|
|
||||||
strncpy(options->service_stop_command, value, sizeof(options->service_stop_command));
|
|
||||||
else if (strcmp(name, "service_restart_command") == 0)
|
|
||||||
strncpy(options->service_restart_command, value, sizeof(options->service_restart_command));
|
|
||||||
else if (strcmp(name, "service_reload_command") == 0)
|
|
||||||
strncpy(options->service_reload_command, value, sizeof(options->service_reload_command));
|
|
||||||
else if (strcmp(name, "service_promote_command") == 0)
|
|
||||||
strncpy(options->service_promote_command, value, sizeof(options->service_promote_command));
|
|
||||||
|
|
||||||
/* repmgrd service settings */
|
|
||||||
else if (strcmp(name, "repmgrd_service_start_command") == 0)
|
|
||||||
strncpy(options->repmgrd_service_start_command, value, sizeof(options->repmgrd_service_start_command));
|
|
||||||
else if (strcmp(name, "repmgrd_service_stop_command") == 0)
|
|
||||||
strncpy(options->repmgrd_service_stop_command, value, sizeof(options->repmgrd_service_stop_command));
|
|
||||||
|
|
||||||
|
|
||||||
/* event notification settings */
|
|
||||||
else if (strcmp(name, "event_notification_command") == 0)
|
|
||||||
strncpy(options->event_notification_command, value, sizeof(options->event_notification_command));
|
|
||||||
else if (strcmp(name, "event_notifications") == 0)
|
|
||||||
{
|
|
||||||
/* store unparsed value for comparison when reloading config */
|
|
||||||
strncpy(options->event_notifications_orig, value, sizeof(options->event_notifications_orig));
|
|
||||||
parse_event_notifications_list(options, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* barman settings */
|
|
||||||
else if (strcmp(name, "barman_host") == 0)
|
|
||||||
strncpy(options->barman_host, value, sizeof(options->barman_host));
|
|
||||||
else if (strcmp(name, "barman_server") == 0)
|
|
||||||
strncpy(options->barman_server, value, sizeof(options->barman_server));
|
|
||||||
else if (strcmp(name, "barman_config") == 0)
|
|
||||||
strncpy(options->barman_config, value, sizeof(options->barman_config));
|
|
||||||
|
|
||||||
/* rsync/ssh settings */
|
|
||||||
else if (strcmp(name, "rsync_options") == 0)
|
|
||||||
strncpy(options->rsync_options, value, sizeof(options->rsync_options));
|
|
||||||
else if (strcmp(name, "ssh_options") == 0)
|
|
||||||
strncpy(options->ssh_options, value, sizeof(options->ssh_options));
|
|
||||||
|
|
||||||
/* undocumented settings for testing */
|
|
||||||
else if (strcmp(name, "promote_delay") == 0)
|
|
||||||
options->promote_delay = repmgr_atoi(value, name, error_list, 1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Following parameters have been deprecated or renamed from 3.x -
|
|
||||||
* issue a warning
|
|
||||||
*/
|
|
||||||
else if (strcmp(name, "cluster") == 0)
|
|
||||||
{
|
|
||||||
item_list_append(warning_list,
|
|
||||||
_("parameter \"cluster\" is deprecated and will be ignored"));
|
|
||||||
known_parameter = false;
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "node") == 0)
|
|
||||||
{
|
|
||||||
item_list_append(warning_list,
|
|
||||||
_("parameter \"node\" has been renamed to \"node_id\""));
|
|
||||||
known_parameter = false;
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "upstream_node") == 0)
|
|
||||||
{
|
|
||||||
item_list_append(warning_list,
|
|
||||||
_("parameter \"upstream_node\" has been removed; use \"--upstream-node-id\" when cloning a standby"));
|
|
||||||
known_parameter = false;
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "loglevel") == 0)
|
|
||||||
{
|
|
||||||
item_list_append(warning_list,
|
|
||||||
_("parameter \"loglevel\" has been renamed to \"log_level\""));
|
|
||||||
known_parameter = false;
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "logfacility") == 0)
|
|
||||||
{
|
|
||||||
item_list_append(warning_list,
|
|
||||||
_("parameter \"logfacility\" has been renamed to \"log_facility\""));
|
|
||||||
known_parameter = false;
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "logfile") == 0)
|
|
||||||
{
|
|
||||||
item_list_append(warning_list,
|
|
||||||
_("parameter \"logfile\" has been renamed to \"log_file\""));
|
|
||||||
known_parameter = false;
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "master_reponse_timeout") == 0)
|
|
||||||
{
|
|
||||||
item_list_append(warning_list,
|
|
||||||
_("parameter \"master_reponse_timeout\" has been removed; use \"async_query_timeout\" instead"));
|
|
||||||
known_parameter = false;
|
|
||||||
}
|
|
||||||
else if (strcmp(name, "retry_promote_interval_secs") == 0)
|
|
||||||
{
|
|
||||||
item_list_append(warning_list,
|
|
||||||
_("parameter \"retry_promote_interval_secs\" has been removed; use \"primary_notification_timeout\" instead"));
|
|
||||||
known_parameter = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
known_parameter = false;
|
|
||||||
log_warning(_("%s/%s: unknown name/value pair provided; ignoring"), name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Raise an error if a known parameter is provided with an empty
|
|
||||||
* value. Currently there's no reason why empty parameters are needed;
|
|
||||||
* if we want to accept those, we'd need to add stricter default
|
|
||||||
* checking, as currently e.g. an empty `node_id` value will be converted
|
|
||||||
* to '0'.
|
|
||||||
*/
|
|
||||||
if (known_parameter == true && !strlen(value))
|
|
||||||
{
|
|
||||||
char error_message_buf[MAXLEN] = "";
|
|
||||||
|
|
||||||
maxlen_snprintf(error_message_buf,
|
|
||||||
_("\"%s\": no value provided"),
|
|
||||||
name);
|
|
||||||
|
|
||||||
item_list_append(error_list, error_message_buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -1180,8 +1190,7 @@ reload_config(t_configuration_options *orig_options, t_server_type server_type)
|
|||||||
_parse_config(&new_options, &config_errors, &config_warnings);
|
_parse_config(&new_options, &config_errors, &config_warnings);
|
||||||
|
|
||||||
|
|
||||||
if (new_options.failover == FAILOVER_AUTOMATIC
|
if (server_type == PRIMARY || server_type == STANDBY)
|
||||||
&& (server_type == PRIMARY || server_type == STANDBY))
|
|
||||||
{
|
{
|
||||||
if (new_options.promote_command[0] == '\0')
|
if (new_options.promote_command[0] == '\0')
|
||||||
{
|
{
|
||||||
@@ -1807,7 +1816,6 @@ parse_bool(const char *s, const char *config_item, ItemList *error_list)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Split argument into old_dir and new_dir and append to tablespace mapping
|
* Split argument into old_dir and new_dir and append to tablespace mapping
|
||||||
* list.
|
* list.
|
||||||
@@ -1875,120 +1883,6 @@ tablespace_list_append(t_configuration_options *options, const char *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
modify_auto_conf(const char *data_dir, KeyValueList *items)
|
|
||||||
{
|
|
||||||
PQExpBufferData auto_conf;
|
|
||||||
PQExpBufferData auto_conf_tmp;
|
|
||||||
PQExpBufferData auto_conf_contents;
|
|
||||||
|
|
||||||
FILE *fp;
|
|
||||||
mode_t um;
|
|
||||||
|
|
||||||
KeyValueList config = {NULL, NULL};
|
|
||||||
KeyValueListCell *cell = NULL;
|
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
|
|
||||||
initPQExpBuffer(&auto_conf);
|
|
||||||
appendPQExpBuffer(&auto_conf, "%s/%s",
|
|
||||||
data_dir, PG_AUTOCONF_FILENAME);
|
|
||||||
|
|
||||||
fp = fopen(auto_conf.data, "r");
|
|
||||||
|
|
||||||
if (fp == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "unable to open \"%s\": %s\n",
|
|
||||||
auto_conf.data,
|
|
||||||
strerror(errno));
|
|
||||||
termPQExpBuffer(&auto_conf);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX check return value
|
|
||||||
(void) ProcessPostgresConfigFile(fp, auto_conf.data, &config, NULL, NULL);
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Append requested items to items extracted from the existing file.
|
|
||||||
*/
|
|
||||||
for (cell = items->head; cell; cell = cell->next)
|
|
||||||
{
|
|
||||||
key_value_list_replace_or_set(&config,
|
|
||||||
cell->key,
|
|
||||||
cell->value);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
initPQExpBuffer(&auto_conf_tmp);
|
|
||||||
appendPQExpBuffer(&auto_conf_tmp, "%s.tmp",
|
|
||||||
auto_conf.data);
|
|
||||||
|
|
||||||
initPQExpBuffer(&auto_conf_contents);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Keep this in sync with src/backend/utils/misc/guc.c:write_auto_conf_file()
|
|
||||||
*/
|
|
||||||
appendPQExpBufferStr(&auto_conf_contents,
|
|
||||||
"# Do not edit this file manually!\n"
|
|
||||||
"# It will be overwritten by the ALTER SYSTEM command.\n");
|
|
||||||
|
|
||||||
for (cell = config.head; cell; cell = cell->next)
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&auto_conf_contents,
|
|
||||||
"%s = '%s'\n",
|
|
||||||
cell->key, cell->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set umask to 0600 */
|
|
||||||
um = umask((~(S_IRUSR | S_IWUSR)) & (S_IRWXG | S_IRWXO));
|
|
||||||
fp = fopen(auto_conf_tmp.data, "w");
|
|
||||||
umask(um);
|
|
||||||
|
|
||||||
if (fp == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "unable to open \"%s\": %s\n",
|
|
||||||
auto_conf_tmp.data,
|
|
||||||
strerror(errno));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (fwrite(auto_conf_contents.data, strlen(auto_conf_contents.data), 1, fp) != 1)
|
|
||||||
{
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note: durable_rename() is not exposed to frontend code before Pg 10.
|
|
||||||
* We only really need to be modifying postgresql.auto.conf from Pg 12,
|
|
||||||
* but provide backwards compatibitilty for Pg 9.6 and earlier for the
|
|
||||||
* (unlikely) event that a repmgr built against one of those versions
|
|
||||||
* is being used against Pg 12 and later.
|
|
||||||
*/
|
|
||||||
// XXX check return values
|
|
||||||
#if (PG_ACTUAL_VERSION_NUM >= 100000)
|
|
||||||
(void) durable_rename(auto_conf_tmp.data, auto_conf.data, LOG);
|
|
||||||
#else
|
|
||||||
if (rename(auto_conf_tmp.data, auto_conf.data) < 0)
|
|
||||||
{
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
termPQExpBuffer(&auto_conf);
|
|
||||||
termPQExpBuffer(&auto_conf_tmp);
|
|
||||||
termPQExpBuffer(&auto_conf_contents);
|
|
||||||
|
|
||||||
key_value_list_free(&config);
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parse_event_notifications_list()
|
* parse_event_notifications_list()
|
||||||
@@ -2165,6 +2059,9 @@ free_parsed_argv(char ***argv_array)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_options *backup_options, int server_version_num, ItemList *error_list)
|
parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_options *backup_options, int server_version_num, ItemList *error_list)
|
||||||
{
|
{
|
||||||
|
|||||||
14
configfile.h
14
configfile.h
@@ -28,12 +28,6 @@
|
|||||||
/* magic number for use in t_recovery_conf */
|
/* magic number for use in t_recovery_conf */
|
||||||
#define TARGET_TIMELINE_LATEST 0
|
#define TARGET_TIMELINE_LATEST 0
|
||||||
|
|
||||||
/*
|
|
||||||
* This is defined src/include/utils.h, however it's not practical
|
|
||||||
* to include that from a frontend application.
|
|
||||||
*/
|
|
||||||
#define PG_AUTOCONF_FILENAME "postgresql.auto.conf"
|
|
||||||
|
|
||||||
extern bool config_file_found;
|
extern bool config_file_found;
|
||||||
extern char config_file_path[MAXPGPATH];
|
extern char config_file_path[MAXPGPATH];
|
||||||
|
|
||||||
@@ -323,8 +317,6 @@ const char *progname(void);
|
|||||||
void load_config(const char *config_file, bool verbose, bool terse, t_configuration_options *options, char *argv0);
|
void load_config(const char *config_file, bool verbose, bool terse, t_configuration_options *options, char *argv0);
|
||||||
bool reload_config(t_configuration_options *orig_options, t_server_type server_type);
|
bool reload_config(t_configuration_options *orig_options, t_server_type server_type);
|
||||||
|
|
||||||
void parse_configuration_item(t_configuration_options *options, ItemList *error_list, ItemList *warning_list, const char *name, const char *value);
|
|
||||||
|
|
||||||
bool parse_recovery_conf(const char *data_dir, t_recovery_conf *conf);
|
bool parse_recovery_conf(const char *data_dir, t_recovery_conf *conf);
|
||||||
|
|
||||||
bool parse_bool(const char *s,
|
bool parse_bool(const char *s,
|
||||||
@@ -350,10 +342,4 @@ void exit_with_cli_errors(ItemList *error_list, const char *repmgr_command);
|
|||||||
void print_item_list(ItemList *item_list);
|
void print_item_list(ItemList *item_list);
|
||||||
const char *print_connection_check_type(ConnectionCheckType type);
|
const char *print_connection_check_type(ConnectionCheckType type);
|
||||||
|
|
||||||
extern bool modify_auto_conf(const char *data_dir, KeyValueList *items);
|
|
||||||
|
|
||||||
extern bool ProcessRepmgrConfigFile(FILE *fp, const char *config_file, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
|
|
||||||
|
|
||||||
extern bool ProcessPostgresConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, ItemList *error_list, ItemList *warning_list);
|
|
||||||
|
|
||||||
#endif /* _REPMGR_CONFIGFILE_H_ */
|
#endif /* _REPMGR_CONFIGFILE_H_ */
|
||||||
|
|||||||
148
configure
vendored
148
configure
vendored
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# Guess values for system-dependent variables and create Makefiles.
|
||||||
# Generated by GNU Autoconf 2.69 for repmgr 5.0.0.
|
# Generated by GNU Autoconf 2.69 for repmgr 4.4.
|
||||||
#
|
#
|
||||||
# Report bugs to <repmgr@googlegroups.com>.
|
# Report bugs to <repmgr@googlegroups.com>.
|
||||||
#
|
#
|
||||||
@@ -582,16 +582,13 @@ MAKEFLAGS=
|
|||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='repmgr'
|
PACKAGE_NAME='repmgr'
|
||||||
PACKAGE_TARNAME='repmgr'
|
PACKAGE_TARNAME='repmgr'
|
||||||
PACKAGE_VERSION='5.0.0'
|
PACKAGE_VERSION='4.4'
|
||||||
PACKAGE_STRING='repmgr 5.0.0'
|
PACKAGE_STRING='repmgr 4.4'
|
||||||
PACKAGE_BUGREPORT='repmgr@googlegroups.com'
|
PACKAGE_BUGREPORT='repmgr@googlegroups.com'
|
||||||
PACKAGE_URL='https://repmgr.org/'
|
PACKAGE_URL='https://repmgr.org/'
|
||||||
|
|
||||||
ac_subst_vars='LTLIBOBJS
|
ac_subst_vars='LTLIBOBJS
|
||||||
LIBOBJS
|
LIBOBJS
|
||||||
HAVE_SED
|
|
||||||
HAVE_GSED
|
|
||||||
HAVE_GNUSED
|
|
||||||
vpath_build
|
vpath_build
|
||||||
SED
|
SED
|
||||||
PG_CONFIG
|
PG_CONFIG
|
||||||
@@ -1181,7 +1178,7 @@ if test "$ac_init_help" = "long"; then
|
|||||||
# Omit some internal or obsolete options to make the list less imposing.
|
# Omit some internal or obsolete options to make the list less imposing.
|
||||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
cat <<_ACEOF
|
||||||
\`configure' configures repmgr 5.0.0 to adapt to many kinds of systems.
|
\`configure' configures repmgr 4.4 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@@ -1242,7 +1239,7 @@ fi
|
|||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of repmgr 5.0.0:";;
|
short | recursive ) echo "Configuration of repmgr 4.4:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@@ -1316,7 +1313,7 @@ fi
|
|||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
repmgr configure 5.0.0
|
repmgr configure 4.4
|
||||||
generated by GNU Autoconf 2.69
|
generated by GNU Autoconf 2.69
|
||||||
|
|
||||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||||
@@ -1335,7 +1332,7 @@ cat >config.log <<_ACEOF
|
|||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
It was created by repmgr $as_me 5.0.0, which was
|
It was created by repmgr $as_me 4.4, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
$ $0 $@
|
$ $0 $@
|
||||||
@@ -1850,133 +1847,6 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Extract the first word of "gnused", so it can be a program name with args.
|
|
||||||
set dummy gnused; ac_word=$2
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
|
||||||
$as_echo_n "checking for $ac_word... " >&6; }
|
|
||||||
if ${ac_cv_prog_HAVE_GNUSED+:} false; then :
|
|
||||||
$as_echo_n "(cached) " >&6
|
|
||||||
else
|
|
||||||
if test -n "$HAVE_GNUSED"; then
|
|
||||||
ac_cv_prog_HAVE_GNUSED="$HAVE_GNUSED" # Let the user override the test.
|
|
||||||
else
|
|
||||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
|
||||||
for as_dir in $PATH
|
|
||||||
do
|
|
||||||
IFS=$as_save_IFS
|
|
||||||
test -z "$as_dir" && as_dir=.
|
|
||||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
|
||||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
|
||||||
ac_cv_prog_HAVE_GNUSED="yes"
|
|
||||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
|
||||||
break 2
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
IFS=$as_save_IFS
|
|
||||||
|
|
||||||
test -z "$ac_cv_prog_HAVE_GNUSED" && ac_cv_prog_HAVE_GNUSED="no"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
HAVE_GNUSED=$ac_cv_prog_HAVE_GNUSED
|
|
||||||
if test -n "$HAVE_GNUSED"; then
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_GNUSED" >&5
|
|
||||||
$as_echo "$HAVE_GNUSED" >&6; }
|
|
||||||
else
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
|
||||||
$as_echo "no" >&6; }
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# Extract the first word of "gsed", so it can be a program name with args.
|
|
||||||
set dummy gsed; ac_word=$2
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
|
||||||
$as_echo_n "checking for $ac_word... " >&6; }
|
|
||||||
if ${ac_cv_prog_HAVE_GSED+:} false; then :
|
|
||||||
$as_echo_n "(cached) " >&6
|
|
||||||
else
|
|
||||||
if test -n "$HAVE_GSED"; then
|
|
||||||
ac_cv_prog_HAVE_GSED="$HAVE_GSED" # Let the user override the test.
|
|
||||||
else
|
|
||||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
|
||||||
for as_dir in $PATH
|
|
||||||
do
|
|
||||||
IFS=$as_save_IFS
|
|
||||||
test -z "$as_dir" && as_dir=.
|
|
||||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
|
||||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
|
||||||
ac_cv_prog_HAVE_GSED="yes"
|
|
||||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
|
||||||
break 2
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
IFS=$as_save_IFS
|
|
||||||
|
|
||||||
test -z "$ac_cv_prog_HAVE_GSED" && ac_cv_prog_HAVE_GSED="no"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
HAVE_GSED=$ac_cv_prog_HAVE_GSED
|
|
||||||
if test -n "$HAVE_GSED"; then
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_GSED" >&5
|
|
||||||
$as_echo "$HAVE_GSED" >&6; }
|
|
||||||
else
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
|
||||||
$as_echo "no" >&6; }
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# Extract the first word of "sed", so it can be a program name with args.
|
|
||||||
set dummy sed; ac_word=$2
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
|
||||||
$as_echo_n "checking for $ac_word... " >&6; }
|
|
||||||
if ${ac_cv_prog_HAVE_SED+:} false; then :
|
|
||||||
$as_echo_n "(cached) " >&6
|
|
||||||
else
|
|
||||||
if test -n "$HAVE_SED"; then
|
|
||||||
ac_cv_prog_HAVE_SED="$HAVE_SED" # Let the user override the test.
|
|
||||||
else
|
|
||||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
|
||||||
for as_dir in $PATH
|
|
||||||
do
|
|
||||||
IFS=$as_save_IFS
|
|
||||||
test -z "$as_dir" && as_dir=.
|
|
||||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
|
||||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
|
||||||
ac_cv_prog_HAVE_SED="yes"
|
|
||||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
|
||||||
break 2
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
IFS=$as_save_IFS
|
|
||||||
|
|
||||||
test -z "$ac_cv_prog_HAVE_SED" && ac_cv_prog_HAVE_SED="no"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
HAVE_SED=$ac_cv_prog_HAVE_SED
|
|
||||||
if test -n "$HAVE_SED"; then
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_SED" >&5
|
|
||||||
$as_echo "$HAVE_SED" >&6; }
|
|
||||||
else
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
|
||||||
$as_echo "no" >&6; }
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if test "$HAVE_GNUSED" = yes; then
|
|
||||||
SED=gnused
|
|
||||||
else
|
|
||||||
if test "$HAVE_GSED" = yes; then
|
|
||||||
SED=gsed
|
|
||||||
else
|
|
||||||
SED=sed
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ac_config_files="$ac_config_files Makefile"
|
ac_config_files="$ac_config_files Makefile"
|
||||||
|
|
||||||
ac_config_files="$ac_config_files Makefile.global"
|
ac_config_files="$ac_config_files Makefile.global"
|
||||||
@@ -2487,7 +2357,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
|||||||
# report actual input values of CONFIG_FILES etc. instead of their
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by repmgr $as_me 5.0.0, which was
|
This file was extended by repmgr $as_me 4.4, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
@@ -2550,7 +2420,7 @@ _ACEOF
|
|||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
repmgr config.status 5.0.0
|
repmgr config.status 4.4
|
||||||
configured by $0, generated by GNU Autoconf 2.69,
|
configured by $0, generated by GNU Autoconf 2.69,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
|||||||
18
configure.in
18
configure.in
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT([repmgr], [5.0.0], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
|
AC_INIT([repmgr], [4.4], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
|
||||||
|
|
||||||
AC_COPYRIGHT([Copyright (c) 2010-2019, 2ndQuadrant Ltd.])
|
AC_COPYRIGHT([Copyright (c) 2010-2019, 2ndQuadrant Ltd.])
|
||||||
|
|
||||||
@@ -57,22 +57,6 @@ else
|
|||||||
fi
|
fi
|
||||||
AC_SUBST(vpath_build)
|
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)
|
|
||||||
|
|
||||||
if test "$HAVE_GNUSED" = yes; then
|
|
||||||
SED=gnused
|
|
||||||
else
|
|
||||||
if test "$HAVE_GSED" = yes; then
|
|
||||||
SED=gsed
|
|
||||||
else
|
|
||||||
SED=sed
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
AC_SUBST(SED)
|
|
||||||
|
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile])
|
AC_CONFIG_FILES([Makefile])
|
||||||
AC_CONFIG_FILES([Makefile.global])
|
AC_CONFIG_FILES([Makefile.global])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
@@ -73,16 +73,7 @@ while(<$fh>) {
|
|||||||
if ($param eq 'data_directory') {
|
if ($param eq 'data_directory') {
|
||||||
$data_directory_found = 1;
|
$data_directory_found = 1;
|
||||||
}
|
}
|
||||||
|
push @outp, $line;
|
||||||
# Don't quote numbers
|
|
||||||
if ($value =~ /^\d+$/) {
|
|
||||||
push @outp, sprintf(q|%s=%s|, $param, $value);
|
|
||||||
}
|
|
||||||
# Quote everything else
|
|
||||||
else {
|
|
||||||
$value =~ s/'/''/g;
|
|
||||||
push @outp, sprintf(q|%s='%s'|, $param, $value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +83,6 @@ print join("\n", @outp);
|
|||||||
print "\n";
|
print "\n";
|
||||||
|
|
||||||
if ($data_directory_found == 0) {
|
if ($data_directory_found == 0) {
|
||||||
print "data_directory=''\n";
|
print "data_directory=\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -312,7 +312,6 @@ get_controlfile(const char *DataDir)
|
|||||||
|
|
||||||
if (version_num >= 120000)
|
if (version_num >= 120000)
|
||||||
{
|
{
|
||||||
#if PG_ACTUAL_VERSION_NUM >= 120000
|
|
||||||
ControlFileData12 *ptr = (struct ControlFileData12 *)ControlFileDataPtr;
|
ControlFileData12 *ptr = (struct ControlFileData12 *)ControlFileDataPtr;
|
||||||
control_file_info->system_identifier = ptr->system_identifier;
|
control_file_info->system_identifier = ptr->system_identifier;
|
||||||
control_file_info->state = ptr->state;
|
control_file_info->state = ptr->state;
|
||||||
@@ -321,10 +320,6 @@ get_controlfile(const char *DataDir)
|
|||||||
control_file_info->timeline = ptr->checkPointCopy.ThisTimeLineID;
|
control_file_info->timeline = ptr->checkPointCopy.ThisTimeLineID;
|
||||||
control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI;
|
control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI;
|
||||||
control_file_info->minRecoveryPoint = ptr->minRecoveryPoint;
|
control_file_info->minRecoveryPoint = ptr->minRecoveryPoint;
|
||||||
#else
|
|
||||||
fprintf(stderr, "ERROR: please use a repmgr version built for PostgreSQL 12\n");
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if (version_num >= 110000)
|
else if (version_num >= 110000)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "catalog/pg_control.h"
|
#include "catalog/pg_control.h"
|
||||||
|
|
||||||
|
|
||||||
#define MAX_VERSION_STRING 24
|
#define MAX_VERSION_STRING 24
|
||||||
/*
|
/*
|
||||||
* A simplified representation of pg_control containing only those fields
|
* A simplified representation of pg_control containing only those fields
|
||||||
@@ -56,7 +55,7 @@ typedef struct CheckPoint93
|
|||||||
} CheckPoint93;
|
} CheckPoint93;
|
||||||
|
|
||||||
|
|
||||||
/* Same for 9.5, 9.6, 10, 11 */
|
/* Same for 9.5, 9.6, 10, HEAD */
|
||||||
typedef struct CheckPoint95
|
typedef struct CheckPoint95
|
||||||
{
|
{
|
||||||
XLogRecPtr redo; /* next RecPtr available when we began to
|
XLogRecPtr redo; /* next RecPtr available when we began to
|
||||||
@@ -84,50 +83,6 @@ typedef struct CheckPoint95
|
|||||||
} CheckPoint95;
|
} CheckPoint95;
|
||||||
|
|
||||||
|
|
||||||
#if PG_ACTUAL_VERSION_NUM >= 120000
|
|
||||||
/*
|
|
||||||
* Following fields removed in PostgreSQL 12;
|
|
||||||
*
|
|
||||||
* uint32 nextXidEpoch;
|
|
||||||
* TransactionId nextXid;
|
|
||||||
*
|
|
||||||
* and replaced by:
|
|
||||||
*
|
|
||||||
* FullTransactionId nextFullXid;
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct CheckPoint12
|
|
||||||
{
|
|
||||||
XLogRecPtr redo; /* next RecPtr available when we began to
|
|
||||||
* create CheckPoint (i.e. REDO start point) */
|
|
||||||
TimeLineID ThisTimeLineID; /* current TLI */
|
|
||||||
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
|
|
||||||
* timeline (equals ThisTimeLineID otherwise) */
|
|
||||||
bool fullPageWrites; /* current full_page_writes */
|
|
||||||
FullTransactionId nextFullXid; /* next free full transaction ID */
|
|
||||||
Oid nextOid; /* next free OID */
|
|
||||||
MultiXactId nextMulti; /* next free MultiXactId */
|
|
||||||
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
|
|
||||||
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
|
|
||||||
Oid oldestXidDB; /* database with minimum datfrozenxid */
|
|
||||||
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
|
|
||||||
Oid oldestMultiDB; /* database with minimum datminmxid */
|
|
||||||
pg_time_t time; /* time stamp of checkpoint */
|
|
||||||
TransactionId oldestCommitTsXid; /* oldest Xid with valid commit
|
|
||||||
* timestamp */
|
|
||||||
TransactionId newestCommitTsXid; /* newest Xid with valid commit
|
|
||||||
* timestamp */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Oldest XID still running. This is only needed to initialize hot standby
|
|
||||||
* mode from an online checkpoint, so we only bother calculating this for
|
|
||||||
* online checkpoints and only when wal_level is replica. Otherwise it's
|
|
||||||
* set to InvalidTransactionId.
|
|
||||||
*/
|
|
||||||
TransactionId oldestActiveXid;
|
|
||||||
} CheckPoint12;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct ControlFileData93
|
typedef struct ControlFileData93
|
||||||
{
|
{
|
||||||
uint64 system_identifier;
|
uint64 system_identifier;
|
||||||
@@ -378,11 +333,19 @@ typedef struct ControlFileData11
|
|||||||
} ControlFileData11;
|
} ControlFileData11;
|
||||||
|
|
||||||
|
|
||||||
#if PG_ACTUAL_VERSION_NUM >= 120000
|
|
||||||
/*
|
/*
|
||||||
* Following field added in Pg12:
|
* Following field added in Pg12:
|
||||||
*
|
*
|
||||||
* int max_wal_senders;
|
* int max_wal_senders;
|
||||||
|
*
|
||||||
|
* Following fields removed:
|
||||||
|
*
|
||||||
|
* uint32 nextXidEpoch;
|
||||||
|
* TransactionId nextXid;
|
||||||
|
*
|
||||||
|
* and replaced by:
|
||||||
|
*
|
||||||
|
* FullTransactionId nextFullXid;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct ControlFileData12
|
typedef struct ControlFileData12
|
||||||
@@ -396,7 +359,7 @@ typedef struct ControlFileData12
|
|||||||
pg_time_t time; /* time stamp of last pg_control update */
|
pg_time_t time; /* time stamp of last pg_control update */
|
||||||
XLogRecPtr checkPoint; /* last check point record ptr */
|
XLogRecPtr checkPoint; /* last check point record ptr */
|
||||||
|
|
||||||
CheckPoint12 checkPointCopy; /* copy of last check point record */
|
CheckPoint checkPointCopy; /* copy of last check point record */
|
||||||
|
|
||||||
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
|
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
|
||||||
|
|
||||||
@@ -435,7 +398,6 @@ typedef struct ControlFileData12
|
|||||||
|
|
||||||
uint32 data_checksum_version;
|
uint32 data_checksum_version;
|
||||||
} ControlFileData12;
|
} ControlFileData12;
|
||||||
#endif
|
|
||||||
|
|
||||||
extern int get_pg_version(const char *data_directory, char *version_string);
|
extern int get_pg_version(const char *data_directory, char *version_string);
|
||||||
extern DBState get_db_state(const char *data_directory);
|
extern DBState get_db_state(const char *data_directory);
|
||||||
|
|||||||
74
dbutils.c
74
dbutils.c
@@ -67,12 +67,6 @@ static bool _is_bdr_db(PGconn *conn, PQExpBufferData *output, bool quiet);
|
|||||||
static void _populate_bdr_node_record(PGresult *res, t_bdr_node_info *node_info, int row);
|
static void _populate_bdr_node_record(PGresult *res, t_bdr_node_info *node_info, int row);
|
||||||
static void _populate_bdr_node_records(PGresult *res, BdrNodeInfoList *node_list);
|
static void _populate_bdr_node_records(PGresult *res, BdrNodeInfoList *node_list);
|
||||||
|
|
||||||
/*
|
|
||||||
* This provides a standardized way of logging database errors. Note
|
|
||||||
* that the provided PGconn can be a normal or a replication connection;
|
|
||||||
* no attempt is made to write to the database, only to report the output
|
|
||||||
* of PQerrorMessage().
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
log_db_error(PGconn *conn, const char *query_text, const char *fmt,...)
|
log_db_error(PGconn *conn, const char *query_text, const char *fmt,...)
|
||||||
{
|
{
|
||||||
@@ -342,10 +336,12 @@ establish_db_connection_by_params(t_conninfo_param_list *param_list,
|
|||||||
bool
|
bool
|
||||||
is_superuser_connection(PGconn *conn, t_connection_user *userinfo)
|
is_superuser_connection(PGconn *conn, t_connection_user *userinfo)
|
||||||
{
|
{
|
||||||
|
char *current_user = NULL;
|
||||||
|
const char *superuser_status = NULL;
|
||||||
bool is_superuser = false;
|
bool is_superuser = false;
|
||||||
const char *current_user = PQuser(conn);
|
|
||||||
const char *superuser_status = PQparameterStatus(conn, "is_superuser");
|
|
||||||
|
|
||||||
|
current_user = PQuser(conn);
|
||||||
|
superuser_status = PQparameterStatus(conn, "is_superuser");
|
||||||
is_superuser = (strcmp(superuser_status, "on") == 0) ? true : false;
|
is_superuser = (strcmp(superuser_status, "on") == 0) ? true : false;
|
||||||
|
|
||||||
if (userinfo != NULL)
|
if (userinfo != NULL)
|
||||||
@@ -360,51 +356,6 @@ is_superuser_connection(PGconn *conn, t_connection_user *userinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
connection_has_pg_settings(PGconn *conn)
|
|
||||||
{
|
|
||||||
bool has_pg_settings = false;
|
|
||||||
|
|
||||||
/* superusers can always read pg_settings */
|
|
||||||
if (is_superuser_connection(conn, NULL) == true)
|
|
||||||
{
|
|
||||||
has_pg_settings = true;
|
|
||||||
}
|
|
||||||
/* from PostgreSQL 10, a non-superuser may have been granted access */
|
|
||||||
else if(PQserverVersion(conn) >= 100000)
|
|
||||||
{
|
|
||||||
PQExpBufferData query;
|
|
||||||
PGresult *res;
|
|
||||||
|
|
||||||
initPQExpBuffer(&query);
|
|
||||||
appendPQExpBufferStr(&query,
|
|
||||||
" SELECT CASE "
|
|
||||||
" WHEN pg_catalog.pg_has_role('pg_monitor','MEMBER') "
|
|
||||||
" THEN TRUE "
|
|
||||||
" WHEN pg_catalog.pg_has_role('pg_read_all_settings','MEMBER') "
|
|
||||||
" THEN TRUE "
|
|
||||||
" ELSE FALSE "
|
|
||||||
" END AS has_pg_settings");
|
|
||||||
|
|
||||||
res = PQexec(conn, query.data);
|
|
||||||
|
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
|
||||||
{
|
|
||||||
log_db_error(conn, query.data,
|
|
||||||
_("connection_has_pg_settings(): unable to query user roles"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
has_pg_settings = atobool(PQgetvalue(res, 0, 0));
|
|
||||||
}
|
|
||||||
termPQExpBuffer(&query);
|
|
||||||
PQclear(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
return has_pg_settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
close_connection(PGconn **conn)
|
close_connection(PGconn **conn)
|
||||||
{
|
{
|
||||||
@@ -1914,20 +1865,8 @@ repmgrd_set_pid(PGconn *conn, pid_t repmgrd_pid, const char *pidfile)
|
|||||||
initPQExpBuffer(&query);
|
initPQExpBuffer(&query);
|
||||||
|
|
||||||
appendPQExpBuffer(&query,
|
appendPQExpBuffer(&query,
|
||||||
"SELECT repmgr.set_repmgrd_pid(%i, ",
|
"SELECT repmgr.set_repmgrd_pid(%i, '%s')",
|
||||||
(int) repmgrd_pid);
|
(int) repmgrd_pid, pidfile);
|
||||||
|
|
||||||
if (pidfile != NULL)
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&query,
|
|
||||||
" '%s')",
|
|
||||||
pidfile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
appendPQExpBufferStr(&query,
|
|
||||||
" NULL)");
|
|
||||||
}
|
|
||||||
|
|
||||||
res = PQexec(conn, query.data);
|
res = PQexec(conn, query.data);
|
||||||
termPQExpBuffer(&query);
|
termPQExpBuffer(&query);
|
||||||
@@ -5134,7 +5073,6 @@ init_replication_info(ReplInfo *replication_info)
|
|||||||
replication_info->receiving_streamed_wal = true;
|
replication_info->receiving_streamed_wal = true;
|
||||||
replication_info->wal_replay_paused = false;
|
replication_info->wal_replay_paused = false;
|
||||||
replication_info->upstream_last_seen = -1;
|
replication_info->upstream_last_seen = -1;
|
||||||
replication_info->upstream_node_id = UNKNOWN_NODE_ID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -438,7 +438,6 @@ PGconn *get_primary_connection(PGconn *standby_conn, int *primary_id, char *p
|
|||||||
PGconn *get_primary_connection_quiet(PGconn *standby_conn, int *primary_id, char *primary_conninfo_out);
|
PGconn *get_primary_connection_quiet(PGconn *standby_conn, int *primary_id, char *primary_conninfo_out);
|
||||||
|
|
||||||
bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo);
|
bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo);
|
||||||
bool connection_has_pg_settings(PGconn *conn);
|
|
||||||
void close_connection(PGconn **conn);
|
void close_connection(PGconn **conn);
|
||||||
|
|
||||||
/* conninfo manipulation functions */
|
/* conninfo manipulation functions */
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ ALLXML := $(wildcard $(srcdir)/*.xml) $(GENERATED_XML)
|
|||||||
version.xml: $(repmgr_top_builddir)/repmgr_version.h
|
version.xml: $(repmgr_top_builddir)/repmgr_version.h
|
||||||
{ \
|
{ \
|
||||||
echo "<!ENTITY repmgrversion \"$(REPMGR_VERSION)\">"; \
|
echo "<!ENTITY repmgrversion \"$(REPMGR_VERSION)\">"; \
|
||||||
echo "<!ENTITY releasedate \"$(REPMGR_RELEASE_DATE)\">"; \
|
|
||||||
} > $@
|
} > $@
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|||||||
@@ -3,464 +3,437 @@
|
|||||||
<title>FAQ (Frequently Asked Questions)</title>
|
<title>FAQ (Frequently Asked Questions)</title>
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>FAQ (Frequently Asked Questions)</primary>
|
<primary>FAQ (Frequently Asked Questions)</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<sect1 id="faq-general" xreflabel="General">
|
<sect1 id="faq-general" xreflabel="General">
|
||||||
<title>General</title>
|
<title>General</title>
|
||||||
|
|
||||||
<sect2 id="faq-xrepmgr-version-diff" xreflabel="Version differences">
|
<sect2 id="faq-xrepmgr-version-diff" xreflabel="Version differences">
|
||||||
<title>What's the difference between the repmgr versions?</title>
|
<title>What's the difference between the repmgr versions?</title>
|
||||||
<para>
|
<para>
|
||||||
&repmgr; 4 is a complete rewrite of the previous &repmgr; code base
|
&repmgr; 4 is a complete rewrite of the existing &repmgr; code base
|
||||||
and implements &repmgr; as a PostgreSQL extension. It
|
and implements &repmgr; as a PostgreSQL extension. It
|
||||||
supports all PostgreSQL versions from 9.3 (although some &repmgr;
|
supports all PostgreSQL versions from 9.3 (although some &repmgr;
|
||||||
features are not available for PostgreSQL 9.3 and 9.4).
|
features are not available for PostgreSQL 9.3 and 9.4).
|
||||||
</para>
|
</para>
|
||||||
<note>
|
<para>
|
||||||
<para>
|
&repmgr; 3.x builds on the improved replication facilities added
|
||||||
&repmgr; 5 is fundamentally the same code base as &repmgr; 4, but provides
|
in PostgreSQL 9.3, as well as improved automated failover support
|
||||||
support for the revised replication configuration mechanism in PostgreSQL 12.
|
via &repmgrd;, and is not compatible with PostgreSQL 9.2
|
||||||
</para>
|
and earlier. We recommend upgrading to &repmgr; 4, as the &repmgr; 3.x
|
||||||
</note>
|
series is no longer maintained.
|
||||||
<para>
|
</para>
|
||||||
&repmgr; 3.x builds on the improved replication facilities added
|
<para>
|
||||||
in PostgreSQL 9.3, as well as improved automated failover support
|
&repmgr; 2.x supports PostgreSQL 9.0 ~ 9.3. While it is compatible
|
||||||
via &repmgrd;, and is not compatible with PostgreSQL 9.2
|
with PostgreSQL 9.3, we recommend using repmgr 4.x. &repmgr; 2.x is
|
||||||
and earlier. We recommend upgrading to &repmgr; 4, as the &repmgr; 3.x
|
no longer maintained.
|
||||||
series is no longer maintained.
|
</para>
|
||||||
</para>
|
<para>
|
||||||
<para>
|
See also <link linkend="install-compatibility-matrix">&repmgr; compatibility matrix</link>
|
||||||
&repmgr; 2.x supports PostgreSQL 9.0 ~ 9.3. While it is compatible
|
and <link linkend="faq-upgrade-repmgr">Should I upgrade &repmgr;?</link>.
|
||||||
with PostgreSQL 9.3, we recommend using repmgr 4.x. &repmgr; 2.x is
|
</para>
|
||||||
no longer maintained.
|
</sect2>
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
See also <link linkend="install-compatibility-matrix">&repmgr; compatibility matrix</link>
|
|
||||||
and <link linkend="faq-upgrade-repmgr">Should I upgrade &repmgr;?</link>.
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2 id="faq-replication-slots-advantage" xreflabel="Advantages of replication slots">
|
<sect2 id="faq-replication-slots-advantage" xreflabel="Advantages of replication slots">
|
||||||
<title>What's the advantage of using replication slots?</title>
|
<title>What's the advantage of using replication slots?</title>
|
||||||
<para>
|
<para>
|
||||||
Replication slots, introduced in PostgreSQL 9.4, ensure that the
|
Replication slots, introduced in PostgreSQL 9.4, ensure that the
|
||||||
primary server will retain WAL files until they have been consumed
|
primary server will retain WAL files until they have been consumed
|
||||||
by all standby servers. This means standby servers should never
|
by all standby servers. This means standby servers should never
|
||||||
fail due to not being able to retrieve required WAL files from the
|
fail due to not being able to retrieve required WAL files from the
|
||||||
primary.
|
primary.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
However this does mean that if a standby is no longer connected to the
|
However this does mean that if a standby is no longer connected to the
|
||||||
primary, the presence of the replication slot will cause WAL files
|
primary, the presence of the replication slot will cause WAL files
|
||||||
to be retained indefinitely, and eventually lead to disk space
|
to be retained indefinitely, and eventually lead to disk space
|
||||||
exhaustion.
|
exhaustion.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<tip>
|
<tip>
|
||||||
<para>
|
<para>
|
||||||
2ndQuadrant's recommended configuration is to configure
|
2ndQuadrant's recommended configuration is to configure
|
||||||
<ulink url="https://www.pgbarman.org/">Barman</ulink> as a fallback
|
<ulink url="https://www.pgbarman.org/">Barman</ulink> as a fallback
|
||||||
source of WAL files, rather than maintain replication slots for
|
source of WAL files, rather than maintain replication slots for
|
||||||
each standby. See also: <link linkend="cloning-from-barman-restore-command">Using Barman as a WAL file source</link>.
|
each standby. See also: <link linkend="cloning-from-barman-restore-command">Using Barman as a WAL file source</link>.
|
||||||
</para>
|
</para>
|
||||||
</tip>
|
</tip>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-replication-slots-number" xreflabel="Number of replication slots">
|
<sect2 id="faq-replication-slots-number" xreflabel="Number of replication slots">
|
||||||
<title>How many replication slots should I define in <varname>max_replication_slots</varname>?</title>
|
<title>How many replication slots should I define in <varname>max_replication_slots</varname>?</title>
|
||||||
<para>
|
<para>
|
||||||
Normally at least same number as the number of standbys which will connect
|
Normally at least same number as the number of standbys which will connect
|
||||||
to the node. Note that changes to <varname>max_replication_slots</varname> require a server
|
to the node. Note that changes to <varname>max_replication_slots</varname> require a server
|
||||||
restart to take effect, and as there is no particular penalty for unused
|
restart to take effect, and as there is no particular penalty for unused
|
||||||
replication slots, setting a higher figure will make adding new nodes
|
replication slots, setting a higher figure will make adding new nodes
|
||||||
easier.
|
easier.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-hash-index" xreflabel="Hash indexes">
|
<sect2 id="faq-hash-index" xreflabel="Hash indexes">
|
||||||
<title>Does &repmgr; support hash indexes?</title>
|
<title>Does &repmgr; support hash indexes?</title>
|
||||||
<para>
|
<para>
|
||||||
Before PostgreSQL 10, hash indexes were not WAL logged and are therefore not suitable
|
Before PostgreSQL 10, hash indexes were not WAL logged and are therefore not suitable
|
||||||
for use in streaming replication in PostgreSQL 9.6 and earlier. See the
|
for use in streaming replication in PostgreSQL 9.6 and earlier. See the
|
||||||
<ulink url="https://www.postgresql.org/docs/9.6/sql-createindex.html#AEN80279">PostgreSQL documentation</ulink>
|
<ulink url="https://www.postgresql.org/docs/9.6/sql-createindex.html#AEN80279">PostgreSQL documentation</ulink>
|
||||||
for details.
|
for details.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
From PostgreSQL 10, this restriction has been lifted and hash indexes can be used
|
From PostgreSQL 10, this restriction has been lifted and hash indexes can be used
|
||||||
in a streaming replication cluster.
|
in a streaming replication cluster.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-upgrades" xreflabel="Upgrading PostgreSQL with repmgr">
|
<sect2 id="faq-upgrades" xreflabel="Upgrading PostgreSQL with repmgr">
|
||||||
<title>Can &repmgr; assist with upgrading a PostgreSQL cluster?</title>
|
<title>Can &repmgr; assist with upgrading a PostgreSQL cluster?</title>
|
||||||
<para>
|
<para>
|
||||||
For <emphasis>minor</emphasis> version upgrades, e.g. from 9.6.7 to 9.6.8, a common
|
For <emphasis>minor</emphasis> version upgrades, e.g. from 9.6.7 to 9.6.8, a common
|
||||||
approach is to upgrade a standby to the latest version, perform a
|
approach is to upgrade a standby to the latest version, perform a
|
||||||
<link linkend="performing-switchover">switchover</link> promoting it to a primary,
|
<link linkend="performing-switchover">switchover</link> promoting it to a primary,
|
||||||
then upgrade the former primary.
|
then upgrade the former primary.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
For <emphasis>major</emphasis> version upgrades (e.g. from PostgreSQL 9.6 to PostgreSQL 10),
|
For <emphasis>major</emphasis> version upgrades (e.g. from PostgreSQL 9.6 to PostgreSQL 10),
|
||||||
the traditional approach is to "reseed" a cluster by upgrading a single
|
the traditional approach is to "reseed" a cluster by upgrading a single
|
||||||
node with <ulink url="https://www.postgresql.org/docs/current/pgupgrade.html">pg_upgrade</ulink>
|
node with <ulink url="https://www.postgresql.org/docs/current/pgupgrade.html">pg_upgrade</ulink>
|
||||||
and recloning standbys from this.
|
and recloning standbys from this.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To minimize downtime during major upgrades from PostgreSQL 9.4 and later,
|
To minimize downtime during major upgrades from PostgreSQL 9.4 and later,
|
||||||
<ulink url="https://www.2ndquadrant.com/en/resources/pglogical/">pglogical</ulink>
|
<ulink url="https://www.2ndquadrant.com/en/resources/pglogical/">pglogical</ulink>
|
||||||
can be used to set up a parallel cluster using the newer PostgreSQL version,
|
can be used to set up a parallel cluster using the newer PostgreSQL version,
|
||||||
which can be kept in sync with the existing production cluster until the
|
which can be kept in sync with the existing production cluster until the
|
||||||
new cluster is ready to be put into production.
|
new cluster is ready to be put into production.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-libdir-repmgr-error">
|
<sect2 id="faq-libdir-repmgr-error">
|
||||||
<title>What does this error mean: <literal>ERROR: could not access file "$libdir/repmgr"</literal>?</title>
|
<title>What does this error mean: <literal>ERROR: could not access file "$libdir/repmgr"</literal>?</title>
|
||||||
<para>
|
<para>
|
||||||
It means the &repmgr; extension code is not installed in the
|
It means the &repmgr; extension code is not installed in the
|
||||||
PostgreSQL application directory. This typically happens when using PostgreSQL
|
PostgreSQL application directory. This typically happens when using PostgreSQL
|
||||||
packages provided by a third-party vendor, which often have different
|
packages provided by a third-party vendor, which often have different
|
||||||
filesystem layouts.
|
filesystem layouts.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Either use PostgreSQL packages provided by the community or 2ndQuadrant; if this
|
Either use PostgreSQL packages provided by the community or 2ndQuadrant; if this
|
||||||
is not possible, contact your vendor for assistance.
|
is not possible, contact your vendor for assistance.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-old-packages">
|
<sect2 id="faq-old-packages">
|
||||||
<title>How can I obtain old versions of &repmgr; packages?</title>
|
<title>How can I obtain old versions of &repmgr; packages?</title>
|
||||||
<para>
|
<para>
|
||||||
See appendix <xref linkend="packages-old-versions"/> for details.
|
See appendix <xref linkend="packages-old-versions"/> for details.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-required-for-replication">
|
<sect2 id="faq-repmgr-required-for-replication">
|
||||||
<title>Is &repmgr; required for streaming replication?</title>
|
<title>Is &repmgr; required for streaming replication?</title>
|
||||||
<para>
|
<para>
|
||||||
No.
|
No.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
&repmgr; (together with &repmgrd;) assists with
|
&repmgr; (together with &repmgrd;) assists with
|
||||||
<emphasis>managing</emphasis> replication. It does not actually perform replication, which
|
<emphasis>managing</emphasis> replication. It does not actually perform replication, which
|
||||||
is part of the core PostgreSQL functionality.
|
is part of the core PostgreSQL functionality.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-what-if-repmgr-uninstalled">
|
<sect2 id="faq-what-if-repmgr-uninstalled">
|
||||||
<title>Will replication stop working if &repmgr; is uninstalled?</title>
|
<title>Will replication stop working if &repmgr; is uninstalled?</title>
|
||||||
<para>
|
<para>
|
||||||
No. See preceding question.
|
No. See preceding question.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-version-mix">
|
<sect2 id="faq-version-mix">
|
||||||
<title>Does it matter if different &repmgr; versions are present in the replication cluster?</title>
|
<title>Does it matter if different &repmgr; versions are present in the replication cluster?</title>
|
||||||
<para>
|
<para>
|
||||||
Yes. If different "major" &repmgr; versions (e.g. 3.3.x and 4.1.x) are present,
|
Yes. If different "major" &repmgr; versions (e.g. 3.3.x and 4.1.x) are present,
|
||||||
&repmgr; (in particular &repmgrd;)
|
&repmgr; (in particular &repmgrd;)
|
||||||
may not run, or run properly, or in the worst case (if different &repmgrd;
|
may not run, or run properly, or in the worst case (if different &repmgrd;
|
||||||
versions are running and there are differences in the failover implementation) break
|
versions are running and there are differences in the failover implementation) break
|
||||||
your replication cluster.
|
your replication cluster.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
If different "minor" &repmgr; versions (e.g. 4.1.1 and 4.1.6) are installed,
|
If different "minor" &repmgr; versions (e.g. 4.1.1 and 4.1.6) are installed,
|
||||||
&repmgr; will function, but we strongly recommend always running the same version
|
&repmgr; will function, but we strongly recommend always running the same version
|
||||||
to ensure there are no unexpected suprises, e.g. a newer version behaving slightly
|
to ensure there are no unexpected suprises, e.g. a newer version behaving slightly
|
||||||
differently to the older version.
|
differently to the older version.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
See also <link linkend="faq-upgrade-repmgr">Should I upgrade &repmgr;?</link>.
|
See also <link linkend="faq-upgrade-repmgr">Should I upgrade &repmgr;?</link>.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-upgrade-repmgr">
|
<sect2 id="faq-upgrade-repmgr">
|
||||||
<title>Should I upgrade &repmgr;?</title>
|
<title>Should I upgrade &repmgr;?</title>
|
||||||
<para>
|
<para>
|
||||||
Yes.
|
Yes.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
We don't release new versions for fun, you know. Upgrading may require a little effort,
|
We don't release new versions for fun, you know. Upgrading may require a little effort,
|
||||||
but running an older &repmgr; version with bugs which have since been fixed may end up
|
but running an older &repmgr; version with bugs which have since been fixed may end up
|
||||||
costing you more effort. The same applies to PostgreSQL itself.
|
costing you more effort. The same applies to PostgreSQL itself.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-conf-data-directory">
|
</sect2>
|
||||||
<title>Why do I need to specify the data directory location in repmgr.conf?</title>
|
|
||||||
<para>
|
|
||||||
In some circumstances &repmgr; may need to access a PostgreSQL data
|
|
||||||
directory while the PostgreSQL server is not running, e.g. to confirm
|
|
||||||
it shut down cleanly during a <link linkend="performing-switchover">switchover</link>.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Additionally, this provides support when using &repmgr; on PostgreSQL 9.6 and
|
|
||||||
earlier, where the <literal>repmgr</literal> user is not a superuser; in that
|
|
||||||
case the <literal>repmgr</literal> user will not be able to access the
|
|
||||||
<literal>data_directory</literal> configuration setting, access to which is restricted
|
|
||||||
to superusers.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
In PostgreSQL 10 and later, non-superusers can be added to the
|
|
||||||
<ulink url="https://www.postgresql.org/docs/current/default-roles.html">default role</ulink>
|
|
||||||
<option>pg_read_all_settings</option> (or the meta-role <option>pg_monitor</option>)
|
|
||||||
which will enable them to read this setting.
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2 id="faq-third-party-packages" xreflabel="Compatability with third party vendor packages">
|
<sect2 id="faq-repmgr-conf-data-directory">
|
||||||
<title>Are &repmgr; packages compatible with <literal>$third_party_vendor</literal>'s packages?</title>
|
<title>Why do I need to specify the data directory location in repmgr.conf?</title>
|
||||||
<para>
|
<para>
|
||||||
&repmgr; packages provided by 2ndQuadrant are compatible with the community-provided PostgreSQL
|
In some circumstances &repmgr; may need to access a PostgreSQL data
|
||||||
packages and any software provided by 2ndQuadrant.
|
directory while the PostgreSQL server is not running, e.g. to confirm
|
||||||
</para>
|
it shut down cleanly during a <link linkend="performing-switchover">switchover</link>.
|
||||||
<para>
|
</para>
|
||||||
A number of other vendors provide their own versions of PostgreSQL packages, often with different
|
<para>
|
||||||
package naming schemes and/or file locations.
|
Additionally, this provides support when using &repmgr; on PostgreSQL 9.6 and
|
||||||
</para>
|
earlier, where the <literal>repmgr</literal> user is not a superuser; in that
|
||||||
<para>
|
case the <literal>repmgr</literal> user will not be able to access the
|
||||||
We cannot guarantee that &repmgr; packages will be compatible with these packages.
|
<literal>data_directory</literal> configuration setting, access to which is restricted
|
||||||
It may be possible to override package dependencies (e.g. <literal>rpm --nodeps</literal>
|
to superusers. (In PostgreSQL 10 and later, non-superusers can be added to the
|
||||||
for CentOS-based systems or <literal>dpkg --force-depends</literal> for Debian-based systems).
|
group <option>pg_read_all_settings</option> which will enable them to read this setting).
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="faq-repmgr" xreflabel="repmgr">
|
<sect1 id="faq-repmgr" xreflabel="repmgr">
|
||||||
<title><command>repmgr</command></title>
|
<title><command>repmgr</command></title>
|
||||||
|
|
||||||
<sect2 id="faq-register-existing-node" xreflabel="registering an existing node">
|
<sect2 id="faq-register-existing-node" xreflabel="registering an existing node">
|
||||||
<title>Can I register an existing PostgreSQL server with repmgr?</title>
|
<title>Can I register an existing PostgreSQL server with repmgr?</title>
|
||||||
<para>
|
<para>
|
||||||
Yes, any existing PostgreSQL server which is part of the same replication
|
Yes, any existing PostgreSQL server which is part of the same replication
|
||||||
cluster can be registered with &repmgr;. There's no requirement for a
|
cluster can be registered with &repmgr;. There's no requirement for a
|
||||||
standby to have been cloned using &repmgr;.
|
standby to have been cloned using &repmgr;.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-clone-other-source" >
|
<sect2 id="faq-repmgr-clone-other-source" >
|
||||||
<title>Can I use a standby not cloned by &repmgr; as a &repmgr; node?</title>
|
<title>Can I use a standby not cloned by &repmgr; as a &repmgr; node?</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
For a standby which has been manually cloned or recovered from an external
|
For a standby which has been manually cloned or recovered from an external
|
||||||
backup manager such as Barman, the command
|
backup manager such as Barman, the command
|
||||||
<command><link linkend="repmgr-standby-clone">repmgr standby clone --recovery-conf-only</link></command>
|
<command><link linkend="repmgr-standby-clone">repmgr standby clone --recovery-conf-only</link></command>
|
||||||
can be used to create the correct <filename>recovery.conf</filename> file for
|
can be used to create the correct <filename>recovery.conf</filename> file for
|
||||||
use with &repmgr; (and will create a replication slot if required). Once this has been done,
|
use with &repmgr; (and will create a replication slot if required). Once this has been done,
|
||||||
<link linkend="repmgr-standby-register">register the node</link> as usual.
|
<link linkend="repmgr-standby-register">register the node</link> as usual.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-recovery-conf" >
|
<sect2 id="faq-repmgr-recovery-conf" >
|
||||||
<title>What does &repmgr; write in <filename>recovery.conf</filename>, and what options can be set there?</title>
|
<title>What does &repmgr; write in <filename>recovery.conf</filename>, and what options can be set there?</title>
|
||||||
<para>
|
<para>
|
||||||
See section <link linkend="repmgr-standby-clone-recovery-conf">Customising recovery.conf</link>.
|
See section <link linkend="repmgr-standby-clone-recovery-conf">Customising recovery.conf</link>.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-failed-primary-standby" xreflabel="Reintegrate a failed primary as a standby">
|
<sect2 id="faq-repmgr-failed-primary-standby" xreflabel="Reintegrate a failed primary as a standby">
|
||||||
<title>How can a failed primary be re-added as a standby?</title>
|
<title>How can a failed primary be re-added as a standby?</title>
|
||||||
<para>
|
<para>
|
||||||
This is a two-stage process. First, the failed primary's data directory
|
This is a two-stage process. First, the failed primary's data directory
|
||||||
must be re-synced with the current primary; secondly the failed primary
|
must be re-synced with the current primary; secondly the failed primary
|
||||||
needs to be re-registered as a standby.
|
needs to be re-registered as a standby.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
It's possible to use <command>pg_rewind</command> to re-synchronise the existing data
|
It's possible to use <command>pg_rewind</command> to re-synchronise the existing data
|
||||||
directory, which will usually be much
|
directory, which will usually be much
|
||||||
faster than re-cloning the server. However <command>pg_rewind</command> can only
|
faster than re-cloning the server. However <command>pg_rewind</command> can only
|
||||||
be used if PostgreSQL either has <varname>wal_log_hints</varname> enabled, or
|
be used if PostgreSQL either has <varname>wal_log_hints</varname> enabled, or
|
||||||
data checksums were enabled when the cluster was initialized.
|
data checksums were enabled when the cluster was initialized.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Note that <command>pg_rewind</command> is available as part of the core PostgreSQL
|
Note that <command>pg_rewind</command> is available as part of the core PostgreSQL
|
||||||
distribution from PostgreSQL 9.5, and as a third-party utility for PostgreSQL 9.3 and 9.4.
|
distribution from PostgreSQL 9.5, and as a third-party utility for PostgreSQL 9.3 and 9.4.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
&repmgr; provides the command <command>repmgr node rejoin</command> which can
|
&repmgr; provides the command <command>repmgr node rejoin</command> which can
|
||||||
optionally execute <command>pg_rewind</command>; see the <xref linkend="repmgr-node-rejoin"/>
|
optionally execute <command>pg_rewind</command>; see the <xref linkend="repmgr-node-rejoin"/>
|
||||||
documentation for details, in particular the section <xref linkend="repmgr-node-rejoin-pg-rewind"/>.
|
documentation for details, in particular the section <xref linkend="repmgr-node-rejoin-pg-rewind"/>.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
If <command>pg_rewind</command> cannot be used, then the data directory will need
|
If <command>pg_rewind</command> cannot be used, then the data directory will need
|
||||||
to be re-cloned from scratch.
|
to be re-cloned from scratch.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-check-configuration" xreflabel="Check PostgreSQL configuration">
|
<sect2 id="faq-repmgr-check-configuration" xreflabel="Check PostgreSQL configuration">
|
||||||
<title>Is there an easy way to check my primary server is correctly configured for use with &repmgr;?</title>
|
<title>Is there an easy way to check my primary server is correctly configured for use with &repmgr;?</title>
|
||||||
<para>
|
<para>
|
||||||
Execute <command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>
|
Execute <command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>
|
||||||
with the <literal>--dry-run</literal> option; this will report any configuration problems
|
with the <literal>--dry-run</literal> option; this will report any configuration problems
|
||||||
which need to be rectified.
|
which need to be rectified.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-clone-skip-config-files" xreflabel="">
|
<sect2 id="faq-repmgr-clone-skip-config-files" xreflabel="">
|
||||||
<title>When cloning a standby, how can I get &repmgr; to copy
|
<title>When cloning a standby, how can I get &repmgr; to copy
|
||||||
<filename>postgresql.conf</filename> and <filename>pg_hba.conf</filename> from the PostgreSQL configuration
|
<filename>postgresql.conf</filename> and <filename>pg_hba.conf</filename> from the PostgreSQL configuration
|
||||||
directory in <filename>/etc</filename>?</title>
|
directory in <filename>/etc</filename>?</title>
|
||||||
<para>
|
<para>
|
||||||
Use the command line option <literal>--copy-external-config-files</literal>. For more details
|
Use the command line option <literal>--copy-external-config-files</literal>. For more details
|
||||||
see <xref linkend="repmgr-standby-clone-config-file-copying"/>.
|
see <xref linkend="repmgr-standby-clone-config-file-copying"/>.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-shared-preload-libaries-no-repmgrd" xreflabel="shared_preload_libraries without repmgrd">
|
<sect2 id="faq-repmgr-shared-preload-libaries-no-repmgrd" xreflabel="shared_preload_libraries without repmgrd">
|
||||||
<title>Do I need to include <literal>shared_preload_libraries = 'repmgr'</literal>
|
<title>Do I need to include <literal>shared_preload_libraries = 'repmgr'</literal>
|
||||||
in <filename>postgresql.conf</filename> if I'm not using &repmgrd;?</title>
|
in <filename>postgresql.conf</filename> if I'm not using &repmgrd;?</title>
|
||||||
<para>
|
<para>
|
||||||
No, the <literal>repmgr</literal> shared library is only needed when running &repmgrd;.
|
No, the <literal>repmgr</literal> shared library is only needed when running &repmgrd;.
|
||||||
If you later decide to run &repmgrd;, you just need to add
|
If you later decide to run &repmgrd;, you just need to add
|
||||||
<literal>shared_preload_libraries = 'repmgr'</literal> and restart PostgreSQL.
|
<literal>shared_preload_libraries = 'repmgr'</literal> and restart PostgreSQL.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-permissions" xreflabel="Replication permission problems">
|
<sect2 id="faq-repmgr-permissions" xreflabel="Replication permission problems">
|
||||||
<title>I've provided replication permission for the <literal>repmgr</literal> user in <filename>pg_hba.conf</filename>
|
<title>I've provided replication permission for the <literal>repmgr</literal> user in <filename>pg_hba.conf</filename>
|
||||||
but <command>repmgr</command>/&repmgrd; complains it can't connect to the server... Why?</title>
|
but <command>repmgr</command>/&repmgrd; complains it can't connect to the server... Why?</title>
|
||||||
<para>
|
<para>
|
||||||
<command>repmgr</command> and &repmgrd; need to be able to connect to the repmgr database
|
<command>repmgr</command> and &repmgrd; need to be able to connect to the repmgr database
|
||||||
with a normal connection to query metadata. The <literal>replication</literal> connection
|
with a normal connection to query metadata. The <literal>replication</literal> connection
|
||||||
permission is for PostgreSQL's streaming replication (and doesn't necessarily need to be the <literal>repmgr</literal> user).
|
permission is for PostgreSQL's streaming replication (and doesn't necessarily need to be the <literal>repmgr</literal> user).
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-clone-provide-primary-conninfo" xreflabel="Providing primary connection parameters">
|
<sect2 id="faq-repmgr-clone-provide-primary-conninfo" xreflabel="Providing primary connection parameters">
|
||||||
<title>When cloning a standby, why do I need to provide the connection parameters
|
<title>When cloning a standby, why do I need to provide the connection parameters
|
||||||
for the primary server on the command line, not in the configuration file?</title>
|
for the primary server on the command line, not in the configuration file?</title>
|
||||||
<para>
|
<para>
|
||||||
Cloning a standby is a one-time action; the role of the server being cloned
|
Cloning a standby is a one-time action; the role of the server being cloned
|
||||||
from could change, so fixing it in the configuration file would create
|
from could change, so fixing it in the configuration file would create
|
||||||
confusion. If &repmgr; needs to establish a connection to the primary
|
confusion. If &repmgr; needs to establish a connection to the primary
|
||||||
server, it can retrieve this from the <literal>repmgr.nodes</literal> table on the local
|
server, it can retrieve this from the <literal>repmgr.nodes</literal> table on the local
|
||||||
node, and if necessary scan the replication cluster until it locates the active primary.
|
node, and if necessary scan the replication cluster until it locates the active primary.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-clone-waldir-xlogdir" xreflabel="Providing a custom WAL directory">
|
<sect2 id="faq-repmgr-clone-waldir-xlogdir" xreflabel="Providing a custom WAL directory">
|
||||||
<title>When cloning a standby, how do I ensure the WAL files are placed in a custom directory?</title>
|
<title>When cloning a standby, how do I ensure the WAL files are placed in a custom directory?</title>
|
||||||
<para>
|
<para>
|
||||||
Provide the option <literal>--waldir</literal> (<literal>--xlogdir</literal> in PostgreSQL 9.6
|
Provide the option <literal>--waldir</literal> (<literal>--xlogdir</literal> in PostgreSQL 9.6
|
||||||
and earlier) with the absolute path to the WAL directory in <varname>pg_basebackup_options</varname>.
|
and earlier) with the absolute path to the WAL directory in <varname>pg_basebackup_options</varname>.
|
||||||
For more details see <xref linkend="cloning-advanced-pg-basebackup-options"/>.
|
For more details see <xref linkend="cloning-advanced-pg-basebackup-options"/>.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-events-no-fkey" xreflabel="No foreign key on node_id in repmgr.events">
|
<sect2 id="faq-repmgr-events-no-fkey" xreflabel="No foreign key on node_id in repmgr.events">
|
||||||
<title>Why is there no foreign key on the <literal>node_id</literal> column in the <literal>repmgr.events</literal>
|
<title>Why is there no foreign key on the <literal>node_id</literal> column in the <literal>repmgr.events</literal>
|
||||||
table?</title>
|
table?</title>
|
||||||
<para>
|
<para>
|
||||||
Under some circumstances event notifications can be generated for servers
|
Under some circumstances event notifications can be generated for servers
|
||||||
which have not yet been registered; it's also useful to retain a record
|
which have not yet been registered; it's also useful to retain a record
|
||||||
of events which includes servers removed from the replication cluster
|
of events which includes servers removed from the replication cluster
|
||||||
which no longer have an entry in the <literal>repmgr.nodes</literal> table.
|
which no longer have an entry in the <literal>repmgr.nodes</literal> table.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgr-recovery-conf-quoted-values" xreflabel="Quoted values in recovery.conf">
|
<sect2 id="faq-repmgr-recovery-conf-quoted-values" xreflabel="Quoted values in recovery.conf">
|
||||||
<title>Why are some values in <filename>recovery.conf</filename> surrounded by pairs of single quotes?</title>
|
<title>Why are some values in <filename>recovery.conf</filename> surrounded by pairs of single quotes?</title>
|
||||||
<para>
|
<para>
|
||||||
This is to ensure that user-supplied values which are written as parameter values in <filename>recovery.conf</filename>
|
This is to ensure that user-supplied values which are written as parameter values in <filename>recovery.conf</filename>
|
||||||
are escaped correctly and do not cause errors when <filename>recovery.conf</filename> is parsed.
|
are escaped correctly and do not cause errors when <filename>recovery.conf</filename> is parsed.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The escaping is performed by an internal PostgreSQL routine, which leaves strings consisting
|
The escaping is performed by an internal PostgreSQL routine, which leaves strings consisting
|
||||||
of digits and alphabetical characters only as-is, but wraps everything else in pairs of single quotes,
|
of digits and alphabetical characters only as-is, but wraps everything else in pairs of single quotes,
|
||||||
even if the string does not contain any characters which need escaping.
|
even if the string does not contain any characters which need escaping.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
<sect1 id="faq-repmgrd" xreflabel="repmgrd">
|
<sect1 id="faq-repmgrd" xreflabel="repmgrd">
|
||||||
<title>&repmgrd;</title>
|
<title>&repmgrd;</title>
|
||||||
|
|
||||||
|
|
||||||
<sect2 id="faq-repmgrd-prevent-promotion" xreflabel="Prevent standby from being promoted to primary">
|
<sect2 id="faq-repmgrd-prevent-promotion" xreflabel="Prevent standby from being promoted to primary">
|
||||||
<title>How can I prevent a node from ever being promoted to primary?</title>
|
<title>How can I prevent a node from ever being promoted to primary?</title>
|
||||||
<para>
|
<para>
|
||||||
In <filename>repmgr.conf</filename>, set its priority to a value of <literal>0</literal>; apply the changed setting with
|
In <filename>repmgr.conf</filename>, set its priority to a value of <literal>0</literal>; apply the changed setting with
|
||||||
<command><link linkend="repmgr-standby-register">repmgr standby register --force</link></command>.
|
<command><link linkend="repmgr-standby-register">repmgr standby register --force</link></command>.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Additionally, if <varname>failover</varname> is set to <literal>manual</literal>, the node will never
|
Additionally, if <varname>failover</varname> is set to <literal>manual</literal>, the node will never
|
||||||
be considered as a promotion candidate.
|
be considered as a promotion candidate.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgrd-delayed-standby" xreflabel="Delayed standby support">
|
<sect2 id="faq-repmgrd-delayed-standby" xreflabel="Delayed standby support">
|
||||||
<title>Does &repmgrd; support delayed standbys?</title>
|
<title>Does &repmgrd; support delayed standbys?</title>
|
||||||
<para>
|
<para>
|
||||||
&repmgrd; can monitor delayed standbys - those set up with
|
&repmgrd; can monitor delayed standbys - those set up with
|
||||||
<varname>recovery_min_apply_delay</varname> set to a non-zero value
|
<varname>recovery_min_apply_delay</varname> set to a non-zero value
|
||||||
in <filename>recovery.conf</filename> - but as it's not currently possible
|
in <filename>recovery.conf</filename> - but as it's not currently possible
|
||||||
to directly examine the value applied to the standby, &repmgrd;
|
to directly examine the value applied to the standby, &repmgrd;
|
||||||
may not be able to properly evaluate the node as a promotion candidate.
|
may not be able to properly evaluate the node as a promotion candidate.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
We recommend that delayed standbys are explicitly excluded from promotion
|
We recommend that delayed standbys are explicitly excluded from promotion
|
||||||
by setting <varname>priority</varname> to <literal>0</literal> in
|
by setting <varname>priority</varname> to <literal>0</literal> in
|
||||||
<filename>repmgr.conf</filename>.
|
<filename>repmgr.conf</filename>.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Note that after registering a delayed standby, &repmgrd; will only start
|
Note that after registering a delayed standby, &repmgrd; will only start
|
||||||
once the metadata added in the primary node has been replicated.
|
once the metadata added in the primary node has been replicated.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgrd-logfile-rotate" xreflabel="repmgrd logfile rotation">
|
<sect2 id="faq-repmgrd-logfile-rotate" xreflabel="repmgrd logfile rotation">
|
||||||
<title>How can I get &repmgrd; to rotate its logfile?</title>
|
<title>How can I get &repmgrd; to rotate its logfile?</title>
|
||||||
<para>
|
<para>
|
||||||
Configure your system's <literal>logrotate</literal> service to do this; see <xref linkend="repmgrd-log-rotation"/>.
|
Configure your system's <literal>logrotate</literal> service to do this; see <xref linkend="repmgrd-log-rotation"/>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgrd-recloned-no-start" xreflabel="repmgrd not restarting after node cloned">
|
<sect2 id="faq-repmgrd-recloned-no-start" xreflabel="repmgrd not restarting after node cloned">
|
||||||
<title>I've recloned a failed primary as a standby, but &repmgrd; refuses to start?</title>
|
<title>I've recloned a failed primary as a standby, but &repmgrd; refuses to start?</title>
|
||||||
<para>
|
<para>
|
||||||
Check you registered the standby after recloning. If unregistered, the standby
|
Check you registered the standby after recloning. If unregistered, the standby
|
||||||
cannot be considered as a promotion candidate even if <varname>failover</varname> is set to
|
cannot be considered as a promotion candidate even if <varname>failover</varname> is set to
|
||||||
<literal>automatic</literal>, which is probably not what you want. &repmgrd; will start if
|
<literal>automatic</literal>, which is probably not what you want. &repmgrd; will start if
|
||||||
<varname>failover</varname> is set to <literal>manual</literal> so the node's replication status can still
|
<varname>failover</varname> is set to <literal>manual</literal> so the node's replication status can still
|
||||||
be monitored, if desired.
|
be monitored, if desired.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgrd-pg-bindir" xreflabel="repmgrd does not apply pg_bindir to promote_command or follow_command">
|
<sect2 id="faq-repmgrd-pg-bindir" xreflabel="repmgrd does not apply pg_bindir to promote_command or follow_command">
|
||||||
<title>
|
<title>
|
||||||
&repmgrd; ignores pg_bindir when executing <varname>promote_command</varname> or <varname>follow_command</varname>
|
&repmgrd; ignores pg_bindir when executing <varname>promote_command</varname> or <varname>follow_command</varname>
|
||||||
</title>
|
</title>
|
||||||
<para>
|
<para>
|
||||||
<varname>promote_command</varname> or <varname>follow_command</varname> can be user-defined scripts,
|
<varname>promote_command</varname> or <varname>follow_command</varname> can be user-defined scripts,
|
||||||
so &repmgr; will not apply <option>pg_bindir</option> even if excuting &repmgr;. Always provide the full
|
so &repmgr; will not apply <option>pg_bindir</option> even if excuting &repmgr;. Always provide the full
|
||||||
path; see <xref linkend="repmgrd-automatic-failover-configuration"/> for more details.
|
path; see <xref linkend="repmgrd-automatic-failover-configuration"/> for more details.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="faq-repmgrd-startup-no-upstream" xreflabel="repmgrd does not start if upstream node is not running">
|
<sect2 id="faq-repmgrd-startup-no-upstream" xreflabel="repmgrd does not start if upstream node is not running">
|
||||||
<title>
|
<title>
|
||||||
&repmgrd; aborts startup with the error "<literal>upstream node must be running before repmgrd can start</literal>"
|
&repmgrd; aborts startup with the error "<literal>upstream node must be running before repmgrd can start</literal>"
|
||||||
</title>
|
</title>
|
||||||
<para>
|
<para>
|
||||||
&repmgrd; does this to avoid starting up on a replication cluster
|
&repmgrd; does this to avoid starting up on a replication cluster
|
||||||
which is not in a healthy state. If the upstream is unavailable, &repmgrd;
|
which is not in a healthy state. If the upstream is unavailable, &repmgrd;
|
||||||
may initiate a failover immediately after starting up, which could have unintended side-effects,
|
may initiate a failover immediately after starting up, which could have unintended side-effects,
|
||||||
particularly if &repmgrd; is not running on other nodes.
|
particularly if &repmgrd; is not running on other nodes.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
In particular, it's possible that the node's local copy of the <literal>repmgr.nodes</literal> copy
|
In particular, it's possible that the node's local copy of the <literal>repmgr.nodes</literal> copy
|
||||||
is out-of-date, which may lead to incorrect failover behaviour.
|
is out-of-date, which may lead to incorrect failover behaviour.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The onus is therefore on the adminstrator to manually set the cluster to a stable, healthy state before
|
The onus is therefore on the adminstrator to manually set the cluster to a stable, healthy state before
|
||||||
starting &repmgrd;.
|
starting &repmgrd;.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
</appendix>
|
</appendix>
|
||||||
|
|||||||
@@ -122,7 +122,7 @@
|
|||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Package name example:</entry>
|
<entry>Package name example:</entry>
|
||||||
<entry><filename>repmgr11-4.4.0-1.rhel7.x86_64</filename></entry>
|
<entry><filename>repmgr10-4.0.4-1.rhel7.x86_64</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
@@ -132,12 +132,12 @@
|
|||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Installation command:</entry>
|
<entry>Installation command:</entry>
|
||||||
<entry><literal>yum install repmgr11</literal></entry>
|
<entry><literal>yum install repmgr10</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Binary location:</entry>
|
<entry>Binary location:</entry>
|
||||||
<entry><filename>/usr/pgsql-11/bin</filename></entry>
|
<entry><filename>/usr/pgsql-10/bin</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
@@ -147,22 +147,22 @@
|
|||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Configuration file location:</entry>
|
<entry>Configuration file location:</entry>
|
||||||
<entry><filename>/etc/repmgr/11/repmgr.conf</filename></entry>
|
<entry><filename>/etc/repmgr/10/repmgr.conf</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Data directory:</entry>
|
<entry>Data directory:</entry>
|
||||||
<entry><filename>/var/lib/pgsql/11/data</filename></entry>
|
<entry><filename>/var/lib/pgsql/10/data</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>repmgrd service command:</entry>
|
<entry>repmgrd service command:</entry>
|
||||||
<entry><command>systemctl [start|stop|restart|reload] repmgr11</command></entry>
|
<entry><command>systemctl [start|stop|restart|reload] repmgr10</command></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>repmgrd service file location:</entry>
|
<entry>repmgrd service file location:</entry>
|
||||||
<entry><filename>/usr/lib/systemd/system/repmgr11.service</filename></entry>
|
<entry><filename>/usr/lib/systemd/system/repmgr10.service</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
@@ -253,14 +253,20 @@
|
|||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
&repmgr; <literal>.deb</literal> packages are provided by 2ndQuadrant as well as the
|
&repmgr; <literal>.deb</literal> packages are provided via the
|
||||||
PostgreSQL Community APT repository, and are available for each community-supported
|
PostgreSQL Community APT repository, and are available for each community-supported
|
||||||
PostgreSQL version, currently supported Debian releases, and currently supported
|
PostgreSQL version, currently supported Debian releases, and currently supported
|
||||||
Ubuntu LTS releases.
|
Ubuntu LTS releases.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<sect2 id="packages-apt-repository">
|
<sect2 id="packages-apt-repository">
|
||||||
<title>APT repositories</title>
|
<title>APT repository</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
&repmgr; packages are available from the PostgreSQL Community APT repository,
|
||||||
|
which is updated immediately after each &repmgr; release.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
|
||||||
<table id="apt-2ndquadrant-repository">
|
<table id="apt-2ndquadrant-repository">
|
||||||
<title>2ndQuadrant public repository</title>
|
<title>2ndQuadrant public repository</title>
|
||||||
@@ -285,7 +291,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<row>
|
<row>
|
||||||
<entry>Repository URL:</entry>
|
<entry>Repository URL:</entry>
|
||||||
<entry><ulink url="https://apt.postgresql.org/">https://apt.postgresql.org/</ulink></entry>
|
<entry><ulink url="http://apt.postgresql.org/">http://apt.postgresql.org/</ulink></entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>Repository documentation:</entry>
|
<entry>Repository documentation:</entry>
|
||||||
@@ -317,7 +323,7 @@
|
|||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Package name example:</entry>
|
<entry>Package name example:</entry>
|
||||||
<entry><filename>postgresql-11-repmgr</filename></entry>
|
<entry><filename>postgresql-10-repmgr</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
@@ -327,12 +333,12 @@
|
|||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Installation command:</entry>
|
<entry>Installation command:</entry>
|
||||||
<entry><literal>apt-get install postgresql-11-repmgr</literal></entry>
|
<entry><literal>apt-get install postgresql-10-repmgr</literal></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Binary location:</entry>
|
<entry>Binary location:</entry>
|
||||||
<entry><filename>/usr/lib/postgresql/11/bin</filename></entry>
|
<entry><filename>/usr/lib/postgresql/10/bin</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
@@ -347,12 +353,12 @@
|
|||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>Data directory:</entry>
|
<entry>Data directory:</entry>
|
||||||
<entry><filename>/var/lib/postgresql/11/main</filename></entry>
|
<entry><filename>/var/lib/postgresql/10/main</filename></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>PostgreSQL service command:</entry>
|
<entry>PostgreSQL service command:</entry>
|
||||||
<entry><command>systemctl [start|stop|restart|reload] postgresql@11-main</command></entry>
|
<entry><command>systemctl [start|stop|restart|reload] postgresql@10-main</command></entry>
|
||||||
|
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
@@ -376,11 +382,11 @@
|
|||||||
</table>
|
</table>
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
When using Debian packages, instead of using the <application>systemd</application> service
|
Instead of using the <application>systemd</application> service command directly,
|
||||||
command directly, it's recommended to execute <command>pg_ctlcluster</command>
|
it's recommended to execute <command>pg_ctlcluster</command> (as <literal>root</literal>,
|
||||||
(as <literal>root</literal>, either directly or via <command>sudo</command>), e.g.:
|
either directly or via <command>sudo</command>), e.g.:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
<command>pg_ctlcluster 11 main [start|stop|restart|reload]</command></programlisting>
|
<command>pg_ctlcluster 10 main [start|stop|restart|reload]</command></programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
For pre-<application>systemd</application> systems, <command>pg_ctlcluster</command>
|
For pre-<application>systemd</application> systems, <command>pg_ctlcluster</command>
|
||||||
@@ -471,7 +477,7 @@ repmgr96-4.1.1-0.0git320.g5113ab0.1.el7.x86_64.rpm</programlisting>
|
|||||||
<title>Debian/Ubuntu</title>
|
<title>Debian/Ubuntu</title>
|
||||||
<para>
|
<para>
|
||||||
An archive of old packages (<literal>3.3.2</literal> and later) for Debian/Ubuntu-based systems is available here:
|
An archive of old packages (<literal>3.3.2</literal> and later) for Debian/Ubuntu-based systems is available here:
|
||||||
<ulink url="https://apt-archive.postgresql.org/">https://apt-archive.postgresql.org/</ulink>
|
<ulink url="http://atalia.postgresql.org/morgue/r/repmgr/">http://atalia.postgresql.org/morgue/r/repmgr/</ulink>
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|||||||
@@ -15,310 +15,9 @@
|
|||||||
See also: <xref linkend="upgrading-repmgr"/>
|
See also: <xref linkend="upgrading-repmgr"/>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<!-- remember to update the release date in ../repmgr_version.h.in -->
|
|
||||||
<sect1 id="release-5.0.1">
|
|
||||||
<title>Release 5.0.1</title>
|
|
||||||
<para><emphasis>???</emphasis></para>
|
|
||||||
<para>
|
|
||||||
&repmgr; 5.0.1 is a minor release.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<sect2>
|
|
||||||
<title>Bug fixes</title>
|
|
||||||
<para>
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<command><link linkend="repmgr-standby-follow">repmgr standby follow</link></command>:
|
|
||||||
ensure an existing replication slot is not deleted if the
|
|
||||||
follow target is the node's current upstream.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
|
|
||||||
<sect1 id="release-5.0">
|
|
||||||
<title id="release-current">Release 5.0</title>
|
|
||||||
<para><emphasis>Tue 15 October, 2019</emphasis></para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
&repmgr; 5.0 is a major release.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
For details on how to upgrade an existing &repmgr; installation, see
|
|
||||||
documentation section <link linkend="upgrading-major-version">Upgrading a major version release</link>.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
If &repmgrd; is in use, a PostgreSQL restart <emphasis>is</emphasis> required;
|
|
||||||
in that case we suggest combining this &repmgr; upgrade with the next PostgreSQL
|
|
||||||
minor release, which will require a PostgreSQL restart in any case.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
|
|
||||||
<sect2>
|
|
||||||
<title>Compatibility changes</title>
|
|
||||||
|
|
||||||
<sect3 id="repmgr-5-0-config-file-parsing">
|
|
||||||
<title>Configuration file parsing has been made stricter</title>
|
|
||||||
<para>
|
|
||||||
&repmgr; now parses <link linkend="configuration-file-format">configuration files</link>
|
|
||||||
in the same way that PostgreSQL itself does, which means some files used with
|
|
||||||
earlier &repmgr; versions may need slight modification before they can be used
|
|
||||||
with &repmgr; 5 and later.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The main change is that string parameters should always be enclosed in single quotes.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
For example, in &repmgr; 4.4 and earlier, the following <filename>repmgr.conf</filename>
|
|
||||||
entry was valid:
|
|
||||||
<programlisting>
|
|
||||||
conninfo=host=node1 user=repmgr dbname=repmgr connect_timeout=2</programlisting>
|
|
||||||
This must now be changed to:
|
|
||||||
<programlisting>
|
|
||||||
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Note that simple string identifiers (e.g. <literal>node_name=node1</literal>)
|
|
||||||
may remain unquoted, though we recommend always enclosing
|
|
||||||
strings in single quotes.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Additionally, leading/trailing white space between single quotes will no longer
|
|
||||||
be trimmed; the entire string between single quotes will be
|
|
||||||
taken literally.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Strings enclosed in double quotes (e.g. <literal>node_name="node1"</literal>)
|
|
||||||
will now be rejected; previously they were accepted, but the double quotes were
|
|
||||||
interpreted as part of the string, which was a frequent cause of confusion.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This syntax matches that used by PostgreSQL itself.
|
|
||||||
</para>
|
|
||||||
</sect3>
|
|
||||||
|
|
||||||
<sect3>
|
|
||||||
<title>Some "repmgr daemon ..." commands renamed</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Some "<command>repmgr daemon ...</command>" commands have been renamed to
|
|
||||||
"<command>repmgr service ...</command>" as they have a cluster-wide effect
|
|
||||||
and to avoid giving the impression they affect only the local &repmgr; daemon.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The following commands are affected:
|
|
||||||
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<command>repmgr daemon pause</command>
|
|
||||||
(now <link linkend="repmgr-service-pause"><command>repmgr service pause</command></link>)
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<command>repmgr daemon unpause</command>
|
|
||||||
(now <link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link>)
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
<command>repmgr daemon status</command>
|
|
||||||
(now <link linkend="repmgr-service-status"><command>repmgr service status</command></link>)
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The "<command>repmgr daemon ...</command>" form will still be accepted
|
|
||||||
for backwards compatibility.
|
|
||||||
</para>
|
|
||||||
</sect3>
|
|
||||||
|
|
||||||
<sect3>
|
|
||||||
<title>Some deprecated command line options removed</title>
|
|
||||||
<para>
|
|
||||||
The following command line options, which have been deprecated since &repmgr; 3.3
|
|
||||||
(and which no longer had any effect other than to generate a warning about their use)
|
|
||||||
have been removed:
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara><option>--data-dir</option></simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara><option>--no-conninfo-password</option></simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara><option>--recovery-min-apply-delay</option></simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</sect3>
|
|
||||||
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2>
|
|
||||||
<title>General enhancements</title>
|
|
||||||
<para>
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Support for PostgreSQL 12 added.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Beginning with PostgreSQL 12, replication configuration has been integrated
|
|
||||||
into the main PostgreSQL configuraton system and the conventional
|
|
||||||
<filename>recovery.conf</filename> file is no longer valid.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
&repmgr; has been modified to be compatible with this change.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
&repmgr; additionally takes advantage of the new <command>pg_promote()</command>
|
|
||||||
function, which enables a standby to be promoted to primary using an SQL
|
|
||||||
command.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
For an overview of general changes to replication configuration, see this blog entry:
|
|
||||||
<ulink url="https://www.2ndquadrant.com/en/blog/replication-configuration-changes-in-postgresql-12/">Replication configuration changes in PostgreSQL 12</ulink>
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
The &repmgr; configuration file is now parsed using
|
|
||||||
<command>flex</command>, meaning it will be parsed in
|
|
||||||
the same way as PostgreSQL parses its own configuration
|
|
||||||
files.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This makes configuration file parsing more robust
|
|
||||||
and consistent.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
See item <link linkend="repmgr-5-0-config-file-parsing">Configuration file parsing has been made stricter</link>
|
|
||||||
for details.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<link linkend="repmgr-standby-clone"><command>repmgr standby clone</command></link>:
|
|
||||||
checks for availability of the &repmgr; extension on the upstream node have
|
|
||||||
been improved and error messages improved.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
When executing &repmgr; remotely, if the &repmgr; log level was explicitly
|
|
||||||
provided (with <option>-L</option>/<option>--log-level</option>), that log level
|
|
||||||
will be passed to the remote &repmgr;.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This makes it possible to return log output when executing repmgr
|
|
||||||
remotely at a different level to the one defined in the remote
|
|
||||||
&repmgr;'s <filename>repmgr.conf</filename>.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This is particularly useful when <literal>DEBUG</literal> output is required.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2>
|
|
||||||
<title>Bug fixes</title>
|
|
||||||
<para>
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Check role membership when trying to read <literal>pg_settings</literal>.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Previously &repmgr; assumed only superusers could read <literal>pg_settings</literal>,
|
|
||||||
but from PostgreSQL 10, all members of the roles <literal>pg_read_all_settings</literal>
|
|
||||||
or <literal>pg_monitor</literal> are permitted to do this as well.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
&repmgrd;: Fix handling of upstream node change check.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
&repmgrd; has a check to see if the upstream node has unexpectedly
|
|
||||||
changed, e.g. if the repmgrd service is paused and the PostgreSQL
|
|
||||||
instance has been pointed to another node.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
However this check was relying on the node record on the local node
|
|
||||||
being up-to-date, which may not be the case immediately after a
|
|
||||||
failover, when the node is still replaying records updated prior
|
|
||||||
to the node's own record being updated. In this case it will
|
|
||||||
mistakenly assume the node is following the original primary
|
|
||||||
and attempt to restart monitoring, which will fail as the original
|
|
||||||
primary is no longer available.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
To prevent this, the node's record on the upstream node is checked
|
|
||||||
to see if the reported upstream <literal>node_id</literal> matches
|
|
||||||
the expected <literal>node_id</literal>. GitHub #587/#588.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect2>
|
|
||||||
</sect1>
|
|
||||||
|
|
||||||
<sect1 id="release-4.4">
|
<sect1 id="release-4.4">
|
||||||
<title>Release 4.4</title>
|
<title>Release 4.4</title>
|
||||||
<para><emphasis>Thu 27 June, 2019</emphasis></para>
|
<para><emphasis>27 June, 2019</emphasis></para>
|
||||||
|
|
||||||
<para>
|
|
||||||
&repmgr; 4.4 is a major release.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
For details on how to upgrade an existing &repmgr; installation, see
|
|
||||||
documentation section <link linkend="upgrading-major-version">Upgrading a major version release</link>.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
If &repmgrd; is in use, a PostgreSQL restart <emphasis>is</emphasis> required;
|
|
||||||
in that case we suggest combining this &repmgr; upgrade with the next PostgreSQL
|
|
||||||
minor release, which will require a PostgreSQL restart in any case.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
|
|
||||||
<important>
|
|
||||||
<para>
|
|
||||||
On Debian-based systems, including Ubuntu, if using &repmgrd;
|
|
||||||
please ensure that in the file <filename>/etc/init.d/repmgrd</filename>, the parameter
|
|
||||||
<varname>REPMGRD_OPTS</varname> contains "<literal>--daemonize=false</literal>", e.g.:
|
|
||||||
<programlisting>
|
|
||||||
# additional options
|
|
||||||
REPMGRD_OPTS="--daemonize=false"</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
For further details, see <link linkend="repmgrd-configuration-debian-ubuntu">repmgrd configuration on Debian/Ubuntu</link>.
|
|
||||||
</para>
|
|
||||||
</important>
|
|
||||||
|
|
||||||
<sect2>
|
<sect2>
|
||||||
<title>repmgr client enhancements</title>
|
<title>repmgr client enhancements</title>
|
||||||
@@ -413,7 +112,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>:
|
<link linkend="repmgr-daemon-status"><command>repmgr daemon status</command></link>:
|
||||||
make output similar to that of
|
make output similar to that of
|
||||||
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>
|
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>
|
||||||
for consistency and to make it easier to identify nodes not in the expected
|
for consistency and to make it easier to identify nodes not in the expected
|
||||||
@@ -431,7 +130,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>
|
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>
|
||||||
and <link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>:
|
and <link linkend="repmgr-daemon-status"><command>repmgr daemon status</command></link>:
|
||||||
show the upstream node name as reported by each individual node - this helps visualise
|
show the upstream node name as reported by each individual node - this helps visualise
|
||||||
situations where the cluster is in an unexpected state, and provide a better idea of the
|
situations where the cluster is in an unexpected state, and provide a better idea of the
|
||||||
actual cluster state.
|
actual cluster state.
|
||||||
@@ -449,7 +148,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>
|
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>
|
||||||
and <link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>:
|
and <link linkend="repmgr-daemon-status"><command>repmgr daemon status</command></link>:
|
||||||
check if a node is attached to its advertised upstream node, and issue a
|
check if a node is attached to its advertised upstream node, and issue a
|
||||||
warning if the node is not attached.
|
warning if the node is not attached.
|
||||||
</para>
|
</para>
|
||||||
@@ -597,7 +296,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
|||||||
&repmgr; 4.3 is a major release.
|
&repmgr; 4.3 is a major release.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
For details on how to upgrade an existing &repmgr; installation, see
|
For details on how to upgrade an existing &repmgr; instrallation, see
|
||||||
documentation section <link linkend="upgrading-major-version">Upgrading a major version release</link>.
|
documentation section <link linkend="upgrading-major-version">Upgrading a major version release</link>.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
@@ -666,7 +365,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>
|
<link linkend="repmgr-daemon-status"><command>repmgr daemon status</command></link>
|
||||||
additionally displays the node priority and the interval (in seconds) since the
|
additionally displays the node priority and the interval (in seconds) since the
|
||||||
&repmgrd; instance last verified its upstream node was available.
|
&repmgrd; instance last verified its upstream node was available.
|
||||||
</para>
|
</para>
|
||||||
|
|||||||
@@ -43,12 +43,6 @@
|
|||||||
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
PostgreSQL version
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara>
|
<simpara>
|
||||||
&repmgr; version
|
&repmgr; version
|
||||||
@@ -74,18 +68,9 @@
|
|||||||
</simpara>
|
</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara>
|
<simpara>
|
||||||
PostgreSQL 11 and earlier: contents of the <filename>recovery.conf</filename> file
|
PostgreSQL version
|
||||||
(suitably anonymized if necessary).
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
PostgreSQL 12 and later: contents of the <filename>postgresql.auto.conf</filename> file
|
|
||||||
(suitably anonymized if necessary), and whether or not the PostgreSQL data directory
|
|
||||||
contains the files <filename>standby.signal</filename> and/or <filename>recovery.signal</filename>.
|
|
||||||
</simpara>
|
</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
@@ -105,8 +90,8 @@
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
In all cases it is <emphasis>extremely</emphasis> useful to receive
|
In all cases it is <emphasis>extremely</emphasis> useful to receive
|
||||||
as much detail as possible on how to reliably reproduce
|
information on how to reliably reproduce an issue with as much detail as
|
||||||
an issue.
|
possible.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|||||||
@@ -52,24 +52,6 @@
|
|||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|
||||||
<note>
|
|
||||||
<para>
|
|
||||||
Currently &repmgr;'s support for cloning from Barman is implemented by using
|
|
||||||
<productname>rsync</productname> to clone from the Barman server.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
It is therefore not able to make use of Barman's parallel restore facility, which
|
|
||||||
is executed on the Barman server and clones to the target server.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Barman's parallel restore facility can be used by executing it manually on
|
|
||||||
the Barman server and integrating the resulting cloned standby using
|
|
||||||
<command><link linkend="repmgr-standby-clone">repmgr standby clone --recovery-conf-only</link></command>.
|
|
||||||
</para>
|
|
||||||
</note>
|
|
||||||
|
|
||||||
|
|
||||||
<sect2 id="cloning-from-barman-prerequisites">
|
<sect2 id="cloning-from-barman-prerequisites">
|
||||||
<title>Prerequisites for cloning from Barman</title>
|
<title>Prerequisites for cloning from Barman</title>
|
||||||
<para>
|
<para>
|
||||||
@@ -78,7 +60,8 @@
|
|||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
the Barman catalogue must include at least one valid backup for this server;
|
the <varname>barman_server</varname> setting in <filename>repmgr.conf</filename> is the same as the
|
||||||
|
server configured in Barman;
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
@@ -89,81 +72,19 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
the <varname>barman_server</varname> setting in <filename>repmgr.conf</filename> is the same as the
|
the <varname>restore_command</varname> setting in <filename>repmgr.conf</filename> is configured to
|
||||||
server configured in Barman.
|
use a copy of the <command>barman-wal-restore</command> script shipped with the
|
||||||
|
<literal>barman-cli</literal> package (see section <xref linkend="cloning-from-barman-restore-command"/>
|
||||||
|
below).
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
the Barman catalogue includes at least one valid backup for this server.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
For example, assuming Barman is located on the host "<literal>barmansrv</literal>"
|
|
||||||
under the "<literal>barman</literal>" user account,
|
|
||||||
<filename>repmgr.conf</filename> should contain the following entries:
|
|
||||||
<programlisting>
|
|
||||||
barman_host='barman@barmansrv'
|
|
||||||
barman_server='pg'</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Here <literal>pg</literal> corresponds to a section in Barman's configuration file for a specific
|
|
||||||
server backup configuration, which would look something like:
|
|
||||||
<programlisting>
|
|
||||||
[pg]
|
|
||||||
description = "Main cluster"
|
|
||||||
...
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
More details on Barman configuration can be found in the
|
|
||||||
<ulink url="https://docs.pgbarman.org/">Barman documentation</ulink>'s
|
|
||||||
<ulink url="https://docs.pgbarman.org/#configuration">configuration section</ulink>.
|
|
||||||
</para>
|
|
||||||
<note>
|
|
||||||
<para>
|
|
||||||
To use a non-default Barman configuration file on the Barman server,
|
|
||||||
specify this in <filename>repmgr.conf</filename> with <filename>barman_config</filename>:
|
|
||||||
<programlisting>
|
|
||||||
barman_config='/path/to/barman.conf'</programlisting>
|
|
||||||
</para>
|
|
||||||
</note>
|
|
||||||
|
|
||||||
|
|
||||||
<para>
|
|
||||||
We also recommend configuring the <varname>restore_command</varname> setting in <filename>repmgr.conf</filename>
|
|
||||||
to use the <command>barman-wal-restore</command> script
|
|
||||||
(see section <xref linkend="cloning-from-barman-restore-command"/> below).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
|
|
||||||
<tip>
|
|
||||||
<simpara>
|
|
||||||
If you have a non-default SSH configuration on the Barman
|
|
||||||
server, e.g. using a port other than 22, then you can set those
|
|
||||||
parameters in a dedicated Host section in <filename>~/.ssh/config</filename>
|
|
||||||
corresponding to the value of <varname>barman_host</varname> in
|
|
||||||
<filename>repmgr.conf</filename>. See the <literal>Host</literal>
|
|
||||||
section in <command>man 5 ssh_config</command> for more details.
|
|
||||||
</simpara>
|
|
||||||
</tip>
|
|
||||||
<para>
|
|
||||||
It's now possible to clone a standby from Barman, e.g.:
|
|
||||||
<programlisting>
|
|
||||||
$ repmgr -f /etc/repmgr.conf -h node1 -U repmgr -d repmgr standby clone
|
|
||||||
NOTICE: destination directory "/var/lib/postgresql/data" provided
|
|
||||||
INFO: connecting to Barman server to verify backup for "test_cluster"
|
|
||||||
INFO: checking and correcting permissions on existing directory "/var/lib/postgresql/data"
|
|
||||||
INFO: creating directory "/var/lib/postgresql/data/repmgr"...
|
|
||||||
INFO: connecting to Barman server to fetch server parameters
|
|
||||||
INFO: connecting to source node
|
|
||||||
DETAIL: current installation size is 30 MB
|
|
||||||
NOTICE: retrieving backup from Barman...
|
|
||||||
(...)
|
|
||||||
NOTICE: standby clone (from Barman) complete
|
|
||||||
NOTICE: you can now start your PostgreSQL server
|
|
||||||
HINT: for example: pg_ctl -D /var/lib/postgresql/data start</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<simpara>
|
<simpara>
|
||||||
Barman support is automatically enabled if <varname>barman_server</varname>
|
Barman support is automatically enabled if <varname>barman_server</varname>
|
||||||
@@ -173,7 +94,37 @@ description = "Main cluster"
|
|||||||
command line option.
|
command line option.
|
||||||
</simpara>
|
</simpara>
|
||||||
</note>
|
</note>
|
||||||
|
<tip>
|
||||||
|
<simpara>
|
||||||
|
If you have a non-default SSH configuration on the Barman
|
||||||
|
server, e.g. using a port other than 22, then you can set those
|
||||||
|
parameters in a dedicated Host section in <filename>~/.ssh/config</filename>
|
||||||
|
corresponding to the value of<varname>barman_host</varname> in
|
||||||
|
<filename>repmgr.conf</filename>. See the <literal>Host</literal>
|
||||||
|
section in <command>man 5 ssh_config</command> for more details.
|
||||||
|
</simpara>
|
||||||
|
</tip>
|
||||||
|
<para>
|
||||||
|
It's now possible to clone a standby from Barman, e.g.:
|
||||||
|
<programlisting>
|
||||||
|
NOTICE: using configuration file "/etc/repmgr.conf"
|
||||||
|
NOTICE: destination directory "/var/lib/postgresql/data" provided
|
||||||
|
INFO: connecting to Barman server to verify backup for test_cluster
|
||||||
|
INFO: checking and correcting permissions on existing directory "/var/lib/postgresql/data"
|
||||||
|
INFO: creating directory "/var/lib/postgresql/data/repmgr"...
|
||||||
|
INFO: connecting to Barman server to fetch server parameters
|
||||||
|
INFO: connecting to upstream node
|
||||||
|
INFO: connected to source node, checking its state
|
||||||
|
INFO: successfully connected to source node
|
||||||
|
DETAIL: current installation size is 29 MB
|
||||||
|
NOTICE: retrieving backup from Barman...
|
||||||
|
receiving file list ...
|
||||||
|
(...)
|
||||||
|
NOTICE: standby clone (from Barman) complete
|
||||||
|
NOTICE: you can now start your PostgreSQL server
|
||||||
|
HINT: for example: pg_ctl -D /var/lib/postgresql/data start</programlisting>
|
||||||
|
|
||||||
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
<sect2 id="cloning-from-barman-restore-command" xreflabel="Using Barman as a WAL file source">
|
<sect2 id="cloning-from-barman-restore-command" xreflabel="Using Barman as a WAL file source">
|
||||||
<title>Using Barman as a WAL file source</title>
|
<title>Using Barman as a WAL file source</title>
|
||||||
@@ -191,28 +142,35 @@ description = "Main cluster"
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
<command>barman-wal-restore</command> is a Python script provided as part of the <literal>barman-cli</literal>
|
<command>barman-wal-restore</command> is a Python script provided as part of the <literal>barman-cli</literal>
|
||||||
package (Barman 2.0 ~ 2.7) or as part of the core Barman distribution (Barman 2.8 and later).
|
package (Barman 2.0 and later; for Barman 1.x the script is provided separately as
|
||||||
|
<command>barman-wal-restore.py</command>) which performs this function for Barman.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To use <command>barman-wal-restore</command> with &repmgr;,
|
To use <command>barman-wal-restore</command> with &repmgr;
|
||||||
assuming Barman is located on the host "<literal>barmansrv</literal>"
|
and assuming Barman is located on the <literal>barmansrv</literal> host
|
||||||
under the "<literal>barman</literal>" user account,
|
|
||||||
and that <command>barman-wal-restore</command> is located as an executable at
|
and that <command>barman-wal-restore</command> is located as an executable at
|
||||||
<filename>/usr/bin/barman-wal-restore</filename>,
|
<filename>/usr/bin/barman-wal-restore</filename>,
|
||||||
<filename>repmgr.conf</filename> should include the following lines:
|
<filename>repmgr.conf</filename> should include the following lines:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
barman_host='barman@barmansrv'
|
barman_host=barmansrv
|
||||||
barman_server='pg'
|
barman_server=somedb
|
||||||
restore_command='/usr/bin/barman-wal-restore barmansrv pg %f %p'</programlisting>
|
restore_command=/usr/bin/barman-wal-restore barmansrv somedb %f %p</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<note>
|
<note>
|
||||||
<simpara>
|
<simpara>
|
||||||
<command>barman-wal-restore</command> supports command line switches to
|
<command>barman-wal-restore</command> supports command line switches to
|
||||||
control parallelism (<literal>--parallel=N</literal>) and compression
|
control parallelism (<literal>--parallel=N</literal>) and compression (
|
||||||
(<literal>--bzip2</literal>, <literal>--gzip</literal>).
|
<literal>--bzip2</literal>, <literal>--gzip</literal>).
|
||||||
</simpara>
|
</simpara>
|
||||||
</note>
|
</note>
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
To use a non-default Barman configuration file on the Barman server,
|
||||||
|
specify this in <filename>repmgr.conf</filename> with <filename>barman_config</filename>:
|
||||||
|
<programlisting>
|
||||||
|
barman_config=/path/to/barman.conf</programlisting>
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
</sect2>
|
</sect2>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@@ -457,8 +415,10 @@ description = "Main cluster"
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
The recommended way to do this is to store the password in the <literal>postgres</literal> system
|
The recommended way to do this is to store the password in the <literal>postgres</literal> system
|
||||||
user's <filename>~/.pgpass</filename> file. For more information on using the password file, see
|
user's <filename>~/.pgpass</filename> file. It's also possible to store the password in the
|
||||||
the documentation section <xref linkend="configuration-password-file"/>.
|
environment variable <varname>PGPASSWORD</varname>, however this is not recommended for
|
||||||
|
security reasons. For more details see the
|
||||||
|
<ulink url="https://www.postgresql.org/docs/current/libpq-pgpass.html">PostgreSQL password file documentation</ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
@@ -480,6 +440,19 @@ description = "Main cluster"
|
|||||||
will need to be set during any action which causes <filename>recovery.conf</filename> to be
|
will need to be set during any action which causes <filename>recovery.conf</filename> to be
|
||||||
rewritten, e.g. <xref linkend="repmgr-standby-follow"/>.
|
rewritten, e.g. <xref linkend="repmgr-standby-follow"/>.
|
||||||
</para>
|
</para>
|
||||||
|
<para>
|
||||||
|
It is of course also possible to include the password value in the <varname>conninfo</varname>
|
||||||
|
string for each node, but this is obviously a security risk and should be avoided.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
From PostgreSQL 9.6, <application>libpq</application> supports the <varname>passfile</varname>
|
||||||
|
parameter in connection strings, which can be used to specify a password file other than
|
||||||
|
the default <filename>~/.pgpass</filename>.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
To have &repmgr; write a custom password file in <varname>primary_conninfo</varname>,
|
||||||
|
specify its location in <varname>passfile</varname> in <filename>repmgr.conf</filename>.
|
||||||
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="cloning-advanced-replication-user" xreflabel="Separate replication user">
|
<sect2 id="cloning-advanced-replication-user" xreflabel="Separate replication user">
|
||||||
@@ -495,34 +468,6 @@ description = "Main cluster"
|
|||||||
cloning a node or executing <xref linkend="repmgr-standby-follow"/>.
|
cloning a node or executing <xref linkend="repmgr-standby-follow"/>.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|
||||||
<sect2 id="cloning-advanced-tablespace-mapping" xreflabel="Tablespace mapping">
|
|
||||||
<title>Tablespace mapping</title>
|
|
||||||
<indexterm>
|
|
||||||
<primary>tablespace mapping</primary>
|
|
||||||
</indexterm>
|
|
||||||
<para>
|
|
||||||
&repmgr; provides a <option>tablespace_mapping</option> configuration
|
|
||||||
file option, which will makes it possible to map the tablespace on the source node to
|
|
||||||
a different location on the local node.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
To use this, add <option>tablespace_mapping</option> to <filename>repmgr.conf</filename>
|
|
||||||
like this:
|
|
||||||
<programlisting>
|
|
||||||
tablespace_mapping='/var/lib/pgsql/tblspc1=/data/pgsql/tblspc1'
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
where the left-hand value represents the tablespace on the source node,
|
|
||||||
and the right-hand value represents the tablespace on the standby to be cloned.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This parameter can be provided multiple times.
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -119,27 +119,6 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="repmgr-conf-ssh-options" xreflabel="ssh_options">
|
|
||||||
<term><varname>ssh_options</varname> (<type>string</type>)
|
|
||||||
<indexterm>
|
|
||||||
<primary><varname>ssh_options</varname> configuration file parameter</primary>
|
|
||||||
</indexterm>
|
|
||||||
</term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Options to append to the <command>ssh</command> command when executed
|
|
||||||
by &repmgr;.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
We recommend adding <literal>-q</literal> to suppress any superfluous
|
|
||||||
SSH chatter such as login banners, and also an explicit
|
|
||||||
<option>ConnectTimeout</option> value,
|
|
||||||
e.g.:
|
|
||||||
<programlisting>
|
|
||||||
ssh_options='-q -o ConnectTimeout=10'</programlisting>
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|||||||
@@ -31,8 +31,6 @@
|
|||||||
<secondary>format</secondary>
|
<secondary>format</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<filename>repmgr.conf</filename> is a plain text file with one parameter/value
|
<filename>repmgr.conf</filename> is a plain text file with one parameter/value
|
||||||
combination per line.
|
combination per line.
|
||||||
@@ -41,10 +39,14 @@
|
|||||||
Whitespace is insignificant (except within a quoted parameter value) and blank lines are ignored.
|
Whitespace is insignificant (except within a quoted parameter value) and blank lines are ignored.
|
||||||
Hash marks (<literal>#</literal>) designate the remainder of the line as a comment.
|
Hash marks (<literal>#</literal>) designate the remainder of the line as a comment.
|
||||||
Parameter values that are not simple identifiers or numbers should be single-quoted.
|
Parameter values that are not simple identifiers or numbers should be single-quoted.
|
||||||
|
Note that single quote cannot be embedded in a parameter value.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<important>
|
||||||
To embed a single quote in a parameter value, write either two quotes (preferred) or backslash-quote.
|
<para>
|
||||||
</para>
|
&repmgr; will interpret double-quotes as being part of a string value; only use single quotes
|
||||||
|
to quote parameter values.
|
||||||
|
</para>
|
||||||
|
</important>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Example of a valid <filename>repmgr.conf</filename> file:
|
Example of a valid <filename>repmgr.conf</filename> file:
|
||||||
@@ -54,32 +56,9 @@
|
|||||||
node_id=1
|
node_id=1
|
||||||
node_name= node1
|
node_name= node1
|
||||||
conninfo ='host=node1 dbname=repmgr user=repmgr connect_timeout=2'
|
conninfo ='host=node1 dbname=repmgr user=repmgr connect_timeout=2'
|
||||||
data_directory = '/var/lib/pgsql/12/data'</programlisting>
|
data_directory = /var/lib/pgsql/11/data</programlisting>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
|
||||||
<para>
|
|
||||||
Beginning with <link linkend="release-5.0">repmgr 5.0</link>, configuration
|
|
||||||
file parsing has been tightened up and now matches the way PostgreSQL
|
|
||||||
itself parses configuration files.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
This means <filename>repmgr.conf</filename> files used with earlier &repmgr;
|
|
||||||
versions may need slight modification before they can be used with &repmgr; 5
|
|
||||||
and later.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The main change is that &repmgr; requires most string values to be
|
|
||||||
enclosed in single quotes. For example, this was previously valid:
|
|
||||||
<programlisting>
|
|
||||||
conninfo=host=node1 user=repmgr dbname=repmgr connect_timeout=2</programlisting>
|
|
||||||
but must now be changed to:
|
|
||||||
<programlisting>
|
|
||||||
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'</programlisting>
|
|
||||||
</para>
|
|
||||||
</note>
|
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,147 +0,0 @@
|
|||||||
<sect1 id="configuration-password-management" xreflabel="password management">
|
|
||||||
|
|
||||||
<title>Password Management</title>
|
|
||||||
<indexterm>
|
|
||||||
<primary>passwords</primary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<sect2 id="configuration-password-management-options" xreflabel="password management options">
|
|
||||||
<title>Password Management Options</title>
|
|
||||||
<indexterm>
|
|
||||||
<primary>passwords</primary>
|
|
||||||
<secondary>options for managing</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
For security purposes it's desirable to protect database access using a password.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
PostgreSQL has three ways of providing a password:
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
including the password in the <option>conninfo</option> string
|
|
||||||
(e.g. "<literal>host=node1 dbname=repmgr user=repmgr password=foo</literal>")
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
exporting the password as an environment variable (<envar>PGPASSWORD</envar>)
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara>
|
|
||||||
storing the password in a dedicated password file
|
|
||||||
</simpara>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
We strongly advise against including the password in the <option>conninfo</option> string, as
|
|
||||||
this will result in the database password being exposed in various places, including in the
|
|
||||||
<filename>repmgr.conf</filename> file, the <literal>repmgr.nodes</literal> table, any output
|
|
||||||
generated by &repmgr; which lists the node <option>conninfo</option> strings (e.g.
|
|
||||||
<link linkend="repmgr-cluster-show">repmgr cluster show</link>) and in the &repmgr; log file,
|
|
||||||
particularly at <option>log_level=DEBUG</option>.
|
|
||||||
</para>
|
|
||||||
<note>
|
|
||||||
<para>
|
|
||||||
Currently &repmgr; does not fully support use of the <option>password</option> option in the
|
|
||||||
<option>conninfo</option> string.
|
|
||||||
</para>
|
|
||||||
</note>
|
|
||||||
<para>
|
|
||||||
Exporting the password as an environment variable (<envar>PGPASSWORD</envar>) is considered
|
|
||||||
less insecure, but the PostgreSQL documentation explicitly recommends against doing this:
|
|
||||||
<blockquote>
|
|
||||||
<attribution><ulink url="https://www.postgresql.org/docs/current/libpq-envars.html">Environment Variables</ulink></attribution>
|
|
||||||
<para>
|
|
||||||
<envar>PGPASSWORD</envar> behaves the same as the <option>password</option>
|
|
||||||
connection parameter. Use of this environment variable
|
|
||||||
is not recommended for security reasons, as some operating systems
|
|
||||||
allow non-root users to see process environment variables via
|
|
||||||
<application>ps</application>; instead consider using a password file.
|
|
||||||
</para>
|
|
||||||
</blockquote>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The most secure option for managing passwords is to use a dedicated password file; see the following
|
|
||||||
section for more details.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2 id="configuration-password-file" xreflabel="password file">
|
|
||||||
<title>Using a password file</title>
|
|
||||||
<indexterm>
|
|
||||||
<primary>pgpass</primary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<indexterm>
|
|
||||||
<primary>.pgpass</primary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<indexterm>
|
|
||||||
<primary>passwords</primary>
|
|
||||||
<secondary>using a password file</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
The most secure way of storing passwords is in a password file,
|
|
||||||
which by default is <filename>~/.pgpass</filename>. This file
|
|
||||||
can only be read by the system user who owns the file, and
|
|
||||||
PostgreSQL will refuse to use the file unless read/write
|
|
||||||
permissions are restricted to the file owner. The password(s)
|
|
||||||
contained in the file will not be directly accessed by
|
|
||||||
&repmgr; (or any other libpq-based client software such as <application>psql</application>).
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
For full details see the
|
|
||||||
<ulink url="https://www.postgresql.org/docs/current/libpq-pgpass.html">PostgreSQL password file documentation</ulink>.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
For use with &repmgr;, the <filename>~/.pgpass</filename> must two entries for each
|
|
||||||
node in the replication cluster: one for the &repmgr; user who accesses the &repmgr; metadatabase,
|
|
||||||
and one for replication connections (regardless of whether a dedicated replication user is used).
|
|
||||||
The file must be present on each node in the replication cluster.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
A <filename>~/.pgpass</filename> file for a 3-node cluster where the <literal>repmgr</literal> database user
|
|
||||||
is used for both for accessing the &repmgr; metadatabase and for replication connections would look like this:
|
|
||||||
<programlisting>
|
|
||||||
node1:5432:repmgr:repmgr:foo
|
|
||||||
node1:5432:replication:repmgr:foo
|
|
||||||
node2:5432:repmgr:repmgr:foo
|
|
||||||
node2:5432:replication:repmgr:foo
|
|
||||||
node3:5432:repmgr:repmgr:foo
|
|
||||||
node3:5432:replication:repmgr:foo</programlisting>
|
|
||||||
If a dedicated replication user (here: <literal>repluser</literal>) is in use, the file would look like this:
|
|
||||||
<programlisting>
|
|
||||||
node1:5432:repmgr:repmgr:foo
|
|
||||||
node1:5432:replication:repluser:foo
|
|
||||||
node2:5432:repmgr:repmgr:foo
|
|
||||||
node2:5432:replication:repluser:foo
|
|
||||||
node3:5432:repmgr:repmgr:foo
|
|
||||||
node3:5432:replication:repluser:foo</programlisting>
|
|
||||||
|
|
||||||
</para>
|
|
||||||
<note>
|
|
||||||
<para>
|
|
||||||
It's possible to specify an alternative location for the <filename>~/.pgpass</filename> file, either via
|
|
||||||
the environment variable <envar>PGPASSFILE</envar>, or (from PostgreSQL 9.6) using the
|
|
||||||
<varname>passfile</varname> parameter in connection strings.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
If using the <varname>passfile</varname> parameter, it's essential to ensure the file is in the same
|
|
||||||
location on all nodes, as when connecting to a remote node, the file referenced is the one on the
|
|
||||||
local node.
|
|
||||||
</para>
|
|
||||||
</note>
|
|
||||||
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
</sect1>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<sect1 id="configuration-permissions" xreflabel="Database user permissions">
|
|
||||||
<title>repmgr database user permissions</title>
|
|
||||||
|
|
||||||
<indexterm>
|
|
||||||
<primary>configuration</primary>
|
|
||||||
<secondary>database user permissions</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
&repmgr; requires that the database defined in the <varname>conninfo</varname>
|
|
||||||
setting contains the <literal>repmgr</literal> extension. The database user defined in the
|
|
||||||
<varname>conninfo</varname> setting must be able to access this database and
|
|
||||||
the database objects contained within the extension.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The <literal>repmgr</literal> extension can only be installed by a superuser.
|
|
||||||
If the &repmgr; user is a superuser, &repmgr; will create the extension automatically.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Alternatively, the extension can be created manually by a superuser
|
|
||||||
(with "<command>CREATE EXTENSION repmgr</command>") before executing
|
|
||||||
<link linkend="repmgr-primary-register">repmgr primary register</link>.
|
|
||||||
</para>
|
|
||||||
</sect1>
|
|
||||||
@@ -148,19 +148,9 @@
|
|||||||
instances in the replication cluster which may potentially become a primary server or
|
instances in the replication cluster which may potentially become a primary server or
|
||||||
(in cascading replication) the upstream server of a standby.
|
(in cascading replication) the upstream server of a standby.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
PostgreSQL documentation: <ulink url="https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-MAX-WAL-SENDERS">max_wal_senders</ulink>.
|
PostgreSQL documentation: <ulink url="https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-MAX-WAL-SENDERS">max_wal_senders</ulink>.
|
||||||
</para>
|
</para>
|
||||||
<note>
|
|
||||||
<para>
|
|
||||||
From <productname>PostgreSQL 12</productname>, <option>max_wal_senders</option>
|
|
||||||
<emphasis>must</emphasis> be set to the same or a higher value as the primary node
|
|
||||||
(at the time the node was cloned), otherwise the standby will refuse
|
|
||||||
to start (unless <option>hot_standby</option> is set to <literal>off</literal>, which
|
|
||||||
will prevent the node from accepting queries).
|
|
||||||
</para>
|
|
||||||
</note>
|
|
||||||
|
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
@@ -318,7 +308,23 @@
|
|||||||
&configuration-file-optional-settings;
|
&configuration-file-optional-settings;
|
||||||
&configuration-file-log-settings;
|
&configuration-file-log-settings;
|
||||||
&configuration-file-service-commands;
|
&configuration-file-service-commands;
|
||||||
&configuration-permissions;
|
|
||||||
&configuration-password-management;
|
|
||||||
|
|
||||||
|
<sect1 id="configuration-permissions" xreflabel="Database user permissions">
|
||||||
|
<title>repmgr database user permissions</title>
|
||||||
|
|
||||||
|
<indexterm>
|
||||||
|
<primary>configuration</primary>
|
||||||
|
<secondary>database user permissions</secondary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
&repmgr; will create an extension database containing objects
|
||||||
|
for administering &repmgr; metadata. The user defined in the <varname>conninfo</varname>
|
||||||
|
setting must be able to access all objects. Additionally, superuser permissions
|
||||||
|
are required to install the &repmgr; extension. The easiest way to do this
|
||||||
|
is create the &repmgr; user as a superuser, however if this is not
|
||||||
|
desirable, the &repmgr; user can be created as a normal user and a
|
||||||
|
superuser specified with <literal>--superuser</literal> when registering a &repmgr; node.
|
||||||
|
</para>
|
||||||
|
</sect1>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|||||||
@@ -148,7 +148,7 @@
|
|||||||
the notification types can be filtered to explicitly named ones using the
|
the notification types can be filtered to explicitly named ones using the
|
||||||
<varname>event_notifications</varname> parameter, e.g.:
|
<varname>event_notifications</varname> parameter, e.g.:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
event_notifications='primary_register,standby_register,witness_register'</programlisting>
|
event_notifications=primary_register,standby_register,witness_register</programlisting>
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,6 @@
|
|||||||
<!ENTITY configuration-file-optional-settings SYSTEM "configuration-file-optional-settings.xml">
|
<!ENTITY configuration-file-optional-settings SYSTEM "configuration-file-optional-settings.xml">
|
||||||
<!ENTITY configuration-file-log-settings SYSTEM "configuration-file-log-settings.xml">
|
<!ENTITY configuration-file-log-settings SYSTEM "configuration-file-log-settings.xml">
|
||||||
<!ENTITY configuration-file-service-commands SYSTEM "configuration-file-service-commands.xml">
|
<!ENTITY configuration-file-service-commands SYSTEM "configuration-file-service-commands.xml">
|
||||||
<!ENTITY configuration-permissions SYSTEM "configuration-permissions.xml">
|
|
||||||
<!ENTITY configuration-password-management SYSTEM "configuration-password-management.xml">
|
|
||||||
<!ENTITY cloning-standbys SYSTEM "cloning-standbys.xml">
|
<!ENTITY cloning-standbys SYSTEM "cloning-standbys.xml">
|
||||||
<!ENTITY promoting-standby SYSTEM "promoting-standby.xml">
|
<!ENTITY promoting-standby SYSTEM "promoting-standby.xml">
|
||||||
<!ENTITY follow-new-primary SYSTEM "follow-new-primary.xml">
|
<!ENTITY follow-new-primary SYSTEM "follow-new-primary.xml">
|
||||||
@@ -56,11 +54,11 @@
|
|||||||
<!ENTITY repmgr-cluster-crosscheck SYSTEM "repmgr-cluster-crosscheck.xml">
|
<!ENTITY repmgr-cluster-crosscheck SYSTEM "repmgr-cluster-crosscheck.xml">
|
||||||
<!ENTITY repmgr-cluster-event SYSTEM "repmgr-cluster-event.xml">
|
<!ENTITY repmgr-cluster-event SYSTEM "repmgr-cluster-event.xml">
|
||||||
<!ENTITY repmgr-cluster-cleanup SYSTEM "repmgr-cluster-cleanup.xml">
|
<!ENTITY repmgr-cluster-cleanup SYSTEM "repmgr-cluster-cleanup.xml">
|
||||||
<!ENTITY repmgr-service-status SYSTEM "repmgr-service-status.xml">
|
<!ENTITY repmgr-daemon-status SYSTEM "repmgr-daemon-status.xml">
|
||||||
<!ENTITY repmgr-service-pause SYSTEM "repmgr-service-pause.xml">
|
|
||||||
<!ENTITY repmgr-service-unpause SYSTEM "repmgr-service-unpause.xml">
|
|
||||||
<!ENTITY repmgr-daemon-start SYSTEM "repmgr-daemon-start.xml">
|
<!ENTITY repmgr-daemon-start SYSTEM "repmgr-daemon-start.xml">
|
||||||
<!ENTITY repmgr-daemon-stop SYSTEM "repmgr-daemon-stop.xml">
|
<!ENTITY repmgr-daemon-stop SYSTEM "repmgr-daemon-stop.xml">
|
||||||
|
<!ENTITY repmgr-daemon-pause SYSTEM "repmgr-daemon-pause.xml">
|
||||||
|
<!ENTITY repmgr-daemon-unpause SYSTEM "repmgr-daemon-unpause.xml">
|
||||||
|
|
||||||
<!ENTITY appendix-release-notes SYSTEM "appendix-release-notes.xml">
|
<!ENTITY appendix-release-notes SYSTEM "appendix-release-notes.xml">
|
||||||
<!ENTITY appendix-faq SYSTEM "appendix-faq.xml">
|
<!ENTITY appendix-faq SYSTEM "appendix-faq.xml">
|
||||||
|
|||||||
@@ -26,18 +26,10 @@
|
|||||||
<ulink url="https://dl.2ndquadrant.com/">public repository</ulink>; see following
|
<ulink url="https://dl.2ndquadrant.com/">public repository</ulink>; see following
|
||||||
section for details.
|
section for details.
|
||||||
</para>
|
</para>
|
||||||
<note>
|
|
||||||
<para>
|
|
||||||
Currently the <ulink url="https://2ndquadrant.com">2ndQuadrant</ulink>
|
|
||||||
<ulink url="https://dl.2ndquadrant.com/">public repository</ulink> provides
|
|
||||||
support for RedHat/CentOS versions 5, 6 and 7. Support for version 8 is
|
|
||||||
available via the PGDG repository; see below for details.
|
|
||||||
</para>
|
|
||||||
</note>
|
|
||||||
<para>
|
<para>
|
||||||
RPM packages for &repmgr; are also available via Yum through
|
RPM packages for &repmgr; are also available via Yum through
|
||||||
the PostgreSQL Global Development Group (PGDG) RPM repository
|
the PostgreSQL Global Development Group RPM repository
|
||||||
(<ulink url="https://yum.postgresql.org/">https://yum.postgresql.org/</ulink>).
|
(<ulink url="https://yum.postgresql.org/">http://yum.postgresql.org/</ulink>).
|
||||||
Follow the instructions for your distribution (RedHat, CentOS,
|
Follow the instructions for your distribution (RedHat, CentOS,
|
||||||
Fedora, etc.) and architecture as detailed there. Note that it can take some days
|
Fedora, etc.) and architecture as detailed there. Note that it can take some days
|
||||||
for new &repmgr; packages to become available via the this repository.
|
for new &repmgr; packages to become available via the this repository.
|
||||||
@@ -50,10 +42,6 @@
|
|||||||
customers, as the PostgreSQL filesystem layout may be different to the community RPMs.
|
customers, as the PostgreSQL filesystem layout may be different to the community RPMs.
|
||||||
Please contact your support vendor for assistance.
|
Please contact your support vendor for assistance.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
See also <link linkend="appendix-faq">FAQ</link> entry
|
|
||||||
<xref linkend="faq-third-party-packages"/>.
|
|
||||||
</para>
|
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -93,9 +81,9 @@
|
|||||||
(this enables the 2ndQuadrant repository as a source of &repmgr; packages).
|
(this enables the 2ndQuadrant repository as a source of &repmgr; packages).
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
For example, for PostgreSQL 11 on CentOS, execute:
|
For example, for PostgreSQL 10 on CentOS, execute:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
curl https://dl.2ndquadrant.com/default/release/get/11/rpm | sudo bash</programlisting>
|
curl https://dl.2ndquadrant.com/default/release/get/10/rpm | sudo bash</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -111,8 +99,8 @@ curl https://dl.2ndquadrant.com/default/release/get/9.6/rpm | sudo bash</program
|
|||||||
sudo yum repolist</programlisting>
|
sudo yum repolist</programlisting>
|
||||||
The output should contain two entries like this:
|
The output should contain two entries like this:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
2ndquadrant-dl-default-release-pg11/7/x86_64 2ndQuadrant packages (PG11) for 7 - x86_64 18
|
2ndquadrant-dl-default-release-pg10/7/x86_64 2ndQuadrant packages (PG10) for 7 - x86_64 4
|
||||||
2ndquadrant-dl-default-release-pg11-debug/7/x86_64 2ndQuadrant packages (PG11) for 7 - x86_64 - Debug 8</programlisting>
|
2ndquadrant-dl-default-release-pg10-debug/7/x86_64 2ndQuadrant packages (PG10) for 7 - x86_64 - Debug 3</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
@@ -120,7 +108,7 @@ sudo yum repolist</programlisting>
|
|||||||
<para>
|
<para>
|
||||||
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
|
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
|
||||||
<programlisting>
|
<programlisting>
|
||||||
sudo yum install repmgr11</programlisting>
|
sudo yum install repmgr10</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
@@ -165,23 +153,19 @@ yum search repmgr</programlisting>
|
|||||||
To install a specific package version, execute <command>yum --showduplicates list</command>
|
To install a specific package version, execute <command>yum --showduplicates list</command>
|
||||||
for the package in question:
|
for the package in question:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[root@localhost ~]# yum --showduplicates list repmgr11
|
[root@localhost ~]# yum --showduplicates list repmgr10
|
||||||
Loaded plugins: fastestmirror
|
Loaded plugins: fastestmirror
|
||||||
Loading mirror speeds from cached hostfile
|
Loading mirror speeds from cached hostfile
|
||||||
* base: ftp.tsukuba.wide.ad.jp
|
* base: ftp.iij.ad.jp
|
||||||
* epel: nrt.edge.kernel.org
|
* extras: ftp.iij.ad.jp
|
||||||
* extras: ftp.tsukuba.wide.ad.jp
|
* updates: ftp.iij.ad.jp
|
||||||
* updates: ftp.tsukuba.wide.ad.jp
|
Available Packages
|
||||||
Installed Packages
|
repmgr10.x86_64 4.0.3-1.rhel7 pgdg10
|
||||||
repmgr11.x86_64 4.4.0-1.rhel7 @pgdg11
|
repmgr10.x86_64 4.0.4-1.rhel7 pgdg10
|
||||||
Available Packages
|
repmgr10.x86_64 4.0.5-1.el7 2ndquadrant-repo-10</programlisting>
|
||||||
repmgr11.x86_64 4.2-1.el7 2ndquadrant-dl-default-release-pg11
|
|
||||||
repmgr11.x86_64 4.2-2.el7 2ndquadrant-dl-default-release-pg11
|
|
||||||
repmgr11.x86_64 4.3-1.el7 2ndquadrant-dl-default-release-pg11
|
|
||||||
repmgr11.x86_64 4.4-1.el7 2ndquadrant-dl-default-release-pg11</programlisting>
|
|
||||||
then append the appropriate version number to the package name with a hyphen, e.g.:
|
then append the appropriate version number to the package name with a hyphen, e.g.:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[root@localhost ~]# yum install repmgr11-4.3-1.el7</programlisting>
|
[root@localhost ~]# yum install repmgr10-4.0.3-1.rhel7</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -206,7 +190,7 @@ repmgr11.x86_64 4.4-1.el7 2nd
|
|||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>.deb packages for &repmgr; are available from the
|
<para>.deb packages for &repmgr; are available from the
|
||||||
PostgreSQL Community APT repository (<ulink url="https://apt.postgresql.org/">https://apt.postgresql.org/</ulink>).
|
PostgreSQL Community APT repository (<ulink url="http://apt.postgresql.org/">http://apt.postgresql.org/</ulink>).
|
||||||
Instructions can be found in the APT section of the PostgreSQL Wiki
|
Instructions can be found in the APT section of the PostgreSQL Wiki
|
||||||
(<ulink url="https://wiki.postgresql.org/wiki/Apt">https://wiki.postgresql.org/wiki/Apt</ulink>).
|
(<ulink url="https://wiki.postgresql.org/wiki/Apt">https://wiki.postgresql.org/wiki/Apt</ulink>).
|
||||||
</para>
|
</para>
|
||||||
@@ -236,13 +220,13 @@ repmgr11.x86_64 4.4-1.el7 2nd
|
|||||||
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Install the repository definition for your distribution and PostgreSQL version
|
Install the repository definition for your distribution and PostgreSQL version
|
||||||
(this enables the 2ndQuadrant repository as a source of &repmgr; packages) by executing:
|
(this enables the 2ndQuadrant repository as a source of &repmgr; packages) by executing:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
curl https://dl.2ndquadrant.com/default/release/get/deb | sudo bash</programlisting>
|
curl https://dl.2ndquadrant.com/default/release/get/deb | sudo bash</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
This will automatically install the following additional packages, if not already present:
|
This will automatically install the following additional packages, if not already present:
|
||||||
@@ -258,20 +242,20 @@ repmgr11.x86_64 4.4-1.el7 2nd
|
|||||||
</note>
|
</note>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr11</literal>):
|
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
|
||||||
<programlisting>
|
<programlisting>
|
||||||
sudo apt-get install postgresql-11-repmgr</programlisting>
|
sudo apt-get install postgresql-10-repmgr</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
For packages for PostgreSQL 9.6 and earlier, the package name includes
|
For packages for PostgreSQL 9.6 and earlier, the package name includes
|
||||||
a period between major and minor version numbers, e.g.
|
a period between major and minor version numbers, e.g.
|
||||||
<literal>postgresql-9.6-repmgr</literal>.
|
<literal>postgresql-9.6-repmgr</literal>.
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
&repmgr; &repmgrversion; is compatible with all PostgreSQL versions from 9.3. See
|
&repmgr; 4.x is compatible with all PostgreSQL versions from 9.3. See
|
||||||
section <link linkend="install-compatibility-matrix">&repmgr; compatibility matrix</link>
|
section <link linkend="install-compatibility-matrix">&repmgr; compatibility matrix</link>
|
||||||
for an overview of version compatibility.
|
for an overview of version compatibility.
|
||||||
</para>
|
</para>
|
||||||
@@ -39,13 +39,13 @@
|
|||||||
|
|
||||||
<note>
|
<note>
|
||||||
<simpara>
|
<simpara>
|
||||||
The same "major" &repmgr; version (e.g. <literal>&repmgrversion;.x</literal>) <emphasis>must</emphasis>
|
The same "major" &repmgr; version (e.g. <literal>4.2.x</literal>) <emphasis>must</emphasis>
|
||||||
be installed on all node in the replication cluster. We strongly recommend keeping all
|
be installed on all node in the replication cluster. We strongly recommend keeping all
|
||||||
nodes on the same (preferably latest) "minor" &repmgr; version to minimize the risk
|
nodes on the same (preferably latest) "minor" &repmgr; version to minimize the risk
|
||||||
of incompatibilities.
|
of incompatibilities.
|
||||||
</simpara>
|
</simpara>
|
||||||
<simpara>
|
<simpara>
|
||||||
If different "major" &repmgr; versions (e.g. 4.1.x and &repmgrversion;.x)
|
If different "major" &repmgr; versions (e.g. 3.3.x and 4.1.x)
|
||||||
are installed on different nodes, in the best case &repmgr; (in particular &repmgrd;)
|
are installed on different nodes, in the best case &repmgr; (in particular &repmgrd;)
|
||||||
will not run. In the worst case, you will end up with a broken cluster.
|
will not run. In the worst case, you will end up with a broken cluster.
|
||||||
</simpara>
|
</simpara>
|
||||||
@@ -99,9 +99,6 @@
|
|||||||
<entry>
|
<entry>
|
||||||
&repmgr; version
|
&repmgr; version
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
|
||||||
Supported?
|
|
||||||
</entry>
|
|
||||||
<entry>
|
<entry>
|
||||||
Latest release
|
Latest release
|
||||||
</entry>
|
</entry>
|
||||||
@@ -112,31 +109,12 @@
|
|||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
||||||
<row>
|
|
||||||
<entry>
|
|
||||||
&repmgr; 5.x
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
YES
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
<link linkend="release-current">&repmgrversion;</link> (&releasedate;)
|
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
9.3, 9.4, 9.5, 9.6, 10, 11, 12
|
|
||||||
</entry>
|
|
||||||
</row>
|
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry>
|
<entry>
|
||||||
&repmgr; 4.x
|
&repmgr; 4.x
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
NO
|
<link linkend="release-4.2">4.2</link> (2018-10-24)
|
||||||
</entry>
|
|
||||||
<entry>
|
|
||||||
<link linkend="release-4.4">4.4</link> (2019-06-27)
|
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
9.3, 9.4, 9.5, 9.6, 10, 11
|
9.3, 9.4, 9.5, 9.6, 10, 11
|
||||||
@@ -147,9 +125,6 @@
|
|||||||
<entry>
|
<entry>
|
||||||
&repmgr; 3.x
|
&repmgr; 3.x
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
|
||||||
NO
|
|
||||||
</entry>
|
|
||||||
<entry>
|
<entry>
|
||||||
<ulink url="https://repmgr.org/release-notes-3.3.2.html">3.3.2</ulink> (2017-05-30)
|
<ulink url="https://repmgr.org/release-notes-3.3.2.html">3.3.2</ulink> (2017-05-30)
|
||||||
</entry>
|
</entry>
|
||||||
@@ -162,9 +137,6 @@
|
|||||||
<entry>
|
<entry>
|
||||||
&repmgr; 2.x
|
&repmgr; 2.x
|
||||||
</entry>
|
</entry>
|
||||||
<entry>
|
|
||||||
NO
|
|
||||||
</entry>
|
|
||||||
<entry>
|
<entry>
|
||||||
<ulink url="https://repmgr.org/release-notes-2.0.3.html">2.0.3</ulink> (2015-04-16)
|
<ulink url="https://repmgr.org/release-notes-2.0.3.html">2.0.3</ulink> (2015-04-16)
|
||||||
</entry>
|
</entry>
|
||||||
@@ -182,26 +154,11 @@
|
|||||||
The &repmgr; 2.x and 3.x series are no longer maintained or supported.
|
The &repmgr; 2.x and 3.x series are no longer maintained or supported.
|
||||||
We strongly recommend upgrading to the latest &repmgr; version.
|
We strongly recommend upgrading to the latest &repmgr; version.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
Following the release of &repmgr; 5.0, there will be no further releases of
|
|
||||||
the &repmgr; 4.x series. Note that &repmgr; 5.x is an incremental development
|
|
||||||
of the 4.x series and &repmgr; 4.x users should upgrade to this as soon as possible.
|
|
||||||
</para>
|
|
||||||
</important>
|
</important>
|
||||||
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2 id="install-postgresql-93-94">
|
|
||||||
|
|
||||||
<title>PostgreSQL 9.3 and 9.4 support</title>
|
|
||||||
|
|
||||||
<indexterm>
|
|
||||||
<primary>PostgreSQL 9.3</primary>
|
|
||||||
<secondary>repmgr support</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Note that some &repmgr; functionality is not available in PostgreSQL 9.3 and PostgreSQL 9.4:
|
Note that some &repmgr; functionality is not available in PostgreSQL 9.3 and PostgreSQL 9.4.
|
||||||
</para>
|
</para>
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
|
|
||||||
@@ -220,26 +177,5 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<important>
|
|
||||||
<para>
|
|
||||||
PostgreSQL 9.3 has reached the end of its community support period (final release was
|
|
||||||
<ulink url="https://www.postgresql.org/docs/9.3/release-9-3-25.html">9.3.25</ulink>
|
|
||||||
in November 2018) and will no longer be updated with security or bugfixes.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
PostgreSQL 9.4 has reached the end of its community support period (final release was
|
|
||||||
<ulink url="https://www.postgresql.org/docs/9.4/release-9-4-26.html">9.4.26</ulink>
|
|
||||||
in February 2020) and will no longer be updated with security or bugfixes.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
We recommend that users of these versions migrate to a recent PostgreSQL version
|
|
||||||
as soon as possible.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
For further details, see the <ulink url="https://www.postgresql.org/support/versioning/">PostgreSQL Versioning Policy</ulink>.
|
|
||||||
</para>
|
|
||||||
</important>
|
|
||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|||||||
@@ -24,7 +24,8 @@
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<literal>Debian</literal> and <literal>Ubuntu</literal>: First
|
<literal>Debian</literal> and <literal>Ubuntu</literal>: First
|
||||||
add the <ulink url="https://apt.postgresql.org/">apt.postgresql.org</ulink>
|
add the <ulink
|
||||||
|
url="http://apt.postgresql.org/">apt.postgresql.org</ulink>
|
||||||
repository to your <filename>sources.list</filename> if you
|
repository to your <filename>sources.list</filename> if you
|
||||||
have not already done so, and ensure the source repository is enabled.
|
have not already done so, and ensure the source repository is enabled.
|
||||||
</para>
|
</para>
|
||||||
@@ -35,8 +36,8 @@
|
|||||||
line in the repository file, which is usually
|
line in the repository file, which is usually
|
||||||
<filename>/etc/apt/sources.list.d/pgdg.list</filename>, e.g.:
|
<filename>/etc/apt/sources.list.d/pgdg.list</filename>, e.g.:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
deb https://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main
|
deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main
|
||||||
deb-src https://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisting>
|
deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</tip>
|
</tip>
|
||||||
<para>
|
<para>
|
||||||
@@ -60,9 +61,6 @@ deb-src https://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlist
|
|||||||
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara><literal>flex</literal></simpara>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara><literal>libedit-dev</literal></simpara>
|
<simpara><literal>libedit-dev</literal></simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
@@ -117,9 +115,6 @@ deb-src https://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlist
|
|||||||
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<simpara><literal>flex</literal></simpara>
|
|
||||||
</listitem>
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<simpara><literal>libselinux-devel</literal></simpara>
|
<simpara><literal>libselinux-devel</literal></simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
@@ -182,8 +177,7 @@ deb-src https://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlist
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
There are also tags for each <ulink url="https://github.com/2ndQuadrant/repmgr/releases">&repmgr; release</ulink>, e.g.
|
There are also tags for each &repmgr; release, e.g. <literal>v4.2.0</literal>.
|
||||||
<literal><ulink url="https://github.com/2ndQuadrant/repmgr/releases/tag/v4.4.0">v4.4.0</ulink></literal>.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -254,7 +254,7 @@
|
|||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
node_id=1
|
node_id=1
|
||||||
node_name='node1'
|
node_name=node1
|
||||||
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'
|
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'
|
||||||
data_directory='/var/lib/postgresql/data'
|
data_directory='/var/lib/postgresql/data'
|
||||||
</programlisting>
|
</programlisting>
|
||||||
@@ -265,6 +265,7 @@
|
|||||||
server. See sections <xref linkend="configuration"/> and <xref linkend="configuration-file"/>
|
server. See sections <xref linkend="configuration"/> and <xref linkend="configuration-file"/>
|
||||||
for further details about <filename>repmgr.conf</filename>.
|
for further details about <filename>repmgr.conf</filename>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
&repmgr; only uses <option>pg_bindir</option> when it executes
|
&repmgr; only uses <option>pg_bindir</option> when it executes
|
||||||
@@ -367,7 +368,7 @@
|
|||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
node_id=2
|
node_id=2
|
||||||
node_name='node2'
|
node_name=node2
|
||||||
conninfo='host=node2 user=repmgr dbname=repmgr connect_timeout=2'
|
conninfo='host=node2 user=repmgr dbname=repmgr connect_timeout=2'
|
||||||
data_directory='/var/lib/postgresql/data'</programlisting>
|
data_directory='/var/lib/postgresql/data'</programlisting>
|
||||||
<para>
|
<para>
|
||||||
@@ -477,8 +478,6 @@
|
|||||||
latest_end_lsn | 0/7000538
|
latest_end_lsn | 0/7000538
|
||||||
latest_end_time | 2017-08-28 15:20:56.418735+09
|
latest_end_time | 2017-08-28 15:20:56.418735+09
|
||||||
slot_name |
|
slot_name |
|
||||||
sender_host | node1
|
|
||||||
sender_port | 5432
|
|
||||||
conninfo | user=repmgr dbname=replication host=node1 application_name=node2
|
conninfo | user=repmgr dbname=replication host=node1 application_name=node2
|
||||||
</programlisting>
|
</programlisting>
|
||||||
Note that the <varname>conninfo</varname> value is that generated in <filename>recovery.conf</filename>
|
Note that the <varname>conninfo</varname> value is that generated in <filename>recovery.conf</filename>
|
||||||
@@ -498,12 +497,11 @@
|
|||||||
<para>
|
<para>
|
||||||
Check the node is registered by executing <command>repmgr cluster show</command> on the standby:
|
Check the node is registered by executing <command>repmgr cluster show</command> on the standby:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ repmgr -f /etc/repmgr.conf cluster show
|
$ repmgr -f /etc/repmgr.conf cluster show
|
||||||
|
ID | Name | Role | Status | Upstream | Location | Connection string
|
||||||
ID | Name | Role | Status | Upstream | Location | Priority | Timeline | Connection string
|
----+-------+---------+-----------+----------+----------+--------------------------------------
|
||||||
----+-------+---------+-----------+----------+----------+----------+----------+--------------------------------------
|
1 | node1 | primary | * running | | default | host=node1 dbname=repmgr user=repmgr
|
||||||
1 | node1 | primary | * running | | default | 100 | 1 | host=node1 dbname=repmgr user=repmgr
|
2 | node2 | standby | running | node1 | default | host=node2 dbname=repmgr user=repmgr</programlisting>
|
||||||
2 | node2 | standby | running | node1 | default | 100 | 1 | host=node2 dbname=repmgr user=repmgr</programlisting>
|
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Both nodes are now registered with &repmgr; and the records have been copied to the standby server.
|
Both nodes are now registered with &repmgr; and the records have been copied to the standby server.
|
||||||
|
|||||||
@@ -233,7 +233,7 @@
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See also</title>
|
<title>See also</title>
|
||||||
<para>
|
<para>
|
||||||
<xref linkend="repmgr-node-status"/>, <xref linkend="repmgr-node-check"/>, <xref linkend="repmgr-service-status"/>
|
<xref linkend="repmgr-node-status"/>, <xref linkend="repmgr-node-check"/>, <xref linkend="repmgr-daemon-status"/>
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<refentry id="repmgr-service-pause">
|
<refentry id="repmgr-daemon-pause">
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>repmgr service pause</primary>
|
<primary>repmgr daemon pause</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
@@ -9,11 +9,11 @@
|
|||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<refmeta>
|
<refmeta>
|
||||||
<refentrytitle>repmgr service pause</refentrytitle>
|
<refentrytitle>repmgr daemon pause</refentrytitle>
|
||||||
</refmeta>
|
</refmeta>
|
||||||
|
|
||||||
<refnamediv>
|
<refnamediv>
|
||||||
<refname>repmgr service pause</refname>
|
<refname>repmgr daemon pause</refname>
|
||||||
<refpurpose>Instruct all &repmgrd; instances in the replication cluster to pause failover operations</refpurpose>
|
<refpurpose>Instruct all &repmgrd; instances in the replication cluster to pause failover operations</refpurpose>
|
||||||
</refnamediv>
|
</refnamediv>
|
||||||
|
|
||||||
@@ -32,29 +32,20 @@
|
|||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
It's important to wait a few seconds after restarting PostgreSQL on any node before running
|
It's important to wait a few seconds after restarting PostgreSQL on any node before running
|
||||||
<command>repmgr service pause</command>, as the &repmgrd; instance
|
<command>repmgr daemon pause</command>, as the &repmgrd; instance
|
||||||
on the restarted node will take a second or two before it has updated its status.
|
on the restarted node will take a second or two before it has updated its status.
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
<para>
|
<para>
|
||||||
<xref linkend="repmgr-service-unpause"/> will instruct all previously paused &repmgrd;
|
<xref linkend="repmgr-daemon-unpause"/> will instruct all previously paused &repmgrd;
|
||||||
instances to resume normal failover operation.
|
instances to resume normal failover operation.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
<title>Prerequisites</title>
|
|
||||||
<para>
|
|
||||||
PostgreSQL must be accessible on all nodes (using the <varname>conninfo</varname> string shown by
|
|
||||||
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>)
|
|
||||||
from the node where <command>repmgr service pause</command> is executed.
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Execution</title>
|
<title>Execution</title>
|
||||||
<para>
|
<para>
|
||||||
<command>repmgr service pause</command> can be executed on any active node in the
|
<command>repmgr daemon pause</command> can be executed on any active node in the
|
||||||
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
|
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
|
||||||
It will have no effect on previously paused nodes.
|
It will have no effect on previously paused nodes.
|
||||||
</para>
|
</para>
|
||||||
@@ -64,7 +55,7 @@
|
|||||||
<title>Example</title>
|
<title>Example</title>
|
||||||
<para>
|
<para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ repmgr -f /etc/repmgr.conf service pause
|
$ repmgr -f /etc/repmgr.conf daemon pause
|
||||||
NOTICE: node 1 (node1) paused
|
NOTICE: node 1 (node1) paused
|
||||||
NOTICE: node 2 (node2) paused
|
NOTICE: node 2 (node2) paused
|
||||||
NOTICE: node 3 (node3) paused</programlisting>
|
NOTICE: node 3 (node3) paused</programlisting>
|
||||||
@@ -88,7 +79,7 @@ NOTICE: node 3 (node3) paused</programlisting>
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Exit codes</title>
|
<title>Exit codes</title>
|
||||||
<para>
|
<para>
|
||||||
One of the following exit codes will be emitted by <command>repmgr service unpause</command>:
|
One of the following exit codes will be emitted by <command>repmgr daemon unpause</command>:
|
||||||
</para>
|
</para>
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
@@ -116,11 +107,7 @@ NOTICE: node 3 (node3) paused</programlisting>
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See also</title>
|
<title>See also</title>
|
||||||
<para>
|
<para>
|
||||||
<xref linkend="repmgr-service-unpause"/>,
|
<xref linkend="repmgr-daemon-unpause"/>, <xref linkend="repmgr-daemon-status"/>
|
||||||
<xref linkend="repmgr-service-status"/>,
|
|
||||||
<xref linkend="repmgrd-pausing"/>,
|
|
||||||
<xref linkend="repmgr-daemon-start"/>,
|
|
||||||
<xref linkend="repmgr-daemon-stop"/>
|
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
</refentry>
|
</refentry>
|
||||||
@@ -14,13 +14,13 @@
|
|||||||
|
|
||||||
<refnamediv>
|
<refnamediv>
|
||||||
<refname>repmgr daemon start</refname>
|
<refname>repmgr daemon start</refname>
|
||||||
<refpurpose>Start the &repmgrd; daemon on the local node</refpurpose>
|
<refpurpose>Start the &repmgrd; daemon</refpurpose>
|
||||||
</refnamediv>
|
</refnamediv>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Description</title>
|
<title>Description</title>
|
||||||
<para>
|
<para>
|
||||||
This command starts the &repmgrd; service on the
|
This command starts the &repmgrd; daemon on the
|
||||||
local node.
|
local node.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
@@ -197,11 +197,7 @@
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See also</title>
|
<title>See also</title>
|
||||||
<para>
|
<para>
|
||||||
<xref linkend="repmgr-daemon-stop"/>,
|
<xref linkend="repmgr-daemon-stop"/>, <xref linkend="repmgr-daemon-status"/>, <xref linkend="repmgrd-daemon"/>
|
||||||
<xref linkend="repmgrd-daemon"/>,
|
|
||||||
<xref linkend="repmgr-service-status"/>,
|
|
||||||
<xref linkend="repmgr-service-pause"/>,
|
|
||||||
<xref linkend="repmgr-service-unpause"/>
|
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
<refentry id="repmgr-service-status">
|
<refentry id="repmgr-daemon-status">
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>repmgr service status</primary>
|
<primary>repmgr daemon status</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>repmgrd</primary>
|
<primary>repmgrd</primary>
|
||||||
<secondary>displaying service status</secondary>
|
<secondary>displaying daemon status</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<refmeta>
|
<refmeta>
|
||||||
<refentrytitle>repmgr service status</refentrytitle>
|
<refentrytitle>repmgr daemon status</refentrytitle>
|
||||||
</refmeta>
|
</refmeta>
|
||||||
|
|
||||||
<refnamediv>
|
<refnamediv>
|
||||||
<refname>repmgr service status</refname>
|
<refname>repmgr daemon status</refname>
|
||||||
<refpurpose>display information about the status of &repmgrd; on each node in the cluster</refpurpose>
|
<refpurpose>display information about the status of &repmgrd; on each node in the cluster</refpurpose>
|
||||||
</refnamediv>
|
</refnamediv>
|
||||||
|
|
||||||
@@ -22,33 +22,21 @@
|
|||||||
<para>
|
<para>
|
||||||
This command provides an overview over all active nodes in the cluster and the state
|
This command provides an overview over all active nodes in the cluster and the state
|
||||||
of each node's &repmgrd; instance. It can be used to check
|
of each node's &repmgrd; instance. It can be used to check
|
||||||
the result of <xref linkend="repmgr-service-pause"/> and <xref linkend="repmgr-service-unpause"/>
|
the result of <xref linkend="repmgr-daemon-pause"/> and <xref linkend="repmgr-daemon-unpause"/>
|
||||||
operations.
|
operations.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
<title>Prerequisites</title>
|
|
||||||
<para>
|
|
||||||
PostgreSQL should be accessible on all nodes (using the <varname>conninfo</varname> string shown by
|
|
||||||
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>)
|
|
||||||
from the node where <command>repmgr service status</command> is executed.
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Execution</title>
|
<title>Execution</title>
|
||||||
<para>
|
<para>
|
||||||
<command>repmgr service status</command> can be executed on any active node in the
|
<command>repmgr daemon status</command> can be executed on any active node in the
|
||||||
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
|
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
If a node is not accessible, or PostgreSQL itself is not running on the node,
|
If PostgreSQL is not running on a node, &repmgr; will not be able to determine the
|
||||||
&repmgr; will not be able to determine the status of that node's &repmgrd; instance,
|
status of that node's &repmgrd; instance.
|
||||||
and "<literal>n/a</literal>" will be displayed in the node's <literal>repmgrd</literal>
|
|
||||||
column.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
After restarting PostgreSQL on any node, the &repmgrd; instance
|
After restarting PostgreSQL on any node, the &repmgrd; instance
|
||||||
@@ -63,7 +51,7 @@
|
|||||||
<title>Examples</title>
|
<title>Examples</title>
|
||||||
<para>
|
<para>
|
||||||
&repmgrd; running normally on all nodes:
|
&repmgrd; running normally on all nodes:
|
||||||
<programlisting>$ repmgr -f /etc/repmgr.conf service status
|
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
|
||||||
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
||||||
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
|
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
|
||||||
1 | node1 | primary | * running | | running | 96563 | no | n/a
|
1 | node1 | primary | * running | | running | 96563 | no | n/a
|
||||||
@@ -72,8 +60,8 @@
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
&repmgrd; paused on all nodes (using <xref linkend="repmgr-service-pause"/>):
|
&repmgrd; paused on all nodes (using <xref linkend="repmgr-daemon-pause"/>):
|
||||||
<programlisting>$ repmgr -f /etc/repmgr.conf service status
|
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
|
||||||
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
||||||
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
|
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
|
||||||
1 | node1 | primary | * running | | running | 96563 | yes | n/a
|
1 | node1 | primary | * running | | running | 96563 | yes | n/a
|
||||||
@@ -83,7 +71,7 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
&repmgrd; not running on one node:
|
&repmgrd; not running on one node:
|
||||||
<programlisting>$ repmgr -f /etc/repmgr.conf service status
|
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
|
||||||
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
||||||
----+-------+---------+-----------+----------+-------------+-------+---------+--------------------
|
----+-------+---------+-----------+----------+-------------+-------+---------+--------------------
|
||||||
1 | node1 | primary | * running | | running | 96563 | yes | n/a
|
1 | node1 | primary | * running | | running | 96563 | yes | n/a
|
||||||
@@ -101,11 +89,11 @@
|
|||||||
<term><option>--csv</option></term>
|
<term><option>--csv</option></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<command>repmgr service status</command> accepts an optional parameter <literal>--csv</literal>, which
|
<command>repmgr daemon status</command> accepts an optional parameter <literal>--csv</literal>, which
|
||||||
outputs the replication cluster's status in a simple CSV format, suitable for
|
outputs the replication cluster's status in a simple CSV format, suitable for
|
||||||
parsing by scripts, e.g.:
|
parsing by scripts, e.g.:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ repmgr -f /etc/repmgr.conf service status --csv
|
$ repmgr -f /etc/repmgr.conf daemon status --csv
|
||||||
1,node1,primary,1,1,5722,1,100,-1,default
|
1,node1,primary,1,1,5722,1,100,-1,default
|
||||||
2,node2,standby,1,0,-1,1,100,1,default
|
2,node2,standby,1,0,-1,1,100,1,default
|
||||||
3,node3,standby,1,1,5779,1,100,1,default</programlisting>
|
3,node3,standby,1,1,5779,1,100,1,default</programlisting>
|
||||||
@@ -183,7 +171,7 @@
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Display additional information (<literal>location</literal>, <literal>priority</literal>)
|
Display additional information (<literal>location</literal>, <literal>priority</literal>)
|
||||||
about the &repmgr; configuration.
|
about the &repmgr; configuration.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@@ -192,7 +180,7 @@
|
|||||||
<term><option>--verbose</option></term>
|
<term><option>--verbose</option></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Display the full text of any database connection error messages.
|
Display the full text of any database connection error messages
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@@ -204,12 +192,7 @@
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See also</title>
|
<title>See also</title>
|
||||||
<para>
|
<para>
|
||||||
<xref linkend="repmgr-service-pause"/>,
|
<xref linkend="repmgr-daemon-pause"/>, <xref linkend="repmgr-daemon-unpause"/>, <xref linkend="repmgr-cluster-show"/>
|
||||||
<xref linkend="repmgr-service-unpause"/>,
|
|
||||||
<xref linkend="repmgr-cluster-show"/>,
|
|
||||||
<xref linkend="repmgrd-pausing"/>,
|
|
||||||
<xref linkend="repmgr-daemon-start"/>,
|
|
||||||
<xref linkend="repmgr-daemon-stop"/>
|
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
</refentry>
|
</refentry>
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<refnamediv>
|
<refnamediv>
|
||||||
<refname>repmgr daemon stop</refname>
|
<refname>repmgr daemon stop</refname>
|
||||||
<refpurpose>Stop the &repmgrd; daemon on the local node</refpurpose>
|
<refpurpose>Stop the &repmgrd; daemon</refpurpose>
|
||||||
</refnamediv>
|
</refnamediv>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
@@ -194,11 +194,7 @@
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See also</title>
|
<title>See also</title>
|
||||||
<para>
|
<para>
|
||||||
<xref linkend="repmgr-daemon-start"/>,
|
<xref linkend="repmgr-daemon-start"/>, <xref linkend="repmgr-daemon-status"/>, <xref linkend="repmgrd-daemon"/>
|
||||||
<xref linkend="repmgrd-daemon"/>,
|
|
||||||
<xref linkend="repmgr-service-status"/>,
|
|
||||||
<xref linkend="repmgr-service-pause"/>,
|
|
||||||
<xref linkend="repmgr-service-unpause"/>
|
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<refentry id="repmgr-service-unpause">
|
<refentry id="repmgr-daemon-unpause">
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>repmgr service unpause</primary>
|
<primary>repmgr daemon unpause</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
@@ -8,12 +8,13 @@
|
|||||||
<secondary>unpausing</secondary>
|
<secondary>unpausing</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
|
|
||||||
<refmeta>
|
<refmeta>
|
||||||
<refentrytitle>repmgr service unpause</refentrytitle>
|
<refentrytitle>repmgr daemon unpause</refentrytitle>
|
||||||
</refmeta>
|
</refmeta>
|
||||||
|
|
||||||
<refnamediv>
|
<refnamediv>
|
||||||
<refname>repmgr service unpause</refname>
|
<refname>repmgr daemon unpause</refname>
|
||||||
<refpurpose>Instruct all &repmgrd; instances in the replication cluster to resume failover operations</refpurpose>
|
<refpurpose>Instruct all &repmgrd; instances in the replication cluster to resume failover operations</refpurpose>
|
||||||
</refnamediv>
|
</refnamediv>
|
||||||
|
|
||||||
@@ -22,33 +23,24 @@
|
|||||||
<para>
|
<para>
|
||||||
This command can be run on any active node in the replication cluster to instruct all
|
This command can be run on any active node in the replication cluster to instruct all
|
||||||
running &repmgrd; instances to "unpause"
|
running &repmgrd; instances to "unpause"
|
||||||
(following a previous execution of <xref linkend="repmgr-service-pause"/>)
|
(following a previous execution of <xref linkend="repmgr-daemon-pause"/>)
|
||||||
and resume normal failover/monitoring operation.
|
and resume normal failover/monitoring operation.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
It's important to wait a few seconds after restarting PostgreSQL on any node before running
|
It's important to wait a few seconds after restarting PostgreSQL on any node before running
|
||||||
<command>repmgr service pause</command>, as the &repmgrd; instance
|
<command>repmgr daemon pause</command>, as the &repmgrd; instance
|
||||||
on the restarted node will take a second or two before it has updated its status.
|
on the restarted node will take a second or two before it has updated its status.
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
<title>Prerequisites</title>
|
|
||||||
<para>
|
|
||||||
PostgreSQL must be accessible on all nodes (using the <varname>conninfo</varname> string shown by
|
|
||||||
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>)
|
|
||||||
from the node where <command>repmgr service pause</command> is executed.
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Execution</title>
|
<title>Execution</title>
|
||||||
<para>
|
<para>
|
||||||
<command>repmgr service unpause</command> can be executed on any active node in the
|
<command>repmgr daemon unpause</command> can be executed on any active node in the
|
||||||
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
|
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
|
||||||
It will have no effect on nodes which are not already paused.
|
It will have no effect on nodes which are not already paused.
|
||||||
</para>
|
</para>
|
||||||
@@ -58,7 +50,7 @@
|
|||||||
<title>Example</title>
|
<title>Example</title>
|
||||||
<para>
|
<para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ repmgr -f /etc/repmgr.conf service unpause
|
$ repmgr -f /etc/repmgr.conf daemon unpause
|
||||||
NOTICE: node 1 (node1) unpaused
|
NOTICE: node 1 (node1) unpaused
|
||||||
NOTICE: node 2 (node2) unpaused
|
NOTICE: node 2 (node2) unpaused
|
||||||
NOTICE: node 3 (node3) unpaused</programlisting>
|
NOTICE: node 3 (node3) unpaused</programlisting>
|
||||||
@@ -82,7 +74,7 @@ NOTICE: node 3 (node3) unpaused</programlisting>
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Exit codes</title>
|
<title>Exit codes</title>
|
||||||
<para>
|
<para>
|
||||||
One of the following exit codes will be emitted by <command>repmgr service unpause</command>:
|
One of the following exit codes will be emitted by <command>repmgr daemon unpause</command>:
|
||||||
</para>
|
</para>
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
@@ -110,11 +102,7 @@ NOTICE: node 3 (node3) unpaused</programlisting>
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See also</title>
|
<title>See also</title>
|
||||||
<para>
|
<para>
|
||||||
<xref linkend="repmgr-service-pause"/>,
|
<xref linkend="repmgr-daemon-pause"/>, <xref linkend="repmgr-daemon-status"/>
|
||||||
<xref linkend="repmgr-service-status"/>,
|
|
||||||
<xref linkend="repmgrd-pausing"/>,
|
|
||||||
<xref linkend="repmgr-daemon-start"/>,
|
|
||||||
<xref linkend="repmgr-daemon-stop"/>
|
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
</refentry>
|
</refentry>
|
||||||
@@ -356,7 +356,7 @@
|
|||||||
<command>repmgr node rejoin</command> attempts to determine whether it will succeed by
|
<command>repmgr node rejoin</command> attempts to determine whether it will succeed by
|
||||||
comparing the timelines and relative WAL positions of the local node (rejoin candidate) and primary
|
comparing the timelines and relative WAL positions of the local node (rejoin candidate) and primary
|
||||||
(rejoin target). This is particularly important if planning to use <application>pg_rewind</application>,
|
(rejoin target). This is particularly important if planning to use <application>pg_rewind</application>,
|
||||||
which currently (as of PostgreSQL 12) may appear to succeed (or indicate there is no action
|
which currently (as of PostgreSQL 11) may appear to succeed (or indicate there is no action
|
||||||
needed) but potentially allow an impossible action, such as trying to rejoin a standby to a
|
needed) but potentially allow an impossible action, such as trying to rejoin a standby to a
|
||||||
primary which is behind the standby. &repmgr; will prevent this situation from occurring.
|
primary which is behind the standby. &repmgr; will prevent this situation from occurring.
|
||||||
</para>
|
</para>
|
||||||
|
|||||||
@@ -114,38 +114,38 @@
|
|||||||
<para>
|
<para>
|
||||||
See what action would be taken for a restart:
|
See what action would be taken for a restart:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --action=restart --checkpoint --dry-run
|
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --action=restart --checkpoint --dry-run
|
||||||
INFO: a CHECKPOINT would be issued here
|
INFO: a CHECKPOINT would be issued here
|
||||||
INFO: would execute server command "sudo service postgresql-12 restart"</programlisting>
|
INFO: would execute server command "sudo service postgresql-11 restart"</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Restart the PostgreSQL instance:
|
Restart the PostgreSQL instance:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --action=restart --checkpoint
|
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --action=restart --checkpoint
|
||||||
NOTICE: issuing CHECKPOINT
|
NOTICE: issuing CHECKPOINT
|
||||||
DETAIL: executing server command "sudo service postgresql-12 restart"
|
DETAIL: executing server command "sudo service postgresql-11 restart"
|
||||||
Redirecting to /bin/systemctl restart postgresql-12.service</programlisting>
|
Redirecting to /bin/systemctl restart postgresql-11.service</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
List all commands:
|
List all commands:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --list-actions
|
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --list-actions
|
||||||
Following commands would be executed for each action:
|
Following commands would be executed for each action:
|
||||||
|
|
||||||
start: "sudo service postgresql-12 start"
|
start: "sudo service postgresql-11 start"
|
||||||
stop: "sudo service postgresql-12 stop"
|
stop: "sudo service postgresql-11 stop"
|
||||||
restart: "sudo service postgresql-12 restart"
|
restart: "sudo service postgresql-11 restart"
|
||||||
reload: "sudo service postgresql-12 reload"
|
reload: "sudo service postgresql-11 reload"
|
||||||
promote: "/usr/pgsql-12/bin/pg_ctl -w -D '/var/lib/pgsql/12/data' promote"</programlisting>
|
promote: "/usr/pgsql-11/bin/pg_ctl -w -D '/var/lib/pgsql/11/data' promote"</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
List a single command:
|
List a single command:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --list-actions --action=promote
|
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --list-actions --action=promote
|
||||||
/usr/pgsql-12/bin/pg_ctl -w -D '/var/lib/pgsql/12/data' promote </programlisting>
|
/usr/pgsql-11/bin/pg_ctl -w -D '/var/lib/pgsql/11/data' promote </programlisting>
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
</refentry>
|
</refentry>
|
||||||
|
|||||||
@@ -24,15 +24,10 @@
|
|||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
&repmgr; will attempt to install the &repmgr; extension as part of this command,
|
It's possibly to install the &repmgr; extension manually before executing
|
||||||
however this will fail if the <literal>repmgr</literal> user is not a superuser.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
It's possible to install the &repmgr; extension manually before executing
|
|
||||||
<command>repmgr primary register</command>; in this case &repmgr; will
|
<command>repmgr primary register</command>; in this case &repmgr; will
|
||||||
detect the presence of the extension and skip that step.
|
detect the presence of the extension and skip that step.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
@@ -64,21 +59,6 @@
|
|||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
<title>User permission requirements</title>
|
|
||||||
<para>
|
|
||||||
The <literal>repmgr</literal> user must be a superuser in order for &repmgr;
|
|
||||||
to be able to install the <literal>repmgr</literal> extension.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
If this is not the case, the <literal>repmgr</literal> extension can be installed
|
|
||||||
manually before executing <command>repmgr primary register</command>.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
A future &repmgr; release will enable the provision of a <option>--superuser</option>
|
|
||||||
name for the installation of the extension.
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
|
||||||
<title>Options</title>
|
<title>Options</title>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<para>
|
<para>
|
||||||
<command>repmgr standby clone</command> clones a PostgreSQL node from another
|
<command>repmgr standby clone</command> clones a PostgreSQL node from another
|
||||||
PostgreSQL node, typically the primary, but optionally from any other node in
|
PostgreSQL node, typically the primary, but optionally from any other node in
|
||||||
the cluster or from Barman. It creates the replication configuration required
|
the cluster or from Barman. It creates the <filename>recovery.conf</filename> file required
|
||||||
to attach the cloned node to the primary node (or another standby, if cascading replication
|
to attach the cloned node to the primary node (or another standby, if cascading replication
|
||||||
is in use).
|
is in use).
|
||||||
</para>
|
</para>
|
||||||
@@ -85,20 +85,15 @@
|
|||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1 id="repmgr-standby-clone-recovery-conf">
|
<refsect1 id="repmgr-standby-clone-recovery-conf">
|
||||||
<title>Customising replication configuration</title>
|
<title>Customising recovery.conf</title>
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>recovery.conf</primary>
|
<primary>recovery.conf</primary>
|
||||||
<secondary>customising with "repmgr standby clone"</secondary>
|
<secondary>customising with "repmgr standby clone"</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<indexterm>
|
|
||||||
<primary>replication configuration</primary>
|
|
||||||
<secondary>customising with "repmgr standby clone"</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
By default, &repmgr; will create a minimal replication configuration
|
By default, &repmgr; will create a minimal <filename>recovery.conf</filename>
|
||||||
containing following parameters:
|
containing following parameters:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@@ -124,7 +119,7 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
The following additional parameters can be specified in <filename>repmgr.conf</filename>
|
The following additional parameters can be specified in <filename>repmgr.conf</filename>
|
||||||
for inclusion in the replication configuration:
|
for inclusion in <filename>recovery.conf</filename>:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
@@ -198,50 +193,37 @@
|
|||||||
<secondary>generating for a standby cloned by another method</secondary>
|
<secondary>generating for a standby cloned by another method</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<indexterm>
|
|
||||||
<primary>replication configuration</primary>
|
|
||||||
<secondary>generating for a standby cloned by another method</secondary>
|
|
||||||
</indexterm>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
&repmgr; supports standbys cloned by another method (e.g. using <application>barman</application>'s
|
&repmgr; supports standbys cloned by another method (e.g. using <application>barman</application>'s
|
||||||
<command><ulink url="https://docs.pgbarman.org/#recover">barman recover</ulink></command> command).
|
<command><ulink url="http://docs.pgbarman.org/release/2.5/#recover">barman recover</ulink></command> command).
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
To integrate the standby as a &repmgr; node, once the standby has been cloned,
|
To integrate the standby as a &repmgr; node, once the standby has been cloned,
|
||||||
ensure the <filename>repmgr.conf</filename>
|
ensure the <filename>repmgr.conf</filename>
|
||||||
file is created for the node, and that it has been registered using
|
file is created for the node, and that it has been registered using
|
||||||
<command><link linkend="repmgr-standby-register">repmgr standby register</link></command>.
|
<command><link linkend="repmgr-standby-register">repmgr standby register</link></command>.
|
||||||
</para>
|
|
||||||
<tip>
|
|
||||||
<para>
|
|
||||||
To register a standby which is not running, execute
|
|
||||||
<link linkend="repmgr-standby-register">repmgr standby register --force</link>
|
|
||||||
and provide the connection details for the primary.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
See <xref linkend="repmgr-standby-register-inactive-node"/> for more details.
|
|
||||||
</para>
|
|
||||||
</tip>
|
|
||||||
<para>
|
|
||||||
Then execute the command <command>repmgr standby clone --recovery-conf-only</command>.
|
Then execute the command <command>repmgr standby clone --recovery-conf-only</command>.
|
||||||
This will create the <filename>recovery.conf</filename> file needed to attach
|
This will create the <filename>recovery.conf</filename> file needed to attach
|
||||||
the node to its upstream (in PostgreSQL 12 and later: append replication configuration
|
the node to its upstream, and will also create a replication slot on the
|
||||||
to <filename>postgresql.auto.conf</filename>), and will also create a replication slot on the
|
|
||||||
upstream node if required.
|
upstream node if required.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Note that the upstream node must be running. In PostgreSQL 11 and earlier, an existing
|
Note that the upstream node must be running. An existing
|
||||||
<filename>recovery.conf</filename> will not be overwritten unless the
|
<filename>recovery.conf</filename> will not be overwritten unless the
|
||||||
<option>-F/--force</option> option is provided.
|
<option>-F/--force</option> option is provided.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Execute <command>repmgr standby clone --recovery-conf-only --dry-run</command>
|
Execute <command>repmgr standby clone --recovery-conf-only --dry-run</command>
|
||||||
to check the prerequisites for creating the recovery configuration,
|
to check the prerequisites for creating the <filename>recovery.conf</filename> file,
|
||||||
and display the contents of the configuration which would be added without actually
|
and display the contents of the file without actually creating it.
|
||||||
making any changes.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
<option>--recovery-conf-only</option> was introduced in &repmgr; <link linkend="release-4.0.4">4.0.4</link>.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
@@ -267,8 +249,8 @@
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
If <option>--recovery-conf-only</option> specified, the contents of
|
If <option>--recovery-conf-only</option> specified, the contents of
|
||||||
the generated recovery configuration will be displayed
|
the generated <filename>recovery.conf</filename> file will be displayed
|
||||||
but not written.
|
but the file itself not written.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@@ -315,16 +297,8 @@
|
|||||||
<term><option> --recovery-conf-only</option></term>
|
<term><option> --recovery-conf-only</option></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Create recovery configuration for a previously cloned instance.
|
Create <filename>recovery.conf</filename> file for a previously cloned instance. &repmgr; 4.0.4 and later.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
In PostgreSQL 11 and earlier, the replication configuration will be
|
|
||||||
written to <filename>recovery.conf</filename>.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
In PostgreSQL 12 and later, the replication configuration will be
|
|
||||||
written to <filename>postgresql.auto.conf</filename>.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
@@ -352,7 +326,7 @@
|
|||||||
<term><option>--upstream-conninfo</option></term>
|
<term><option>--upstream-conninfo</option></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<literal>primary_conninfo</literal> value to include in the recovery configuration
|
<literal>primary_conninfo</literal> value to write in <filename>recovery.conf</filename>
|
||||||
when the intended upstream server does not yet exist.
|
when the intended upstream server does not yet exist.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -171,7 +171,7 @@
|
|||||||
be possible to follow the new upstream node, and &repmgr; will emit an error
|
be possible to follow the new upstream node, and &repmgr; will emit an error
|
||||||
message like this:
|
message like this:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
ERROR: this node cannot attach to follow target node "node3" (ID 3)
|
ERROR: this node cannot attach to follow target node 3
|
||||||
DETAIL: follow target server's timeline 2 forked off current database system timeline 1 before current recovery point 0/6108880</programlisting>
|
DETAIL: follow target server's timeline 2 forked off current database system timeline 1 before current recovery point 0/6108880</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -23,8 +23,7 @@
|
|||||||
<important>
|
<important>
|
||||||
<para>
|
<para>
|
||||||
If &repmgrd; is active, you must execute
|
If &repmgrd; is active, you must execute
|
||||||
<command><link linkend="repmgr-service-pause">repmgr service pause</link></command>
|
<command><link linkend="repmgr-daemon-pause">repmgr daemon pause</link></command>
|
||||||
(&repmgr; 4.2 - 4.4: <command><link linkend="repmgr-service-pause">repmgr service pause</link></command>)
|
|
||||||
to temporarily disable &repmgrd; while making any changes
|
to temporarily disable &repmgrd; while making any changes
|
||||||
to the replication cluster.
|
to the replication cluster.
|
||||||
</para>
|
</para>
|
||||||
@@ -86,7 +85,6 @@
|
|||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Example</title>
|
<title>Example</title>
|
||||||
<para>
|
<para>
|
||||||
@@ -102,31 +100,6 @@
|
|||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
<title>User permission requirements</title>
|
|
||||||
<para><emphasis>pg_promote() (PostgreSQL 12)</emphasis></para>
|
|
||||||
<para>
|
|
||||||
From PostgreSQL 12, &repmgr; uses the <command>pg_promote()</command> function to promote a standby
|
|
||||||
to primary.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
By default, execution of <command>pg_promote()</command> is restricted to superusers.
|
|
||||||
If the <literal>repmgr</literal> use is not a superuser, execution permission for this
|
|
||||||
function must be granted with e.g.:
|
|
||||||
<programlisting>
|
|
||||||
GRANT EXECUTE ON FUNCTION pg_catalog.pg_promote TO repmgr</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Note that permissions are only effective for the database they are granted in, so
|
|
||||||
this <emphasis>must</emphasis> be executed in the &repmgr; database to be effective.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
A future &repmgr; release will relax this restriction by falling back to
|
|
||||||
<command>pg_ctl promote</command>, as used for pre-PostgreSQL 12 versions.
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Options</title>
|
<title>Options</title>
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|||||||
@@ -75,22 +75,10 @@
|
|||||||
<para>
|
<para>
|
||||||
Under some circumstances you may wish to register a standby which is not
|
Under some circumstances you may wish to register a standby which is not
|
||||||
yet running; this can be the case when using provisioning tools to create
|
yet running; this can be the case when using provisioning tools to create
|
||||||
a complex replication cluster, or if the node was not cloned by &repmgr;.
|
a complex replication cluster. In this case, by using the <option>-F/--force</option>
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
In this case, by using the <option>-F/--force</option>
|
|
||||||
option and providing the connection parameters to the primary server,
|
option and providing the connection parameters to the primary server,
|
||||||
the standby can be registered even if it has not yet been started.
|
the standby can be registered.
|
||||||
</para>
|
</para>
|
||||||
<tip>
|
|
||||||
<para>
|
|
||||||
Connection parameters can either be provided either as a <literal>conninfo</literal> string
|
|
||||||
(e.g. <option>-d 'host=node1 user=repmgr'</option> or as individual connection parameters
|
|
||||||
(<option>-h/--host</option>, <option>-d/--dbname</option>,
|
|
||||||
<option>-U/--user</option>, <option>-p/--port</option> etc.).
|
|
||||||
</para>
|
|
||||||
</tip>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Similarly, with cascading replication it may be necessary to register
|
Similarly, with cascading replication it may be necessary to register
|
||||||
a standby whose upstream node has not yet been registered - in this case,
|
a standby whose upstream node has not yet been registered - in this case,
|
||||||
@@ -108,11 +96,9 @@
|
|||||||
<title>Registering a node not cloned by repmgr</title>
|
<title>Registering a node not cloned by repmgr</title>
|
||||||
<para>
|
<para>
|
||||||
If you've cloned a standby using another method (e.g. <application>barman</application>'s
|
If you've cloned a standby using another method (e.g. <application>barman</application>'s
|
||||||
<command><ulink url="https://docs.pgbarman.org/#recover">barman recover</ulink></command>
|
<command>barman recover</command> command), first execute
|
||||||
command), register the node as detailed in section
|
|
||||||
<xref linkend="repmgr-standby-register-inactive-node"/> then execute
|
|
||||||
<link linkend="repmgr-standby-create-recovery-conf">repmgr standby clone --recovery-conf-only</link>
|
<link linkend="repmgr-standby-create-recovery-conf">repmgr standby clone --recovery-conf-only</link>
|
||||||
to generate the appropriate replication configuration.
|
to add the <filename>recovery.conf</filename> file, then register the standby as usual.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
@@ -133,7 +119,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-F</option>/<option>--force</option></term>
|
<term><option>-F</option><option>--force</option></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Overwrite an existing node record
|
Overwrite an existing node record
|
||||||
|
|||||||
@@ -63,37 +63,6 @@
|
|||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>User permission requirements</title>
|
|
||||||
<para><emphasis>CHECKPOINT</emphasis></para>
|
|
||||||
<para>
|
|
||||||
&repmgr; executes <command>CHECKPOINT</command> on the demotion candidate as part of the shutdown
|
|
||||||
process.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
Note that <command>CHECKPOINT</command> requires database superuser permissions to execute.
|
|
||||||
If the <literal>repmgr</literal> user is not a superuser, the checkpoint operation will
|
|
||||||
fail, though this is not a fatal error &repmgr; will continue the switchover process.
|
|
||||||
</para>
|
|
||||||
<para><emphasis>pg_promote() (PostgreSQL 12)</emphasis></para>
|
|
||||||
<para>
|
|
||||||
From PostgreSQL 12, &repmgr; uses the <command>pg_promote()</command> function to promote a standby
|
|
||||||
to primary.
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
By default, execution of <command>pg_promote()</command> is restricted to superusers.
|
|
||||||
If the <literal>repmgr</literal> use is not a superuser, execution permission for this
|
|
||||||
function must be granted with e.g.:
|
|
||||||
<programlisting>
|
|
||||||
GRANT EXECUTE ON FUNCTION pg_catalog.pg_promote TO repmgr</programlisting>
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
A future &repmgr; release will relax this restriction by falling back to
|
|
||||||
<command>pg_ctl promote</command>, as used for pre-PostgreSQL 12 versions.
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
|
|
||||||
<title>Options</title>
|
<title>Options</title>
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<abstract>
|
<abstract>
|
||||||
<para>
|
<para>
|
||||||
This is the official documentation of &repmgr; &repmgrversion; for
|
This is the official documentation of &repmgr; &repmgrversion; for
|
||||||
use with PostgreSQL 9.3 - PostgreSQL 12.
|
use with PostgreSQL 9.3 - PostgreSQL 11.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
&repmgr; is being continually developed and we strongly recommend using the
|
&repmgr; is being continually developed and we strongly recommend using the
|
||||||
@@ -116,11 +116,11 @@
|
|||||||
&repmgr-cluster-crosscheck;
|
&repmgr-cluster-crosscheck;
|
||||||
&repmgr-cluster-event;
|
&repmgr-cluster-event;
|
||||||
&repmgr-cluster-cleanup;
|
&repmgr-cluster-cleanup;
|
||||||
&repmgr-service-status;
|
&repmgr-daemon-status;
|
||||||
&repmgr-service-pause;
|
|
||||||
&repmgr-service-unpause;
|
|
||||||
&repmgr-daemon-start;
|
&repmgr-daemon-start;
|
||||||
&repmgr-daemon-stop;
|
&repmgr-daemon-stop;
|
||||||
|
&repmgr-daemon-pause;
|
||||||
|
&repmgr-daemon-unpause;
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
&appendix-release-notes;
|
&appendix-release-notes;
|
||||||
|
|||||||
@@ -192,23 +192,21 @@
|
|||||||
connected. Beginning with <link linkend="release-4.4">&repmgr; 4.4</link>
|
connected. Beginning with <link linkend="release-4.4">&repmgr; 4.4</link>
|
||||||
it is now possible for the affected standbys to build a consensus about whether
|
it is now possible for the affected standbys to build a consensus about whether
|
||||||
the primary is still available to some standbys ("primary visibility consensus").
|
the primary is still available to some standbys ("primary visibility consensus").
|
||||||
This is done by polling each standby (and the witness, if present) for the time it last saw the
|
This is done by polling each standby for the time it last saw the primary;
|
||||||
primary; if any have seen the primary very recently, it's reasonable
|
if any have seen the primary very recently, it's reasonable
|
||||||
to infer that the primary is still available and a failover should not be started.
|
to infer that the primary is still available and a failover should not be started.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The time the primary was last seen by each node can be checked by executing
|
The time the primary was last seen by each node can be checked by executing
|
||||||
<link linkend="repmgr-service-status"><command>repmgr service status</command></link>
|
<link linkend="repmgr-daemon-status"><command>repmgr daemon status</command></link>,
|
||||||
(&repmgr; 4.2 - 4.4: <link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>)
|
|
||||||
which includes this in its output, e.g.:
|
which includes this in its output, e.g.:
|
||||||
<programlisting>$ repmgr -f /etc/repmgr.conf service status
|
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
|
||||||
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
||||||
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
|
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
|
||||||
1 | node1 | primary | * running | | running | 27259 | no | n/a
|
1 | node1 | primary | * running | | running | 96563 | no | n/a
|
||||||
2 | node2 | standby | running | node1 | running | 27272 | no | 1 second(s) ago
|
2 | node2 | standby | running | node1 | running | 96572 | no | 1 second(s) ago
|
||||||
3 | node3 | standby | running | node1 | running | 27282 | no | 0 second(s) ago
|
3 | node3 | standby | running | node1 | running | 96584 | no | 0 second(s) ago</programlisting>
|
||||||
4 | node4 | witness | * running | node1 | running | 27298 | no | 1 second(s) ago</programlisting>
|
|
||||||
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@@ -269,12 +267,11 @@
|
|||||||
<para>
|
<para>
|
||||||
If <option>standby_disconnect_on_failover</option> is set to <literal>true</literal> in
|
If <option>standby_disconnect_on_failover</option> is set to <literal>true</literal> in
|
||||||
<filename>repmgr.conf</filename>, in a failover situation &repmgrd; will forcibly disconnect
|
<filename>repmgr.conf</filename>, in a failover situation &repmgrd; will forcibly disconnect
|
||||||
the local node's WAL receiver, and wait for the WAL receiver on all sibling nodes to be
|
the local node's WAL receiver before making a failover decision.
|
||||||
disconnected, before making a failover decision.
|
|
||||||
</para>
|
</para>
|
||||||
<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 from PostgreSQL 9.5 and later.
|
||||||
Additionally 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.
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
@@ -293,12 +290,6 @@
|
|||||||
plus however many seconds it takes to confirm the WAL receiver is disconnected before
|
plus however many seconds it takes to confirm the WAL receiver is disconnected before
|
||||||
&repmgrd; proceeds with the failover decision.
|
&repmgrd; proceeds with the failover decision.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
&repmgrd; will wait up to <option>sibling_nodes_disconnect_timeout</option> seconds (default:
|
|
||||||
<literal>30</literal>) to confirm that the WAL receiver on all sibling nodes hase been
|
|
||||||
disconnected before proceding with the failover operation. If the timeout is reached, the
|
|
||||||
failover operation will go ahead anyway.
|
|
||||||
</para>
|
|
||||||
<para>
|
<para>
|
||||||
Following the failover operation, no matter what the outcome, each node will reconnect its WAL receiver.
|
Following the failover operation, no matter what the outcome, each node will reconnect its WAL receiver.
|
||||||
</para>
|
</para>
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
replication_type='bdr'
|
replication_type='bdr'
|
||||||
|
|
||||||
# Event notification configuration
|
# Event notification configuration
|
||||||
event_notifications='bdr_failover'
|
event_notifications=bdr_failover
|
||||||
event_notification_command='/path/to/bdr-pgbouncer.sh %n %e %s "%c" "%a" >> /tmp/bdr-failover.log 2>&1'
|
event_notification_command='/path/to/bdr-pgbouncer.sh %n %e %s "%c" "%a" >> /tmp/bdr-failover.log 2>&1'
|
||||||
|
|
||||||
# repmgrd options
|
# repmgrd options
|
||||||
|
|||||||
@@ -8,20 +8,16 @@
|
|||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
&repmgrd; is a daemon process which runs on each PostgreSQL node,
|
&repmgrd; is a daemon which runs on each PostgreSQL node,
|
||||||
monitoring the local node, and (unless it's the primary node) the upstream server
|
monitoring the local node, and (unless it's the primary node) the upstream server
|
||||||
(the primary server or with cascading replication, another standby) which it's
|
(the primary server or with cascading replication, another standby) which it's
|
||||||
connected to.
|
connected to.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
&repmgrd; can be configured to provide failover
|
&repmgrd; can be configured to provide failover
|
||||||
capability in case the primary or upstream node becomes unreachable, and/or
|
capability in case the primary upstream node becomes unreachable, and/or
|
||||||
provide monitoring data to the &repmgr; metadatabase.
|
provide monitoring data to the &repmgr; metadatabase.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
|
||||||
From &repmgr; 4.4, when running on the primary node, &repmgrd; can also monitor
|
|
||||||
standby disconnections/reconnections (see <xref linkend="repmgrd-primary-child-disconnection"/>).
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<sect1 id="repmgrd-basic-configuration">
|
<sect1 id="repmgrd-basic-configuration">
|
||||||
<title>repmgrd configuration</title>
|
<title>repmgrd configuration</title>
|
||||||
@@ -81,7 +77,7 @@
|
|||||||
<listitem>
|
<listitem>
|
||||||
<simpara>
|
<simpara>
|
||||||
<literal>connection</literal> - determines server availability
|
<literal>connection</literal> - determines server availability
|
||||||
by attempting to make a new connection to the upstream node
|
by attempt ingto make a new connection to the upstream node
|
||||||
</simpara>
|
</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
@@ -226,17 +222,6 @@
|
|||||||
Normally <option>promote_command</option> is set as &repmgr;'s
|
Normally <option>promote_command</option> is set as &repmgr;'s
|
||||||
<command><link linkend="repmgr-standby-promote">repmgr standby promote</link></command> command.
|
<command><link linkend="repmgr-standby-promote">repmgr standby promote</link></command> command.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
|
||||||
<para>
|
|
||||||
When invoking <command>repmgr standby promote</command> (either directly via
|
|
||||||
the <option>promote_command</option>, or in a script called
|
|
||||||
via <option>promote_command</option>), <option>--siblings-follow</option>
|
|
||||||
<emphasis>must not</emphasis> be included as a
|
|
||||||
command line option for <command>repmgr standby promote</command>.
|
|
||||||
</para>
|
|
||||||
</note>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
It is also possible to provide a shell script to e.g. perform user-defined tasks
|
It is also possible to provide a shell script to e.g. perform user-defined tasks
|
||||||
before promoting the current node. In this case the script <emphasis>must</emphasis>
|
before promoting the current node. In this case the script <emphasis>must</emphasis>
|
||||||
@@ -398,8 +383,8 @@
|
|||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If <literal>true</literal>, only continue with failover if no standbys
|
If <literal>true</literal>, only continue with failover if no standbys have seen
|
||||||
(or the witness server, if present) have seen the primary node recently.
|
the primary node recently.
|
||||||
</para>
|
</para>
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
@@ -490,23 +475,6 @@
|
|||||||
|
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
|
|
||||||
<sect2 id="repmgrd-automatic-failover-configuration-pgbouncer-fencing">
|
|
||||||
<title>Configuring &repmgrd; and pgbouncer to fence a failed primary node</title>
|
|
||||||
<indexterm>
|
|
||||||
<primary>fencing</primary>
|
|
||||||
<secondary>using repmgrd and pgbouncer to fence a failed primary node</secondary>
|
|
||||||
</indexterm>
|
|
||||||
<indexterm>
|
|
||||||
<primary>PgBouncer</primary>
|
|
||||||
<secondary>using repmgrd and pgbouncer to fence a failed primary node</secondary>
|
|
||||||
</indexterm>
|
|
||||||
<para>
|
|
||||||
For further details and a reference implementation, see the separate document
|
|
||||||
<ulink url="https://github.com/2ndQuadrant/repmgr/blob/master/doc/repmgrd-node-fencing.md">Fencing a failed master node with repmgrd and PgBouncer</ulink>.
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2 id="postgresql-service-configuration">
|
<sect2 id="postgresql-service-configuration">
|
||||||
<title>PostgreSQL service configuration</title>
|
<title>PostgreSQL service configuration</title>
|
||||||
|
|
||||||
@@ -540,8 +508,7 @@
|
|||||||
</indexterm>
|
</indexterm>
|
||||||
<para>
|
<para>
|
||||||
If you are intending to use the <link linkend="repmgr-daemon-start"><command>repmgr daemon start</command></link>
|
If you are intending to use the <link linkend="repmgr-daemon-start"><command>repmgr daemon start</command></link>
|
||||||
and <link linkend="repmgr-daemon-stop"><command>repmgr daemon stop</command></link>
|
and <link linkend="repmgr-daemon-stop"><command>repmgr daemon stop</command></link> commands, the following
|
||||||
commands, the following
|
|
||||||
parameters <emphasis>must</emphasis> be set in <filename>repmgr.conf</filename>:
|
parameters <emphasis>must</emphasis> be set in <filename>repmgr.conf</filename>:
|
||||||
<itemizedlist spacing="compact" mark="bullet">
|
<itemizedlist spacing="compact" mark="bullet">
|
||||||
|
|
||||||
@@ -557,10 +524,10 @@
|
|||||||
|
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Example (for &repmgr; with PostgreSQL 12 on CentOS 7):
|
Example (for &repmgr; with PostgreSQL 11 on CentOS 7):
|
||||||
<programlisting>
|
<programlisting>
|
||||||
repmgrd_service_start_command='sudo systemctl repmgr12 start'
|
repmgrd_service_start_command='sudo systemctl repmgr11 start'
|
||||||
repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
|
repmgrd_service_stop_command='sudo systemctl repmgr11 stop'
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
@@ -587,8 +554,7 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
|
|||||||
the option <option>monitor_interval_secs</option> (see above).
|
the option <option>monitor_interval_secs</option> (see above).
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
For more details on monitoring, see <xref linkend="repmgrd-monitoring"/>. For information on
|
For more details on monitoring, see <xref linkend="repmgrd-monitoring"/>.
|
||||||
monitoring standby disconnections, see <xref linkend="repmgrd-primary-child-disconnection"/>.
|
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
@@ -883,7 +849,7 @@ repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
|
|||||||
<para>
|
<para>
|
||||||
The commands <link linkend="repmgr-daemon-start"><command>repmgr daemon start</command></link> and
|
The commands <link linkend="repmgr-daemon-start"><command>repmgr daemon start</command></link> and
|
||||||
<link linkend="repmgr-daemon-stop"><command>repmgr daemon stop</command></link> can be used
|
<link linkend="repmgr-daemon-stop"><command>repmgr daemon stop</command></link> can be used
|
||||||
as convenience wrappers to start and stop &repmgrd; on the local node.
|
as convenience wrappers to start and stop &repmgrd;.
|
||||||
</para>
|
</para>
|
||||||
<important>
|
<important>
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ Script and template file should be installed on each node where `repmgrd` is run
|
|||||||
Finally, set `promote_command` in `repmgr.conf` on each node to
|
Finally, set `promote_command` in `repmgr.conf` on each node to
|
||||||
point to the custom promote script:
|
point to the custom promote script:
|
||||||
|
|
||||||
promote_command='/var/lib/postgres/repmgr/promote.sh'
|
promote_command=/var/lib/postgres/repmgr/promote.sh
|
||||||
|
|
||||||
and reload/restart any running `repmgrd` instances for the changes to take
|
and reload/restart any running `repmgrd` instances for the changes to take
|
||||||
effect.
|
effect.
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
<secondary>operation</secondary>
|
<secondary>operation</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
|
|
||||||
<sect1 id="repmgrd-pausing" xreflabel="pausing the repmgrd service">
|
<sect1 id="repmgrd-pausing">
|
||||||
|
|
||||||
<title>Pausing the repmgrd service</title>
|
<title>Pausing repmgrd</title>
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>repmgrd</primary>
|
<primary>repmgrd</primary>
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
For major PostgreSQL upgrades, e.g. from PostgreSQL 11 to PostgreSQL 12,
|
For major PostgreSQL upgrades, e.g. from PostgreSQL 10 to PostgreSQL 11,
|
||||||
&repmgrd; should be shut down completely and only started up
|
&repmgrd; should be shut down completely and only started up
|
||||||
once the &repmgr; packages for the new PostgreSQL major version have been installed.
|
once the &repmgr; packages for the new PostgreSQL major version have been installed.
|
||||||
</para>
|
</para>
|
||||||
@@ -88,21 +88,17 @@
|
|||||||
<sect2 id="repmgrd-pausing-execution">
|
<sect2 id="repmgrd-pausing-execution">
|
||||||
<title>Pausing/unpausing &repmgrd;</title>
|
<title>Pausing/unpausing &repmgrd;</title>
|
||||||
<para>
|
<para>
|
||||||
To pause &repmgrd;, execute <link linkend="repmgr-service-pause"><command>repmgr service pause</command></link>
|
To pause &repmgrd;, execute <link linkend="repmgr-daemon-pause"><command>repmgr daemon pause</command></link>, e.g.:
|
||||||
(&repmgr; 4.2 - 4.4: <link linkend="repmgr-service-pause"><command>repmgr daemon pause</command></link>),
|
|
||||||
e.g.:
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ repmgr -f /etc/repmgr.conf service pause
|
$ repmgr -f /etc/repmgr.conf daemon pause
|
||||||
NOTICE: node 1 (node1) paused
|
NOTICE: node 1 (node1) paused
|
||||||
NOTICE: node 2 (node2) paused
|
NOTICE: node 2 (node2) paused
|
||||||
NOTICE: node 3 (node3) paused</programlisting>
|
NOTICE: node 3 (node3) paused</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The state of &repmgrd; on each node can be checked with
|
The state of &repmgrd; on each node can be checked with
|
||||||
<link linkend="repmgr-service-status"><command>repmgr service status</command></link>
|
<link linkend="repmgr-daemon-status"><command>repmgr daemon status</command></link>, e.g.:
|
||||||
(&repmgr; 4.2 - 4.4: <link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>),
|
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
|
||||||
e.g.:
|
|
||||||
<programlisting>$ repmgr -f /etc/repmgr.conf service status
|
|
||||||
ID | Name | Role | Status | repmgrd | PID | Paused?
|
ID | Name | Role | Status | repmgrd | PID | Paused?
|
||||||
----+-------+---------+---------+---------+------+---------
|
----+-------+---------+---------+---------+------+---------
|
||||||
1 | node1 | primary | running | running | 7851 | yes
|
1 | node1 | primary | running | running | 7851 | yes
|
||||||
@@ -112,8 +108,8 @@ NOTICE: node 3 (node3) paused</programlisting>
|
|||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
If executing a switchover with <link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>,
|
If executing a switchover with <link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>,
|
||||||
&repmgr; will automatically pause/unpause the &repmgrd; service as part of the switchover process.
|
&repmgr; will automatically pause/unpause &repmgrd; as part of the switchover process.
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
@@ -121,32 +117,29 @@ NOTICE: node 3 (node3) paused</programlisting>
|
|||||||
If the primary (in this example, <literal>node1</literal>) is stopped, &repmgrd;
|
If the primary (in this example, <literal>node1</literal>) is stopped, &repmgrd;
|
||||||
running on one of the standbys (here: <literal>node2</literal>) will react like this:
|
running on one of the standbys (here: <literal>node2</literal>) will react like this:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[2019-08-28 12:22:21] [WARNING] unable to connect to upstream node "node1" (node ID: 1)
|
[2018-09-20 12:22:21] [WARNING] unable to connect to upstream node "node1" (ID: 1)
|
||||||
[2019-08-28 12:22:21] [INFO] checking state of node 1, 1 of 5 attempts
|
[2018-09-20 12:22:21] [INFO] checking state of node 1, 1 of 5 attempts
|
||||||
[2019-08-28 12:22:21] [INFO] sleeping 1 seconds until next reconnection attempt
|
[2018-09-20 12:22:21] [INFO] sleeping 1 seconds until next reconnection attempt
|
||||||
...
|
...
|
||||||
[2019-08-28 12:22:24] [INFO] sleeping 1 seconds until next reconnection attempt
|
[2018-09-20 12:22:24] [INFO] sleeping 1 seconds until next reconnection attempt
|
||||||
[2019-08-28 12:22:25] [INFO] checking state of node 1, 5 of 5 attempts
|
[2018-09-20 12:22:25] [INFO] checking state of node 1, 5 of 5 attempts
|
||||||
[2019-08-28 12:22:25] [WARNING] unable to reconnect to node 1 after 5 attempts
|
[2018-09-20 12:22:25] [WARNING] unable to reconnect to node 1 after 5 attempts
|
||||||
[2019-08-28 12:22:25] [NOTICE] node is paused
|
[2018-09-20 12:22:25] [NOTICE] node is paused
|
||||||
[2019-08-28 12:22:33] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (node ID: 1) in degraded state
|
[2018-09-20 12:22:33] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (ID: 1) in degraded state
|
||||||
[2019-08-28 12:22:33] [DETAIL] repmgrd paused by administrator
|
[2018-09-20 12:22:33] [DETAIL] repmgrd paused by administrator
|
||||||
[2019-08-28 12:22:33] [HINT] execute "repmgr service unpause" to resume normal failover mode</programlisting>
|
[2018-09-20 12:22:33] [HINT] execute "repmgr daemon unpause" to resume normal failover mode</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
If the primary becomes available again (e.g. following a software upgrade), &repmgrd;
|
If the primary becomes available again (e.g. following a software upgrade), &repmgrd;
|
||||||
will automatically reconnect, e.g.:
|
will automatically reconnect, e.g.:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[2019-08-28 12:25:41] [NOTICE] reconnected to upstream node 1 after 8 seconds, resuming monitoring</programlisting>
|
[2018-09-20 13:12:41] [NOTICE] reconnected to upstream node 1 after 8 seconds, resuming monitoring</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
To unpause the &repmgrd; service, execute
|
To unpause &repmgrd;, execute <link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link>, e.g.:
|
||||||
<link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link>
|
|
||||||
((&repmgr; 4.2 - 4.4: <link linkend="repmgr-service-unpause"><command>repmgr daemon unpause</command></link>),
|
|
||||||
e.g.:
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
$ repmgr -f /etc/repmgr.conf service unpause
|
$ repmgr -f /etc/repmgr.conf daemon unpause
|
||||||
NOTICE: node 1 (node1) unpaused
|
NOTICE: node 1 (node1) unpaused
|
||||||
NOTICE: node 2 (node2) unpaused
|
NOTICE: node 2 (node2) unpaused
|
||||||
NOTICE: node 3 (node3) unpaused</programlisting>
|
NOTICE: node 3 (node3) unpaused</programlisting>
|
||||||
@@ -157,11 +150,11 @@ NOTICE: node 3 (node3) unpaused</programlisting>
|
|||||||
If the previous primary is no longer accessible when &repmgrd;
|
If the previous primary is no longer accessible when &repmgrd;
|
||||||
is unpaused, no failover action will be taken. Instead, a new primary must be manually promoted using
|
is unpaused, no failover action will be taken. Instead, a new primary must be manually promoted using
|
||||||
<link linkend="repmgr-standby-promote"><command>repmgr standby promote</command></link>,
|
<link linkend="repmgr-standby-promote"><command>repmgr standby promote</command></link>,
|
||||||
and any standbys attached to the new primary with
|
and any standbys attached to the new primary with
|
||||||
<link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>.
|
<link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
This is to prevent execution of <link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link>
|
This is to prevent <link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link>
|
||||||
resulting in the automatic promotion of a new primary, which may be a problem particularly
|
resulting in the automatic promotion of a new primary, which may be a problem particularly
|
||||||
in larger clusters, where &repmgrd; could select a different promotion
|
in larger clusters, where &repmgrd; could select a different promotion
|
||||||
candidate to the one intended by the administrator.
|
candidate to the one intended by the administrator.
|
||||||
@@ -175,23 +168,17 @@ NOTICE: node 3 (node3) unpaused</programlisting>
|
|||||||
The pause state of each node will be stored over a PostgreSQL restart.
|
The pause state of each node will be stored over a PostgreSQL restart.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<link linkend="repmgr-service-pause"><command>repmgr service pause</command></link> and
|
<link linkend="repmgr-daemon-pause"><command>repmgr daemon pause</command></link> and
|
||||||
<link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link> can be
|
<link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link> can be
|
||||||
executed even if &repmgrd; is not running; in this case,
|
executed even if &repmgrd; is not running; in this case,
|
||||||
&repmgrd; will start up in whichever pause state has been set.
|
&repmgrd; will start up in whichever pause state has been set.
|
||||||
</para>
|
</para>
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
<link linkend="repmgr-service-pause"><command>repmgr service pause</command></link> and
|
<link linkend="repmgr-daemon-pause"><command>repmgr daemon pause</command></link> and
|
||||||
<link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link>
|
<link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link>
|
||||||
<emphasis>do not</emphasis> start/stop &repmgrd;.
|
<emphasis>do not</emphasis> stop/start &repmgrd;.
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The commands <link linkend="repmgr-daemon-start"><command>repmgr daemon start</command></link>
|
|
||||||
and <link linkend="repmgr-daemon-stop"><command>repmgr daemon stop</command></link>
|
|
||||||
(<link linkend="repmgrd-service-configuration">if correctly configured</link>) can be used to start/stop
|
|
||||||
&repmgrd; on individual nodes.
|
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
<simpara>
|
<simpara>
|
||||||
ability to <link linkend="repmgrd-pausing">pause repmgrd</link>
|
ability to <link linkend="repmgrd-pausing">pause repmgrd</link>
|
||||||
operation on all nodes with a
|
operation on all nodes with a
|
||||||
<link linkend="repmgr-service-pause"><command>single command</command></link>
|
<link linkend="repmgr-daemon-pause"><command>single command</command></link>
|
||||||
</simpara>
|
</simpara>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
@@ -100,11 +100,11 @@
|
|||||||
Start &repmgrd; on each standby and verify that it's running by examining the
|
Start &repmgrd; on each standby and verify that it's running by examining the
|
||||||
log output, which at log level <literal>INFO</literal> will look like this:
|
log output, which at log level <literal>INFO</literal> will look like this:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[2019-08-15 07:14:42] [NOTICE] repmgrd (repmgrd 5.0) starting up
|
[2019-03-15 06:32:05] [NOTICE] repmgrd (repmgrd 4.3) starting up
|
||||||
[2019-08-15 07:14:42] [INFO] connecting to database "host=node2 dbname=repmgr user=repmgr connect_timeout=2"
|
[2019-03-15 06:32:05] [INFO] connecting to database "host=node2 dbname=repmgr user=repmgr connect_timeout=2"
|
||||||
INFO: set_repmgrd_pid(): provided pidfile is /var/run/repmgr/repmgrd-12.pid
|
INFO: set_repmgrd_pid(): provided pidfile is /var/run/repmgr/repmgrd-11.pid
|
||||||
[2019-08-15 07:14:42] [NOTICE] starting monitoring of node "node2" (ID: 2)
|
[2019-03-15 06:32:05] [NOTICE] starting monitoring of node "node2" (ID: 2)
|
||||||
[2019-08-15 07:14:42] [INFO] monitoring connection to upstream node "node1" (ID: 1)</programlisting>
|
[2019-03-15 06:32:05] [INFO] monitoring connection to upstream node "node1" (ID: 1)</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Each &repmgrd; should also have recorded its successful startup as an event:
|
Each &repmgrd; should also have recorded its successful startup as an event:
|
||||||
@@ -112,9 +112,9 @@
|
|||||||
$ repmgr -f /etc/repmgr.conf cluster event --event=repmgrd_start
|
$ repmgr -f /etc/repmgr.conf cluster event --event=repmgrd_start
|
||||||
Node ID | Name | Event | OK | Timestamp | Details
|
Node ID | Name | Event | OK | Timestamp | Details
|
||||||
---------+-------+---------------+----+---------------------+--------------------------------------------------------
|
---------+-------+---------------+----+---------------------+--------------------------------------------------------
|
||||||
3 | node3 | repmgrd_start | t | 2019-08-15 07:14:42 | monitoring connection to upstream node "node1" (ID: 1)
|
3 | node3 | repmgrd_start | t | 2019-03-14 04:17:30 | monitoring connection to upstream node "node1" (ID: 1)
|
||||||
2 | node2 | repmgrd_start | t | 2019-08-15 07:14:41 | monitoring connection to upstream node "node1" (ID: 1)
|
2 | node2 | repmgrd_start | t | 2019-03-14 04:11:47 | monitoring connection to upstream node "node1" (ID: 1)
|
||||||
1 | node1 | repmgrd_start | t | 2019-08-15 07:14:39 | monitoring cluster primary "node1" (ID: 1)</programlisting>
|
1 | node1 | repmgrd_start | t | 2019-03-14 04:04:31 | monitoring cluster primary "node1" (ID: 1)</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Now stop the current primary server with e.g.:
|
Now stop the current primary server with e.g.:
|
||||||
@@ -128,33 +128,33 @@
|
|||||||
decision is made. This is an extract from the log of a standby server (<literal>node2</literal>)
|
decision is made. This is an extract from the log of a standby server (<literal>node2</literal>)
|
||||||
which has promoted to new primary after failure of the original primary (<literal>node1</literal>).
|
which has promoted to new primary after failure of the original primary (<literal>node1</literal>).
|
||||||
<programlisting>
|
<programlisting>
|
||||||
[2019-08-15 07:27:50] [WARNING] unable to connect to upstream node "node1" (ID: 1)
|
[2019-03-15 06:37:50] [WARNING] unable to connect to upstream node "node1" (ID: 1)
|
||||||
[2019-08-15 07:27:50] [INFO] checking state of node 1, 1 of 3 attempts
|
[2019-03-15 06:37:50] [INFO] checking state of node 1, 1 of 3 attempts
|
||||||
[2019-08-15 07:27:50] [INFO] sleeping 5 seconds until next reconnection attempt
|
[2019-03-15 06:37:50] [INFO] sleeping 5 seconds until next reconnection attempt
|
||||||
[2019-08-15 07:27:55] [INFO] checking state of node 1, 2 of 3 attempts
|
[2019-03-15 06:37:55] [INFO] checking state of node 1, 2 of 3 attempts
|
||||||
[2019-08-15 07:27:55] [INFO] sleeping 5 seconds until next reconnection attempt
|
[2019-03-15 06:37:55] [INFO] sleeping 5 seconds until next reconnection attempt
|
||||||
[2019-08-15 07:28:00] [INFO] checking state of node 1, 3 of 3 attempts
|
[2019-03-15 06:38:00] [INFO] checking state of node 1, 3 of 3 attempts
|
||||||
[2019-08-15 07:28:00] [WARNING] unable to reconnect to node 1 after 3 attempts
|
[2019-03-15 06:38:00] [WARNING] unable to reconnect to node 1 after 3 attempts
|
||||||
[2019-08-15 07:28:00] [INFO] primary and this node have the same location ("default")
|
[2019-03-15 06:38:00] [INFO] primary and this node have the same location ("default")
|
||||||
[2019-08-15 07:28:00] [INFO] local node's last receive lsn: 0/900CBF8
|
[2019-03-15 06:38:00] [INFO] local node's last receive lsn: 0/900CBF8
|
||||||
[2019-08-15 07:28:00] [INFO] node 3 last saw primary node 12 second(s) ago
|
[2019-03-15 06:38:00] [INFO] node 3 last saw primary node 12 second(s) ago
|
||||||
[2019-08-15 07:28:00] [INFO] last receive LSN for sibling node "node3" (ID: 3) is: 0/900CBF8
|
[2019-03-15 06:38:00] [INFO] last receive LSN for sibling node "node3" (ID: 3) is: 0/900CBF8
|
||||||
[2019-08-15 07:28:00] [INFO] node "node3" (ID: 3) has same LSN as current candidate "node2" (ID: 2)
|
[2019-03-15 06:38:00] [INFO] node "node3" (ID: 3) has same LSN as current candidate "node2" (ID: 2)
|
||||||
[2019-08-15 07:28:00] [INFO] visible nodes: 2; total nodes: 2; no nodes have seen the primary within the last 4 seconds
|
[2019-03-15 06:38:00] [INFO] visible nodes: 2; total nodes: 2; no nodes have seen the primary within the last 4 seconds
|
||||||
[2019-08-15 07:28:00] [NOTICE] promotion candidate is "node2" (ID: 2)
|
[2019-03-15 06:38:00] [NOTICE] promotion candidate is "node2" (ID: 2)
|
||||||
[2019-08-15 07:28:00] [NOTICE] this node is the winner, will now promote itself and inform other nodes
|
[2019-03-15 06:38:00] [NOTICE] this node is the winner, will now promote itself and inform other nodes
|
||||||
[2019-08-15 07:28:00] [INFO] promote_command is:
|
[2019-03-15 06:38:00] [INFO] promote_command is:
|
||||||
"/usr/pgsql-12/bin/repmgr -f /etc/repmgr/12/repmgr.conf standby promote"
|
"/usr/pgsql-11/bin/repmgr -f /etc/repmgr/11/repmgr.conf standby promote"
|
||||||
NOTICE: promoting standby to primary
|
NOTICE: promoting standby to primary
|
||||||
DETAIL: promoting server "node2" (ID: 2) using "/usr/pgsql-12/bin/pg_ctl -w -D '/var/lib/pgsql/12/data' promote"
|
DETAIL: promoting server "node2" (ID: 2) using "/usr/pgsql-11/bin/pg_ctl -w -D '/var/lib/pgsql/11/data' promote"
|
||||||
NOTICE: waiting up to 60 seconds (parameter "promote_check_timeout") for promotion to complete
|
NOTICE: waiting up to 60 seconds (parameter "promote_check_timeout") for promotion to complete
|
||||||
NOTICE: STANDBY PROMOTE successful
|
NOTICE: STANDBY PROMOTE successful
|
||||||
DETAIL: server "node2" (ID: 2) was successfully promoted to primary
|
DETAIL: server "node2" (ID: 2) was successfully promoted to primary
|
||||||
[2019-08-15 07:28:01] [INFO] 3 followers to notify
|
[2019-03-15 06:38:01] [INFO] 3 followers to notify
|
||||||
[2019-08-15 07:28:01] [NOTICE] notifying node "node3" (ID: 3) to follow node 2
|
[2019-03-15 06:38:01] [NOTICE] notifying node "node3" (ID: 3) to follow node 2
|
||||||
INFO: node 3 received notification to follow node 2
|
INFO: node 3 received notification to follow node 2
|
||||||
[2019-08-15 07:28:01] [INFO] switching to primary monitoring mode
|
[2019-03-15 06:38:01] [INFO] switching to primary monitoring mode
|
||||||
[2019-08-15 07:28:01] [NOTICE] monitoring cluster primary "node2" (ID: 2)</programlisting>
|
[2019-03-15 06:38:01] [NOTICE] monitoring cluster primary "node2" (ID: 2)</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The cluster status will now look like this, with the original primary (<literal>node1</literal>)
|
The cluster status will now look like this, with the original primary (<literal>node1</literal>)
|
||||||
@@ -176,11 +176,11 @@
|
|||||||
$ repmgr -f /etc/repmgr.conf cluster event
|
$ repmgr -f /etc/repmgr.conf cluster event
|
||||||
Node ID | Name | Event | OK | Timestamp | Details
|
Node ID | Name | Event | OK | Timestamp | Details
|
||||||
---------+-------+----------------------------+----+---------------------+-------------------------------------------------------------
|
---------+-------+----------------------------+----+---------------------+-------------------------------------------------------------
|
||||||
3 | node3 | repmgrd_failover_follow | t | 2019-08-15 07:38:03 | node 3 now following new upstream node 2
|
3 | node3 | repmgrd_failover_follow | t | 2019-03-15 06:38:03 | node 3 now following new upstream node 2
|
||||||
3 | node3 | standby_follow | t | 2019-08-15 07:38:02 | standby attached to upstream node "node2" (ID: 2)
|
3 | node3 | standby_follow | t | 2019-03-15 06:38:02 | standby attached to upstream node "node2" (ID: 2)
|
||||||
2 | node2 | repmgrd_reload | t | 2019-08-15 07:38:01 | monitoring cluster primary "node2" (ID: 2)
|
2 | node2 | repmgrd_reload | t | 2019-03-15 06:38:01 | monitoring cluster primary "node2" (ID: 2)
|
||||||
2 | node2 | repmgrd_failover_promote | t | 2019-08-15 07:38:01 | node 2 promoted to primary; old primary 1 marked as failed
|
2 | node2 | repmgrd_failover_promote | t | 2019-03-15 06:38:01 | node 2 promoted to primary; old primary 1 marked as failed
|
||||||
2 | node2 | standby_promote | t | 2019-08-15 07:38:01 | server "node2" (ID: 2) was successfully promoted to primary</programlisting>
|
2 | node2 | standby_promote | t | 2019-03-15 06:38:01 | server "node2" (ID: 2) was successfully promoted to primary</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|||||||
@@ -186,7 +186,6 @@
|
|||||||
NOTICE: local node "node2" (ID: 2) will be promoted to primary; current primary "node1" (ID: 1) will be demoted to standby
|
NOTICE: local node "node2" (ID: 2) will be promoted to primary; current primary "node1" (ID: 1) will be demoted to standby
|
||||||
INFO: following shutdown command would be run on node "node1":
|
INFO: following shutdown command would be run on node "node1":
|
||||||
"pg_ctl -l /var/log/postgresql/startup.log -D '/var/lib/postgresql/data' -m fast -W stop"
|
"pg_ctl -l /var/log/postgresql/startup.log -D '/var/lib/postgresql/data' -m fast -W stop"
|
||||||
INFO: parameter "shutdown_check_timeout" is set to 60 seconds
|
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@@ -318,9 +317,7 @@
|
|||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
If &repmgrd; is in use, it's worth double-checking that
|
If &repmgrd; is in use, it's worth double-checking that
|
||||||
all nodes are unpaused by executing
|
all nodes are unpaused by executing <command><link linkend="repmgr-daemon-status">repmgr-daemon-status</link></command>.
|
||||||
<command><link linkend="repmgr-service-status">repmgr service status</link></command>
|
|
||||||
(&repmgr; 4.2 - 4.4: <command><link linkend="repmgr-service-status">repmgr daemon status</link></command>).
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
|
|||||||
@@ -216,9 +216,7 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
|||||||
<secondary>checking repmgrd status</secondary>
|
<secondary>checking repmgrd status</secondary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
<para>
|
<para>
|
||||||
From <link linkend="release-4.2">repmgr 4.2</link>, once the upgrade is complete, execute the
|
From <link linkend="release-4.2">repmgr 4.2</link>, once the upgrade is complete, execute the <command><link linkend="repmgr-daemon-status">repmgr daemon status</link></command>
|
||||||
<command><link linkend="repmgr-service-status">repmgr service status</link></command>
|
|
||||||
(&repmgr; 4.2 - 4.4: <command><link linkend="repmgr-service-status">repmgr daemon status</link></command>)
|
|
||||||
command (on any node) to show an overview of the status of &repmgrd; on all nodes.
|
command (on any node) to show an overview of the status of &repmgrd; on all nodes.
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
@@ -419,13 +417,13 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
|||||||
<programlisting>
|
<programlisting>
|
||||||
$ ./convert-config.pl /etc/repmgr.conf
|
$ ./convert-config.pl /etc/repmgr.conf
|
||||||
node_id=2
|
node_id=2
|
||||||
node_name='node2'
|
node_name=node2
|
||||||
conninfo='host=node2 dbname=repmgr user=repmgr connect_timeout=2'
|
conninfo=host=node2 dbname=repmgr user=repmgr connect_timeout=2
|
||||||
pg_ctl_options='-l /var/log/postgres/startup.log'
|
pg_ctl_options='-l /var/log/postgres/startup.log'
|
||||||
rsync_options='--exclude=postgresql.local.conf --archive'
|
rsync_options=--exclude=postgresql.local.conf --archive
|
||||||
log_level='INFO'
|
log_level=INFO
|
||||||
pg_basebackup_options='--no-slot'
|
pg_basebackup_options=--no-slot
|
||||||
data_directory=''</programlisting>
|
data_directory=</programlisting>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
The converted file is printed to <literal>STDOUT</literal> and the original file is not
|
The converted file is printed to <literal>STDOUT</literal> and the original file is not
|
||||||
@@ -434,7 +432,8 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
|||||||
<para>
|
<para>
|
||||||
Please note that the the conversion script will add an empty
|
Please note that the the conversion script will add an empty
|
||||||
placeholder parameter for <varname>data_directory</varname>, which
|
placeholder parameter for <varname>data_directory</varname>, which
|
||||||
is a required parameter from &repmgr; 4.
|
is a required parameter in repmgr4 and which <emphasis>must</emphasis>
|
||||||
|
be provided.
|
||||||
</para>
|
</para>
|
||||||
</sect3>
|
</sect3>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
|
||||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
|
||||||
|
|
||||||
ALTER FUNCTION set_repmgrd_pid(INT, TEXT) RETURNS NULL ON NULL INPUT;
|
|
||||||
|
|
||||||
224
repmgr--5.0.sql
224
repmgr--5.0.sql
@@ -1,224 +0,0 @@
|
|||||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
|
||||||
\echo Use "CREATE EXTENSION repmgr" to load this file. \quit
|
|
||||||
|
|
||||||
CREATE TABLE repmgr.nodes (
|
|
||||||
node_id INTEGER PRIMARY KEY,
|
|
||||||
upstream_node_id INTEGER NULL REFERENCES nodes (node_id) DEFERRABLE,
|
|
||||||
active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
||||||
node_name TEXT NOT NULL,
|
|
||||||
type TEXT NOT NULL CHECK (type IN('primary','standby','witness','bdr')),
|
|
||||||
location TEXT NOT NULL DEFAULT 'default',
|
|
||||||
priority INT NOT NULL DEFAULT 100,
|
|
||||||
conninfo TEXT NOT NULL,
|
|
||||||
repluser VARCHAR(63) NOT NULL,
|
|
||||||
slot_name TEXT NULL,
|
|
||||||
config_file TEXT NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE repmgr.events (
|
|
||||||
node_id INTEGER NOT NULL,
|
|
||||||
event TEXT NOT NULL,
|
|
||||||
successful BOOLEAN NOT NULL DEFAULT TRUE,
|
|
||||||
event_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
details TEXT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
DO $repmgr$
|
|
||||||
DECLARE
|
|
||||||
DECLARE server_version_num INT;
|
|
||||||
BEGIN
|
|
||||||
SELECT setting
|
|
||||||
FROM pg_catalog.pg_settings
|
|
||||||
WHERE name = 'server_version_num'
|
|
||||||
INTO server_version_num;
|
|
||||||
IF server_version_num >= 90400 THEN
|
|
||||||
EXECUTE $repmgr_func$
|
|
||||||
CREATE TABLE repmgr.monitoring_history (
|
|
||||||
primary_node_id INTEGER NOT NULL,
|
|
||||||
standby_node_id INTEGER NOT NULL,
|
|
||||||
last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
||||||
last_apply_time TIMESTAMP WITH TIME ZONE,
|
|
||||||
last_wal_primary_location PG_LSN NOT NULL,
|
|
||||||
last_wal_standby_location PG_LSN,
|
|
||||||
replication_lag BIGINT NOT NULL,
|
|
||||||
apply_lag BIGINT NOT NULL
|
|
||||||
)
|
|
||||||
$repmgr_func$;
|
|
||||||
ELSE
|
|
||||||
EXECUTE $repmgr_func$
|
|
||||||
CREATE TABLE repmgr.monitoring_history (
|
|
||||||
primary_node_id INTEGER NOT NULL,
|
|
||||||
standby_node_id INTEGER NOT NULL,
|
|
||||||
last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
||||||
last_apply_time TIMESTAMP WITH TIME ZONE,
|
|
||||||
last_wal_primary_location TEXT NOT NULL,
|
|
||||||
last_wal_standby_location TEXT,
|
|
||||||
replication_lag BIGINT NOT NULL,
|
|
||||||
apply_lag BIGINT NOT NULL
|
|
||||||
)
|
|
||||||
$repmgr_func$;
|
|
||||||
END IF;
|
|
||||||
END$repmgr$;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CREATE INDEX idx_monitoring_history_time
|
|
||||||
ON repmgr.monitoring_history (last_monitor_time, standby_node_id);
|
|
||||||
|
|
||||||
CREATE VIEW repmgr.show_nodes AS
|
|
||||||
SELECT n.node_id,
|
|
||||||
n.node_name,
|
|
||||||
n.active,
|
|
||||||
n.upstream_node_id,
|
|
||||||
un.node_name AS upstream_node_name,
|
|
||||||
n.type,
|
|
||||||
n.priority,
|
|
||||||
n.conninfo
|
|
||||||
FROM repmgr.nodes n
|
|
||||||
LEFT JOIN repmgr.nodes un
|
|
||||||
ON un.node_id = n.upstream_node_id;
|
|
||||||
|
|
||||||
CREATE TABLE repmgr.voting_term (
|
|
||||||
term INT NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX voting_term_restrict
|
|
||||||
ON repmgr.voting_term ((TRUE));
|
|
||||||
|
|
||||||
CREATE RULE voting_term_delete AS
|
|
||||||
ON DELETE TO repmgr.voting_term
|
|
||||||
DO INSTEAD NOTHING;
|
|
||||||
|
|
||||||
|
|
||||||
/* ================= */
|
|
||||||
/* repmgrd functions */
|
|
||||||
/* ================= */
|
|
||||||
|
|
||||||
/* monitoring functions */
|
|
||||||
|
|
||||||
CREATE FUNCTION set_local_node_id(INT)
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'set_local_node_id'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_local_node_id()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_local_node_id'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION standby_set_last_updated()
|
|
||||||
RETURNS TIMESTAMP WITH TIME ZONE
|
|
||||||
AS 'MODULE_PATHNAME', 'standby_set_last_updated'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION standby_get_last_updated()
|
|
||||||
RETURNS TIMESTAMP WITH TIME ZONE
|
|
||||||
AS 'MODULE_PATHNAME', 'standby_get_last_updated'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION set_upstream_last_seen(INT)
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'set_upstream_last_seen'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_upstream_last_seen()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_upstream_last_seen'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_upstream_node_id()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_upstream_node_id'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION set_upstream_node_id(INT)
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'set_upstream_node_id'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
/* failover functions */
|
|
||||||
|
|
||||||
CREATE FUNCTION notify_follow_primary(INT)
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'notify_follow_primary'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_new_primary()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_new_primary'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION reset_voting_status()
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'reset_voting_status'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION am_bdr_failover_handler(INT)
|
|
||||||
RETURNS BOOL
|
|
||||||
AS 'MODULE_PATHNAME', 'am_bdr_failover_handler'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION unset_bdr_failover_handler()
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'unset_bdr_failover_handler'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_repmgrd_pid()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pid'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_repmgrd_pidfile()
|
|
||||||
RETURNS TEXT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_repmgrd_pidfile'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION set_repmgrd_pid(INT, TEXT)
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'set_repmgrd_pid'
|
|
||||||
LANGUAGE C CALLED ON NULL INPUT;
|
|
||||||
|
|
||||||
CREATE FUNCTION repmgrd_is_running()
|
|
||||||
RETURNS BOOL
|
|
||||||
AS 'MODULE_PATHNAME', 'repmgrd_is_running'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION repmgrd_pause(BOOL)
|
|
||||||
RETURNS VOID
|
|
||||||
AS 'MODULE_PATHNAME', 'repmgrd_pause'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION repmgrd_is_paused()
|
|
||||||
RETURNS BOOL
|
|
||||||
AS 'MODULE_PATHNAME', 'repmgrd_is_paused'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
CREATE FUNCTION get_wal_receiver_pid()
|
|
||||||
RETURNS INT
|
|
||||||
AS 'MODULE_PATHNAME', 'get_wal_receiver_pid'
|
|
||||||
LANGUAGE C STRICT;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* views */
|
|
||||||
|
|
||||||
CREATE VIEW repmgr.replication_status AS
|
|
||||||
SELECT m.primary_node_id, m.standby_node_id, n.node_name AS standby_name,
|
|
||||||
n.type AS node_type, n.active, last_monitor_time,
|
|
||||||
CASE WHEN n.type='standby' THEN m.last_wal_primary_location ELSE NULL END AS last_wal_primary_location,
|
|
||||||
m.last_wal_standby_location,
|
|
||||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.replication_lag) ELSE NULL END AS replication_lag,
|
|
||||||
CASE WHEN n.type='standby' THEN
|
|
||||||
CASE WHEN replication_lag > 0 THEN age(now(), m.last_apply_time) ELSE '0'::INTERVAL END
|
|
||||||
ELSE NULL
|
|
||||||
END AS replication_time_lag,
|
|
||||||
CASE WHEN n.type='standby' THEN pg_catalog.pg_size_pretty(m.apply_lag) ELSE NULL END AS apply_lag,
|
|
||||||
AGE(NOW(), CASE WHEN pg_catalog.pg_is_in_recovery() THEN repmgr.standby_get_last_updated() ELSE m.last_monitor_time END) AS communication_time_lag
|
|
||||||
FROM repmgr.monitoring_history m
|
|
||||||
JOIN repmgr.nodes n ON m.standby_node_id = n.node_id
|
|
||||||
WHERE (m.standby_node_id, m.last_monitor_time) IN (
|
|
||||||
SELECT m1.standby_node_id, MAX(m1.last_monitor_time)
|
|
||||||
FROM repmgr.monitoring_history m1 GROUP BY 1
|
|
||||||
);
|
|
||||||
|
|
||||||
@@ -247,13 +247,13 @@ do_cluster_show(void)
|
|||||||
if (cell->node_info->replication_info->timeline_id == UNKNOWN_TIMELINE_ID)
|
if (cell->node_info->replication_info->timeline_id == UNKNOWN_TIMELINE_ID)
|
||||||
{
|
{
|
||||||
/* display "?" */
|
/* display "?" */
|
||||||
headers_show[SHOW_TIMELINE_ID].cur_length = 1;
|
headers_show[SHOW_PRIORITY].cur_length = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
initPQExpBuffer(&buf);
|
initPQExpBuffer(&buf);
|
||||||
appendPQExpBuffer(&buf, "%i", cell->node_info->replication_info->timeline_id);
|
appendPQExpBuffer(&buf, "%i", cell->node_info->replication_info->timeline_id);
|
||||||
headers_show[SHOW_TIMELINE_ID].cur_length = strlen(buf.data);
|
headers_show[SHOW_PRIORITY].cur_length = strlen(buf.data);
|
||||||
termPQExpBuffer(&buf);
|
termPQExpBuffer(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -987,19 +987,7 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length, Ite
|
|||||||
make_remote_repmgr_path(&command, cell->node_info);
|
make_remote_repmgr_path(&command, cell->node_info);
|
||||||
|
|
||||||
appendPQExpBufferStr(&command,
|
appendPQExpBufferStr(&command,
|
||||||
" cluster show --csv --terse");
|
" cluster show --csv -L NOTICE --terse\"");
|
||||||
|
|
||||||
/*
|
|
||||||
* Usually we'll want NOTICE as the log level, but if the user
|
|
||||||
* explicitly provided one with --log-level, that will be passed
|
|
||||||
* in the remote repmgr invocation.
|
|
||||||
*/
|
|
||||||
if (runtime_options.log_level[0] == '\0')
|
|
||||||
{
|
|
||||||
appendPQExpBufferStr(&command,
|
|
||||||
" -L NOTICE");
|
|
||||||
}
|
|
||||||
appendPQExpBufferChar(&command, '"');
|
|
||||||
|
|
||||||
log_verbose(LOG_DEBUG, "build_cluster_matrix(): executing:\n %s", command.data);
|
log_verbose(LOG_DEBUG, "build_cluster_matrix(): executing:\n %s", command.data);
|
||||||
|
|
||||||
@@ -1187,18 +1175,7 @@ build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length, Item
|
|||||||
make_remote_repmgr_path(&command, cell->node_info);
|
make_remote_repmgr_path(&command, cell->node_info);
|
||||||
|
|
||||||
appendPQExpBufferStr(&command,
|
appendPQExpBufferStr(&command,
|
||||||
" cluster matrix --csv --terse");
|
" cluster matrix --csv -L NOTICE --terse");
|
||||||
|
|
||||||
/*
|
|
||||||
* Usually we'll want NOTICE as the log level, but if the user
|
|
||||||
* explicitly provided one with --log-level, that will be passed
|
|
||||||
* in the remote repmgr invocation.
|
|
||||||
*/
|
|
||||||
if (runtime_options.log_level[0] == '\0')
|
|
||||||
{
|
|
||||||
appendPQExpBufferStr(&command,
|
|
||||||
" -L NOTICE");
|
|
||||||
}
|
|
||||||
|
|
||||||
initPQExpBuffer(&command_output);
|
initPQExpBuffer(&command_output);
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,478 @@
|
|||||||
#include "repmgr-client-global.h"
|
#include "repmgr-client-global.h"
|
||||||
#include "repmgr-action-daemon.h"
|
#include "repmgr-action-daemon.h"
|
||||||
|
|
||||||
#define REPMGR_SERVICE_STOP_START_WAIT 15
|
#define REPMGR_DAEMON_STOP_START_WAIT 15
|
||||||
#define REPMGR_SERVICE_STATUS_START_HINT _("use \"repmgr service status\" to confirm that repmgrd was successfully started")
|
#define REPMGR_DAEMON_STATUS_START_HINT _("use \"repmgr daemon status\" to confirm that repmgrd was successfully started")
|
||||||
#define REPMGR_SERVICE_STATUS_STOP_HINT _("use \"repmgr service status\" to confirm that repmgrd was successfully stopped")
|
#define REPMGR_DAEMON_STATUS_STOP_HINT _("use \"repmgr daemon status\" to confirm that repmgrd was successfully stopped")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Possibly also show:
|
||||||
|
* - repmgrd start time?
|
||||||
|
* - repmgrd mode
|
||||||
|
* - priority
|
||||||
|
* - whether promotion candidate (due to zero priority/different location)
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
STATUS_ID = 0,
|
||||||
|
STATUS_NAME,
|
||||||
|
STATUS_ROLE,
|
||||||
|
STATUS_PG,
|
||||||
|
STATUS_UPSTREAM_NAME,
|
||||||
|
STATUS_LOCATION,
|
||||||
|
STATUS_PRIORITY,
|
||||||
|
STATUS_REPMGRD,
|
||||||
|
STATUS_PID,
|
||||||
|
STATUS_PAUSED,
|
||||||
|
STATUS_UPSTREAM_LAST_SEEN
|
||||||
|
} StatusHeader;
|
||||||
|
|
||||||
|
#define STATUS_HEADER_COUNT 11
|
||||||
|
|
||||||
|
struct ColHeader headers_status[STATUS_HEADER_COUNT];
|
||||||
|
|
||||||
|
static void fetch_node_records(PGconn *conn, NodeInfoList *node_list);
|
||||||
|
static void _do_repmgr_pause(bool pause);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
do_daemon_status(void)
|
||||||
|
{
|
||||||
|
PGconn *conn = NULL;
|
||||||
|
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||||
|
NodeInfoListCell *cell = NULL;
|
||||||
|
int i;
|
||||||
|
RepmgrdInfo **repmgrd_info;
|
||||||
|
ItemList warnings = {NULL, NULL};
|
||||||
|
bool connection_error_found = false;
|
||||||
|
|
||||||
|
/* Connect to local database to obtain cluster connection data */
|
||||||
|
log_verbose(LOG_INFO, _("connecting to database"));
|
||||||
|
|
||||||
|
if (strlen(config_file_options.conninfo))
|
||||||
|
conn = establish_db_connection(config_file_options.conninfo, true);
|
||||||
|
else
|
||||||
|
conn = establish_db_connection_by_params(&source_conninfo, true);
|
||||||
|
|
||||||
|
fetch_node_records(conn, &nodes);
|
||||||
|
|
||||||
|
repmgrd_info = (RepmgrdInfo **) pg_malloc0(sizeof(RepmgrdInfo *) * nodes.node_count);
|
||||||
|
|
||||||
|
if (repmgrd_info == NULL)
|
||||||
|
{
|
||||||
|
log_error(_("unable to allocate memory"));
|
||||||
|
exit(ERR_OUT_OF_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(headers_status[STATUS_ID].title, _("ID"), MAXLEN);
|
||||||
|
strncpy(headers_status[STATUS_NAME].title, _("Name"), MAXLEN);
|
||||||
|
strncpy(headers_status[STATUS_ROLE].title, _("Role"), MAXLEN);
|
||||||
|
strncpy(headers_status[STATUS_PG].title, _("Status"), MAXLEN);
|
||||||
|
strncpy(headers_status[STATUS_UPSTREAM_NAME].title, _("Upstream"), MAXLEN);
|
||||||
|
|
||||||
|
/* following only displayed with the --detail option */
|
||||||
|
strncpy(headers_status[STATUS_LOCATION].title, _("Location"), MAXLEN);
|
||||||
|
if (runtime_options.compact == true)
|
||||||
|
strncpy(headers_status[STATUS_PRIORITY].title, _("Prio."), MAXLEN);
|
||||||
|
else
|
||||||
|
strncpy(headers_status[STATUS_PRIORITY].title, _("Priority"), MAXLEN);
|
||||||
|
|
||||||
|
strncpy(headers_status[STATUS_REPMGRD].title, _("repmgrd"), MAXLEN);
|
||||||
|
strncpy(headers_status[STATUS_PID].title, _("PID"), MAXLEN);
|
||||||
|
strncpy(headers_status[STATUS_PAUSED].title, _("Paused?"), MAXLEN);
|
||||||
|
|
||||||
|
if (runtime_options.compact == true)
|
||||||
|
strncpy(headers_status[STATUS_UPSTREAM_LAST_SEEN].title, _("Upstr. last"), MAXLEN);
|
||||||
|
else
|
||||||
|
strncpy(headers_status[STATUS_UPSTREAM_LAST_SEEN].title, _("Upstream last seen"), MAXLEN);
|
||||||
|
|
||||||
|
for (i = 0; i < STATUS_HEADER_COUNT; i++)
|
||||||
|
{
|
||||||
|
headers_status[i].max_length = strlen(headers_status[i].title);
|
||||||
|
headers_status[i].display = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runtime_options.detail == false)
|
||||||
|
{
|
||||||
|
headers_status[STATUS_LOCATION].display = false;
|
||||||
|
headers_status[STATUS_PRIORITY].display = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
for (cell = nodes.head; cell; cell = cell->next)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
PQExpBufferData node_status;
|
||||||
|
PQExpBufferData upstream;
|
||||||
|
|
||||||
|
repmgrd_info[i] = pg_malloc0(sizeof(RepmgrdInfo));
|
||||||
|
repmgrd_info[i]->node_id = cell->node_info->node_id;
|
||||||
|
repmgrd_info[i]->pid = UNKNOWN_PID;
|
||||||
|
repmgrd_info[i]->recovery_type = RECTYPE_UNKNOWN;
|
||||||
|
repmgrd_info[i]->paused = false;
|
||||||
|
repmgrd_info[i]->running = false;
|
||||||
|
repmgrd_info[i]->pg_running = true;
|
||||||
|
repmgrd_info[i]->wal_paused_pending_wal = false;
|
||||||
|
repmgrd_info[i]->upstream_last_seen = -1;
|
||||||
|
|
||||||
|
cell->node_info->conn = establish_db_connection_quiet(cell->node_info->conninfo);
|
||||||
|
|
||||||
|
if (PQstatus(cell->node_info->conn) != CONNECTION_OK)
|
||||||
|
{
|
||||||
|
|
||||||
|
connection_error_found = true;
|
||||||
|
|
||||||
|
if (runtime_options.verbose)
|
||||||
|
{
|
||||||
|
char error[MAXLEN];
|
||||||
|
|
||||||
|
strncpy(error, PQerrorMessage(cell->node_info->conn), MAXLEN);
|
||||||
|
|
||||||
|
item_list_append_format(&warnings,
|
||||||
|
"when attempting to connect to node \"%s\" (ID: %i), following error encountered :\n\"%s\"",
|
||||||
|
cell->node_info->node_name, cell->node_info->node_id, trim(error));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item_list_append_format(&warnings,
|
||||||
|
"unable to connect to node \"%s\" (ID: %i)",
|
||||||
|
cell->node_info->node_name, cell->node_info->node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
repmgrd_info[i]->pg_running = false;
|
||||||
|
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("n/a"));
|
||||||
|
maxlen_snprintf(repmgrd_info[i]->pid_text, "%s", _("n/a"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cell->node_info->node_status = NODE_STATUS_UP;
|
||||||
|
cell->node_info->recovery_type = get_recovery_type(cell->node_info->conn);
|
||||||
|
|
||||||
|
repmgrd_info[i]->pid = repmgrd_get_pid(cell->node_info->conn);
|
||||||
|
|
||||||
|
repmgrd_info[i]->running = repmgrd_is_running(cell->node_info->conn);
|
||||||
|
|
||||||
|
if (repmgrd_info[i]->running == true)
|
||||||
|
{
|
||||||
|
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("running"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("not running"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repmgrd_info[i]->pid == UNKNOWN_PID)
|
||||||
|
{
|
||||||
|
maxlen_snprintf(repmgrd_info[i]->pid_text, "%s", _("n/a"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maxlen_snprintf(repmgrd_info[i]->pid_text, "%i", repmgrd_info[i]->pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
repmgrd_info[i]->paused = repmgrd_is_paused(cell->node_info->conn);
|
||||||
|
|
||||||
|
repmgrd_info[i]->recovery_type = get_recovery_type(cell->node_info->conn);
|
||||||
|
|
||||||
|
if (repmgrd_info[i]->recovery_type == RECTYPE_STANDBY)
|
||||||
|
{
|
||||||
|
repmgrd_info[i]->wal_paused_pending_wal = is_wal_replay_paused(cell->node_info->conn, true);
|
||||||
|
|
||||||
|
if (repmgrd_info[i]->wal_paused_pending_wal == true)
|
||||||
|
{
|
||||||
|
item_list_append_format(&warnings,
|
||||||
|
_("WAL replay is paused on node \"%s\" (ID: %i) with WAL replay pending; this node cannot be manually promoted until WAL replay is resumed"),
|
||||||
|
cell->node_info->node_name, cell->node_info->node_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repmgrd_info[i]->upstream_last_seen = get_upstream_last_seen(cell->node_info->conn, cell->node_info->type);
|
||||||
|
if (repmgrd_info[i]->upstream_last_seen < 0)
|
||||||
|
{
|
||||||
|
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, "%s", _("n/a"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (runtime_options.compact == true)
|
||||||
|
{
|
||||||
|
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, _("%i sec(s) ago"), repmgrd_info[i]->upstream_last_seen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, _("%i second(s) ago"), repmgrd_info[i]->upstream_last_seen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initPQExpBuffer(&node_status);
|
||||||
|
initPQExpBuffer(&upstream);
|
||||||
|
|
||||||
|
(void)format_node_status(cell->node_info, &node_status, &upstream, &warnings);
|
||||||
|
snprintf(repmgrd_info[i]->pg_running_text, sizeof(cell->node_info->details),
|
||||||
|
"%s", node_status.data);
|
||||||
|
|
||||||
|
snprintf(cell->node_info->upstream_node_name, sizeof(cell->node_info->upstream_node_name),
|
||||||
|
"%s", upstream.data);
|
||||||
|
|
||||||
|
termPQExpBuffer(&node_status);
|
||||||
|
termPQExpBuffer(&upstream);
|
||||||
|
|
||||||
|
PQfinish(cell->node_info->conn);
|
||||||
|
|
||||||
|
headers_status[STATUS_NAME].cur_length = strlen(cell->node_info->node_name);
|
||||||
|
headers_status[STATUS_ROLE].cur_length = strlen(get_node_type_string(cell->node_info->type));
|
||||||
|
headers_status[STATUS_PG].cur_length = strlen(repmgrd_info[i]->pg_running_text);
|
||||||
|
headers_status[STATUS_UPSTREAM_NAME].cur_length = strlen(cell->node_info->upstream_node_name);
|
||||||
|
|
||||||
|
if (runtime_options.detail == true)
|
||||||
|
{
|
||||||
|
PQExpBufferData buf;
|
||||||
|
|
||||||
|
headers_status[STATUS_LOCATION].cur_length = strlen(cell->node_info->location);
|
||||||
|
|
||||||
|
initPQExpBuffer(&buf);
|
||||||
|
appendPQExpBuffer(&buf, "%i", cell->node_info->priority);
|
||||||
|
headers_status[STATUS_PRIORITY].cur_length = strlen(buf.data);
|
||||||
|
termPQExpBuffer(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
headers_status[STATUS_PID].cur_length = strlen(repmgrd_info[i]->pid_text);
|
||||||
|
headers_status[STATUS_REPMGRD].cur_length = strlen(repmgrd_info[i]->repmgrd_running);
|
||||||
|
|
||||||
|
headers_status[STATUS_UPSTREAM_LAST_SEEN].cur_length = strlen(repmgrd_info[i]->upstream_last_seen_text);
|
||||||
|
|
||||||
|
for (j = 0; j < STATUS_HEADER_COUNT; j++)
|
||||||
|
{
|
||||||
|
if (headers_status[j].cur_length > headers_status[j].max_length)
|
||||||
|
{
|
||||||
|
headers_status[j].max_length = headers_status[j].cur_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print column header row (text mode only) */
|
||||||
|
if (runtime_options.output_mode == OM_TEXT)
|
||||||
|
{
|
||||||
|
print_status_header(STATUS_HEADER_COUNT, headers_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
for (cell = nodes.head; cell; cell = cell->next)
|
||||||
|
{
|
||||||
|
if (runtime_options.output_mode == OM_CSV)
|
||||||
|
{
|
||||||
|
int running = repmgrd_info[i]->running ? 1 : 0;
|
||||||
|
int paused = repmgrd_info[i]->paused ? 1 : 0;
|
||||||
|
|
||||||
|
/* If PostgreSQL is not running, repmgrd status is unknown */
|
||||||
|
if (repmgrd_info[i]->pg_running == false)
|
||||||
|
{
|
||||||
|
running = -1;
|
||||||
|
paused = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%i,%s,%s,%i,%i,%i,%i,%i,%i,%s\n",
|
||||||
|
cell->node_info->node_id,
|
||||||
|
cell->node_info->node_name,
|
||||||
|
get_node_type_string(cell->node_info->type),
|
||||||
|
repmgrd_info[i]->pg_running ? 1 : 0,
|
||||||
|
running,
|
||||||
|
repmgrd_info[i]->pid,
|
||||||
|
paused,
|
||||||
|
cell->node_info->priority,
|
||||||
|
repmgrd_info[i]->pid == UNKNOWN_PID
|
||||||
|
? -1
|
||||||
|
: repmgrd_info[i]->upstream_last_seen,
|
||||||
|
cell->node_info->location);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf(" %-*i ", headers_status[STATUS_ID].max_length, cell->node_info->node_id);
|
||||||
|
printf("| %-*s ", headers_status[STATUS_NAME].max_length, cell->node_info->node_name);
|
||||||
|
printf("| %-*s ", headers_status[STATUS_ROLE].max_length, get_node_type_string(cell->node_info->type));
|
||||||
|
printf("| %-*s ", headers_status[STATUS_PG].max_length, repmgrd_info[i]->pg_running_text);
|
||||||
|
printf("| %-*s ", headers_status[STATUS_UPSTREAM_NAME].max_length, cell->node_info->upstream_node_name);
|
||||||
|
|
||||||
|
if (runtime_options.detail == true)
|
||||||
|
{
|
||||||
|
printf("| %-*s ", headers_status[STATUS_LOCATION].max_length, cell->node_info->location);
|
||||||
|
printf("| %-*i ", headers_status[STATUS_PRIORITY].max_length, cell->node_info->priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("| %-*s ", headers_status[STATUS_REPMGRD].max_length, repmgrd_info[i]->repmgrd_running);
|
||||||
|
printf("| %-*s ", headers_status[STATUS_PID].max_length, repmgrd_info[i]->pid_text);
|
||||||
|
|
||||||
|
if (repmgrd_info[i]->pid == UNKNOWN_PID)
|
||||||
|
{
|
||||||
|
printf("| %-*s ", headers_status[STATUS_PAUSED].max_length, _("n/a"));
|
||||||
|
printf("| %-*s ", headers_status[STATUS_UPSTREAM_LAST_SEEN].max_length, _("n/a"));
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("| %-*s ", headers_status[STATUS_PAUSED].max_length, repmgrd_info[i]->paused ? _("yes") : _("no"));
|
||||||
|
|
||||||
|
printf("| %-*s ", headers_status[STATUS_UPSTREAM_LAST_SEEN].max_length, repmgrd_info[i]->upstream_last_seen_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
pfree(repmgrd_info[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfree(repmgrd_info);
|
||||||
|
|
||||||
|
/* emit any warnings */
|
||||||
|
|
||||||
|
if (warnings.head != NULL && runtime_options.terse == false && runtime_options.output_mode != OM_CSV)
|
||||||
|
{
|
||||||
|
ItemListCell *cell = NULL;
|
||||||
|
|
||||||
|
printf(_("\nWARNING: following issues were detected\n"));
|
||||||
|
for (cell = warnings.head; cell; cell = cell->next)
|
||||||
|
{
|
||||||
|
printf(_(" - %s\n"), cell->string);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runtime_options.verbose == false && connection_error_found == true)
|
||||||
|
{
|
||||||
|
log_hint(_("execute with --verbose option to see connection error messages"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
do_daemon_pause(void)
|
||||||
|
{
|
||||||
|
_do_repmgr_pause(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
do_daemon_unpause(void)
|
||||||
|
{
|
||||||
|
_do_repmgr_pause(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
_do_repmgr_pause(bool pause)
|
||||||
|
{
|
||||||
|
PGconn *conn = NULL;
|
||||||
|
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||||
|
NodeInfoListCell *cell = NULL;
|
||||||
|
int i;
|
||||||
|
int error_nodes = 0;
|
||||||
|
|
||||||
|
/* Connect to local database to obtain cluster connection data */
|
||||||
|
log_verbose(LOG_INFO, _("connecting to database"));
|
||||||
|
|
||||||
|
if (strlen(config_file_options.conninfo))
|
||||||
|
conn = establish_db_connection(config_file_options.conninfo, true);
|
||||||
|
else
|
||||||
|
conn = establish_db_connection_by_params(&source_conninfo, true);
|
||||||
|
|
||||||
|
fetch_node_records(conn, &nodes);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
for (cell = nodes.head; cell; cell = cell->next)
|
||||||
|
{
|
||||||
|
log_verbose(LOG_DEBUG, "pausing node %i (%s)",
|
||||||
|
cell->node_info->node_id,
|
||||||
|
cell->node_info->node_name);
|
||||||
|
cell->node_info->conn = establish_db_connection_quiet(cell->node_info->conninfo);
|
||||||
|
|
||||||
|
if (PQstatus(cell->node_info->conn) != CONNECTION_OK)
|
||||||
|
{
|
||||||
|
log_warning(_("unable to connect to node %i"),
|
||||||
|
cell->node_info->node_id);
|
||||||
|
error_nodes++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (runtime_options.dry_run == true)
|
||||||
|
{
|
||||||
|
if (pause == true)
|
||||||
|
{
|
||||||
|
log_info(_("would pause node %i (%s) "),
|
||||||
|
cell->node_info->node_id,
|
||||||
|
cell->node_info->node_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_info(_("would unpause node %i (%s) "),
|
||||||
|
cell->node_info->node_id,
|
||||||
|
cell->node_info->node_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool success = repmgrd_pause(cell->node_info->conn, pause);
|
||||||
|
|
||||||
|
if (success == false)
|
||||||
|
error_nodes++;
|
||||||
|
|
||||||
|
log_notice(_("node %i (%s) %s"),
|
||||||
|
cell->node_info->node_id,
|
||||||
|
cell->node_info->node_name,
|
||||||
|
success == true
|
||||||
|
? pause == true ? "paused" : "unpaused"
|
||||||
|
: pause == true ? "not paused" : "not unpaused");
|
||||||
|
}
|
||||||
|
PQfinish(cell->node_info->conn);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error_nodes > 0)
|
||||||
|
{
|
||||||
|
if (pause == true)
|
||||||
|
{
|
||||||
|
log_error(_("unable to pause %i node(s)"), error_nodes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_error(_("unable to unpause %i node(s)"), error_nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_hint(_("execute \"repmgr daemon status\" to view current status"));
|
||||||
|
|
||||||
|
exit(ERR_REPMGRD_PAUSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
fetch_node_records(PGconn *conn, NodeInfoList *node_list)
|
||||||
|
{
|
||||||
|
bool success = get_all_node_records_with_upstream(conn, node_list);
|
||||||
|
|
||||||
|
if (success == false)
|
||||||
|
{
|
||||||
|
/* get_all_node_records() will display any error message */
|
||||||
|
PQfinish(conn);
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node_list->node_count == 0)
|
||||||
|
{
|
||||||
|
log_error(_("no node records were found"));
|
||||||
|
log_hint(_("ensure at least one node is registered"));
|
||||||
|
PQfinish(conn);
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
do_daemon_start(void)
|
do_daemon_start(void)
|
||||||
@@ -114,12 +583,12 @@ do_daemon_start(void)
|
|||||||
|
|
||||||
if (runtime_options.no_wait == true || runtime_options.wait == 0)
|
if (runtime_options.no_wait == true || runtime_options.wait == 0)
|
||||||
{
|
{
|
||||||
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
|
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int timeout = REPMGR_SERVICE_STOP_START_WAIT;
|
int timeout = REPMGR_DAEMON_STOP_START_WAIT;
|
||||||
|
|
||||||
if (runtime_options.wait_provided)
|
if (runtime_options.wait_provided)
|
||||||
timeout = runtime_options.wait;
|
timeout = runtime_options.wait;
|
||||||
@@ -129,7 +598,7 @@ do_daemon_start(void)
|
|||||||
if (PQstatus(conn) != CONNECTION_OK)
|
if (PQstatus(conn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
log_notice(_("unable to connect to local node"));
|
log_notice(_("unable to connect to local node"));
|
||||||
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
|
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
|
||||||
exit(ERR_DB_CONN);
|
exit(ERR_DB_CONN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +616,7 @@ do_daemon_start(void)
|
|||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
log_error(_("repmgrd does not appear to have started after %i seconds"),
|
log_error(_("repmgrd does not appear to have started after %i seconds"),
|
||||||
timeout);
|
timeout);
|
||||||
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
|
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
|
||||||
exit(ERR_REPMGRD_SERVICE);
|
exit(ERR_REPMGRD_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,12 +712,12 @@ void do_daemon_stop(void)
|
|||||||
if (runtime_options.no_wait == true || runtime_options.wait == 0)
|
if (runtime_options.no_wait == true || runtime_options.wait == 0)
|
||||||
{
|
{
|
||||||
if (have_db_connection == true)
|
if (have_db_connection == true)
|
||||||
log_hint(REPMGR_SERVICE_STATUS_STOP_HINT);
|
log_hint(REPMGR_DAEMON_STATUS_STOP_HINT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int timeout = REPMGR_SERVICE_STOP_START_WAIT;
|
int timeout = REPMGR_DAEMON_STOP_START_WAIT;
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -263,7 +732,7 @@ void do_daemon_stop(void)
|
|||||||
log_warning(_("unable to determine repmgrd PID"));
|
log_warning(_("unable to determine repmgrd PID"));
|
||||||
|
|
||||||
if (have_db_connection == true)
|
if (have_db_connection == true)
|
||||||
log_hint(REPMGR_SERVICE_STATUS_STOP_HINT);
|
log_hint(REPMGR_DAEMON_STATUS_STOP_HINT);
|
||||||
|
|
||||||
exit(ERR_REPMGRD_SERVICE);
|
exit(ERR_REPMGRD_SERVICE);
|
||||||
}
|
}
|
||||||
@@ -295,7 +764,7 @@ void do_daemon_stop(void)
|
|||||||
timeout);
|
timeout);
|
||||||
|
|
||||||
if (have_db_connection == true)
|
if (have_db_connection == true)
|
||||||
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
|
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
|
||||||
|
|
||||||
exit(ERR_REPMGRD_SERVICE);
|
exit(ERR_REPMGRD_SERVICE);
|
||||||
}
|
}
|
||||||
@@ -314,29 +783,53 @@ void do_daemon_help(void)
|
|||||||
print_help_header();
|
print_help_header();
|
||||||
|
|
||||||
printf(_("Usage:\n"));
|
printf(_("Usage:\n"));
|
||||||
|
printf(_(" %s [OPTIONS] daemon status\n"), progname());
|
||||||
|
printf(_(" %s [OPTIONS] daemon pause\n"), progname());
|
||||||
|
printf(_(" %s [OPTIONS] daemon unpause\n"), progname());
|
||||||
printf(_(" %s [OPTIONS] daemon start\n"), progname());
|
printf(_(" %s [OPTIONS] daemon start\n"), progname());
|
||||||
printf(_(" %s [OPTIONS] daemon stop\n"), progname());
|
printf(_(" %s [OPTIONS] daemon stop\n"), progname());
|
||||||
|
puts("");
|
||||||
|
|
||||||
|
printf(_("DAEMON STATUS\n"));
|
||||||
|
puts("");
|
||||||
|
printf(_(" \"daemon status\" shows the status of repmgrd on each node in the cluster\n"));
|
||||||
|
puts("");
|
||||||
|
printf(_(" --csv emit output as CSV\n"));
|
||||||
|
printf(_(" --detail show additional detail\n"));
|
||||||
|
printf(_(" --verbose show text of database connection error messages\n"));
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
printf(_("DAEMON START\n"));
|
printf(_("DAEMON START\n"));
|
||||||
puts("");
|
puts("");
|
||||||
printf(_(" \"daemon start\" attempts to start repmgrd on the local node\n"));
|
printf(_(" \"daemon start\" attempts to start repmgrd\n"));
|
||||||
puts("");
|
puts("");
|
||||||
printf(_(" --dry-run check prerequisites but don't start repmgrd\n"));
|
printf(_(" --dry-run check prerequisites but don't start repmgrd\n"));
|
||||||
printf(_(" -w/--wait wait for repmgrd to start (default: %i seconds)\n"), REPMGR_SERVICE_STOP_START_WAIT);
|
printf(_(" -w/--wait wait for repmgrd to start (default: %i seconds)\n"), REPMGR_DAEMON_STOP_START_WAIT);
|
||||||
printf(_(" --no-wait don't wait for repmgrd to start\n"));
|
printf(_(" --no-wait don't wait for repmgrd to start\n"));
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
printf(_("DAEMON STOP\n"));
|
printf(_("DAEMON STOP\n"));
|
||||||
puts("");
|
puts("");
|
||||||
printf(_(" \"daemon stop\" attempts to stop repmgrd on the local node\n"));
|
printf(_(" \"daemon stop\" attempts to stop repmgrd\n"));
|
||||||
puts("");
|
puts("");
|
||||||
printf(_(" --dry-run check prerequisites but don't stop repmgrd\n"));
|
printf(_(" --dry-run check prerequisites but don't stop repmgrd\n"));
|
||||||
printf(_(" -w/--wait wait for repmgrd to stop (default: %i seconds)\n"), REPMGR_SERVICE_STOP_START_WAIT);
|
printf(_(" -w/--wait wait for repmgrd to stop (default: %i seconds)\n"), REPMGR_DAEMON_STOP_START_WAIT);
|
||||||
printf(_(" --no-wait don't wait for repmgrd to stop\n"));
|
printf(_(" --no-wait don't wait for repmgrd to stop\n"));
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
|
printf(_("DAEMON PAUSE\n"));
|
||||||
|
puts("");
|
||||||
|
printf(_(" \"daemon pause\" instructs repmgrd on each node to pause failover detection\n"));
|
||||||
|
puts("");
|
||||||
|
printf(_(" --dry-run check if nodes are reachable but don't pause repmgrd\n"));
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
|
printf(_("DAEMON UNPAUSE\n"));
|
||||||
|
puts("");
|
||||||
|
printf(_(" \"daemon unpause\" instructs repmgrd on each node to resume failover detection\n"));
|
||||||
|
puts("");
|
||||||
|
printf(_(" --dry-run check if nodes are reachable but don't unpause repmgrd\n"));
|
||||||
|
puts("");
|
||||||
|
|
||||||
|
puts("");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,10 @@
|
|||||||
#ifndef _REPMGR_ACTION_DAEMON_H_
|
#ifndef _REPMGR_ACTION_DAEMON_H_
|
||||||
#define _REPMGR_ACTION_DAEMON_H_
|
#define _REPMGR_ACTION_DAEMON_H_
|
||||||
|
|
||||||
|
|
||||||
|
extern void do_daemon_status(void);
|
||||||
|
extern void do_daemon_pause(void);
|
||||||
|
extern void do_daemon_unpause(void);
|
||||||
extern void do_daemon_start(void);
|
extern void do_daemon_start(void);
|
||||||
extern void do_daemon_stop(void);
|
extern void do_daemon_stop(void);
|
||||||
|
|
||||||
|
|||||||
@@ -1833,7 +1833,7 @@ do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_in
|
|||||||
* a superuser connection
|
* a superuser connection
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (connection_has_pg_settings(conn) == true)
|
if (is_superuser_connection(conn, NULL) == true)
|
||||||
{
|
{
|
||||||
/* we expect to have a database connection */
|
/* we expect to have a database connection */
|
||||||
if (get_pg_setting(conn, "data_directory", actual_data_directory) == false)
|
if (get_pg_setting(conn, "data_directory", actual_data_directory) == false)
|
||||||
@@ -1878,7 +1878,7 @@ do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_in
|
|||||||
/* XXX add -S/--superuser option */
|
/* XXX add -S/--superuser option */
|
||||||
if (PQserverVersion(conn) >= 100000)
|
if (PQserverVersion(conn) >= 100000)
|
||||||
{
|
{
|
||||||
log_hint(_("add the \"%s\" user to group \"pg_read_all_settings\" or \"pg_monitor\""),
|
log_hint(_("add the \"%s\" user to group \"pg_read_all_settings\""),
|
||||||
PQuser(conn));
|
PQuser(conn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ do_primary_register(void)
|
|||||||
current_primary_id = get_primary_node_id(conn);
|
current_primary_id = get_primary_node_id(conn);
|
||||||
if (current_primary_id != NODE_NOT_FOUND && current_primary_id != config_file_options.node_id)
|
if (current_primary_id != NODE_NOT_FOUND && current_primary_id != config_file_options.node_id)
|
||||||
{
|
{
|
||||||
log_debug("current active primary node ID is %i", current_primary_id);
|
log_debug("XXX %i", current_primary_id);
|
||||||
primary_conn = establish_primary_db_connection(conn, false);
|
primary_conn = establish_primary_db_connection(conn, false);
|
||||||
|
|
||||||
if (PQstatus(primary_conn) == CONNECTION_OK)
|
if (PQstatus(primary_conn) == CONNECTION_OK)
|
||||||
|
|||||||
@@ -1,535 +0,0 @@
|
|||||||
/*
|
|
||||||
* repmgr-action-service.c
|
|
||||||
*
|
|
||||||
* Implements repmgrd actions for the repmgr command line utility
|
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2019
|
|
||||||
*
|
|
||||||
* 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 <signal.h>
|
|
||||||
#include <sys/stat.h> /* for stat() */
|
|
||||||
|
|
||||||
#include "repmgr.h"
|
|
||||||
|
|
||||||
#include "repmgr-client-global.h"
|
|
||||||
#include "repmgr-action-service.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Possibly also show:
|
|
||||||
* - repmgrd start time?
|
|
||||||
* - repmgrd mode
|
|
||||||
* - priority
|
|
||||||
* - whether promotion candidate (due to zero priority/different location)
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
STATUS_ID = 0,
|
|
||||||
STATUS_NAME,
|
|
||||||
STATUS_ROLE,
|
|
||||||
STATUS_PG,
|
|
||||||
STATUS_UPSTREAM_NAME,
|
|
||||||
STATUS_LOCATION,
|
|
||||||
STATUS_PRIORITY,
|
|
||||||
STATUS_REPMGRD,
|
|
||||||
STATUS_PID,
|
|
||||||
STATUS_PAUSED,
|
|
||||||
STATUS_UPSTREAM_LAST_SEEN
|
|
||||||
} StatusHeader;
|
|
||||||
|
|
||||||
#define STATUS_HEADER_COUNT 11
|
|
||||||
|
|
||||||
struct ColHeader headers_status[STATUS_HEADER_COUNT];
|
|
||||||
|
|
||||||
static void fetch_node_records(PGconn *conn, NodeInfoList *node_list);
|
|
||||||
static void _do_repmgr_pause(bool pause);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
do_service_status(void)
|
|
||||||
{
|
|
||||||
PGconn *conn = NULL;
|
|
||||||
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
|
|
||||||
NodeInfoListCell *cell = NULL;
|
|
||||||
int i;
|
|
||||||
RepmgrdInfo **repmgrd_info;
|
|
||||||
ItemList warnings = {NULL, NULL};
|
|
||||||
bool connection_error_found = false;
|
|
||||||
|
|
||||||
/* Connect to local database to obtain cluster connection data */
|
|
||||||
log_verbose(LOG_INFO, _("connecting to database"));
|
|
||||||
|
|
||||||
if (strlen(config_file_options.conninfo))
|
|
||||||
conn = establish_db_connection(config_file_options.conninfo, true);
|
|
||||||
else
|
|
||||||
conn = establish_db_connection_by_params(&source_conninfo, true);
|
|
||||||
|
|
||||||
fetch_node_records(conn, &nodes);
|
|
||||||
|
|
||||||
repmgrd_info = (RepmgrdInfo **) pg_malloc0(sizeof(RepmgrdInfo *) * nodes.node_count);
|
|
||||||
|
|
||||||
if (repmgrd_info == NULL)
|
|
||||||
{
|
|
||||||
log_error(_("unable to allocate memory"));
|
|
||||||
exit(ERR_OUT_OF_MEMORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(headers_status[STATUS_ID].title, _("ID"), MAXLEN);
|
|
||||||
strncpy(headers_status[STATUS_NAME].title, _("Name"), MAXLEN);
|
|
||||||
strncpy(headers_status[STATUS_ROLE].title, _("Role"), MAXLEN);
|
|
||||||
strncpy(headers_status[STATUS_PG].title, _("Status"), MAXLEN);
|
|
||||||
strncpy(headers_status[STATUS_UPSTREAM_NAME].title, _("Upstream"), MAXLEN);
|
|
||||||
|
|
||||||
/* following only displayed with the --detail option */
|
|
||||||
strncpy(headers_status[STATUS_LOCATION].title, _("Location"), MAXLEN);
|
|
||||||
if (runtime_options.compact == true)
|
|
||||||
strncpy(headers_status[STATUS_PRIORITY].title, _("Prio."), MAXLEN);
|
|
||||||
else
|
|
||||||
strncpy(headers_status[STATUS_PRIORITY].title, _("Priority"), MAXLEN);
|
|
||||||
|
|
||||||
strncpy(headers_status[STATUS_REPMGRD].title, _("repmgrd"), MAXLEN);
|
|
||||||
strncpy(headers_status[STATUS_PID].title, _("PID"), MAXLEN);
|
|
||||||
strncpy(headers_status[STATUS_PAUSED].title, _("Paused?"), MAXLEN);
|
|
||||||
|
|
||||||
if (runtime_options.compact == true)
|
|
||||||
strncpy(headers_status[STATUS_UPSTREAM_LAST_SEEN].title, _("Upstr. last"), MAXLEN);
|
|
||||||
else
|
|
||||||
strncpy(headers_status[STATUS_UPSTREAM_LAST_SEEN].title, _("Upstream last seen"), MAXLEN);
|
|
||||||
|
|
||||||
for (i = 0; i < STATUS_HEADER_COUNT; i++)
|
|
||||||
{
|
|
||||||
headers_status[i].max_length = strlen(headers_status[i].title);
|
|
||||||
headers_status[i].display = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtime_options.detail == false)
|
|
||||||
{
|
|
||||||
headers_status[STATUS_LOCATION].display = false;
|
|
||||||
headers_status[STATUS_PRIORITY].display = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
for (cell = nodes.head; cell; cell = cell->next)
|
|
||||||
{
|
|
||||||
int j;
|
|
||||||
PQExpBufferData node_status;
|
|
||||||
PQExpBufferData upstream;
|
|
||||||
|
|
||||||
repmgrd_info[i] = pg_malloc0(sizeof(RepmgrdInfo));
|
|
||||||
repmgrd_info[i]->node_id = cell->node_info->node_id;
|
|
||||||
repmgrd_info[i]->pid = UNKNOWN_PID;
|
|
||||||
repmgrd_info[i]->recovery_type = RECTYPE_UNKNOWN;
|
|
||||||
repmgrd_info[i]->paused = false;
|
|
||||||
repmgrd_info[i]->running = false;
|
|
||||||
repmgrd_info[i]->pg_running = true;
|
|
||||||
repmgrd_info[i]->wal_paused_pending_wal = false;
|
|
||||||
repmgrd_info[i]->upstream_last_seen = -1;
|
|
||||||
|
|
||||||
cell->node_info->conn = establish_db_connection_quiet(cell->node_info->conninfo);
|
|
||||||
|
|
||||||
if (PQstatus(cell->node_info->conn) != CONNECTION_OK)
|
|
||||||
{
|
|
||||||
|
|
||||||
connection_error_found = true;
|
|
||||||
|
|
||||||
if (runtime_options.verbose)
|
|
||||||
{
|
|
||||||
char error[MAXLEN];
|
|
||||||
|
|
||||||
strncpy(error, PQerrorMessage(cell->node_info->conn), MAXLEN);
|
|
||||||
|
|
||||||
item_list_append_format(&warnings,
|
|
||||||
"when attempting to connect to node \"%s\" (ID: %i), following error encountered :\n\"%s\"",
|
|
||||||
cell->node_info->node_name, cell->node_info->node_id, trim(error));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item_list_append_format(&warnings,
|
|
||||||
"unable to connect to node \"%s\" (ID: %i)",
|
|
||||||
cell->node_info->node_name, cell->node_info->node_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
repmgrd_info[i]->pg_running = false;
|
|
||||||
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("n/a"));
|
|
||||||
maxlen_snprintf(repmgrd_info[i]->pid_text, "%s", _("n/a"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cell->node_info->node_status = NODE_STATUS_UP;
|
|
||||||
cell->node_info->recovery_type = get_recovery_type(cell->node_info->conn);
|
|
||||||
|
|
||||||
repmgrd_info[i]->pid = repmgrd_get_pid(cell->node_info->conn);
|
|
||||||
|
|
||||||
repmgrd_info[i]->running = repmgrd_is_running(cell->node_info->conn);
|
|
||||||
|
|
||||||
if (repmgrd_info[i]->running == true)
|
|
||||||
{
|
|
||||||
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("running"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
maxlen_snprintf(repmgrd_info[i]->repmgrd_running, "%s", _("not running"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (repmgrd_info[i]->pid == UNKNOWN_PID)
|
|
||||||
{
|
|
||||||
maxlen_snprintf(repmgrd_info[i]->pid_text, "%s", _("n/a"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
maxlen_snprintf(repmgrd_info[i]->pid_text, "%i", repmgrd_info[i]->pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
repmgrd_info[i]->paused = repmgrd_is_paused(cell->node_info->conn);
|
|
||||||
|
|
||||||
repmgrd_info[i]->recovery_type = get_recovery_type(cell->node_info->conn);
|
|
||||||
|
|
||||||
if (repmgrd_info[i]->recovery_type == RECTYPE_STANDBY)
|
|
||||||
{
|
|
||||||
repmgrd_info[i]->wal_paused_pending_wal = is_wal_replay_paused(cell->node_info->conn, true);
|
|
||||||
|
|
||||||
if (repmgrd_info[i]->wal_paused_pending_wal == true)
|
|
||||||
{
|
|
||||||
item_list_append_format(&warnings,
|
|
||||||
_("WAL replay is paused on node \"%s\" (ID: %i) with WAL replay pending; this node cannot be manually promoted until WAL replay is resumed"),
|
|
||||||
cell->node_info->node_name, cell->node_info->node_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repmgrd_info[i]->upstream_last_seen = get_upstream_last_seen(cell->node_info->conn, cell->node_info->type);
|
|
||||||
if (repmgrd_info[i]->upstream_last_seen < 0)
|
|
||||||
{
|
|
||||||
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, "%s", _("n/a"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (runtime_options.compact == true)
|
|
||||||
{
|
|
||||||
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, _("%i sec(s) ago"), repmgrd_info[i]->upstream_last_seen);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
maxlen_snprintf(repmgrd_info[i]->upstream_last_seen_text, _("%i second(s) ago"), repmgrd_info[i]->upstream_last_seen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initPQExpBuffer(&node_status);
|
|
||||||
initPQExpBuffer(&upstream);
|
|
||||||
|
|
||||||
(void)format_node_status(cell->node_info, &node_status, &upstream, &warnings);
|
|
||||||
snprintf(repmgrd_info[i]->pg_running_text, sizeof(cell->node_info->details),
|
|
||||||
"%s", node_status.data);
|
|
||||||
|
|
||||||
snprintf(cell->node_info->upstream_node_name, sizeof(cell->node_info->upstream_node_name),
|
|
||||||
"%s", upstream.data);
|
|
||||||
|
|
||||||
termPQExpBuffer(&node_status);
|
|
||||||
termPQExpBuffer(&upstream);
|
|
||||||
|
|
||||||
PQfinish(cell->node_info->conn);
|
|
||||||
|
|
||||||
headers_status[STATUS_NAME].cur_length = strlen(cell->node_info->node_name);
|
|
||||||
headers_status[STATUS_ROLE].cur_length = strlen(get_node_type_string(cell->node_info->type));
|
|
||||||
headers_status[STATUS_PG].cur_length = strlen(repmgrd_info[i]->pg_running_text);
|
|
||||||
headers_status[STATUS_UPSTREAM_NAME].cur_length = strlen(cell->node_info->upstream_node_name);
|
|
||||||
|
|
||||||
if (runtime_options.detail == true)
|
|
||||||
{
|
|
||||||
PQExpBufferData buf;
|
|
||||||
|
|
||||||
headers_status[STATUS_LOCATION].cur_length = strlen(cell->node_info->location);
|
|
||||||
|
|
||||||
initPQExpBuffer(&buf);
|
|
||||||
appendPQExpBuffer(&buf, "%i", cell->node_info->priority);
|
|
||||||
headers_status[STATUS_PRIORITY].cur_length = strlen(buf.data);
|
|
||||||
termPQExpBuffer(&buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
headers_status[STATUS_PID].cur_length = strlen(repmgrd_info[i]->pid_text);
|
|
||||||
headers_status[STATUS_REPMGRD].cur_length = strlen(repmgrd_info[i]->repmgrd_running);
|
|
||||||
|
|
||||||
headers_status[STATUS_UPSTREAM_LAST_SEEN].cur_length = strlen(repmgrd_info[i]->upstream_last_seen_text);
|
|
||||||
|
|
||||||
for (j = 0; j < STATUS_HEADER_COUNT; j++)
|
|
||||||
{
|
|
||||||
if (headers_status[j].cur_length > headers_status[j].max_length)
|
|
||||||
{
|
|
||||||
headers_status[j].max_length = headers_status[j].cur_length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Print column header row (text mode only) */
|
|
||||||
if (runtime_options.output_mode == OM_TEXT)
|
|
||||||
{
|
|
||||||
print_status_header(STATUS_HEADER_COUNT, headers_status);
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
for (cell = nodes.head; cell; cell = cell->next)
|
|
||||||
{
|
|
||||||
if (runtime_options.output_mode == OM_CSV)
|
|
||||||
{
|
|
||||||
int running = repmgrd_info[i]->running ? 1 : 0;
|
|
||||||
int paused = repmgrd_info[i]->paused ? 1 : 0;
|
|
||||||
|
|
||||||
/* If PostgreSQL is not running, repmgrd status is unknown */
|
|
||||||
if (repmgrd_info[i]->pg_running == false)
|
|
||||||
{
|
|
||||||
running = -1;
|
|
||||||
paused = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%i,%s,%s,%i,%i,%i,%i,%i,%i,%s\n",
|
|
||||||
cell->node_info->node_id,
|
|
||||||
cell->node_info->node_name,
|
|
||||||
get_node_type_string(cell->node_info->type),
|
|
||||||
repmgrd_info[i]->pg_running ? 1 : 0,
|
|
||||||
running,
|
|
||||||
repmgrd_info[i]->pid,
|
|
||||||
paused,
|
|
||||||
cell->node_info->priority,
|
|
||||||
repmgrd_info[i]->pid == UNKNOWN_PID
|
|
||||||
? -1
|
|
||||||
: repmgrd_info[i]->upstream_last_seen,
|
|
||||||
cell->node_info->location);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf(" %-*i ", headers_status[STATUS_ID].max_length, cell->node_info->node_id);
|
|
||||||
printf("| %-*s ", headers_status[STATUS_NAME].max_length, cell->node_info->node_name);
|
|
||||||
printf("| %-*s ", headers_status[STATUS_ROLE].max_length, get_node_type_string(cell->node_info->type));
|
|
||||||
printf("| %-*s ", headers_status[STATUS_PG].max_length, repmgrd_info[i]->pg_running_text);
|
|
||||||
printf("| %-*s ", headers_status[STATUS_UPSTREAM_NAME].max_length, cell->node_info->upstream_node_name);
|
|
||||||
|
|
||||||
if (runtime_options.detail == true)
|
|
||||||
{
|
|
||||||
printf("| %-*s ", headers_status[STATUS_LOCATION].max_length, cell->node_info->location);
|
|
||||||
printf("| %-*i ", headers_status[STATUS_PRIORITY].max_length, cell->node_info->priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("| %-*s ", headers_status[STATUS_REPMGRD].max_length, repmgrd_info[i]->repmgrd_running);
|
|
||||||
printf("| %-*s ", headers_status[STATUS_PID].max_length, repmgrd_info[i]->pid_text);
|
|
||||||
|
|
||||||
if (repmgrd_info[i]->pid == UNKNOWN_PID)
|
|
||||||
{
|
|
||||||
printf("| %-*s ", headers_status[STATUS_PAUSED].max_length, _("n/a"));
|
|
||||||
printf("| %-*s ", headers_status[STATUS_UPSTREAM_LAST_SEEN].max_length, _("n/a"));
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("| %-*s ", headers_status[STATUS_PAUSED].max_length, repmgrd_info[i]->paused ? _("yes") : _("no"));
|
|
||||||
|
|
||||||
printf("| %-*s ", headers_status[STATUS_UPSTREAM_LAST_SEEN].max_length, repmgrd_info[i]->upstream_last_seen_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
pfree(repmgrd_info[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
pfree(repmgrd_info);
|
|
||||||
|
|
||||||
/* emit any warnings */
|
|
||||||
|
|
||||||
if (warnings.head != NULL && runtime_options.terse == false && runtime_options.output_mode != OM_CSV)
|
|
||||||
{
|
|
||||||
ItemListCell *cell = NULL;
|
|
||||||
|
|
||||||
printf(_("\nWARNING: following issues were detected\n"));
|
|
||||||
for (cell = warnings.head; cell; cell = cell->next)
|
|
||||||
{
|
|
||||||
printf(_(" - %s\n"), cell->string);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtime_options.verbose == false && connection_error_found == true)
|
|
||||||
{
|
|
||||||
log_hint(_("execute with --verbose option to see connection error messages"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
do_service_pause(void)
|
|
||||||
{
|
|
||||||
_do_repmgr_pause(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
do_service_unpause(void)
|
|
||||||
{
|
|
||||||
_do_repmgr_pause(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
_do_repmgr_pause(bool pause)
|
|
||||||
{
|
|
||||||
PGconn *conn = NULL;
|
|
||||||
NodeInfoList nodes = T_NODE_INFO_LIST_INITIALIZER;
|
|
||||||
NodeInfoListCell *cell = NULL;
|
|
||||||
int i;
|
|
||||||
int error_nodes = 0;
|
|
||||||
|
|
||||||
/* Connect to local database to obtain cluster connection data */
|
|
||||||
log_verbose(LOG_INFO, _("connecting to database"));
|
|
||||||
|
|
||||||
if (strlen(config_file_options.conninfo))
|
|
||||||
conn = establish_db_connection(config_file_options.conninfo, true);
|
|
||||||
else
|
|
||||||
conn = establish_db_connection_by_params(&source_conninfo, true);
|
|
||||||
|
|
||||||
fetch_node_records(conn, &nodes);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
for (cell = nodes.head; cell; cell = cell->next)
|
|
||||||
{
|
|
||||||
log_verbose(LOG_DEBUG, "pausing node %i (%s)",
|
|
||||||
cell->node_info->node_id,
|
|
||||||
cell->node_info->node_name);
|
|
||||||
cell->node_info->conn = establish_db_connection_quiet(cell->node_info->conninfo);
|
|
||||||
|
|
||||||
if (PQstatus(cell->node_info->conn) != CONNECTION_OK)
|
|
||||||
{
|
|
||||||
log_warning(_("unable to connect to node %i"),
|
|
||||||
cell->node_info->node_id);
|
|
||||||
error_nodes++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (runtime_options.dry_run == true)
|
|
||||||
{
|
|
||||||
if (pause == true)
|
|
||||||
{
|
|
||||||
log_info(_("would pause node %i (%s) "),
|
|
||||||
cell->node_info->node_id,
|
|
||||||
cell->node_info->node_name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_info(_("would unpause node %i (%s) "),
|
|
||||||
cell->node_info->node_id,
|
|
||||||
cell->node_info->node_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool success = repmgrd_pause(cell->node_info->conn, pause);
|
|
||||||
|
|
||||||
if (success == false)
|
|
||||||
error_nodes++;
|
|
||||||
|
|
||||||
log_notice(_("node %i (%s) %s"),
|
|
||||||
cell->node_info->node_id,
|
|
||||||
cell->node_info->node_name,
|
|
||||||
success == true
|
|
||||||
? pause == true ? "paused" : "unpaused"
|
|
||||||
: pause == true ? "not paused" : "not unpaused");
|
|
||||||
}
|
|
||||||
PQfinish(cell->node_info->conn);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error_nodes > 0)
|
|
||||||
{
|
|
||||||
if (pause == true)
|
|
||||||
{
|
|
||||||
log_error(_("unable to pause %i node(s)"), error_nodes);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_error(_("unable to unpause %i node(s)"), error_nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
log_hint(_("execute \"repmgr service status\" to view current status"));
|
|
||||||
|
|
||||||
exit(ERR_REPMGRD_PAUSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
fetch_node_records(PGconn *conn, NodeInfoList *node_list)
|
|
||||||
{
|
|
||||||
bool success = get_all_node_records_with_upstream(conn, node_list);
|
|
||||||
|
|
||||||
if (success == false)
|
|
||||||
{
|
|
||||||
/* get_all_node_records() will display any error message */
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node_list->node_count == 0)
|
|
||||||
{
|
|
||||||
log_error(_("no node records were found"));
|
|
||||||
log_hint(_("ensure at least one node is registered"));
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void do_service_help(void)
|
|
||||||
{
|
|
||||||
print_help_header();
|
|
||||||
|
|
||||||
printf(_("Usage:\n"));
|
|
||||||
printf(_(" %s [OPTIONS] service status\n"), progname());
|
|
||||||
printf(_(" %s [OPTIONS] service pause\n"), progname());
|
|
||||||
printf(_(" %s [OPTIONS] service unpause\n"), progname());
|
|
||||||
|
|
||||||
puts("");
|
|
||||||
|
|
||||||
printf(_("SERVICE STATUS\n"));
|
|
||||||
puts("");
|
|
||||||
printf(_(" \"service status\" shows the status of repmgrd on each node in the cluster\n"));
|
|
||||||
puts("");
|
|
||||||
printf(_(" --csv emit output as CSV\n"));
|
|
||||||
printf(_(" --detail show additional detail\n"));
|
|
||||||
printf(_(" --verbose show text of database connection error messages\n"));
|
|
||||||
puts("");
|
|
||||||
|
|
||||||
printf(_("SERVICE PAUSE\n"));
|
|
||||||
puts("");
|
|
||||||
printf(_(" \"service pause\" instructs repmgrd on each node to pause failover detection\n"));
|
|
||||||
puts("");
|
|
||||||
printf(_(" --dry-run check if nodes are reachable but don't pause repmgrd\n"));
|
|
||||||
puts("");
|
|
||||||
|
|
||||||
printf(_("SERVICE UNPAUSE\n"));
|
|
||||||
puts("");
|
|
||||||
printf(_(" \"service unpause\" instructs repmgrd on each node to resume failover detection\n"));
|
|
||||||
puts("");
|
|
||||||
printf(_(" --dry-run check if nodes are reachable but don't unpause repmgrd\n"));
|
|
||||||
puts("");
|
|
||||||
|
|
||||||
puts("");
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* repmgr-action-service.h
|
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2019
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _REPMGR_ACTION_SERVICE_H_
|
|
||||||
#define _REPMGR_ACTION_SERVICE_H_
|
|
||||||
|
|
||||||
|
|
||||||
extern void do_service_status(void);
|
|
||||||
extern void do_service_pause(void);
|
|
||||||
extern void do_service_unpause(void);
|
|
||||||
|
|
||||||
extern void do_service_help(void);
|
|
||||||
#endif
|
|
||||||
@@ -112,10 +112,8 @@ static void get_barman_property(char *dst, char *name, char *local_repmgr_direct
|
|||||||
static int get_tablespace_data_barman(char *, TablespaceDataList *);
|
static int get_tablespace_data_barman(char *, TablespaceDataList *);
|
||||||
static char *make_barman_ssh_command(char *buf);
|
static char *make_barman_ssh_command(char *buf);
|
||||||
|
|
||||||
static bool create_recovery_file(t_node_info *node_record, t_conninfo_param_list *primary_conninfo, int server_version_num, char *dest, bool as_file);
|
static bool create_recovery_file(t_node_info *node_record, t_conninfo_param_list *primary_conninfo, char *dest, bool as_file);
|
||||||
static void write_primary_conninfo(PQExpBufferData *dest, t_conninfo_param_list *param_list);
|
static void write_primary_conninfo(PQExpBufferData *dest, t_conninfo_param_list *param_list);
|
||||||
static bool write_standby_signal(void);
|
|
||||||
|
|
||||||
static bool check_sibling_nodes(NodeInfoList *sibling_nodes, SiblingNodeStats *sibling_nodes_stats);
|
static bool check_sibling_nodes(NodeInfoList *sibling_nodes, SiblingNodeStats *sibling_nodes_stats);
|
||||||
static bool check_free_wal_senders(int available_wal_senders, SiblingNodeStats *sibling_nodes_stats, bool *dry_run_success);
|
static bool check_free_wal_senders(int available_wal_senders, SiblingNodeStats *sibling_nodes_stats, bool *dry_run_success);
|
||||||
static bool check_free_slots(t_node_info *local_node_record, SiblingNodeStats *sibling_nodes_stats, bool *dry_run_success);
|
static bool check_free_slots(t_node_info *local_node_record, SiblingNodeStats *sibling_nodes_stats, bool *dry_run_success);
|
||||||
@@ -135,13 +133,12 @@ static bool parse_data_directory_config(const char *node_check_output);
|
|||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* --upstream-conninfo
|
* --upstream-conninfo
|
||||||
* --upstream-node-id
|
|
||||||
* --no-upstream-connection
|
* --no-upstream-connection
|
||||||
* -F/--force
|
* -F/--force
|
||||||
* --dry-run
|
* --dry-run
|
||||||
* -c/--fast-checkpoint
|
* -c/--fast-checkpoint
|
||||||
* --copy-external-config-files
|
* --copy-external-config-files
|
||||||
* -R/--remote-user
|
* --recovery-min-apply-delay
|
||||||
* --replication-user (only required if no upstream record)
|
* --replication-user (only required if no upstream record)
|
||||||
* --without-barman
|
* --without-barman
|
||||||
* --recovery-conf-only
|
* --recovery-conf-only
|
||||||
@@ -218,7 +215,7 @@ do_standby_clone(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise list of conninfo parameters which will later be used to
|
* Initialise list of conninfo parameters which will later be used to
|
||||||
* create the "primary_conninfo" recovery parameter.
|
* create the `primary_conninfo` string in recovery.conf .
|
||||||
*
|
*
|
||||||
* We'll initialise it with the host settings specified on the command
|
* We'll initialise it with the host settings specified on the command
|
||||||
* line. As it's possible the standby will be cloned from a node different
|
* line. As it's possible the standby will be cloned from a node different
|
||||||
@@ -668,21 +665,10 @@ do_standby_clone(void)
|
|||||||
|
|
||||||
/* Write the recovery.conf file */
|
/* Write the recovery.conf file */
|
||||||
|
|
||||||
if (create_recovery_file(&local_node_record,
|
if (create_recovery_file(&local_node_record, &recovery_conninfo, local_data_directory, true) == false)
|
||||||
&recovery_conninfo,
|
|
||||||
source_server_version_num,
|
|
||||||
local_data_directory,
|
|
||||||
true) == false)
|
|
||||||
{
|
{
|
||||||
/* create_recovery_file() will log an error */
|
/* create_recovery_file() will log an error */
|
||||||
if (source_server_version_num >= 120000)
|
log_notice(_("unable to create recovery.conf; see preceding error messages"));
|
||||||
{
|
|
||||||
log_notice(_("unable to write replication configuration; see preceding error messages"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_notice(_("unable to create recovery.conf; see preceding error messages"));
|
|
||||||
}
|
|
||||||
log_hint(_("data directory (\"%s\") may need to be cleaned up manually"),
|
log_hint(_("data directory (\"%s\") may need to be cleaned up manually"),
|
||||||
local_data_directory);
|
local_data_directory);
|
||||||
|
|
||||||
@@ -958,13 +944,6 @@ _do_create_recovery_conf(void)
|
|||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* check connection */
|
|
||||||
source_conn = establish_db_connection_by_params(&source_conninfo, true);
|
|
||||||
|
|
||||||
/* Verify that source is a supported server version */
|
|
||||||
(void) check_server_version(source_conn, "source node", true, NULL);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do some sanity checks on the data directory to make sure
|
* Do some sanity checks on the data directory to make sure
|
||||||
* it contains a valid but dormant instance
|
* it contains a valid but dormant instance
|
||||||
@@ -974,17 +953,14 @@ _do_create_recovery_conf(void)
|
|||||||
case DIR_ERROR:
|
case DIR_ERROR:
|
||||||
log_error(_("unable to access specified data directory \"%s\""), local_data_directory);
|
log_error(_("unable to access specified data directory \"%s\""), local_data_directory);
|
||||||
log_detail("%s", strerror(errno));
|
log_detail("%s", strerror(errno));
|
||||||
PQfinish(source_conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
break;
|
break;
|
||||||
case DIR_NOENT:
|
case DIR_NOENT:
|
||||||
log_error(_("specified data directory \"%s\" does not exist"), local_data_directory);
|
log_error(_("specified data directory \"%s\" does not exist"), local_data_directory);
|
||||||
PQfinish(source_conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
break;
|
break;
|
||||||
case DIR_EMPTY:
|
case DIR_EMPTY:
|
||||||
log_error(_("specified data directory \"%s\" is empty"), local_data_directory);
|
log_error(_("specified data directory \"%s\" is empty"), local_data_directory);
|
||||||
PQfinish(source_conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
break;
|
break;
|
||||||
case DIR_NOT_EMPTY:
|
case DIR_NOT_EMPTY:
|
||||||
@@ -992,7 +968,6 @@ _do_create_recovery_conf(void)
|
|||||||
if (!is_pg_dir(local_data_directory))
|
if (!is_pg_dir(local_data_directory))
|
||||||
{
|
{
|
||||||
log_error(_("specified data directory \"%s\" does not contain a PostgreSQL instance"), local_data_directory);
|
log_error(_("specified data directory \"%s\" does not contain a PostgreSQL instance"), local_data_directory);
|
||||||
PQfinish(source_conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1002,16 +977,7 @@ _do_create_recovery_conf(void)
|
|||||||
{
|
{
|
||||||
log_error(_("specified data directory \"%s\" appears to contain a running PostgreSQL instance"),
|
log_error(_("specified data directory \"%s\" appears to contain a running PostgreSQL instance"),
|
||||||
local_data_directory);
|
local_data_directory);
|
||||||
|
log_hint(_("use -F/--force to create \"recovery.conf\" anyway"));
|
||||||
if (PQserverVersion(source_conn) >= 120000)
|
|
||||||
{
|
|
||||||
log_hint(_("use -F/--force to create replication configuration anyway"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_hint(_("use -F/--force to create \"recovery.conf\" anyway"));
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1019,25 +985,11 @@ _do_create_recovery_conf(void)
|
|||||||
|
|
||||||
if (runtime_options.dry_run == true)
|
if (runtime_options.dry_run == true)
|
||||||
{
|
{
|
||||||
if (PQserverVersion(source_conn) >= 120000)
|
log_warning(_("\"recovery.conf\" would be created in an active data directory"));
|
||||||
{
|
|
||||||
log_warning(_("replication configuration would be created in an active data directory"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_warning(_("\"recovery.conf\" would be created in an active data directory"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (PQserverVersion(source_conn) >= 120000)
|
log_warning(_("creating \"recovery.conf\" in an active data directory"));
|
||||||
{
|
|
||||||
log_warning(_("creating replication configuration in an active data directory"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_warning(_("creating \"recovery.conf\" in an active data directory"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1045,6 +997,8 @@ _do_create_recovery_conf(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check connection */
|
||||||
|
source_conn = establish_db_connection_by_params(&source_conninfo, true);
|
||||||
|
|
||||||
/* determine node for primary_conninfo */
|
/* determine node for primary_conninfo */
|
||||||
|
|
||||||
@@ -1217,92 +1171,60 @@ _do_create_recovery_conf(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if recovery.conf exists (Pg11 and earlier only) */
|
/* check if recovery.conf exists */
|
||||||
if (PQserverVersion(upstream_conn) < 120000)
|
|
||||||
{
|
|
||||||
snprintf(recovery_file_path, sizeof(recovery_file_path),
|
|
||||||
"%s/%s",
|
|
||||||
local_data_directory,
|
|
||||||
RECOVERY_COMMAND_FILE);
|
|
||||||
|
|
||||||
if (stat(recovery_file_path, &st) == -1)
|
snprintf(recovery_file_path, sizeof(recovery_file_path),
|
||||||
|
"%s/%s",
|
||||||
|
local_data_directory,
|
||||||
|
RECOVERY_COMMAND_FILE);
|
||||||
|
|
||||||
|
if (stat(recovery_file_path, &st) == -1)
|
||||||
|
{
|
||||||
|
if (errno != ENOENT)
|
||||||
{
|
{
|
||||||
if (errno != ENOENT)
|
log_error(_("unable to check for existing \"recovery.conf\" file in \"%s\""),
|
||||||
{
|
local_data_directory);
|
||||||
log_error(_("unable to check for existing \"recovery.conf\" file in \"%s\""),
|
log_detail("%s", strerror(errno));
|
||||||
local_data_directory);
|
|
||||||
log_detail("%s", strerror(errno));
|
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (runtime_options.force == false)
|
||||||
|
{
|
||||||
|
log_error(_("\"recovery.conf\" already exists in \"%s\""),
|
||||||
|
local_data_directory);
|
||||||
|
log_hint(_("use -F/--force to overwrite an existing \"recovery.conf\" file"));
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runtime_options.dry_run == true)
|
||||||
|
{
|
||||||
|
log_warning(_("the existing \"recovery.conf\" file would be overwritten"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (runtime_options.force == false)
|
log_warning(_("the existing \"recovery.conf\" file will be overwritten"));
|
||||||
{
|
|
||||||
log_error(_("\"recovery.conf\" already exists in \"%s\""),
|
|
||||||
local_data_directory);
|
|
||||||
log_hint(_("use -F/--force to overwrite an existing \"recovery.conf\" file"));
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtime_options.dry_run == true)
|
|
||||||
{
|
|
||||||
log_warning(_("the existing \"recovery.conf\" file would be overwritten"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_warning(_("the existing \"recovery.conf\" file will be overwritten"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runtime_options.dry_run == true)
|
if (runtime_options.dry_run == true)
|
||||||
{
|
{
|
||||||
char recovery_conf_contents[MAXLEN] = "";
|
char recovery_conf_contents[MAXLEN] = "";
|
||||||
create_recovery_file(&local_node_record,
|
create_recovery_file(&local_node_record, &recovery_conninfo, recovery_conf_contents, false);
|
||||||
&recovery_conninfo,
|
|
||||||
PQserverVersion(upstream_conn),
|
|
||||||
recovery_conf_contents,
|
|
||||||
false);
|
|
||||||
|
|
||||||
if (PQserverVersion(upstream_conn) >= 120000)
|
|
||||||
{
|
|
||||||
log_info(_("following items would be added to \"postgresql.auto.conf\" in \"%s\""), local_data_directory);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_info(_("would create \"recovery.conf\" file in \"%s\""), local_data_directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
log_info(_("would create \"recovery.conf\" file in \"%s\""), local_data_directory);
|
||||||
log_detail(_("\n%s"), recovery_conf_contents);
|
log_detail(_("\n%s"), recovery_conf_contents);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!create_recovery_file(&local_node_record,
|
if (!create_recovery_file(&local_node_record, &recovery_conninfo, local_data_directory, true))
|
||||||
&recovery_conninfo,
|
|
||||||
PQserverVersion(upstream_conn),
|
|
||||||
local_data_directory,
|
|
||||||
true))
|
|
||||||
{
|
{
|
||||||
if (PQserverVersion(upstream_conn) >= 120000)
|
log_error(_("unable to create \"recovery.conf\""));
|
||||||
{
|
|
||||||
log_error(_("unable to write replication configuration to \"postgresql.auto.conf\""));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_error(_("unable to create \"recovery.conf\""));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (PQserverVersion(upstream_conn) >= 120000)
|
log_notice(_("\"recovery.conf\" created as \"%s\""), recovery_file_path);
|
||||||
{
|
|
||||||
log_notice(_("replication configuration written to \"postgresql.auto.conf\""));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_notice(_("\"recovery.conf\" created as \"%s\""), recovery_file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node_is_running == true)
|
if (node_is_running == true)
|
||||||
{
|
{
|
||||||
@@ -1311,23 +1233,6 @@ _do_create_recovery_conf(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pg12 and later: add standby.signal, if not already there */
|
|
||||||
if (PQserverVersion(upstream_conn) >= 120000)
|
|
||||||
{
|
|
||||||
if (runtime_options.dry_run == true)
|
|
||||||
{
|
|
||||||
log_info(_("would write \"standby.signal\" file"));
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (write_standby_signal() == false)
|
|
||||||
{
|
|
||||||
log_error(_("unable to write \"standby.signal\" file"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add replication slot, if required */
|
/* add replication slot, if required */
|
||||||
if (slot_creation_required == true)
|
if (slot_creation_required == true)
|
||||||
{
|
{
|
||||||
@@ -3099,8 +3004,8 @@ do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_n
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store the original upstream node id so we can delete the
|
* store the original upstream node id so we can delete the
|
||||||
* replication slot, if it exists.
|
* replication slot, if exists
|
||||||
*/
|
*/
|
||||||
if (local_node_record.upstream_node_id != UNKNOWN_NODE_ID)
|
if (local_node_record.upstream_node_id != UNKNOWN_NODE_ID)
|
||||||
{
|
{
|
||||||
@@ -3111,17 +3016,9 @@ do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_n
|
|||||||
original_upstream_node_id = follow_target_node_record->node_id;
|
original_upstream_node_id = follow_target_node_record->node_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_file_options.use_replication_slots && runtime_options.host_param_provided == false)
|
if (config_file_options.use_replication_slots && runtime_options.host_param_provided == false && original_upstream_node_id != UNKNOWN_NODE_ID)
|
||||||
{
|
{
|
||||||
/*
|
remove_old_replication_slot = true;
|
||||||
* Only attempt to delete the old replication slot if the old upstream
|
|
||||||
* node is known and is different to the follow target node.
|
|
||||||
*/
|
|
||||||
if (original_upstream_node_id != UNKNOWN_NODE_ID
|
|
||||||
&& original_upstream_node_id != follow_target_node_record->node_id)
|
|
||||||
{
|
|
||||||
remove_old_replication_slot = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fetch original upstream's record */
|
/* Fetch original upstream's record */
|
||||||
@@ -3161,11 +3058,7 @@ do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_n
|
|||||||
log_notice(_("setting node %i's upstream to node %i"),
|
log_notice(_("setting node %i's upstream to node %i"),
|
||||||
config_file_options.node_id, follow_target_node_record->node_id);
|
config_file_options.node_id, follow_target_node_record->node_id);
|
||||||
|
|
||||||
if (!create_recovery_file(&local_node_record,
|
if (!create_recovery_file(&local_node_record, &recovery_conninfo, config_file_options.data_directory, true))
|
||||||
&recovery_conninfo,
|
|
||||||
PQserverVersion(primary_conn),
|
|
||||||
config_file_options.data_directory,
|
|
||||||
true))
|
|
||||||
{
|
{
|
||||||
*error_code = general_error_code;
|
*error_code = general_error_code;
|
||||||
return false;
|
return false;
|
||||||
@@ -3277,6 +3170,8 @@ do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_n
|
|||||||
* Note that if this function is called by do_standby_switchover(), the
|
* Note that if this function is called by do_standby_switchover(), the
|
||||||
* "repmgr node rejoin" command executed on the demotion candidate may already
|
* "repmgr node rejoin" command executed on the demotion candidate may already
|
||||||
* have removed the slot, so there may be nothing to do.
|
* have removed the slot, so there may be nothing to do.
|
||||||
|
*
|
||||||
|
* XXX check if former upstream is current primary?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (remove_old_replication_slot == true)
|
if (remove_old_replication_slot == true)
|
||||||
@@ -3779,9 +3674,7 @@ do_standby_switchover(void)
|
|||||||
|
|
||||||
if (runtime_options.dry_run == true)
|
if (runtime_options.dry_run == true)
|
||||||
{
|
{
|
||||||
log_info(_("able to execute \"%s\" on remote host \"%s\""),
|
log_info(_("able to execute \"%s\" on remote host \"localhost\""), progname());
|
||||||
progname(),
|
|
||||||
remote_host);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3942,7 +3835,7 @@ do_standby_switchover(void)
|
|||||||
exit(ERR_SWITCHOVER_FAIL);
|
exit(ERR_SWITCHOVER_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_warning(_("number of pending archive files on demotion candidate \"%s\" exceeds the critical threshold"),
|
log_warning(_("number of pending archive files on demotion candidate \"%s\" is critical"),
|
||||||
remote_node_record.node_name);
|
remote_node_record.node_name);
|
||||||
log_detail(_("%i pending archive files (critical threshold: %i)"),
|
log_detail(_("%i pending archive files (critical threshold: %i)"),
|
||||||
files, threshold);
|
files, threshold);
|
||||||
@@ -3952,7 +3845,7 @@ do_standby_switchover(void)
|
|||||||
|
|
||||||
case CHECK_STATUS_WARNING:
|
case CHECK_STATUS_WARNING:
|
||||||
{
|
{
|
||||||
log_warning(_("number of pending archive files on demotion candidate \"%s\" exceeds the warning threshold"),
|
log_warning(_("number of pending archive files on demotion candidate \"%s\" is warning"),
|
||||||
remote_node_record.node_name);
|
remote_node_record.node_name);
|
||||||
log_detail(_("%i pending archive files (warning threshold: %i)"),
|
log_detail(_("%i pending archive files (warning threshold: %i)"),
|
||||||
files, threshold);
|
files, threshold);
|
||||||
@@ -4361,9 +4254,6 @@ do_standby_switchover(void)
|
|||||||
remote_node_record.node_name,
|
remote_node_record.node_name,
|
||||||
shutdown_command);
|
shutdown_command);
|
||||||
|
|
||||||
log_info(_("parameter \"shutdown_check_timeout\" is set to %i seconds"),
|
|
||||||
config_file_options.shutdown_check_timeout);
|
|
||||||
|
|
||||||
clear_node_info_list(&sibling_nodes);
|
clear_node_info_list(&sibling_nodes);
|
||||||
|
|
||||||
key_value_list_free(&remote_config_files);
|
key_value_list_free(&remote_config_files);
|
||||||
@@ -4825,7 +4715,7 @@ do_standby_switchover(void)
|
|||||||
log_warning(_("unable to unpause repmgrd on %i node(s)"),
|
log_warning(_("unable to unpause repmgrd on %i node(s)"),
|
||||||
error_node_count);
|
error_node_count);
|
||||||
log_detail(_("errors encountered for following node(s):\n%s"), detail.data);
|
log_detail(_("errors encountered for following node(s):\n%s"), detail.data);
|
||||||
log_hint(_("check node connection and status; unpause manually with \"repmgr service unpause\""));
|
log_hint(_("check node connection and status; unpause manually with \"repmgr daemon unpause\""));
|
||||||
|
|
||||||
termPQExpBuffer(&detail);
|
termPQExpBuffer(&detail);
|
||||||
}
|
}
|
||||||
@@ -4862,7 +4752,6 @@ check_source_server()
|
|||||||
t_node_info upstream_node_record = T_NODE_INFO_INITIALIZER;
|
t_node_info upstream_node_record = T_NODE_INFO_INITIALIZER;
|
||||||
RecordStatus record_status = RECORD_NOT_FOUND;
|
RecordStatus record_status = RECORD_NOT_FOUND;
|
||||||
ExtensionStatus extension_status = REPMGR_UNKNOWN;
|
ExtensionStatus extension_status = REPMGR_UNKNOWN;
|
||||||
t_extension_versions extversions = T_EXTENSION_VERSIONS_INITIALIZER;
|
|
||||||
|
|
||||||
/* Attempt to connect to the upstream server to verify its configuration */
|
/* Attempt to connect to the upstream server to verify its configuration */
|
||||||
log_verbose(LOG_DEBUG, "check_source_server()");
|
log_verbose(LOG_DEBUG, "check_source_server()");
|
||||||
@@ -4926,7 +4815,7 @@ check_source_server()
|
|||||||
* to be used as a standalone clone tool)
|
* to be used as a standalone clone tool)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extension_status = get_repmgr_extension_status(primary_conn, &extversions);
|
extension_status = get_repmgr_extension_status(primary_conn, NULL);
|
||||||
|
|
||||||
if (extension_status != REPMGR_INSTALLED)
|
if (extension_status != REPMGR_INSTALLED)
|
||||||
{
|
{
|
||||||
@@ -4941,25 +4830,20 @@ check_source_server()
|
|||||||
exit(ERR_DB_QUERY);
|
exit(ERR_DB_QUERY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* schema doesn't exist */
|
||||||
|
log_error(_("repmgr extension not found on source node"));
|
||||||
|
|
||||||
if (extension_status == REPMGR_AVAILABLE)
|
if (extension_status == REPMGR_AVAILABLE)
|
||||||
{
|
{
|
||||||
log_error(_("repmgr extension is available but not installed in database \"%s\""),
|
log_detail(_("repmgr extension is available but not installed in database \"%s\""),
|
||||||
param_get(&source_conninfo, "dbname"));
|
param_get(&source_conninfo, "dbname"));
|
||||||
log_hint(_("check that you are cloning from the database where \"repmgr\" is installed"));
|
|
||||||
}
|
}
|
||||||
else if (extension_status == REPMGR_UNAVAILABLE)
|
else if (extension_status == REPMGR_UNAVAILABLE)
|
||||||
{
|
{
|
||||||
log_error(_("repmgr extension is not available on the upstream node"));
|
log_detail(_("repmgr extension is not available on the upstream node"));
|
||||||
}
|
|
||||||
else if (extension_status == REPMGR_OLD_VERSION_INSTALLED)
|
|
||||||
{
|
|
||||||
log_error(_("an older version of the extension is installed on the upstream node"));
|
|
||||||
log_detail(_("version %s is installed but newer version %s is available"),
|
|
||||||
extversions.installed_version,
|
|
||||||
extversions.default_version);
|
|
||||||
log_hint(_("upgrade \"repmgr\" on the source node first"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_hint(_("check that the upstream node is part of a repmgr cluster"));
|
||||||
PQfinish(source_conn);
|
PQfinish(source_conn);
|
||||||
exit(ERR_BAD_CONFIG);
|
exit(ERR_BAD_CONFIG);
|
||||||
}
|
}
|
||||||
@@ -4984,13 +4868,6 @@ check_source_server()
|
|||||||
* later, as this is a precautionary check and we can retrieve the system
|
* later, as this is a precautionary check and we can retrieve the system
|
||||||
* identifier with a normal connection.
|
* identifier with a normal connection.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (runtime_options.dry_run == true)
|
|
||||||
{
|
|
||||||
log_info(_("\"repmgr\" extension is installed in database \"%s\""),
|
|
||||||
param_get(&source_conninfo, "dbname"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_recovery_type(source_conn) == RECTYPE_PRIMARY && PQserverVersion(source_conn) >= 90600)
|
if (get_recovery_type(source_conn) == RECTYPE_PRIMARY && PQserverVersion(source_conn) >= 90600)
|
||||||
{
|
{
|
||||||
uint64 source_system_identifier = system_identifier(source_conn);
|
uint64 source_system_identifier = system_identifier(source_conn);
|
||||||
@@ -5532,7 +5409,7 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea
|
|||||||
{
|
{
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
log_error(_("parameter \"hot_standby\" must be set to \"on\""));
|
log_error(_("parameter 'hot_standby' must be set to 'on'"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exit_on_error == true)
|
if (exit_on_error == true)
|
||||||
@@ -5550,7 +5427,7 @@ check_upstream_config(PGconn *conn, int server_version_num, t_node_info *upstrea
|
|||||||
{
|
{
|
||||||
if (pg_setting_ok == true)
|
if (pg_setting_ok == true)
|
||||||
{
|
{
|
||||||
log_error(_("parameter \"max_wal_senders\" must be set to be at least %i"), i);
|
log_error(_("parameter \"max_wal_senders\" must be set to be at least 1 %i"), i);
|
||||||
log_hint(_("\"max_wal_senders\" should be set to at least the number of expected standbys"));
|
log_hint(_("\"max_wal_senders\" should be set to at least the number of expected standbys"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6115,7 +5992,7 @@ run_basebackup(t_node_info *node_record)
|
|||||||
if (record_status == RECORD_FOUND)
|
if (record_status == RECORD_FOUND)
|
||||||
{
|
{
|
||||||
log_verbose(LOG_INFO,
|
log_verbose(LOG_INFO,
|
||||||
_("replication slot \"%s\" already exists on upstream node %i"),
|
_("replication slot \"%s\" aleady exists on upstream node %i"),
|
||||||
node_record->slot_name,
|
node_record->slot_name,
|
||||||
upstream_node_id);
|
upstream_node_id);
|
||||||
slot_exists_on_upstream = true;
|
slot_exists_on_upstream = true;
|
||||||
@@ -6769,8 +6646,9 @@ make_barman_ssh_command(char *buf)
|
|||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
get_tablespace_data_barman(char *tablespace_data_barman,
|
get_tablespace_data_barman
|
||||||
TablespaceDataList *tablespace_list)
|
(char *tablespace_data_barman,
|
||||||
|
TablespaceDataList *tablespace_list)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Example: [('main', 24674, '/var/lib/postgresql/tablespaces/9.5/main'),
|
* Example: [('main', 24674, '/var/lib/postgresql/tablespaces/9.5/main'),
|
||||||
@@ -7044,55 +6922,49 @@ check_recovery_type(PGconn *conn)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates recovery configuration for a standby.
|
* Creates a recovery.conf file for a standby
|
||||||
*
|
*
|
||||||
* A database connection pointer is required for escaping primary_conninfo
|
* A database connection pointer is required for escaping primary_conninfo
|
||||||
* parameters. When cloning from Barman and --no-upstream-connection supplied,
|
* parameters. When cloning from Barman and --no-upstream-connection supplied,
|
||||||
* this might not be available.
|
* this might not be available.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
create_recovery_file(t_node_info *node_record, t_conninfo_param_list *primary_conninfo, int server_version_num, char *dest, bool as_file)
|
create_recovery_file(t_node_info *node_record, t_conninfo_param_list *primary_conninfo, char *dest, bool as_file)
|
||||||
{
|
{
|
||||||
PQExpBufferData recovery_file_buf;
|
PQExpBufferData recovery_file_buf;
|
||||||
PQExpBufferData primary_conninfo_buf;
|
|
||||||
char recovery_file_path[MAXPGPATH] = "";
|
char recovery_file_path[MAXPGPATH] = "";
|
||||||
FILE *recovery_file;
|
FILE *recovery_file;
|
||||||
mode_t um;
|
mode_t um;
|
||||||
|
|
||||||
KeyValueList recovery_config = {NULL, NULL};
|
/* create file in buffer */
|
||||||
KeyValueListCell *cell = NULL;
|
initPQExpBuffer(&recovery_file_buf);
|
||||||
|
|
||||||
initPQExpBuffer(&primary_conninfo_buf);
|
/* standby_mode = 'on' */
|
||||||
|
appendPQExpBufferStr(&recovery_file_buf,
|
||||||
/* standby_mode = 'on' (Pg 11 and earlier) */
|
"standby_mode = 'on'\n");
|
||||||
if (server_version_num < 120000)
|
|
||||||
{
|
|
||||||
key_value_list_set(&recovery_config,
|
|
||||||
"standby_mode", "on");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* primary_conninfo = '...' */
|
/* primary_conninfo = '...' */
|
||||||
write_primary_conninfo(&primary_conninfo_buf, primary_conninfo);
|
write_primary_conninfo(&recovery_file_buf, primary_conninfo);
|
||||||
key_value_list_set(&recovery_config,
|
|
||||||
"primary_conninfo", primary_conninfo_buf.data);
|
|
||||||
|
|
||||||
/* recovery_target_timeline = 'latest' */
|
/* recovery_target_timeline = 'latest' */
|
||||||
key_value_list_set(&recovery_config,
|
appendPQExpBufferStr(&recovery_file_buf,
|
||||||
"recovery_target_timeline", "latest");
|
"recovery_target_timeline = 'latest'\n");
|
||||||
|
|
||||||
|
|
||||||
/* recovery_min_apply_delay = ... (optional) */
|
/* recovery_min_apply_delay = ... (optional) */
|
||||||
if (config_file_options.recovery_min_apply_delay_provided == true)
|
if (config_file_options.recovery_min_apply_delay_provided == true)
|
||||||
{
|
{
|
||||||
key_value_list_set(&recovery_config,
|
appendPQExpBuffer(&recovery_file_buf,
|
||||||
"recovery_min_apply_delay", config_file_options.recovery_min_apply_delay);
|
"recovery_min_apply_delay = %s\n",
|
||||||
|
config_file_options.recovery_min_apply_delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* primary_slot_name = '...' (optional, for 9.4 and later) */
|
/* primary_slot_name = '...' (optional, for 9.4 and later) */
|
||||||
if (config_file_options.use_replication_slots)
|
if (config_file_options.use_replication_slots)
|
||||||
{
|
{
|
||||||
key_value_list_set(&recovery_config,
|
appendPQExpBuffer(&recovery_file_buf,
|
||||||
"primary_slot_name", node_record->slot_name);
|
"primary_slot_name = %s\n",
|
||||||
|
node_record->slot_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -7103,8 +6975,9 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *primary_co
|
|||||||
{
|
{
|
||||||
char *escaped = escape_recovery_conf_value(config_file_options.restore_command);
|
char *escaped = escape_recovery_conf_value(config_file_options.restore_command);
|
||||||
|
|
||||||
key_value_list_set(&recovery_config,
|
appendPQExpBuffer(&recovery_file_buf,
|
||||||
"restore_command", escaped);
|
"restore_command = '%s'\n",
|
||||||
|
escaped);
|
||||||
free(escaped);
|
free(escaped);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7112,84 +6985,33 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *primary_co
|
|||||||
if (config_file_options.archive_cleanup_command[0] != '\0')
|
if (config_file_options.archive_cleanup_command[0] != '\0')
|
||||||
{
|
{
|
||||||
char *escaped = escape_recovery_conf_value(config_file_options.archive_cleanup_command);
|
char *escaped = escape_recovery_conf_value(config_file_options.archive_cleanup_command);
|
||||||
|
appendPQExpBuffer(&recovery_file_buf,
|
||||||
key_value_list_set(&recovery_config,
|
"archive_cleanup_command = '%s'\n",
|
||||||
"archive_cleanup_command", escaped);
|
escaped);
|
||||||
free(escaped);
|
free(escaped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (as_file == true)
|
||||||
|
|
||||||
|
|
||||||
if (as_file == false)
|
|
||||||
{
|
{
|
||||||
/* create file in buffer */
|
maxpath_snprintf(recovery_file_path, "%s/%s", dest, RECOVERY_COMMAND_FILE);
|
||||||
initPQExpBuffer(&recovery_file_buf);
|
log_debug("create_recovery_file(): creating \"%s\"...",
|
||||||
|
|
||||||
for (cell = recovery_config.head; cell; cell = cell->next)
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(&recovery_file_buf,
|
|
||||||
"%s = '%s'\n",
|
|
||||||
cell->key, cell->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
maxlen_snprintf(dest, "%s", recovery_file_buf.data);
|
|
||||||
|
|
||||||
termPQExpBuffer(&recovery_file_buf);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* PostgreSQL 12 and later: modify postgresql.auto.conf
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if (server_version_num >= 120000)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (modify_auto_conf(dest, &recovery_config) == false)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (write_standby_signal() == false)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* PostgreSQL 11 and earlier: write recovery.conf
|
|
||||||
*/
|
|
||||||
maxpath_snprintf(recovery_file_path, "%s/%s", dest, RECOVERY_COMMAND_FILE);
|
|
||||||
log_debug("create_recovery_file(): creating \"%s\"...",
|
|
||||||
recovery_file_path);
|
|
||||||
|
|
||||||
/* Set umask to 0600 */
|
|
||||||
um = umask((~(S_IRUSR | S_IWUSR)) & (S_IRWXG | S_IRWXO));
|
|
||||||
recovery_file = fopen(recovery_file_path, "w");
|
|
||||||
umask(um);
|
|
||||||
|
|
||||||
if (recovery_file == NULL)
|
|
||||||
{
|
|
||||||
log_error(_("unable to create recovery.conf file at \"%s\""),
|
|
||||||
recovery_file_path);
|
recovery_file_path);
|
||||||
log_detail("%s", strerror(errno));
|
|
||||||
|
|
||||||
return false;
|
/* Set umask to 0600 */
|
||||||
}
|
um = umask((~(S_IRUSR | S_IWUSR)) & (S_IRWXG | S_IRWXO));
|
||||||
|
recovery_file = fopen(recovery_file_path, "w");
|
||||||
|
umask(um);
|
||||||
|
|
||||||
for (cell = recovery_config.head; cell; cell = cell->next)
|
if (recovery_file == NULL)
|
||||||
{
|
{
|
||||||
initPQExpBuffer(&recovery_file_buf);
|
log_error(_("unable to create recovery.conf file at \"%s\""),
|
||||||
appendPQExpBuffer(&recovery_file_buf,
|
recovery_file_path);
|
||||||
"%s = '%s'\n",
|
log_detail("%s", strerror(errno));
|
||||||
cell->key, cell->value);
|
|
||||||
|
|
||||||
log_debug("recovery.conf line: %s", recovery_file_buf.data);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("recovery file is:\n%s", recovery_file_buf.data);
|
||||||
|
|
||||||
if (fputs(recovery_file_buf.data, recovery_file) == EOF)
|
if (fputs(recovery_file_buf.data, recovery_file) == EOF)
|
||||||
{
|
{
|
||||||
@@ -7199,58 +7021,14 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *primary_co
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
termPQExpBuffer(&recovery_file_buf);
|
fclose(recovery_file);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
|
||||||
fclose(recovery_file);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* create standby.signal (PostgreSQL 12 and later)
|
|
||||||
*/
|
|
||||||
|
|
||||||
static bool
|
|
||||||
write_standby_signal(void)
|
|
||||||
{
|
|
||||||
char standby_signal_file_path[MAXPGPATH] = "";
|
|
||||||
FILE *file;
|
|
||||||
mode_t um;
|
|
||||||
|
|
||||||
snprintf(standby_signal_file_path, MAXPGPATH,
|
|
||||||
"%s/%s",
|
|
||||||
config_file_options.data_directory,
|
|
||||||
STANDBY_SIGNAL_FILE);
|
|
||||||
|
|
||||||
/* Set umask to 0600 */
|
|
||||||
um = umask((~(S_IRUSR | S_IWUSR)) & (S_IRWXG | S_IRWXO));
|
|
||||||
file = fopen(standby_signal_file_path, "w");
|
|
||||||
umask(um);
|
|
||||||
|
|
||||||
if (file == NULL)
|
|
||||||
{
|
{
|
||||||
log_error(_("unable to create %s file at \"%s\""),
|
maxlen_snprintf(dest, "%s", recovery_file_buf.data);
|
||||||
STANDBY_SIGNAL_FILE,
|
|
||||||
standby_signal_file_path);
|
|
||||||
log_detail("%s", strerror(errno));
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fputs("# created by repmgr\n", file) == EOF)
|
termPQExpBuffer(&recovery_file_buf);
|
||||||
{
|
|
||||||
log_error(_("unable to write to %s file at \"%s\""),
|
|
||||||
STANDBY_SIGNAL_FILE,
|
|
||||||
standby_signal_file_path);
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -7340,7 +7118,8 @@ write_primary_conninfo(PQExpBufferData *dest, t_conninfo_param_list *param_list)
|
|||||||
|
|
||||||
escaped = escape_recovery_conf_value(conninfo_buf.data);
|
escaped = escape_recovery_conf_value(conninfo_buf.data);
|
||||||
|
|
||||||
appendPQExpBufferStr(dest, escaped);
|
appendPQExpBuffer(dest,
|
||||||
|
"primary_conninfo = '%s'\n", escaped);
|
||||||
|
|
||||||
free(escaped);
|
free(escaped);
|
||||||
free_conninfo_params(&env_conninfo);
|
free_conninfo_params(&env_conninfo);
|
||||||
@@ -7995,7 +7774,7 @@ do_standby_help(void)
|
|||||||
" when the intended upstream server does not yet exist\n"));
|
" when the intended upstream server does not yet exist\n"));
|
||||||
printf(_(" --upstream-node-id ID of the upstream node to replicate from (optional, defaults to primary node)\n"));
|
printf(_(" --upstream-node-id ID of the upstream node to replicate from (optional, defaults to primary node)\n"));
|
||||||
printf(_(" --without-barman do not use Barman even if configured\n"));
|
printf(_(" --without-barman do not use Barman even if configured\n"));
|
||||||
printf(_(" --recovery-conf-only generate replication configuration for a previously cloned instance\n"));
|
printf(_(" --recovery-conf-only create \"recovery.conf\" file for a previously cloned instance\n"));
|
||||||
|
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
|
|||||||
@@ -260,6 +260,5 @@ extern void drop_replication_slot_if_exists(PGconn *conn, int node_id, char *slo
|
|||||||
extern bool check_node_can_attach(TimeLineID local_tli, XLogRecPtr local_xlogpos, PGconn *follow_target_conn, t_node_info *follow_target_node_record, bool is_rejoin);
|
extern bool check_node_can_attach(TimeLineID local_tli, XLogRecPtr local_xlogpos, PGconn *follow_target_conn, t_node_info *follow_target_node_record, bool is_rejoin);
|
||||||
extern void check_shared_library(PGconn *conn);
|
extern void check_shared_library(PGconn *conn);
|
||||||
extern bool is_repmgrd_running(PGconn *conn);
|
extern bool is_repmgrd_running(PGconn *conn);
|
||||||
extern int parse_repmgr_version(const char *version_string);
|
|
||||||
|
|
||||||
#endif /* _REPMGR_CLIENT_GLOBAL_H_ */
|
#endif /* _REPMGR_CLIENT_GLOBAL_H_ */
|
||||||
|
|||||||
252
repmgr-client.c
252
repmgr-client.c
@@ -33,10 +33,9 @@
|
|||||||
* NODE SERVICE
|
* NODE SERVICE
|
||||||
* NODE CONTROL
|
* NODE CONTROL
|
||||||
*
|
*
|
||||||
* SERVICE STATUS
|
* DAEMON STATUS
|
||||||
* SERVICE PAUSE
|
* DAEMON PAUSE
|
||||||
* SERVICE UNPAUSE
|
* DAEMON UNPAUSE
|
||||||
*
|
|
||||||
* DAEMON START
|
* DAEMON START
|
||||||
* DAEMON STOP
|
* DAEMON STOP
|
||||||
*
|
*
|
||||||
@@ -58,7 +57,6 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
|
||||||
#include "repmgr.h"
|
#include "repmgr.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "controldata.h"
|
#include "controldata.h"
|
||||||
@@ -70,11 +68,11 @@
|
|||||||
#include "repmgr-action-bdr.h"
|
#include "repmgr-action-bdr.h"
|
||||||
#include "repmgr-action-node.h"
|
#include "repmgr-action-node.h"
|
||||||
#include "repmgr-action-cluster.h"
|
#include "repmgr-action-cluster.h"
|
||||||
#include "repmgr-action-service.h"
|
|
||||||
#include "repmgr-action-daemon.h"
|
#include "repmgr-action-daemon.h"
|
||||||
|
|
||||||
#include <storage/fd.h> /* for PG_TEMP_FILE_PREFIX */
|
#include <storage/fd.h> /* for PG_TEMP_FILE_PREFIX */
|
||||||
|
|
||||||
|
|
||||||
/* globally available variables *
|
/* globally available variables *
|
||||||
* ============================ */
|
* ============================ */
|
||||||
|
|
||||||
@@ -186,7 +184,7 @@ main(int argc, char **argv)
|
|||||||
strncpy(runtime_options.username, pw->pw_name, MAXLEN);
|
strncpy(runtime_options.username, pw->pw_name, MAXLEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make getopt emit errors */
|
/* Make getopt emitting errors */
|
||||||
opterr = 1;
|
opterr = 1;
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "?Vb:f:FwWd:h:p:U:R:S:D:ck:L:qtvC:", long_options,
|
while ((c = getopt_long(argc, argv, "?Vb:f:FwWd:h:p:U:R:S:D:ck:L:qtvC:", long_options,
|
||||||
@@ -671,20 +669,33 @@ main(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/*-----------------------------
|
/*-----------------------------
|
||||||
* options deprecated since 4.0
|
* options deprecated since 3.3
|
||||||
*-----------------------------
|
*-----------------------------
|
||||||
*/
|
*/
|
||||||
case OPT_CHECK_UPSTREAM_CONFIG:
|
case OPT_CHECK_UPSTREAM_CONFIG:
|
||||||
item_list_append(&cli_warnings,
|
item_list_append(&cli_warnings,
|
||||||
_("--check-upstream-config is deprecated; use --dry-run instead"));
|
_("--check-upstream-config is deprecated; use --dry-run instead"));
|
||||||
break;
|
break;
|
||||||
|
case OPT_DATA_DIR:
|
||||||
|
item_list_append(&cli_warnings,
|
||||||
|
_("--data-dir is deprecated; use -D/--pgdata instead"));
|
||||||
|
break;
|
||||||
|
case OPT_NO_CONNINFO_PASSWORD:
|
||||||
|
item_list_append(&cli_warnings,
|
||||||
|
_("--no-conninfo-password is deprecated; use --use-recovery-conninfo-password to explicitly set a password"));
|
||||||
|
break;
|
||||||
/* -C/--remote-config-file */
|
/* -C/--remote-config-file */
|
||||||
case 'C':
|
case 'C':
|
||||||
item_list_append(&cli_warnings,
|
item_list_append(&cli_warnings,
|
||||||
_("--remote-config-file is no longer required"));
|
_("--remote-config-file is no longer required"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* --recovery-min-apply-delay */
|
||||||
|
case OPT_RECOVERY_MIN_APPLY_DELAY:
|
||||||
|
item_list_append(&cli_warnings,
|
||||||
|
_("--recovery-min-apply-delay is now a configuration file parameter, \"recovery_min_apply_delay\""));
|
||||||
|
break;
|
||||||
|
|
||||||
case ':': /* missing option argument */
|
case ':': /* missing option argument */
|
||||||
option_error_found = true;
|
option_error_found = true;
|
||||||
break;
|
break;
|
||||||
@@ -806,6 +817,7 @@ main(int argc, char **argv)
|
|||||||
exit_with_cli_errors(&cli_errors, NULL);
|
exit_with_cli_errors(&cli_errors, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*----------
|
/*----------
|
||||||
* Determine the node type and action; following are valid:
|
* Determine the node type and action; following are valid:
|
||||||
*
|
*
|
||||||
@@ -815,7 +827,7 @@ main(int argc, char **argv)
|
|||||||
* BDR { REGISTER | UNREGISTER } |
|
* BDR { REGISTER | UNREGISTER } |
|
||||||
* NODE { STATUS | CHECK | REJOIN | SERVICE } |
|
* NODE { STATUS | CHECK | REJOIN | SERVICE } |
|
||||||
* CLUSTER { CROSSCHECK | MATRIX | SHOW | EVENT | CLEANUP }
|
* CLUSTER { CROSSCHECK | MATRIX | SHOW | EVENT | CLEANUP }
|
||||||
* SERVICE { STATUS | PAUSE | UNPAUSE | START | STOP }
|
* DAEMON { STATUS | PAUSE | UNPAUSE | START | STOP }
|
||||||
*
|
*
|
||||||
* [node] is an optional hostname, provided instead of the -h/--host
|
* [node] is an optional hostname, provided instead of the -h/--host
|
||||||
* option
|
* option
|
||||||
@@ -954,22 +966,6 @@ main(int argc, char **argv)
|
|||||||
else if (strcasecmp(repmgr_action, "CLEANUP") == 0)
|
else if (strcasecmp(repmgr_action, "CLEANUP") == 0)
|
||||||
action = CLUSTER_CLEANUP;
|
action = CLUSTER_CLEANUP;
|
||||||
}
|
}
|
||||||
else if (strcasecmp(repmgr_command, "SERVICE") == 0)
|
|
||||||
{
|
|
||||||
if (help_option == true)
|
|
||||||
{
|
|
||||||
do_service_help();
|
|
||||||
exit(SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcasecmp(repmgr_action, "STATUS") == 0)
|
|
||||||
action = SERVICE_STATUS;
|
|
||||||
else if (strcasecmp(repmgr_action, "PAUSE") == 0)
|
|
||||||
action = SERVICE_PAUSE;
|
|
||||||
else if (strcasecmp(repmgr_action, "UNPAUSE") == 0)
|
|
||||||
action = SERVICE_UNPAUSE;
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (strcasecmp(repmgr_command, "DAEMON") == 0)
|
else if (strcasecmp(repmgr_command, "DAEMON") == 0)
|
||||||
{
|
{
|
||||||
if (help_option == true)
|
if (help_option == true)
|
||||||
@@ -978,18 +974,16 @@ main(int argc, char **argv)
|
|||||||
exit(SUCCESS);
|
exit(SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcasecmp(repmgr_action, "START") == 0)
|
if (strcasecmp(repmgr_action, "STATUS") == 0)
|
||||||
|
action = DAEMON_STATUS;
|
||||||
|
else if (strcasecmp(repmgr_action, "PAUSE") == 0)
|
||||||
|
action = DAEMON_PAUSE;
|
||||||
|
else if (strcasecmp(repmgr_action, "UNPAUSE") == 0)
|
||||||
|
action = DAEMON_UNPAUSE;
|
||||||
|
else if (strcasecmp(repmgr_action, "START") == 0)
|
||||||
action = DAEMON_START;
|
action = DAEMON_START;
|
||||||
else if (strcasecmp(repmgr_action, "STOP") == 0)
|
else if (strcasecmp(repmgr_action, "STOP") == 0)
|
||||||
action = DAEMON_STOP;
|
action = DAEMON_STOP;
|
||||||
|
|
||||||
/* allow "daemon" as an alias for "service" for repmgr 4.x compatibility */
|
|
||||||
if (strcasecmp(repmgr_action, "STATUS") == 0)
|
|
||||||
action = SERVICE_STATUS;
|
|
||||||
else if (strcasecmp(repmgr_action, "PAUSE") == 0)
|
|
||||||
action = SERVICE_PAUSE;
|
|
||||||
else if (strcasecmp(repmgr_action, "UNPAUSE") == 0)
|
|
||||||
action = SERVICE_UNPAUSE;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1392,18 +1386,16 @@ main(int argc, char **argv)
|
|||||||
do_cluster_cleanup();
|
do_cluster_cleanup();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* SERVICE */
|
|
||||||
case SERVICE_STATUS:
|
|
||||||
do_service_status();
|
|
||||||
break;
|
|
||||||
case SERVICE_PAUSE:
|
|
||||||
do_service_pause();
|
|
||||||
break;
|
|
||||||
case SERVICE_UNPAUSE:
|
|
||||||
do_service_unpause();
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* DAEMON */
|
/* DAEMON */
|
||||||
|
case DAEMON_STATUS:
|
||||||
|
do_daemon_status();
|
||||||
|
break;
|
||||||
|
case DAEMON_PAUSE:
|
||||||
|
do_daemon_pause();
|
||||||
|
break;
|
||||||
|
case DAEMON_UNPAUSE:
|
||||||
|
do_daemon_unpause();
|
||||||
|
break;
|
||||||
case DAEMON_START:
|
case DAEMON_START:
|
||||||
do_daemon_start();
|
do_daemon_start();
|
||||||
break;
|
break;
|
||||||
@@ -1914,9 +1906,8 @@ check_cli_parameters(const int action)
|
|||||||
case WITNESS_UNREGISTER:
|
case WITNESS_UNREGISTER:
|
||||||
case NODE_REJOIN:
|
case NODE_REJOIN:
|
||||||
case NODE_SERVICE:
|
case NODE_SERVICE:
|
||||||
case SERVICE_PAUSE:
|
case DAEMON_PAUSE:
|
||||||
case SERVICE_UNPAUSE:
|
case DAEMON_UNPAUSE:
|
||||||
case SERVICE_STATUS:
|
|
||||||
case DAEMON_START:
|
case DAEMON_START:
|
||||||
case DAEMON_STOP:
|
case DAEMON_STOP:
|
||||||
break;
|
break;
|
||||||
@@ -1955,7 +1946,7 @@ check_cli_parameters(const int action)
|
|||||||
{
|
{
|
||||||
case CLUSTER_SHOW:
|
case CLUSTER_SHOW:
|
||||||
case CLUSTER_EVENT:
|
case CLUSTER_EVENT:
|
||||||
case SERVICE_STATUS:
|
case DAEMON_STATUS:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
item_list_append_format(&cli_warnings,
|
item_list_append_format(&cli_warnings,
|
||||||
@@ -1969,7 +1960,7 @@ check_cli_parameters(const int action)
|
|||||||
{
|
{
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
case SERVICE_STATUS:
|
case DAEMON_STATUS:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
item_list_append_format(&cli_warnings,
|
item_list_append_format(&cli_warnings,
|
||||||
@@ -2019,7 +2010,7 @@ check_cli_parameters(const int action)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate formatted node status output for display by "cluster show" and
|
* Generate formatted node status output for display by "cluster show" and
|
||||||
* "service status".
|
* "daemon status".
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
format_node_status(t_node_info *node_info, PQExpBufferData *node_status, PQExpBufferData *upstream, ItemList *warnings)
|
format_node_status(t_node_info *node_info, PQExpBufferData *node_status, PQExpBufferData *upstream, ItemList *warnings)
|
||||||
@@ -2456,8 +2447,6 @@ action_name(const int action)
|
|||||||
return "STANDBY PROMOTE";
|
return "STANDBY PROMOTE";
|
||||||
case STANDBY_FOLLOW:
|
case STANDBY_FOLLOW:
|
||||||
return "STANDBY FOLLOW";
|
return "STANDBY FOLLOW";
|
||||||
case STANDBY_SWITCHOVER:
|
|
||||||
return "STANDBY SWITCHOVER";
|
|
||||||
|
|
||||||
case WITNESS_REGISTER:
|
case WITNESS_REGISTER:
|
||||||
return "WITNESS REGISTER";
|
return "WITNESS REGISTER";
|
||||||
@@ -2477,13 +2466,9 @@ action_name(const int action)
|
|||||||
return "NODE REJOIN";
|
return "NODE REJOIN";
|
||||||
case NODE_SERVICE:
|
case NODE_SERVICE:
|
||||||
return "NODE SERVICE";
|
return "NODE SERVICE";
|
||||||
case NODE_CONTROL:
|
|
||||||
return "NODE CONTROL";
|
|
||||||
|
|
||||||
case CLUSTER_SHOW:
|
case CLUSTER_SHOW:
|
||||||
return "CLUSTER SHOW";
|
return "CLUSTER SHOW";
|
||||||
case CLUSTER_CLEANUP:
|
|
||||||
return "CLUSTER CLEANUP";
|
|
||||||
case CLUSTER_EVENT:
|
case CLUSTER_EVENT:
|
||||||
return "CLUSTER EVENT";
|
return "CLUSTER EVENT";
|
||||||
case CLUSTER_MATRIX:
|
case CLUSTER_MATRIX:
|
||||||
@@ -2491,13 +2476,12 @@ action_name(const int action)
|
|||||||
case CLUSTER_CROSSCHECK:
|
case CLUSTER_CROSSCHECK:
|
||||||
return "CLUSTER CROSSCHECK";
|
return "CLUSTER CROSSCHECK";
|
||||||
|
|
||||||
case SERVICE_STATUS:
|
case DAEMON_STATUS:
|
||||||
return "SERVICE STATUS";
|
return "DAEMON STATUS";
|
||||||
case SERVICE_PAUSE:
|
case DAEMON_PAUSE:
|
||||||
return "SERVICE PAUSE";
|
return "DAEMON PAUSE";
|
||||||
case SERVICE_UNPAUSE:
|
case DAEMON_UNPAUSE:
|
||||||
return "SERVICE UNPAUSE";
|
return "DAEMON UNPAUSE";
|
||||||
|
|
||||||
case DAEMON_START:
|
case DAEMON_START:
|
||||||
return "DAEMON START";
|
return "DAEMON START";
|
||||||
case DAEMON_STOP:
|
case DAEMON_STOP:
|
||||||
@@ -2612,12 +2596,11 @@ do_help(void)
|
|||||||
printf(_(" %s [OPTIONS] node {status|check|rejoin|service}\n"), progname());
|
printf(_(" %s [OPTIONS] node {status|check|rejoin|service}\n"), progname());
|
||||||
printf(_(" %s [OPTIONS] cluster {show|event|matrix|crosscheck|cleanup}\n"), progname());
|
printf(_(" %s [OPTIONS] cluster {show|event|matrix|crosscheck|cleanup}\n"), progname());
|
||||||
printf(_(" %s [OPTIONS] witness {register|unregister}\n"), progname());
|
printf(_(" %s [OPTIONS] witness {register|unregister}\n"), progname());
|
||||||
printf(_(" %s [OPTIONS] service {status|pause|unpause}\n"), progname());
|
printf(_(" %s [OPTIONS] daemon {status|pause|unpause|start|stop}\n"), progname());
|
||||||
printf(_(" %s [OPTIONS] daemon {start|stop}\n"), progname());
|
|
||||||
|
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
printf(_(" Execute \"%s {primary|standby|bdr|node|cluster|witness|service} --help\" to see command-specific options\n"), progname());
|
printf(_(" Execute \"%s {primary|standby|bdr|node|cluster|witness|daemon} --help\" to see command-specific options\n"), progname());
|
||||||
|
|
||||||
puts("");
|
puts("");
|
||||||
|
|
||||||
@@ -2850,25 +2833,15 @@ create_repmgr_extension(PGconn *conn)
|
|||||||
int
|
int
|
||||||
check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string)
|
check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string)
|
||||||
{
|
{
|
||||||
char version_string[MAXVERSIONSTR] = "";
|
int conn_server_version_num = get_server_version(conn, server_version_string);
|
||||||
int conn_server_version_num = get_server_version(conn, version_string);
|
|
||||||
|
|
||||||
/* Copy the version string, if the caller wants it */
|
|
||||||
if (server_version_string != NULL)
|
|
||||||
strncpy(server_version_string, version_string, MAXVERSIONSTR);
|
|
||||||
|
|
||||||
if (conn_server_version_num < MIN_SUPPORTED_VERSION_NUM)
|
if (conn_server_version_num < MIN_SUPPORTED_VERSION_NUM)
|
||||||
{
|
{
|
||||||
if (conn_server_version_num > 0)
|
if (conn_server_version_num > 0)
|
||||||
{
|
|
||||||
log_error(_("%s requires %s to be PostgreSQL %s or later"),
|
log_error(_("%s requires %s to be PostgreSQL %s or later"),
|
||||||
progname(),
|
progname(),
|
||||||
server_type,
|
server_type,
|
||||||
MIN_SUPPORTED_VERSION);
|
MIN_SUPPORTED_VERSION);
|
||||||
log_detail(_("%s server version is %s"),
|
|
||||||
server_type,
|
|
||||||
version_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exit_on_error == true)
|
if (exit_on_error == true)
|
||||||
{
|
{
|
||||||
@@ -2879,38 +2852,6 @@ check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *
|
|||||||
return UNKNOWN_SERVER_VERSION_NUM;
|
return UNKNOWN_SERVER_VERSION_NUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If it's clear a particular repmgr feature branch won't be able to support
|
|
||||||
* PostgreSQL from a particular PostgreSQL release onwards (e.g. 4.4 with PostgreSQL
|
|
||||||
* 12 and later due to recovery.conf removal), set MAX_UNSUPPORTED_VERSION and
|
|
||||||
* MAX_UNSUPPORTED_VERSION_NUM in "repmgr.h" to define the first PostgreSQL
|
|
||||||
* version which can't be suppored.
|
|
||||||
*/
|
|
||||||
#ifdef MAX_UNSUPPORTED_VERSION_NUM
|
|
||||||
if (conn_server_version_num >= MAX_UNSUPPORTED_VERSION_NUM)
|
|
||||||
{
|
|
||||||
if (conn_server_version_num > 0)
|
|
||||||
{
|
|
||||||
log_error(_("%s %s does not support PostgreSQL %s or later"),
|
|
||||||
progname(),
|
|
||||||
REPMGR_VERSION,
|
|
||||||
MAX_UNSUPPORTED_VERSION);
|
|
||||||
log_detail(_("%s server version is %s"),
|
|
||||||
server_type,
|
|
||||||
version_string);
|
|
||||||
log_hint(_("For details of supported versions see: https://repmgr.org/docs/current/install-requirements.html#INSTALL-COMPATIBILITY-MATRIX"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exit_on_error == true)
|
|
||||||
{
|
|
||||||
PQfinish(conn);
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
return UNKNOWN_SERVER_VERSION_NUM;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return conn_server_version_num;
|
return conn_server_version_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3088,19 +3029,19 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
|||||||
|
|
||||||
if (*config_file_options.rsync_options == '\0')
|
if (*config_file_options.rsync_options == '\0')
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBuffer(&rsync_flags, "%s",
|
||||||
"--archive --checksum --compress --progress --rsh=ssh");
|
"--archive --checksum --compress --progress --rsh=ssh");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBuffer(&rsync_flags, "%s",
|
||||||
config_file_options.rsync_options);
|
config_file_options.rsync_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runtime_options.force)
|
if (runtime_options.force)
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBuffer(&rsync_flags, "%s",
|
||||||
" --delete --checksum");
|
" --delete --checksum");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!remote_user[0])
|
if (!remote_user[0])
|
||||||
@@ -3126,11 +3067,11 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
|||||||
if (is_directory)
|
if (is_directory)
|
||||||
{
|
{
|
||||||
/* Files which we don't want */
|
/* Files which we don't want */
|
||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBuffer(&rsync_flags, "%s",
|
||||||
" --exclude=postmaster.pid --exclude=postmaster.opts --exclude=global/pg_control");
|
" --exclude=postmaster.pid --exclude=postmaster.opts --exclude=global/pg_control");
|
||||||
|
|
||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBuffer(&rsync_flags, "%s",
|
||||||
" --exclude=recovery.conf --exclude=recovery.done");
|
" --exclude=recovery.conf --exclude=recovery.done");
|
||||||
|
|
||||||
if (server_version_num >= 90400)
|
if (server_version_num >= 90400)
|
||||||
{
|
{
|
||||||
@@ -3138,8 +3079,8 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
|||||||
* Ideally we'd use PG_AUTOCONF_FILENAME from utils/guc.h, but
|
* Ideally we'd use PG_AUTOCONF_FILENAME from utils/guc.h, but
|
||||||
* that has too many dependencies for a mere client program.
|
* that has too many dependencies for a mere client program.
|
||||||
*/
|
*/
|
||||||
appendPQExpBuffer(&rsync_flags, " --exclude=%s.tmp",
|
appendPQExpBuffer(&rsync_flags, "%s",
|
||||||
PG_AUTOCONF_FILENAME);
|
" --exclude=postgresql.auto.conf.tmp");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Temporary files which we don't want, if they exist */
|
/* Temporary files which we don't want, if they exist */
|
||||||
@@ -3150,17 +3091,17 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
|||||||
|
|
||||||
if (server_version_num >= 100000)
|
if (server_version_num >= 100000)
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBuffer(&rsync_flags, "%s",
|
||||||
" --exclude=pg_wal/*");
|
" --exclude=pg_wal/*");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBuffer(&rsync_flags, "%s",
|
||||||
" --exclude=pg_xlog/*");
|
" --exclude=pg_xlog/*");
|
||||||
}
|
}
|
||||||
|
|
||||||
appendPQExpBufferStr(&rsync_flags,
|
appendPQExpBuffer(&rsync_flags, "%s",
|
||||||
" --exclude=pg_log/* --exclude=pg_stat_tmp/*");
|
" --exclude=pg_log/* --exclude=pg_stat_tmp/*");
|
||||||
|
|
||||||
maxlen_snprintf(script, "rsync %s %s:%s/* %s",
|
maxlen_snprintf(script, "rsync %s %s:%s/* %s",
|
||||||
rsync_flags.data, host_string, remote_path, local_path);
|
rsync_flags.data, host_string, remote_path, local_path);
|
||||||
@@ -3215,18 +3156,6 @@ make_remote_repmgr_path(PQExpBufferData *output_buf, t_node_info *remote_node_re
|
|||||||
"%s -f %s ",
|
"%s -f %s ",
|
||||||
progname(),
|
progname(),
|
||||||
remote_node_record->config_file);
|
remote_node_record->config_file);
|
||||||
|
|
||||||
/*
|
|
||||||
* If --log-level was explicitly supplied, pass that through
|
|
||||||
* to the remote repmgr client too.
|
|
||||||
*/
|
|
||||||
if (runtime_options.log_level[0] != '\0')
|
|
||||||
{
|
|
||||||
appendPQExpBuffer(output_buf,
|
|
||||||
" -L %s ",
|
|
||||||
runtime_options.log_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3940,44 +3869,3 @@ is_repmgrd_running(PGconn *conn)
|
|||||||
|
|
||||||
return is_running;
|
return is_running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the string returned by "repmgr --version", e.g. "repmgr 4.1.2",
|
|
||||||
* and return it as a version integer (e.g. 40102).
|
|
||||||
*
|
|
||||||
* This is required for backwards compatibility as versions prior to
|
|
||||||
* 4.3 do not have the --version-number option.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
parse_repmgr_version(const char *version_string)
|
|
||||||
{
|
|
||||||
int series, major, minor;
|
|
||||||
int version_integer = UNKNOWN_REPMGR_VERSION_NUM;
|
|
||||||
PQExpBufferData sscanf_string;
|
|
||||||
|
|
||||||
initPQExpBuffer(&sscanf_string);
|
|
||||||
|
|
||||||
appendPQExpBuffer(&sscanf_string, "%s ",
|
|
||||||
progname());
|
|
||||||
appendPQExpBufferStr(&sscanf_string, "%i.%i.%i");
|
|
||||||
|
|
||||||
if (sscanf(version_string, sscanf_string.data, &series, &major, &minor) == 3)
|
|
||||||
{
|
|
||||||
version_integer = (series * 10000) + (major * 100) + minor;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
resetPQExpBuffer(&sscanf_string);
|
|
||||||
appendPQExpBuffer(&sscanf_string, "%s ",
|
|
||||||
progname());
|
|
||||||
appendPQExpBufferStr(&sscanf_string, "%i.%i");
|
|
||||||
|
|
||||||
if (sscanf(version_string, "repmgr %i.%i", &series, &major) == 2)
|
|
||||||
{
|
|
||||||
version_integer = (series * 10000) + (major * 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return version_integer;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -46,9 +46,9 @@
|
|||||||
#define CLUSTER_MATRIX 20
|
#define CLUSTER_MATRIX 20
|
||||||
#define CLUSTER_CROSSCHECK 21
|
#define CLUSTER_CROSSCHECK 21
|
||||||
#define CLUSTER_EVENT 22
|
#define CLUSTER_EVENT 22
|
||||||
#define SERVICE_STATUS 23
|
#define DAEMON_STATUS 23
|
||||||
#define SERVICE_PAUSE 24
|
#define DAEMON_PAUSE 24
|
||||||
#define SERVICE_UNPAUSE 25
|
#define DAEMON_UNPAUSE 25
|
||||||
#define DAEMON_START 26
|
#define DAEMON_START 26
|
||||||
#define DAEMON_STOP 27
|
#define DAEMON_STOP 27
|
||||||
|
|
||||||
@@ -101,9 +101,13 @@
|
|||||||
#define OPT_DETAIL 1046
|
#define OPT_DETAIL 1046
|
||||||
#define OPT_REPMGRD_FORCE_UNPAUSE 1047
|
#define OPT_REPMGRD_FORCE_UNPAUSE 1047
|
||||||
|
|
||||||
|
/* deprecated since 3.3 */
|
||||||
|
#define OPT_DATA_DIR 999
|
||||||
|
#define OPT_NO_CONNINFO_PASSWORD 998
|
||||||
|
#define OPT_RECOVERY_MIN_APPLY_DELAY 997
|
||||||
/* deprecated since 4.0 */
|
/* deprecated since 4.0 */
|
||||||
#define OPT_CHECK_UPSTREAM_CONFIG 999
|
#define OPT_CHECK_UPSTREAM_CONFIG 996
|
||||||
#define OPT_NODE 998
|
#define OPT_NODE 995
|
||||||
|
|
||||||
|
|
||||||
static struct option long_options[] =
|
static struct option long_options[] =
|
||||||
@@ -153,6 +157,7 @@ static struct option long_options[] =
|
|||||||
{"copy-external-config-files", optional_argument, NULL, OPT_COPY_EXTERNAL_CONFIG_FILES},
|
{"copy-external-config-files", optional_argument, NULL, OPT_COPY_EXTERNAL_CONFIG_FILES},
|
||||||
{"fast-checkpoint", no_argument, NULL, 'c'},
|
{"fast-checkpoint", no_argument, NULL, 'c'},
|
||||||
{"no-upstream-connection", no_argument, NULL, OPT_NO_UPSTREAM_CONNECTION},
|
{"no-upstream-connection", no_argument, NULL, OPT_NO_UPSTREAM_CONNECTION},
|
||||||
|
{"recovery-min-apply-delay", required_argument, NULL, OPT_RECOVERY_MIN_APPLY_DELAY},
|
||||||
{"replication-user", required_argument, NULL, OPT_REPLICATION_USER},
|
{"replication-user", required_argument, NULL, OPT_REPLICATION_USER},
|
||||||
{"upstream-conninfo", required_argument, NULL, OPT_UPSTREAM_CONNINFO},
|
{"upstream-conninfo", required_argument, NULL, OPT_UPSTREAM_CONNINFO},
|
||||||
{"upstream-node-id", required_argument, NULL, OPT_UPSTREAM_NODE_ID},
|
{"upstream-node-id", required_argument, NULL, OPT_UPSTREAM_NODE_ID},
|
||||||
@@ -210,8 +215,11 @@ static struct option long_options[] =
|
|||||||
|
|
||||||
/* deprecated */
|
/* deprecated */
|
||||||
{"check-upstream-config", no_argument, NULL, OPT_CHECK_UPSTREAM_CONFIG},
|
{"check-upstream-config", no_argument, NULL, OPT_CHECK_UPSTREAM_CONFIG},
|
||||||
|
{"no-conninfo-password", no_argument, NULL, OPT_NO_CONNINFO_PASSWORD},
|
||||||
/* previously used by "standby switchover" */
|
/* previously used by "standby switchover" */
|
||||||
{"remote-config-file", required_argument, NULL, 'C'},
|
{"remote-config-file", required_argument, NULL, 'C'},
|
||||||
|
/* legacy alias for -D/--pgdata */
|
||||||
|
{"data-dir", required_argument, NULL, OPT_DATA_DIR},
|
||||||
/* replaced by --node-id */
|
/* replaced by --node-id */
|
||||||
{"node", required_argument, NULL, OPT_NODE},
|
{"node", required_argument, NULL, OPT_NODE},
|
||||||
|
|
||||||
|
|||||||
2
repmgr.c
2
repmgr.c
@@ -702,7 +702,7 @@ set_repmgrd_pid(PG_FUNCTION_ARGS)
|
|||||||
shared_state->repmgrd_pid = repmgrd_pid;
|
shared_state->repmgrd_pid = repmgrd_pid;
|
||||||
memset(shared_state->repmgrd_pidfile, 0, MAXPGPATH);
|
memset(shared_state->repmgrd_pidfile, 0, MAXPGPATH);
|
||||||
|
|
||||||
if (repmgrd_pidfile != NULL)
|
if(repmgrd_pidfile != NULL)
|
||||||
{
|
{
|
||||||
strncpy(shared_state->repmgrd_pidfile, repmgrd_pidfile, MAXPGPATH);
|
strncpy(shared_state->repmgrd_pidfile, repmgrd_pidfile, MAXPGPATH);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,12 @@
|
|||||||
# is noted for each item. Where no default value is shown, the
|
# is noted for each item. Where no default value is shown, the
|
||||||
# parameter will be treated as empty or false.
|
# parameter will be treated as empty or false.
|
||||||
#
|
#
|
||||||
# repmgr parses its configuration file in the same way as PostgreSQL itself
|
# IMPORTANT: string values can be provided as-is, or enclosed in single quotes
|
||||||
# does. In particular, strings must be enclosed in single quotes (although
|
# (but not double-quotes, which will be interpreted as part of the string),
|
||||||
# simple identifiers may be provided as-is).
|
# e.g.:
|
||||||
#
|
#
|
||||||
# For details on the configuration file format see the documentation at:
|
# node_name=foo
|
||||||
#
|
# node_name = 'foo'
|
||||||
# https://repmgr.org/docs/current/configuration-file.html#CONFIGURATION-FILE-FORMAT
|
|
||||||
#
|
#
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Required configuration items
|
# Required configuration items
|
||||||
@@ -21,7 +20,7 @@
|
|||||||
# repmgr and repmgrd require the following items to be explicitly configured.
|
# repmgr and repmgrd require the following items to be explicitly configured.
|
||||||
|
|
||||||
|
|
||||||
#node_id= # A unique integer greater than zero
|
#node_id= # A unique integer greater than zero
|
||||||
#node_name='' # An arbitrary (but unique) string; we recommend
|
#node_name='' # An arbitrary (but unique) string; we recommend
|
||||||
# using the server's hostname or another identifier
|
# using the server's hostname or another identifier
|
||||||
# unambiguously associated with the server to avoid
|
# unambiguously associated with the server to avoid
|
||||||
@@ -29,8 +28,8 @@
|
|||||||
# node's current role, e.g. 'primary' or 'standby1',
|
# node's current role, e.g. 'primary' or 'standby1',
|
||||||
# as roles can change and it will be confusing if
|
# as roles can change and it will be confusing if
|
||||||
# the current primary is called 'standby1'.
|
# the current primary is called 'standby1'.
|
||||||
# The string's maximum length is 63 characters and it should
|
# The string's maximum length is 63 characters and it should
|
||||||
# contain only printable ASCII characters.
|
# contain only printable ASCII characters.
|
||||||
|
|
||||||
#conninfo='' # Database connection information as a conninfo string.
|
#conninfo='' # Database connection information as a conninfo string.
|
||||||
# All servers in the cluster must be able to connect to
|
# All servers in the cluster must be able to connect to
|
||||||
@@ -71,13 +70,13 @@
|
|||||||
#replication_user='repmgr' # User to make replication connections with, if not set
|
#replication_user='repmgr' # User to make replication connections with, if not set
|
||||||
# defaults to the user defined in "conninfo".
|
# defaults to the user defined in "conninfo".
|
||||||
|
|
||||||
#replication_type='physical' # Must be one of "physical" or "bdr".
|
#replication_type=physical # Must be one of "physical" or "bdr".
|
||||||
# NOTE: "bdr" can only be used with BDR 2.x
|
# NOTE: "bdr" can only be used with BDR 2.x
|
||||||
|
|
||||||
#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,
|
||||||
@@ -102,10 +101,10 @@
|
|||||||
# This is mainly intended for those cases when `repmgr` is executed directly
|
# This is mainly intended for those cases when `repmgr` is executed directly
|
||||||
# by `repmgrd`.
|
# by `repmgrd`.
|
||||||
|
|
||||||
#log_level='INFO' # Log level: possible values are DEBUG, INFO, NOTICE,
|
#log_level=INFO # Log level: possible values are DEBUG, INFO, NOTICE,
|
||||||
# WARNING, ERROR, ALERT, CRIT or EMERG
|
# WARNING, ERROR, ALERT, CRIT or EMERG
|
||||||
|
|
||||||
#log_facility='STDERR' # Logging facility: possible values are STDERR, or for
|
#log_facility=STDERR # Logging facility: possible values are STDERR, or for
|
||||||
# syslog integration, one of LOCAL0, LOCAL1, ..., LOCAL7, USER
|
# syslog integration, one of LOCAL0, LOCAL1, ..., LOCAL7, USER
|
||||||
|
|
||||||
#log_file='' # STDERR can be redirected to an arbitrary file
|
#log_file='' # STDERR can be redirected to an arbitrary file
|
||||||
@@ -160,13 +159,12 @@
|
|||||||
|
|
||||||
#repmgr_bindir='' # Path to repmgr binary directory (location of the repmgr
|
#repmgr_bindir='' # Path to repmgr binary directory (location of the repmgr
|
||||||
# binary. Only needed if the repmgr executable is not in
|
# binary. Only needed if the repmgr executable is not in
|
||||||
# the system $PATH or the path defined in "pg_bindir".
|
# the system $PATH or the path defined in "pg_bindir".
|
||||||
|
|
||||||
#use_primary_conninfo_password=false # explicitly set "password" in "primary_conninfo"
|
#use_primary_conninfo_password=false # explicitly set "password" in recovery.conf's
|
||||||
# using the value contained in the environment variable
|
# "primary_conninfo" parameter using the value contained
|
||||||
# PGPASSWORD
|
# in the environment variable PGPASSWORD
|
||||||
#passfile='' # path to .pgpass file to include in "primary_conninfo"
|
#passfile='' # path to .pgpass file to include in "primary_conninfo"
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# external command options
|
# external command options
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
@@ -180,7 +178,7 @@
|
|||||||
# rsync_options=--archive --checksum --compress --progress --rsh="ssh -o \"StrictHostKeyChecking no\""
|
# rsync_options=--archive --checksum --compress --progress --rsh="ssh -o \"StrictHostKeyChecking no\""
|
||||||
# ssh_options=-o "StrictHostKeyChecking no"
|
# ssh_options=-o "StrictHostKeyChecking no"
|
||||||
|
|
||||||
#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"
|
||||||
#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"
|
||||||
@@ -198,19 +196,19 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# tablespace_mapping=/path/to/original/tablespace=/path/to/new/tablespace
|
# tablespace_mapping=/path/to/original/tablespace=/path/to/new/tablespace
|
||||||
# restore_command = 'cp /path/to/archived/wals/%f %p'
|
# restore_command = 'cp /path/to/archived/wals/%f %p'
|
||||||
|
|
||||||
#tablespace_mapping='' # Tablespaces can be remapped from one
|
#tablespace_mapping='' # Tablespaces can be remapped from one
|
||||||
# file system location to another. This
|
# file system location to another. This
|
||||||
# parameter can be provided multiple times.
|
# parameter can be provided multiple times.
|
||||||
|
|
||||||
#restore_command='' # This will be included in the recovery configuration
|
#restore_command='' # This will be placed in the recovery.conf file generated
|
||||||
# generated by repmgr.
|
# by repmgr.
|
||||||
|
|
||||||
#archive_cleanup_command='' # This will be included in the recovery configuration
|
#archive_cleanup_command='' # This will be placed in the recovery.conf file generated
|
||||||
# generated by repmgr. Note we recommend using Barman for
|
# by repmgr. Note we recommend using Barman for managing
|
||||||
# managing WAL archives (see: https://www.pgbarman.org )
|
# WAL archives (see: https://www.pgbarman.org )
|
||||||
|
|
||||||
#recovery_min_apply_delay= # If provided, "recovery_min_apply_delay" will be set to
|
#recovery_min_apply_delay= # If provided, "recovery_min_apply_delay" in recovery.conf
|
||||||
# this value (PostgreSQL 9.4 and later).
|
# will be set to this value (PostgreSQL 9.4 and later).
|
||||||
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
@@ -283,7 +281,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# These settings are only applied when repmgrd is running. Values shown
|
# These settings are only applied when repmgrd is running. Values shown
|
||||||
# are defaults.
|
# are defaults.
|
||||||
|
|
||||||
#failover='manual' # one of 'automatic', 'manual'.
|
#failover=manual # one of 'automatic', 'manual'.
|
||||||
# determines what action to take in the event of upstream failure
|
# determines what action to take in the event of upstream failure
|
||||||
#
|
#
|
||||||
# 'automatic': repmgrd will automatically attempt to promote the
|
# 'automatic': repmgrd will automatically attempt to promote the
|
||||||
@@ -297,17 +295,17 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# (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': execute a throwaway query on the current connection
|
# 'connection': execute a throwaway query on the current connection
|
||||||
#reconnect_attempts=6 # Number of attempts which will be made to reconnect to an unreachable
|
#reconnect_attempts=6 # Number of attempts which will be made to reconnect to an unreachable
|
||||||
# primary (or other upstream node)
|
# primary (or other upstream node)
|
||||||
#reconnect_interval=10 # Interval between attempts to reconnect to an unreachable
|
#reconnect_interval=10 # Interval between attempts to reconnect to an unreachable
|
||||||
# primary (or other upstream node)
|
# primary (or other upstream node)
|
||||||
#promote_command='' # command repmgrd executes when promoting a new primary; use something like:
|
#promote_command= # command repmgrd executes when promoting a new primary; use something like:
|
||||||
#
|
#
|
||||||
# repmgr standby promote -f /etc/repmgr.conf
|
# repmgr standby promote -f /etc/repmgr.conf
|
||||||
#
|
#
|
||||||
#follow_command='' # command repmgrd executes when instructing a standby to follow a new primary;
|
#follow_command= # command repmgrd executes when instructing a standby to follow a new primary;
|
||||||
# use something like:
|
# use something like:
|
||||||
#
|
#
|
||||||
# repmgr standby follow -f /etc/repmgr.conf -W --upstream-node-id=%n
|
# repmgr standby follow -f /etc/repmgr.conf -W --upstream-node-id=%n
|
||||||
@@ -319,8 +317,8 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# for the the local node to restart and become ready to accept connections after
|
# for the the local node to restart and become ready to accept connections after
|
||||||
# executing "follow_command" (defaults to the value set in "standby_reconnect_timeout")
|
# executing "follow_command" (defaults to the value set in "standby_reconnect_timeout")
|
||||||
|
|
||||||
#monitoring_history=no # Whether to write monitoring data to the "montoring_history" table
|
#monitoring_history=no # Whether to write monitoring data to the "montoring_history" table
|
||||||
#monitor_interval_secs=2 # Interval (in seconds) at which to write monitoring data
|
#monitor_interval_secs=2 # Interval (in seconds) at which to write monitoring data
|
||||||
#degraded_monitoring_timeout=-1 # Interval (in seconds) after which repmgrd will terminate if the
|
#degraded_monitoring_timeout=-1 # Interval (in seconds) after which repmgrd will terminate if the
|
||||||
# server(s) being monitored are no longer available. -1 (default)
|
# server(s) being monitored are no longer available. -1 (default)
|
||||||
# disables the timeout completely.
|
# disables the timeout completely.
|
||||||
@@ -341,7 +339,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# 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.
|
||||||
#failover_validation_command='' # Script to execute for an external mechanism to validate the failover
|
#failover_validation_command= # Script to execute for an external mechanism to validate the failover
|
||||||
# decision made by repmgrd. One or both of the following parameter placeholders
|
# decision made by repmgrd. One or both of the following parameter placeholders
|
||||||
# should be provided, which will be replaced by repmgrd with the appropriate
|
# should be provided, which will be replaced by repmgrd with the appropriate
|
||||||
# value: %n (node_id), %a (node_name). *Must* be the same on all nodes.
|
# value: %n (node_id), %a (node_name). *Must* be the same on all nodes.
|
||||||
@@ -349,14 +347,14 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# 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
|
||||||
#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
|
||||||
#child_nodes_disconnect_min_count=-1 # Minimum number of disconnected child nodes required to execute disconnection command
|
#child_nodes_disconnect_min_count=-1 # Minimum number of disconnected child nodes required to execute disconnection command
|
||||||
# (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
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# service control commands
|
# service control commands
|
||||||
@@ -374,7 +372,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# NOTE: These commands must be runnable on remote nodes as well for switchover
|
# NOTE: These commands must be runnable on remote nodes as well for switchover
|
||||||
# to function correctly.
|
# to function correctly.
|
||||||
#
|
#
|
||||||
# If you use sudo, the user repmgr runs as (usually 'postgres') must have
|
# If you use sudo, the user repmgr runs as (usually 'postgres') must have
|
||||||
# passwordless sudo access to execute the command.
|
# passwordless sudo access to execute the command.
|
||||||
#
|
#
|
||||||
# For example, to use systemd, you can set
|
# For example, to use systemd, you can set
|
||||||
@@ -387,8 +385,8 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# # this is required when running sudo over ssh without -t:
|
# # this is required when running sudo over ssh without -t:
|
||||||
# Defaults:postgres !requiretty
|
# Defaults:postgres !requiretty
|
||||||
# postgres ALL = NOPASSWD: /usr/bin/systemctl stop postgresql-9.6, \
|
# postgres ALL = NOPASSWD: /usr/bin/systemctl stop postgresql-9.6, \
|
||||||
# /usr/bin/systemctl start postgresql-9.6, \
|
# /usr/bin/systemctl start postgresql-9.6, \
|
||||||
# /usr/bin/systemctl restart postgresql-9.6
|
# /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.
|
||||||
#
|
#
|
||||||
@@ -404,7 +402,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# for "promote_command"; do not use "repmgr standby promote"
|
# for "promote_command"; do not use "repmgr standby promote"
|
||||||
# (or a script which executes "repmgr standby promote") here.
|
# (or a script which executes "repmgr standby promote") here.
|
||||||
|
|
||||||
# Used by "repmgr service (start|stop)" to control repmgrd
|
# Used by "repmgr daemon (start|stop)" to control repmgrd
|
||||||
#
|
#
|
||||||
#repmgrd_service_start_command = ''
|
#repmgrd_service_start_command = ''
|
||||||
#repmgrd_service_stop_command = ''
|
#repmgrd_service_stop_command = ''
|
||||||
@@ -415,7 +413,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
|
|
||||||
# Various warning/critical thresholds used by "repmgr node check".
|
# Various warning/critical thresholds used by "repmgr node check".
|
||||||
|
|
||||||
#archive_ready_warning=16 # repmgr node check --archive-ready
|
#archive_ready_warning=16 # repmgr node check --archive-ready
|
||||||
#archive_ready_critical=128 #
|
#archive_ready_critical=128 #
|
||||||
# Numbers of files pending archiving via PostgreSQL's
|
# Numbers of files pending archiving via PostgreSQL's
|
||||||
# "archive_command" configuration parameter. If
|
# "archive_command" configuration parameter. If
|
||||||
@@ -440,8 +438,8 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
|||||||
# BDR monitoring options
|
# BDR monitoring options
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
#bdr_local_monitoring_only=false # Only monitor the local node; no checks will be
|
#bdr_local_monitoring_only=false # Only monitor the local node; no checks will be
|
||||||
# performed on the other node
|
# performed on the other node
|
||||||
#bdr_recovery_timeout # If a BDR node was offline and has become available
|
#bdr_recovery_timeout # If a BDR node was offline and has become available
|
||||||
# maximum length of time in seconds to wait for the
|
# maximum length of time in seconds to wait for the
|
||||||
# node to reconnect to the cluster
|
# node to reconnect to the cluster
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# repmgr extension
|
# repmgr extension
|
||||||
comment = 'Replication manager for PostgreSQL'
|
comment = 'Replication manager for PostgreSQL'
|
||||||
default_version = '5.0'
|
default_version = '4.4'
|
||||||
module_pathname = '$libdir/repmgr'
|
module_pathname = '$libdir/repmgr'
|
||||||
relocatable = false
|
relocatable = false
|
||||||
schema = repmgr
|
schema = repmgr
|
||||||
|
|||||||
37
repmgr.h
37
repmgr.h
@@ -21,37 +21,6 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef vsnprintf
|
|
||||||
#undef vsnprintf
|
|
||||||
#endif
|
|
||||||
#ifdef snprintf
|
|
||||||
#undef snprintf
|
|
||||||
#endif
|
|
||||||
#ifdef vsprintf
|
|
||||||
#undef vsprintf
|
|
||||||
#endif
|
|
||||||
#ifdef sprintf
|
|
||||||
#undef sprintf
|
|
||||||
#endif
|
|
||||||
#ifdef vfprintf
|
|
||||||
#undef vfprintf
|
|
||||||
#endif
|
|
||||||
#ifdef fprintf
|
|
||||||
#undef fprintf
|
|
||||||
#endif
|
|
||||||
#ifdef vprintf
|
|
||||||
#undef vprintf
|
|
||||||
#endif
|
|
||||||
#ifdef printf
|
|
||||||
#undef printf
|
|
||||||
#endif
|
|
||||||
#ifdef strerror
|
|
||||||
#undef strerror
|
|
||||||
#endif
|
|
||||||
#ifdef strerror_r
|
|
||||||
#undef strerror_r
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _REPMGR_H_
|
#ifndef _REPMGR_H_
|
||||||
#define _REPMGR_H_
|
#define _REPMGR_H_
|
||||||
|
|
||||||
@@ -82,7 +51,6 @@
|
|||||||
|
|
||||||
#define UNKNOWN_SERVER_VERSION_NUM -1
|
#define UNKNOWN_SERVER_VERSION_NUM -1
|
||||||
#define UNKNOWN_BDR_VERSION_NUM -1
|
#define UNKNOWN_BDR_VERSION_NUM -1
|
||||||
#define UNKNOWN_REPMGR_VERSION_NUM -1
|
|
||||||
|
|
||||||
#define UNKNOWN_TIMELINE_ID -1
|
#define UNKNOWN_TIMELINE_ID -1
|
||||||
#define UNKNOWN_SYSTEM_IDENTIFIER 0
|
#define UNKNOWN_SYSTEM_IDENTIFIER 0
|
||||||
@@ -140,11 +108,6 @@
|
|||||||
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef STANDBY_SIGNAL_FILE
|
|
||||||
#define STANDBY_SIGNAL_FILE "standby.signal"
|
|
||||||
#define RECOVERY_SIGNAL_FILE "recovery.signal"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef TABLESPACE_MAP
|
#ifndef TABLESPACE_MAP
|
||||||
#define TABLESPACE_MAP "tablespace_map"
|
#define TABLESPACE_MAP "tablespace_map"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#define REPMGR_VERSION_DATE ""
|
#define REPMGR_VERSION_DATE ""
|
||||||
#define REPMGR_VERSION "5.0.0"
|
#define REPMGR_VERSION "4.4"
|
||||||
#define REPMGR_VERSION_NUM 50000
|
#define REPMGR_VERSION_NUM 40400
|
||||||
#define REPMGR_RELEASE_DATE "2019-10-15"
|
|
||||||
#define PG_ACTUAL_VERSION_NUM
|
|
||||||
|
|||||||
@@ -1580,7 +1580,7 @@ monitor_streaming_standby(void)
|
|||||||
{
|
{
|
||||||
log_notice(_("repmgrd on this node is paused"));
|
log_notice(_("repmgrd on this node is paused"));
|
||||||
log_detail(_("no failover will be carried out"));
|
log_detail(_("no failover will be carried out"));
|
||||||
log_hint(_("execute \"repmgr service unpause\" to resume normal failover mode"));
|
log_hint(_("execute \"repmgr daemon unpause\" to resume normal failover mode"));
|
||||||
monitoring_state = MS_DEGRADED;
|
monitoring_state = MS_DEGRADED;
|
||||||
INSTR_TIME_SET_CURRENT(degraded_monitoring_start);
|
INSTR_TIME_SET_CURRENT(degraded_monitoring_start);
|
||||||
}
|
}
|
||||||
@@ -1710,6 +1710,9 @@ monitor_streaming_standby(void)
|
|||||||
* has been promoted
|
* has been promoted
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
NodeInfoListCell *cell;
|
||||||
|
int follow_node_id = UNKNOWN_NODE_ID;
|
||||||
|
|
||||||
/* local node has been promoted */
|
/* local node has been promoted */
|
||||||
if (get_recovery_type(local_conn) == RECTYPE_PRIMARY)
|
if (get_recovery_type(local_conn) == RECTYPE_PRIMARY)
|
||||||
{
|
{
|
||||||
@@ -1799,9 +1802,6 @@ monitor_streaming_standby(void)
|
|||||||
|
|
||||||
if (sibling_nodes.node_count > 0)
|
if (sibling_nodes.node_count > 0)
|
||||||
{
|
{
|
||||||
NodeInfoListCell *cell;
|
|
||||||
t_node_info *follow_node_info = NULL;
|
|
||||||
|
|
||||||
log_debug("scanning %i node records to detect new primary...", sibling_nodes.node_count);
|
log_debug("scanning %i node records to detect new primary...", sibling_nodes.node_count);
|
||||||
for (cell = sibling_nodes.head; cell; cell = cell->next)
|
for (cell = sibling_nodes.head; cell; cell = cell->next)
|
||||||
{
|
{
|
||||||
@@ -1828,19 +1828,16 @@ monitor_streaming_standby(void)
|
|||||||
|
|
||||||
if (get_recovery_type(cell->node_info->conn) == RECTYPE_PRIMARY)
|
if (get_recovery_type(cell->node_info->conn) == RECTYPE_PRIMARY)
|
||||||
{
|
{
|
||||||
follow_node_info = cell->node_info;
|
follow_node_id = cell->node_info->node_id;
|
||||||
close_connection(&cell->node_info->conn);
|
close_connection(&cell->node_info->conn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
close_connection(&cell->node_info->conn);
|
close_connection(&cell->node_info->conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (follow_node_info != NULL)
|
if (follow_node_id != UNKNOWN_NODE_ID)
|
||||||
{
|
{
|
||||||
log_info(_("node \"%s\" (node ID: %i) detected as primary"),
|
follow_new_primary(follow_node_id);
|
||||||
follow_node_info->node_name,
|
|
||||||
follow_node_info->node_id);
|
|
||||||
follow_new_primary(follow_node_info->node_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1884,7 +1881,7 @@ loop:
|
|||||||
if (PQstatus(local_conn) == CONNECTION_OK && repmgrd_is_paused(local_conn))
|
if (PQstatus(local_conn) == CONNECTION_OK && repmgrd_is_paused(local_conn))
|
||||||
{
|
{
|
||||||
log_detail(_("repmgrd paused by administrator"));
|
log_detail(_("repmgrd paused by administrator"));
|
||||||
log_hint(_("execute \"repmgr service unpause\" to resume normal failover mode"));
|
log_hint(_("execute \"repmgr daemon unpause\" to resume normal failover mode"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2086,6 +2083,7 @@ loop:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (got_SIGHUP)
|
if (got_SIGHUP)
|
||||||
{
|
{
|
||||||
handle_sighup(&local_conn, STANDBY);
|
handle_sighup(&local_conn, STANDBY);
|
||||||
@@ -2095,34 +2093,13 @@ loop:
|
|||||||
|
|
||||||
if (local_monitoring_state == MS_NORMAL && last_known_upstream_node_id != local_node_info.upstream_node_id)
|
if (local_monitoring_state == MS_NORMAL && last_known_upstream_node_id != local_node_info.upstream_node_id)
|
||||||
{
|
{
|
||||||
/*
|
log_notice(_("local node %i's upstream appears to have changed, restarting monitoring"),
|
||||||
* It's possible that after a change of upstream, the local node record will not
|
local_node_info.node_id);
|
||||||
* yet have been updated with the new upstream node ID. Therefore we check the
|
log_detail(_("currently monitoring upstream %i; new upstream is %i"),
|
||||||
* node record on the upstream, and if that matches "last_known_upstream_node_id",
|
last_known_upstream_node_id,
|
||||||
* take that as the correct value.
|
local_node_info.upstream_node_id);
|
||||||
*/
|
close_connection(&upstream_conn);
|
||||||
|
return;
|
||||||
if (monitoring_state == MS_NORMAL)
|
|
||||||
{
|
|
||||||
t_node_info node_info_on_upstream = T_NODE_INFO_INITIALIZER;
|
|
||||||
record_status = get_node_record(primary_conn, config_file_options.node_id, &node_info_on_upstream);
|
|
||||||
|
|
||||||
if (last_known_upstream_node_id == node_info_on_upstream.upstream_node_id)
|
|
||||||
{
|
|
||||||
local_node_info.upstream_node_id = last_known_upstream_node_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (last_known_upstream_node_id != local_node_info.upstream_node_id)
|
|
||||||
{
|
|
||||||
log_notice(_("local node %i's upstream appears to have changed, restarting monitoring"),
|
|
||||||
local_node_info.node_id);
|
|
||||||
log_detail(_("currently monitoring upstream %i; new upstream is %i"),
|
|
||||||
last_known_upstream_node_id,
|
|
||||||
local_node_info.upstream_node_id);
|
|
||||||
close_connection(&upstream_conn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_verbose(LOG_DEBUG, "sleeping %i seconds (parameter \"monitor_interval_secs\")",
|
log_verbose(LOG_DEBUG, "sleeping %i seconds (parameter \"monitor_interval_secs\")",
|
||||||
@@ -2403,6 +2380,8 @@ monitor_streaming_witness(void)
|
|||||||
* has been promoted
|
* has been promoted
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
NodeInfoListCell *cell;
|
||||||
|
int follow_node_id = UNKNOWN_NODE_ID;
|
||||||
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
|
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||||
|
|
||||||
get_active_sibling_node_records(local_conn,
|
get_active_sibling_node_records(local_conn,
|
||||||
@@ -2412,9 +2391,6 @@ monitor_streaming_witness(void)
|
|||||||
|
|
||||||
if (sibling_nodes.node_count > 0)
|
if (sibling_nodes.node_count > 0)
|
||||||
{
|
{
|
||||||
NodeInfoListCell *cell;
|
|
||||||
t_node_info *follow_node_info = NULL;
|
|
||||||
|
|
||||||
log_debug("scanning %i node records to detect new primary...", sibling_nodes.node_count);
|
log_debug("scanning %i node records to detect new primary...", sibling_nodes.node_count);
|
||||||
for (cell = sibling_nodes.head; cell; cell = cell->next)
|
for (cell = sibling_nodes.head; cell; cell = cell->next)
|
||||||
{
|
{
|
||||||
@@ -2440,22 +2416,18 @@ monitor_streaming_witness(void)
|
|||||||
|
|
||||||
if (get_recovery_type(cell->node_info->conn) == RECTYPE_PRIMARY)
|
if (get_recovery_type(cell->node_info->conn) == RECTYPE_PRIMARY)
|
||||||
{
|
{
|
||||||
follow_node_info = cell->node_info;
|
follow_node_id = cell->node_info->node_id;
|
||||||
close_connection(&cell->node_info->conn);
|
close_connection(&cell->node_info->conn);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
close_connection(&cell->node_info->conn);
|
close_connection(&cell->node_info->conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (follow_node_info != NULL)
|
if (follow_node_id != UNKNOWN_NODE_ID)
|
||||||
{
|
{
|
||||||
log_info(_("node \"%s\" (node ID: %i) detected as primary"),
|
witness_follow_new_primary(follow_node_id);
|
||||||
follow_node_info->node_name,
|
|
||||||
follow_node_info->node_id);
|
|
||||||
witness_follow_new_primary(follow_node_info->node_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_node_info_list(&sibling_nodes);
|
clear_node_info_list(&sibling_nodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3622,10 +3594,6 @@ follow_new_primary(int new_primary_id)
|
|||||||
return FAILOVER_STATE_FOLLOW_FAIL;
|
return FAILOVER_STATE_FOLLOW_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_notice(_("attempting to follow new primary \"%s\" (node ID: %i)"),
|
|
||||||
new_primary.node_name,
|
|
||||||
new_primary_id);
|
|
||||||
|
|
||||||
record_status = get_node_record(local_conn, local_node_info.upstream_node_id, &failed_primary);
|
record_status = get_node_record(local_conn, local_node_info.upstream_node_id, &failed_primary);
|
||||||
|
|
||||||
if (record_status != RECORD_FOUND)
|
if (record_status != RECORD_FOUND)
|
||||||
@@ -3655,7 +3623,7 @@ follow_new_primary(int new_primary_id)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
new_primary_ok = false;
|
new_primary_ok = false;
|
||||||
log_warning(_("new primary is in recovery"));
|
log_warning(_("new primary is not in recovery"));
|
||||||
close_connection(&upstream_conn);
|
close_connection(&upstream_conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3848,7 +3816,7 @@ witness_follow_new_primary(int new_primary_id)
|
|||||||
break;
|
break;
|
||||||
case RECTYPE_STANDBY:
|
case RECTYPE_STANDBY:
|
||||||
new_primary_ok = false;
|
new_primary_ok = false;
|
||||||
log_warning(_("new primary is in recovery"));
|
log_warning(_("new primary is not in recovery"));
|
||||||
break;
|
break;
|
||||||
case RECTYPE_UNKNOWN:
|
case RECTYPE_UNKNOWN:
|
||||||
new_primary_ok = false;
|
new_primary_ok = false;
|
||||||
@@ -4029,9 +3997,7 @@ do_election(NodeInfoList *sibling_nodes, int *new_primary_id)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_info(_("primary node \"%s\" (ID: %i) and this node have the same location (\"%s\")"),
|
log_info(_("primary and this node have the same location (\"%s\")"),
|
||||||
upstream_node_info.node_name,
|
|
||||||
upstream_node_info.node_id,
|
|
||||||
local_node_info.location);
|
local_node_info.location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4271,9 +4237,7 @@ do_election(NodeInfoList *sibling_nodes, int *new_primary_id)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
nodes_with_primary_still_visible++;
|
nodes_with_primary_still_visible++;
|
||||||
log_notice(_("%s node \"%s\" (ID: %i) last saw primary node %i second(s) ago, considering primary still visible"),
|
log_notice(_("node %i last saw primary node %i second(s) ago, considering primary still visible"),
|
||||||
get_node_type_string(cell->node_info->type),
|
|
||||||
cell->node_info->node_name,
|
|
||||||
cell->node_info->node_id,
|
cell->node_info->node_id,
|
||||||
sibling_replication_info.upstream_last_seen);
|
sibling_replication_info.upstream_last_seen);
|
||||||
appendPQExpBuffer(&nodes_with_primary_visible,
|
appendPQExpBuffer(&nodes_with_primary_visible,
|
||||||
@@ -4285,9 +4249,7 @@ do_election(NodeInfoList *sibling_nodes, int *new_primary_id)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_info(_("%s node \"%s\" (ID: %i) last saw primary node %i second(s) ago"),
|
log_info(_("node %i last saw primary node %i second(s) ago"),
|
||||||
get_node_type_string(cell->node_info->type),
|
|
||||||
cell->node_info->node_name,
|
|
||||||
cell->node_info->node_id,
|
cell->node_info->node_id,
|
||||||
sibling_replication_info.upstream_last_seen);
|
sibling_replication_info.upstream_last_seen);
|
||||||
}
|
}
|
||||||
@@ -4947,8 +4909,7 @@ check_node_can_follow(PGconn *local_conn, XLogRecPtr local_xlogpos, PGconn *foll
|
|||||||
*/
|
*/
|
||||||
if (local_xlogpos > follow_target_history->end)
|
if (local_xlogpos > follow_target_history->end)
|
||||||
{
|
{
|
||||||
log_error(_("this node cannot attach to follow target node \"%s\" (ID: %i)"),
|
log_error(_("this node cannot attach to follow target node %i"),
|
||||||
follow_target_node_info->node_name,
|
|
||||||
follow_target_node_info->node_id);
|
follow_target_node_info->node_id);
|
||||||
can_follow = false;
|
can_follow = false;
|
||||||
|
|
||||||
@@ -4960,10 +4921,8 @@ check_node_can_follow(PGconn *local_conn, XLogRecPtr local_xlogpos, PGconn *foll
|
|||||||
|
|
||||||
if (can_follow == true)
|
if (can_follow == true)
|
||||||
{
|
{
|
||||||
log_info(_("local node \"%s\" (ID: %i) can attach to follow target node \"%s\" (ID: %i)"),
|
log_info(_("local node %i can attach to follow target node %i"),
|
||||||
config_file_options.node_name,
|
|
||||||
config_file_options.node_id,
|
config_file_options.node_id,
|
||||||
follow_target_node_info->node_name,
|
|
||||||
follow_target_node_info->node_id);
|
follow_target_node_info->node_id);
|
||||||
|
|
||||||
log_detail(_("local node's recovery point: %X/%X; follow target node's fork point: %X/%X"),
|
log_detail(_("local node's recovery point: %X/%X; follow target node's fork point: %X/%X"),
|
||||||
|
|||||||
76
strutil.c
76
strutil.c
@@ -29,9 +29,6 @@ static int
|
|||||||
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
|
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0)));
|
||||||
|
|
||||||
static void
|
|
||||||
_key_value_list_set(KeyValueList *item_list, bool replace, const char *key, const char *value);
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
|
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||||
{
|
{
|
||||||
@@ -167,74 +164,16 @@ item_list_free(ItemList *item_list)
|
|||||||
void
|
void
|
||||||
key_value_list_set(KeyValueList *item_list, const char *key, const char *value)
|
key_value_list_set(KeyValueList *item_list, const char *key, const char *value)
|
||||||
{
|
{
|
||||||
_key_value_list_set(item_list, false, key, value);
|
key_value_list_set_format(item_list, key, "%s", value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
key_value_list_replace_or_set(KeyValueList *item_list, const char *key, const char *value)
|
key_value_list_set_format(KeyValueList *item_list, const char *key, const char *value,...)
|
||||||
{
|
|
||||||
_key_value_list_set(item_list, true, key, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
key_value_list_set_format(KeyValueList *item_list, const char *key, const char *value, ...)
|
|
||||||
{
|
|
||||||
va_list arglist;
|
|
||||||
char formatted_value[MAXLEN];
|
|
||||||
|
|
||||||
va_start(arglist, value);
|
|
||||||
(void) xvsnprintf(formatted_value, MAXLEN, value, arglist);
|
|
||||||
va_end(arglist);
|
|
||||||
|
|
||||||
return _key_value_list_set(item_list, false, key, formatted_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_key_value_list_set(KeyValueList *item_list, bool replace, const char *key, const char *value)
|
|
||||||
{
|
{
|
||||||
KeyValueListCell *cell = NULL;
|
KeyValueListCell *cell = NULL;
|
||||||
|
va_list arglist;
|
||||||
int keylen = 0;
|
int keylen = 0;
|
||||||
int vallen = 0;
|
|
||||||
|
|
||||||
if (replace == true)
|
|
||||||
{
|
|
||||||
KeyValueListCell *prev_cell = NULL;
|
|
||||||
KeyValueListCell *next_cell = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
for (cell = item_list->head; cell; cell = next_cell)
|
|
||||||
{
|
|
||||||
next_cell = cell->next;
|
|
||||||
|
|
||||||
if (strcmp(cell->key, key) == 0)
|
|
||||||
{
|
|
||||||
if (item_list->head == cell)
|
|
||||||
item_list->head = cell->next;
|
|
||||||
|
|
||||||
if (prev_cell)
|
|
||||||
{
|
|
||||||
prev_cell->next = cell->next;
|
|
||||||
|
|
||||||
if (item_list->tail == cell)
|
|
||||||
item_list->tail = prev_cell;
|
|
||||||
}
|
|
||||||
else if (item_list->tail == cell)
|
|
||||||
{
|
|
||||||
item_list->tail = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pfree(cell->key);
|
|
||||||
pfree(cell->value);
|
|
||||||
pfree(cell);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
prev_cell = cell;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cell = (KeyValueListCell *) pg_malloc0(sizeof(KeyValueListCell));
|
cell = (KeyValueListCell *) pg_malloc0(sizeof(KeyValueListCell));
|
||||||
|
|
||||||
@@ -245,14 +184,17 @@ _key_value_list_set(KeyValueList *item_list, bool replace, const char *key, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
keylen = strlen(key);
|
keylen = strlen(key);
|
||||||
vallen = strlen(value);
|
|
||||||
|
|
||||||
cell->key = pg_malloc0(keylen + 1);
|
cell->key = pg_malloc0(keylen + 1);
|
||||||
cell->value = pg_malloc0(vallen + 1);
|
cell->value = pg_malloc0(MAXLEN);
|
||||||
cell->output_mode = OM_NOT_SET;
|
cell->output_mode = OM_NOT_SET;
|
||||||
|
|
||||||
strncpy(cell->key, key, keylen);
|
strncpy(cell->key, key, keylen);
|
||||||
strncpy(cell->value, value, vallen);
|
|
||||||
|
va_start(arglist, value);
|
||||||
|
(void) xvsnprintf(cell->value, MAXLEN, value, arglist);
|
||||||
|
va_end(arglist);
|
||||||
|
|
||||||
|
|
||||||
if (item_list->tail)
|
if (item_list->tail)
|
||||||
item_list->tail->next = cell;
|
item_list->tail->next = cell;
|
||||||
|
|||||||
@@ -119,9 +119,6 @@ extern void
|
|||||||
extern void
|
extern void
|
||||||
key_value_list_set(KeyValueList *item_list, const char *key, const char *value);
|
key_value_list_set(KeyValueList *item_list, const char *key, const char *value);
|
||||||
|
|
||||||
extern void
|
|
||||||
key_value_list_replace_or_set(KeyValueList *item_list, const char *key, const char *value);
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
key_value_list_set_format(KeyValueList *item_list, const char *key, const char *value,...)
|
key_value_list_set_format(KeyValueList *item_list, const char *key, const char *value,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
|
||||||
|
|||||||
27
sysutils.c
27
sysutils.c
@@ -1,8 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* sysutils.c
|
* sysutils.c
|
||||||
*
|
*
|
||||||
* Functions which need to be executed on the local system.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2ndQuadrant, 2010-2019
|
* Copyright (c) 2ndQuadrant, 2010-2019
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
@@ -117,7 +115,7 @@ bool
|
|||||||
remote_command(const char *host, const char *user, const char *command, const char *ssh_options, PQExpBufferData *outputbuf)
|
remote_command(const char *host, const char *user, const char *command, const char *ssh_options, PQExpBufferData *outputbuf)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
PQExpBufferData ssh_command;
|
char ssh_command[MAXLEN] = "";
|
||||||
PQExpBufferData ssh_host;
|
PQExpBufferData ssh_host;
|
||||||
|
|
||||||
char output[MAXLEN] = "";
|
char output[MAXLEN] = "";
|
||||||
@@ -131,29 +129,24 @@ remote_command(const char *host, const char *user, const char *command, const ch
|
|||||||
|
|
||||||
appendPQExpBufferStr(&ssh_host, host);
|
appendPQExpBufferStr(&ssh_host, host);
|
||||||
|
|
||||||
initPQExpBuffer(&ssh_command);
|
maxlen_snprintf(ssh_command,
|
||||||
|
"ssh -o Batchmode=yes %s %s %s",
|
||||||
appendPQExpBuffer(&ssh_command,
|
ssh_options,
|
||||||
"ssh -o Batchmode=yes %s %s %s",
|
ssh_host.data,
|
||||||
ssh_options,
|
command);
|
||||||
ssh_host.data,
|
|
||||||
command);
|
|
||||||
|
|
||||||
termPQExpBuffer(&ssh_host);
|
termPQExpBuffer(&ssh_host);
|
||||||
|
|
||||||
log_debug("remote_command():\n %s", ssh_command.data);
|
log_debug("remote_command():\n %s", ssh_command);
|
||||||
|
|
||||||
fp = popen(ssh_command.data, "r");
|
fp = popen(ssh_command, "r");
|
||||||
|
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
{
|
{
|
||||||
log_error(_("unable to execute remote command:\n %s"), ssh_command.data);
|
log_error(_("unable to execute remote command:\n %s"), ssh_command);
|
||||||
termPQExpBuffer(&ssh_command);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
termPQExpBuffer(&ssh_command);
|
|
||||||
|
|
||||||
if (outputbuf != NULL)
|
if (outputbuf != NULL)
|
||||||
{
|
{
|
||||||
/* TODO: better error handling */
|
/* TODO: better error handling */
|
||||||
@@ -371,5 +364,3 @@ enable_wal_receiver(PGconn *conn, bool wait_startup)
|
|||||||
|
|
||||||
return wal_receiver_pid;
|
return wal_receiver_pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,4 +28,5 @@ extern bool remote_command(const char *host, const char *user, const char *comma
|
|||||||
extern pid_t disable_wal_receiver(PGconn *conn);
|
extern pid_t disable_wal_receiver(PGconn *conn);
|
||||||
extern pid_t enable_wal_receiver(PGconn *conn, bool wait_startup);
|
extern pid_t enable_wal_receiver(PGconn *conn, bool wait_startup);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _SYSUTILS_H_ */
|
#endif /* _SYSUTILS_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user