mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-23 07:06:30 +00:00
Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39003be5a3 | ||
|
|
c27f134e50 | ||
|
|
5a619244ee | ||
|
|
b5448def7e | ||
|
|
af1c889bc3 | ||
|
|
2304584679 | ||
|
|
4aaa24a5f8 | ||
|
|
ea29af2e68 | ||
|
|
7053ed5b51 | ||
|
|
a845d7126d | ||
|
|
1c317059cd | ||
|
|
dcf5bfb649 | ||
|
|
dbd3d34c89 | ||
|
|
f3c3320a9c | ||
|
|
cfc5bde219 | ||
|
|
ea57269569 | ||
|
|
b885337abc | ||
|
|
e8b5b92893 | ||
|
|
02bdcf657f | ||
|
|
405f70f769 | ||
|
|
577ca35de5 | ||
|
|
a557f2d69e | ||
|
|
1196821457 | ||
|
|
c1d464f3da | ||
|
|
4646bbc289 | ||
|
|
bb9a0c2297 | ||
|
|
1ed8b1067a | ||
|
|
a502b2cf96 | ||
|
|
8e6d111f32 | ||
|
|
50d4cee877 | ||
|
|
db99e98236 | ||
|
|
10f00b8822 | ||
|
|
98e96f4375 | ||
|
|
8489fd061f | ||
|
|
56aae22b6c | ||
|
|
bce039f336 | ||
|
|
19190153a0 | ||
|
|
b1c6418e8d | ||
|
|
12491c6aa1 | ||
|
|
d5b806eeff | ||
|
|
37bfe6ee4f | ||
|
|
97c21ed907 | ||
|
|
3ea47522cd | ||
|
|
935be3d669 | ||
|
|
494444869d | ||
|
|
677a94513e | ||
|
|
931da14df1 | ||
|
|
3e812f6e91 | ||
|
|
ffc7b7817b | ||
|
|
fb6352735a | ||
|
|
f122c44a77 | ||
|
|
b4e6922a26 | ||
|
|
6e200d32a4 | ||
|
|
507b27c05d | ||
|
|
28f4536372 | ||
|
|
2ec761a979 | ||
|
|
b5225a2662 | ||
|
|
d5ed38f573 | ||
|
|
2a37e28304 | ||
|
|
9eb6ce52b4 | ||
|
|
9e072c6773 | ||
|
|
72daa38baa | ||
|
|
f5044465cb | ||
|
|
4ebc43fd63 | ||
|
|
a1775237d4 | ||
|
|
94ba635811 | ||
|
|
c0f3990973 | ||
|
|
d0f5ee1851 | ||
|
|
75c0987e79 | ||
|
|
68be86349b | ||
|
|
666c6f5140 | ||
|
|
3df65d0eb3 | ||
|
|
38b373e6df | ||
|
|
10870503d1 | ||
|
|
5ca0b57d0c | ||
|
|
7d20aea606 | ||
|
|
424d92e311 | ||
|
|
8d55cab25e | ||
|
|
ab7e527af8 | ||
|
|
9274fdc6ba | ||
|
|
018394faa2 | ||
|
|
532a5207e2 | ||
|
|
5bf9605286 | ||
|
|
215f4bb9d9 | ||
|
|
75a381ed27 | ||
|
|
a26b7e29a0 | ||
|
|
d09214b83d | ||
|
|
822abbbe5b | ||
|
|
d51704e272 | ||
|
|
c6ca183247 | ||
|
|
b125628f7b | ||
|
|
cd550fcd5c | ||
|
|
b6dc8af6c7 | ||
|
|
09979eaa91 | ||
|
|
3469152314 | ||
|
|
3bf308509f | ||
|
|
01852f7e3a | ||
|
|
36a09a5c4b | ||
|
|
7180e2bed7 | ||
|
|
6aca764d5e | ||
|
|
341421f8e0 | ||
|
|
f5d29f6591 | ||
|
|
c0ea5ffa04 | ||
|
|
aa44c8abf1 | ||
|
|
456a95f159 | ||
|
|
703a483e81 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -53,3 +53,6 @@ repmgr
|
||||
repmgrd
|
||||
repmgr4
|
||||
repmgrd4
|
||||
|
||||
# generated files
|
||||
configfile-scan.c
|
||||
|
||||
15
HISTORY
15
HISTORY
@@ -1,4 +1,13 @@
|
||||
4.4 2019-??-??
|
||||
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
|
||||
repmgr: improve "daemon status" output (Ian)
|
||||
repmgr: add "--siblings-follow" option to "standby promote" (Ian)
|
||||
repmgr: add "--repmgrd-force-unpause" option to "standby switchover" (Ian)
|
||||
@@ -6,6 +15,8 @@
|
||||
an existing directory is being overwritten (Ian)
|
||||
repmgr: improve "--dry-run" behaviour for "standby promote" and
|
||||
"standby switchover" (Ian)
|
||||
repmgr: when running "standby clone" with the "--upstream-conninfo" option
|
||||
ensure that "application_name" is set correctly in "primary_conninfo" (Ian)
|
||||
repmgr: ensure "--dry-run" together with --force when running "standby clone"
|
||||
in barman mode does not modify an existing data directory (Ian)
|
||||
repmgr: improve "--dry-run" output when running "standby clone" in
|
||||
@@ -21,6 +32,8 @@
|
||||
repmgr: prevent a witness server being registered on the cluster primary (John)
|
||||
repmgr: ensure BDR2-specific functionality cannot be used on
|
||||
BDR3 and later (Ian)
|
||||
repmgr: canonicalize the data directory path (Ian)
|
||||
repmgr: note that "standby follow" requires a primary to be available (Ian)
|
||||
repmgrd: monitor standbys attached to primary (Ian)
|
||||
repmgrd: add "primary visibility consensus" functionality (Ian)
|
||||
repmgrd: fix memory leak which occurs while the monitored PostgreSQL
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Makefile.global.in
|
||||
# @configure_input@
|
||||
|
||||
|
||||
# Can only be built using pgxs
|
||||
USE_PGXS=1
|
||||
|
||||
@@ -14,6 +15,9 @@ ifeq ($(vpath_build),yes)
|
||||
VPATH := $(repmgr_abs_srcdir)/$(repmgr_subdir)
|
||||
USE_VPATH :=$(VPATH)
|
||||
endif
|
||||
|
||||
SED=@SED@
|
||||
|
||||
GIT_WORK_TREE=${repmgr_abs_srcdir}
|
||||
GIT_DIR=${repmgr_abs_srcdir}/.git
|
||||
export GIT_DIR
|
||||
@@ -24,4 +28,13 @@ include $(PGXS)
|
||||
-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_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,7 +19,9 @@ DATA = \
|
||||
repmgr--4.2--4.3.sql \
|
||||
repmgr--4.3.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
|
||||
|
||||
@@ -51,13 +53,16 @@ $(info Building against PostgreSQL $(MAJORVERSION))
|
||||
|
||||
REPMGR_CLIENT_OBJS = repmgr-client.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-daemon.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 log.o dbutils.o strutil.o controldata.o compat.o sysutils.o
|
||||
repmgr-action-bdr.o repmgr-action-cluster.o repmgr-action-node.o repmgr-action-service.o repmgr-action-daemon.o \
|
||||
configfile.o configfile-scan.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
|
||||
DATE=$(shell date "+%Y-%m-%d")
|
||||
|
||||
repmgr_version.h: repmgr_version.h.in
|
||||
sed '0,/REPMGR_VERSION_DATE/s,\(REPMGR_VERSION_DATE\).*,\1 "$(DATE)",' $< >$@
|
||||
$(SED) -E 's/REPMGR_VERSION_DATE.*""/REPMGR_VERSION_DATE "$(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
|
||||
|
||||
@@ -98,6 +103,7 @@ maintainer-clean: additional-maintainer-clean
|
||||
|
||||
additional-clean:
|
||||
rm -f *.o
|
||||
rm -f repmgr_version.h
|
||||
$(MAKE) -C doc clean
|
||||
|
||||
additional-maintainer-clean: clean
|
||||
|
||||
366
configfile-scan.l
Normal file
366
configfile-scan.l
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* 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 */
|
||||
}
|
||||
819
configfile.c
819
configfile.c
@@ -23,6 +23,12 @@
|
||||
#include "configfile.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;
|
||||
char config_file_path[MAXPGPATH] = "";
|
||||
static bool config_file_provided = false;
|
||||
@@ -266,12 +272,6 @@ static void
|
||||
_parse_config(t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
|
||||
{
|
||||
FILE *fp;
|
||||
char *s = NULL,
|
||||
buf[MAXLINELENGTH] = "";
|
||||
char name[MAXLEN] = "";
|
||||
char value[MAXLEN] = "";
|
||||
|
||||
bool node_id_found = false;
|
||||
|
||||
/* Initialize configuration options with sensible defaults */
|
||||
|
||||
@@ -468,360 +468,12 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
else if (strcmp(name, "config_directory") == 0)
|
||||
strncpy(options->config_directory, value, MAXPGPATH);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
(void) ProcessRepmgrConfigFile(fp, config_file_path, options, error_list, warning_list);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
/* check required parameters */
|
||||
if (node_id_found == false)
|
||||
if (options->node_id == UNKNOWN_NODE_ID)
|
||||
{
|
||||
item_list_append(error_list, _("\"node_id\": required parameter was not found"));
|
||||
}
|
||||
@@ -914,6 +566,349 @@ _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
|
||||
@@ -1811,6 +1806,7 @@ parse_bool(const char *s, const char *config_item, ItemList *error_list)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Split argument into old_dir and new_dir and append to tablespace mapping
|
||||
* list.
|
||||
@@ -1878,6 +1874,114 @@ 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;
|
||||
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);
|
||||
}
|
||||
|
||||
fp = fopen(auto_conf_tmp.data, "w");
|
||||
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()
|
||||
@@ -2054,9 +2158,6 @@ free_parsed_argv(char ***argv_array)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool
|
||||
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,6 +28,12 @@
|
||||
/* magic number for use in t_recovery_conf */
|
||||
#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 char config_file_path[MAXPGPATH];
|
||||
|
||||
@@ -317,6 +323,8 @@ const char *progname(void);
|
||||
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);
|
||||
|
||||
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_bool(const char *s,
|
||||
@@ -342,4 +350,10 @@ void exit_with_cli_errors(ItemList *error_list, const char *repmgr_command);
|
||||
void print_item_list(ItemList *item_list);
|
||||
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_ */
|
||||
|
||||
148
configure
vendored
148
configure
vendored
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.69 for repmgr 4.4.
|
||||
# Generated by GNU Autoconf 2.69 for repmgr 5.0.0.
|
||||
#
|
||||
# Report bugs to <repmgr@googlegroups.com>.
|
||||
#
|
||||
@@ -582,13 +582,16 @@ MAKEFLAGS=
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='repmgr'
|
||||
PACKAGE_TARNAME='repmgr'
|
||||
PACKAGE_VERSION='4.4'
|
||||
PACKAGE_STRING='repmgr 4.4'
|
||||
PACKAGE_VERSION='5.0.0'
|
||||
PACKAGE_STRING='repmgr 5.0.0'
|
||||
PACKAGE_BUGREPORT='repmgr@googlegroups.com'
|
||||
PACKAGE_URL='https://repmgr.org/'
|
||||
|
||||
ac_subst_vars='LTLIBOBJS
|
||||
LIBOBJS
|
||||
HAVE_SED
|
||||
HAVE_GSED
|
||||
HAVE_GNUSED
|
||||
vpath_build
|
||||
SED
|
||||
PG_CONFIG
|
||||
@@ -1178,7 +1181,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# 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.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures repmgr 4.4 to adapt to many kinds of systems.
|
||||
\`configure' configures repmgr 5.0.0 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1239,7 +1242,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of repmgr 4.4:";;
|
||||
short | recursive ) echo "Configuration of repmgr 5.0.0:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1313,7 +1316,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
repmgr configure 4.4
|
||||
repmgr configure 5.0.0
|
||||
generated by GNU Autoconf 2.69
|
||||
|
||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
@@ -1332,7 +1335,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by repmgr $as_me 4.4, which was
|
||||
It was created by repmgr $as_me 5.0.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -1847,6 +1850,133 @@ else
|
||||
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.global"
|
||||
@@ -2357,7 +2487,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by repmgr $as_me 4.4, which was
|
||||
This file was extended by repmgr $as_me 5.0.0, which was
|
||||
generated by GNU Autoconf 2.69. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -2420,7 +2550,7 @@ _ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||
ac_cs_version="\\
|
||||
repmgr config.status 4.4
|
||||
repmgr config.status 5.0.0
|
||||
configured by $0, generated by GNU Autoconf 2.69,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
18
configure.in
18
configure.in
@@ -1,4 +1,4 @@
|
||||
AC_INIT([repmgr], [4.4], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
|
||||
AC_INIT([repmgr], [5.0.0], [repmgr@googlegroups.com], [repmgr], [https://repmgr.org/])
|
||||
|
||||
AC_COPYRIGHT([Copyright (c) 2010-2019, 2ndQuadrant Ltd.])
|
||||
|
||||
@@ -57,6 +57,22 @@ else
|
||||
fi
|
||||
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.global])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -73,7 +73,16 @@ while(<$fh>) {
|
||||
if ($param eq 'data_directory') {
|
||||
$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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +92,6 @@ print join("\n", @outp);
|
||||
print "\n";
|
||||
|
||||
if ($data_directory_found == 0) {
|
||||
print "data_directory=\n";
|
||||
print "data_directory=''\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -312,6 +312,7 @@ get_controlfile(const char *DataDir)
|
||||
|
||||
if (version_num >= 120000)
|
||||
{
|
||||
#if PG_ACTUAL_VERSION_NUM >= 120000
|
||||
ControlFileData12 *ptr = (struct ControlFileData12 *)ControlFileDataPtr;
|
||||
control_file_info->system_identifier = ptr->system_identifier;
|
||||
control_file_info->state = ptr->state;
|
||||
@@ -320,6 +321,10 @@ get_controlfile(const char *DataDir)
|
||||
control_file_info->timeline = ptr->checkPointCopy.ThisTimeLineID;
|
||||
control_file_info->minRecoveryPointTLI = ptr->minRecoveryPointTLI;
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "postgres_fe.h"
|
||||
#include "catalog/pg_control.h"
|
||||
|
||||
|
||||
#define MAX_VERSION_STRING 24
|
||||
/*
|
||||
* A simplified representation of pg_control containing only those fields
|
||||
@@ -55,7 +56,7 @@ typedef struct CheckPoint93
|
||||
} CheckPoint93;
|
||||
|
||||
|
||||
/* Same for 9.5, 9.6, 10, HEAD */
|
||||
/* Same for 9.5, 9.6, 10, 11 */
|
||||
typedef struct CheckPoint95
|
||||
{
|
||||
XLogRecPtr redo; /* next RecPtr available when we began to
|
||||
@@ -83,6 +84,50 @@ typedef struct 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
|
||||
{
|
||||
uint64 system_identifier;
|
||||
@@ -333,19 +378,11 @@ typedef struct ControlFileData11
|
||||
} ControlFileData11;
|
||||
|
||||
|
||||
#if PG_ACTUAL_VERSION_NUM >= 120000
|
||||
/*
|
||||
* Following field added in Pg12:
|
||||
*
|
||||
* int max_wal_senders;
|
||||
*
|
||||
* Following fields removed:
|
||||
*
|
||||
* uint32 nextXidEpoch;
|
||||
* TransactionId nextXid;
|
||||
*
|
||||
* and replaced by:
|
||||
*
|
||||
* FullTransactionId nextFullXid;
|
||||
*/
|
||||
|
||||
typedef struct ControlFileData12
|
||||
@@ -359,7 +396,7 @@ typedef struct ControlFileData12
|
||||
pg_time_t time; /* time stamp of last pg_control update */
|
||||
XLogRecPtr checkPoint; /* last check point record ptr */
|
||||
|
||||
CheckPoint checkPointCopy; /* copy of last check point record */
|
||||
CheckPoint12 checkPointCopy; /* copy of last check point record */
|
||||
|
||||
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
|
||||
|
||||
@@ -398,6 +435,7 @@ typedef struct ControlFileData12
|
||||
|
||||
uint32 data_checksum_version;
|
||||
} ControlFileData12;
|
||||
#endif
|
||||
|
||||
extern int get_pg_version(const char *data_directory, char *version_string);
|
||||
extern DBState get_db_state(const char *data_directory);
|
||||
|
||||
72
dbutils.c
72
dbutils.c
@@ -336,12 +336,10 @@ establish_db_connection_by_params(t_conninfo_param_list *param_list,
|
||||
bool
|
||||
is_superuser_connection(PGconn *conn, t_connection_user *userinfo)
|
||||
{
|
||||
char *current_user = NULL;
|
||||
const char *superuser_status = NULL;
|
||||
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;
|
||||
|
||||
if (userinfo != NULL)
|
||||
@@ -356,6 +354,51 @@ 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
|
||||
close_connection(PGconn **conn)
|
||||
{
|
||||
@@ -1865,8 +1908,20 @@ repmgrd_set_pid(PGconn *conn, pid_t repmgrd_pid, const char *pidfile)
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(&query,
|
||||
"SELECT repmgr.set_repmgrd_pid(%i, '%s')",
|
||||
(int) repmgrd_pid, pidfile);
|
||||
"SELECT repmgr.set_repmgrd_pid(%i, ",
|
||||
(int) repmgrd_pid);
|
||||
|
||||
if (pidfile != NULL)
|
||||
{
|
||||
appendPQExpBuffer(&query,
|
||||
" '%s')",
|
||||
pidfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
appendPQExpBufferStr(&query,
|
||||
" NULL)");
|
||||
}
|
||||
|
||||
res = PQexec(conn, query.data);
|
||||
termPQExpBuffer(&query);
|
||||
@@ -2092,9 +2147,9 @@ get_repmgr_extension_status(PGconn *conn, t_extension_versions *extversions)
|
||||
appendPQExpBufferStr(&query,
|
||||
" SELECT ae.name, e.extname, "
|
||||
" ae.default_version, "
|
||||
" (((ae.default_version::NUMERIC::INT) * 10000) + (ae.default_version::NUMERIC - ae.default_version::NUMERIC::INT) * 1000)::INT AS available, "
|
||||
" (((FLOOR(ae.default_version::NUMERIC)::INT) * 10000) + (ae.default_version::NUMERIC - FLOOR(ae.default_version::NUMERIC)::INT) * 1000)::INT AS available, "
|
||||
" ae.installed_version, "
|
||||
" (((ae.installed_version::NUMERIC::INT) * 10000) + (ae.installed_version::NUMERIC - ae.installed_version::NUMERIC::INT) * 1000)::INT AS installed "
|
||||
" (((FLOOR(ae.installed_version::NUMERIC)::INT) * 10000) + (ae.installed_version::NUMERIC - FLOOR(ae.installed_version::NUMERIC)::INT) * 1000)::INT AS installed "
|
||||
" FROM pg_catalog.pg_available_extensions ae "
|
||||
"LEFT JOIN pg_catalog.pg_extension e "
|
||||
" ON e.extname=ae.name "
|
||||
@@ -5073,6 +5128,7 @@ init_replication_info(ReplInfo *replication_info)
|
||||
replication_info->receiving_streamed_wal = true;
|
||||
replication_info->wal_replay_paused = false;
|
||||
replication_info->upstream_last_seen = -1;
|
||||
replication_info->upstream_node_id = UNKNOWN_NODE_ID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -438,6 +438,7 @@ 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);
|
||||
|
||||
bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo);
|
||||
bool connection_has_pg_settings(PGconn *conn);
|
||||
void close_connection(PGconn **conn);
|
||||
|
||||
/* conninfo manipulation functions */
|
||||
|
||||
@@ -31,6 +31,7 @@ ALLXML := $(wildcard $(srcdir)/*.xml) $(GENERATED_XML)
|
||||
version.xml: $(repmgr_top_builddir)/repmgr_version.h
|
||||
{ \
|
||||
echo "<!ENTITY repmgrversion \"$(REPMGR_VERSION)\">"; \
|
||||
echo "<!ENTITY releasedate \"$(REPMGR_RELEASE_DATE)\">"; \
|
||||
} > $@
|
||||
|
||||
##
|
||||
|
||||
@@ -3,437 +3,464 @@
|
||||
<title>FAQ (Frequently Asked Questions)</title>
|
||||
|
||||
<indexterm>
|
||||
<primary>FAQ (Frequently Asked Questions)</primary>
|
||||
<primary>FAQ (Frequently Asked Questions)</primary>
|
||||
</indexterm>
|
||||
|
||||
<sect1 id="faq-general" xreflabel="General">
|
||||
<title>General</title>
|
||||
<sect1 id="faq-general" xreflabel="General">
|
||||
<title>General</title>
|
||||
|
||||
<sect2 id="faq-xrepmgr-version-diff" xreflabel="Version differences">
|
||||
<title>What's the difference between the repmgr versions?</title>
|
||||
<para>
|
||||
&repmgr; 4 is a complete rewrite of the existing &repmgr; code base
|
||||
and implements &repmgr; as a PostgreSQL extension. It
|
||||
supports all PostgreSQL versions from 9.3 (although some &repmgr;
|
||||
features are not available for PostgreSQL 9.3 and 9.4).
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; 3.x builds on the improved replication facilities added
|
||||
in PostgreSQL 9.3, as well as improved automated failover support
|
||||
via &repmgrd;, and is not compatible with PostgreSQL 9.2
|
||||
and earlier. We recommend upgrading to &repmgr; 4, as the &repmgr; 3.x
|
||||
series is no longer maintained.
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; 2.x supports PostgreSQL 9.0 ~ 9.3. While it is compatible
|
||||
with PostgreSQL 9.3, we recommend using repmgr 4.x. &repmgr; 2.x is
|
||||
no longer maintained.
|
||||
</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-xrepmgr-version-diff" xreflabel="Version differences">
|
||||
<title>What's the difference between the repmgr versions?</title>
|
||||
<para>
|
||||
&repmgr; 4 is a complete rewrite of the previous &repmgr; code base
|
||||
and implements &repmgr; as a PostgreSQL extension. It
|
||||
supports all PostgreSQL versions from 9.3 (although some &repmgr;
|
||||
features are not available for PostgreSQL 9.3 and 9.4).
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
&repmgr; 5 is fundamentally the same code base as &repmgr; 4, but provides
|
||||
support for the revised replication configuration mechanism in PostgreSQL 12.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
&repmgr; 3.x builds on the improved replication facilities added
|
||||
in PostgreSQL 9.3, as well as improved automated failover support
|
||||
via &repmgrd;, and is not compatible with PostgreSQL 9.2
|
||||
and earlier. We recommend upgrading to &repmgr; 4, as the &repmgr; 3.x
|
||||
series is no longer maintained.
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; 2.x supports PostgreSQL 9.0 ~ 9.3. While it is compatible
|
||||
with PostgreSQL 9.3, we recommend using repmgr 4.x. &repmgr; 2.x is
|
||||
no longer maintained.
|
||||
</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">
|
||||
<title>What's the advantage of using replication slots?</title>
|
||||
<para>
|
||||
Replication slots, introduced in PostgreSQL 9.4, ensure that the
|
||||
primary server will retain WAL files until they have been consumed
|
||||
by all standby servers. This means standby servers should never
|
||||
fail due to not being able to retrieve required WAL files from the
|
||||
primary.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
to be retained indefinitely, and eventually lead to disk space
|
||||
exhaustion.
|
||||
</para>
|
||||
<sect2 id="faq-replication-slots-advantage" xreflabel="Advantages of replication slots">
|
||||
<title>What's the advantage of using replication slots?</title>
|
||||
<para>
|
||||
Replication slots, introduced in PostgreSQL 9.4, ensure that the
|
||||
primary server will retain WAL files until they have been consumed
|
||||
by all standby servers. This means standby servers should never
|
||||
fail due to not being able to retrieve required WAL files from the
|
||||
primary.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
to be retained indefinitely, and eventually lead to disk space
|
||||
exhaustion.
|
||||
</para>
|
||||
|
||||
<tip>
|
||||
<para>
|
||||
2ndQuadrant's recommended configuration is to configure
|
||||
<ulink url="https://www.pgbarman.org/">Barman</ulink> as a fallback
|
||||
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>.
|
||||
</para>
|
||||
</tip>
|
||||
</sect2>
|
||||
<tip>
|
||||
<para>
|
||||
2ndQuadrant's recommended configuration is to configure
|
||||
<ulink url="https://www.pgbarman.org/">Barman</ulink> as a fallback
|
||||
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>.
|
||||
</para>
|
||||
</tip>
|
||||
</sect2>
|
||||
|
||||
<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>
|
||||
<para>
|
||||
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
|
||||
restart to take effect, and as there is no particular penalty for unused
|
||||
replication slots, setting a higher figure will make adding new nodes
|
||||
easier.
|
||||
</para>
|
||||
</sect2>
|
||||
<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>
|
||||
<para>
|
||||
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
|
||||
restart to take effect, and as there is no particular penalty for unused
|
||||
replication slots, setting a higher figure will make adding new nodes
|
||||
easier.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-hash-index" xreflabel="Hash indexes">
|
||||
<title>Does &repmgr; support hash indexes?</title>
|
||||
<para>
|
||||
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
|
||||
<ulink url="https://www.postgresql.org/docs/9.6/sql-createindex.html#AEN80279">PostgreSQL documentation</ulink>
|
||||
for details.
|
||||
</para>
|
||||
<para>
|
||||
From PostgreSQL 10, this restriction has been lifted and hash indexes can be used
|
||||
in a streaming replication cluster.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-hash-index" xreflabel="Hash indexes">
|
||||
<title>Does &repmgr; support hash indexes?</title>
|
||||
<para>
|
||||
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
|
||||
<ulink url="https://www.postgresql.org/docs/9.6/sql-createindex.html#AEN80279">PostgreSQL documentation</ulink>
|
||||
for details.
|
||||
</para>
|
||||
<para>
|
||||
From PostgreSQL 10, this restriction has been lifted and hash indexes can be used
|
||||
in a streaming replication cluster.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-upgrades" xreflabel="Upgrading PostgreSQL with repmgr">
|
||||
<title>Can &repmgr; assist with upgrading a PostgreSQL cluster?</title>
|
||||
<para>
|
||||
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
|
||||
<link linkend="performing-switchover">switchover</link> promoting it to a primary,
|
||||
then upgrade the former primary.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
node with <ulink url="https://www.postgresql.org/docs/current/pgupgrade.html">pg_upgrade</ulink>
|
||||
and recloning standbys from this.
|
||||
</para>
|
||||
<para>
|
||||
To minimize downtime during major upgrades from PostgreSQL 9.4 and later,
|
||||
<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,
|
||||
which can be kept in sync with the existing production cluster until the
|
||||
new cluster is ready to be put into production.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-upgrades" xreflabel="Upgrading PostgreSQL with repmgr">
|
||||
<title>Can &repmgr; assist with upgrading a PostgreSQL cluster?</title>
|
||||
<para>
|
||||
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
|
||||
<link linkend="performing-switchover">switchover</link> promoting it to a primary,
|
||||
then upgrade the former primary.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
node with <ulink url="https://www.postgresql.org/docs/current/pgupgrade.html">pg_upgrade</ulink>
|
||||
and recloning standbys from this.
|
||||
</para>
|
||||
<para>
|
||||
To minimize downtime during major upgrades from PostgreSQL 9.4 and later,
|
||||
<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,
|
||||
which can be kept in sync with the existing production cluster until the
|
||||
new cluster is ready to be put into production.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-libdir-repmgr-error">
|
||||
<title>What does this error mean: <literal>ERROR: could not access file "$libdir/repmgr"</literal>?</title>
|
||||
<para>
|
||||
It means the &repmgr; extension code is not installed in the
|
||||
PostgreSQL application directory. This typically happens when using PostgreSQL
|
||||
packages provided by a third-party vendor, which often have different
|
||||
filesystem layouts.
|
||||
</para>
|
||||
<para>
|
||||
Either use PostgreSQL packages provided by the community or 2ndQuadrant; if this
|
||||
is not possible, contact your vendor for assistance.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-libdir-repmgr-error">
|
||||
<title>What does this error mean: <literal>ERROR: could not access file "$libdir/repmgr"</literal>?</title>
|
||||
<para>
|
||||
It means the &repmgr; extension code is not installed in the
|
||||
PostgreSQL application directory. This typically happens when using PostgreSQL
|
||||
packages provided by a third-party vendor, which often have different
|
||||
filesystem layouts.
|
||||
</para>
|
||||
<para>
|
||||
Either use PostgreSQL packages provided by the community or 2ndQuadrant; if this
|
||||
is not possible, contact your vendor for assistance.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-old-packages">
|
||||
<title>How can I obtain old versions of &repmgr; packages?</title>
|
||||
<para>
|
||||
See appendix <xref linkend="packages-old-versions"/> for details.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-old-packages">
|
||||
<title>How can I obtain old versions of &repmgr; packages?</title>
|
||||
<para>
|
||||
See appendix <xref linkend="packages-old-versions"/> for details.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgr-required-for-replication">
|
||||
<title>Is &repmgr; required for streaming replication?</title>
|
||||
<para>
|
||||
No.
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; (together with &repmgrd;) assists with
|
||||
<emphasis>managing</emphasis> replication. It does not actually perform replication, which
|
||||
is part of the core PostgreSQL functionality.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-repmgr-required-for-replication">
|
||||
<title>Is &repmgr; required for streaming replication?</title>
|
||||
<para>
|
||||
No.
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; (together with &repmgrd;) assists with
|
||||
<emphasis>managing</emphasis> replication. It does not actually perform replication, which
|
||||
is part of the core PostgreSQL functionality.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-what-if-repmgr-uninstalled">
|
||||
<title>Will replication stop working if &repmgr; is uninstalled?</title>
|
||||
<para>
|
||||
No. See preceding question.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-what-if-repmgr-uninstalled">
|
||||
<title>Will replication stop working if &repmgr; is uninstalled?</title>
|
||||
<para>
|
||||
No. See preceding question.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-version-mix">
|
||||
<title>Does it matter if different &repmgr; versions are present in the replication cluster?</title>
|
||||
<para>
|
||||
Yes. If different "major" &repmgr; versions (e.g. 3.3.x and 4.1.x) are present,
|
||||
&repmgr; (in particular &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
|
||||
your replication cluster.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
to ensure there are no unexpected suprises, e.g. a newer version behaving slightly
|
||||
differently to the older version.
|
||||
</para>
|
||||
<para>
|
||||
See also <link linkend="faq-upgrade-repmgr">Should I upgrade &repmgr;?</link>.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-version-mix">
|
||||
<title>Does it matter if different &repmgr; versions are present in the replication cluster?</title>
|
||||
<para>
|
||||
Yes. If different "major" &repmgr; versions (e.g. 3.3.x and 4.1.x) are present,
|
||||
&repmgr; (in particular &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
|
||||
your replication cluster.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
to ensure there are no unexpected suprises, e.g. a newer version behaving slightly
|
||||
differently to the older version.
|
||||
</para>
|
||||
<para>
|
||||
See also <link linkend="faq-upgrade-repmgr">Should I upgrade &repmgr;?</link>.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-upgrade-repmgr">
|
||||
<title>Should I upgrade &repmgr;?</title>
|
||||
<para>
|
||||
Yes.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
costing you more effort. The same applies to PostgreSQL itself.
|
||||
</para>
|
||||
<sect2 id="faq-upgrade-repmgr">
|
||||
<title>Should I upgrade &repmgr;?</title>
|
||||
<para>
|
||||
Yes.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
costing you more effort. The same applies to PostgreSQL itself.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
</sect2>
|
||||
<sect2 id="faq-repmgr-conf-data-directory">
|
||||
<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-repmgr-conf-data-directory">
|
||||
<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. (In PostgreSQL 10 and later, non-superusers can be added to the
|
||||
group <option>pg_read_all_settings</option> which will enable them to read this setting).
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
<sect2 id="faq-third-party-packages" xreflabel="Compatability with third party vendor packages">
|
||||
<title>Are &repmgr; packages compatible with <literal>$third_party_vendor</literal>'s packages?</title>
|
||||
<para>
|
||||
&repmgr; packages provided by 2ndQuadrant are compatible with the community-provided PostgreSQL
|
||||
packages and any software provided by 2ndQuadrant.
|
||||
</para>
|
||||
<para>
|
||||
A number of other vendors provide their own versions of PostgreSQL packages, often with different
|
||||
package naming schemes and/or file locations.
|
||||
</para>
|
||||
<para>
|
||||
We cannot guarantee that &repmgr; packages will be compatible with these packages.
|
||||
It may be possible to override package dependencies (e.g. <literal>rpm --nodeps</literal>
|
||||
for CentOS-based systems or <literal>dpkg --force-depends</literal> for Debian-based systems).
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="faq-repmgr" xreflabel="repmgr">
|
||||
<title><command>repmgr</command></title>
|
||||
<sect1 id="faq-repmgr" xreflabel="repmgr">
|
||||
<title><command>repmgr</command></title>
|
||||
|
||||
<sect2 id="faq-register-existing-node" xreflabel="registering an existing node">
|
||||
<title>Can I register an existing PostgreSQL server with repmgr?</title>
|
||||
<para>
|
||||
Yes, any existing PostgreSQL server which is part of the same replication
|
||||
cluster can be registered with &repmgr;. There's no requirement for a
|
||||
standby to have been cloned using &repmgr;.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-register-existing-node" xreflabel="registering an existing node">
|
||||
<title>Can I register an existing PostgreSQL server with repmgr?</title>
|
||||
<para>
|
||||
Yes, any existing PostgreSQL server which is part of the same replication
|
||||
cluster can be registered with &repmgr;. There's no requirement for a
|
||||
standby to have been cloned using &repmgr;.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgr-clone-other-source" >
|
||||
<title>Can I use a standby not cloned by &repmgr; as a &repmgr; node?</title>
|
||||
<sect2 id="faq-repmgr-clone-other-source" >
|
||||
<title>Can I use a standby not cloned by &repmgr; as a &repmgr; node?</title>
|
||||
|
||||
<para>
|
||||
For a standby which has been manually cloned or recovered from an external
|
||||
backup manager such as Barman, the 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
|
||||
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.
|
||||
</para>
|
||||
</sect2>
|
||||
<para>
|
||||
For a standby which has been manually cloned or recovered from an external
|
||||
backup manager such as Barman, the 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
|
||||
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.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgr-recovery-conf" >
|
||||
<title>What does &repmgr; write in <filename>recovery.conf</filename>, and what options can be set there?</title>
|
||||
<para>
|
||||
See section <link linkend="repmgr-standby-clone-recovery-conf">Customising recovery.conf</link>.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-repmgr-recovery-conf" >
|
||||
<title>What does &repmgr; write in <filename>recovery.conf</filename>, and what options can be set there?</title>
|
||||
<para>
|
||||
See section <link linkend="repmgr-standby-clone-recovery-conf">Customising recovery.conf</link>.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<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>
|
||||
<para>
|
||||
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
|
||||
needs to be re-registered as a standby.
|
||||
</para>
|
||||
<para>
|
||||
It's possible to use <command>pg_rewind</command> to re-synchronise the existing data
|
||||
directory, which will usually be much
|
||||
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
|
||||
data checksums were enabled when the cluster was initialized.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; provides the command <command>repmgr node rejoin</command> which can
|
||||
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"/>.
|
||||
</para>
|
||||
<para>
|
||||
If <command>pg_rewind</command> cannot be used, then the data directory will need
|
||||
to be re-cloned from scratch.
|
||||
</para>
|
||||
<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>
|
||||
<para>
|
||||
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
|
||||
needs to be re-registered as a standby.
|
||||
</para>
|
||||
<para>
|
||||
It's possible to use <command>pg_rewind</command> to re-synchronise the existing data
|
||||
directory, which will usually be much
|
||||
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
|
||||
data checksums were enabled when the cluster was initialized.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; provides the command <command>repmgr node rejoin</command> which can
|
||||
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"/>.
|
||||
</para>
|
||||
<para>
|
||||
If <command>pg_rewind</command> cannot be used, then the data directory will need
|
||||
to be re-cloned from scratch.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
</sect2>
|
||||
|
||||
<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>
|
||||
<para>
|
||||
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
|
||||
which need to be rectified.
|
||||
</para>
|
||||
</sect2>
|
||||
<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>
|
||||
<para>
|
||||
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
|
||||
which need to be rectified.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgr-clone-skip-config-files" xreflabel="">
|
||||
<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
|
||||
directory in <filename>/etc</filename>?</title>
|
||||
<para>
|
||||
Use the command line option <literal>--copy-external-config-files</literal>. For more details
|
||||
see <xref linkend="repmgr-standby-clone-config-file-copying"/>.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-repmgr-clone-skip-config-files" xreflabel="">
|
||||
<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
|
||||
directory in <filename>/etc</filename>?</title>
|
||||
<para>
|
||||
Use the command line option <literal>--copy-external-config-files</literal>. For more details
|
||||
see <xref linkend="repmgr-standby-clone-config-file-copying"/>.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<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>
|
||||
in <filename>postgresql.conf</filename> if I'm not using &repmgrd;?</title>
|
||||
<para>
|
||||
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
|
||||
<literal>shared_preload_libraries = 'repmgr'</literal> and restart PostgreSQL.
|
||||
</para>
|
||||
</sect2>
|
||||
<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>
|
||||
in <filename>postgresql.conf</filename> if I'm not using &repmgrd;?</title>
|
||||
<para>
|
||||
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
|
||||
<literal>shared_preload_libraries = 'repmgr'</literal> and restart PostgreSQL.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<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>
|
||||
but <command>repmgr</command>/&repmgrd; complains it can't connect to the server... Why?</title>
|
||||
<para>
|
||||
<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
|
||||
permission is for PostgreSQL's streaming replication (and doesn't necessarily need to be the <literal>repmgr</literal> user).
|
||||
</para>
|
||||
</sect2>
|
||||
<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>
|
||||
but <command>repmgr</command>/&repmgrd; complains it can't connect to the server... Why?</title>
|
||||
<para>
|
||||
<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
|
||||
permission is for PostgreSQL's streaming replication (and doesn't necessarily need to be the <literal>repmgr</literal> user).
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<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
|
||||
for the primary server on the command line, not in the configuration file?</title>
|
||||
<para>
|
||||
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
|
||||
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
|
||||
node, and if necessary scan the replication cluster until it locates the active primary.
|
||||
</para>
|
||||
</sect2>
|
||||
<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
|
||||
for the primary server on the command line, not in the configuration file?</title>
|
||||
<para>
|
||||
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
|
||||
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
|
||||
node, and if necessary scan the replication cluster until it locates the active primary.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<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>
|
||||
<para>
|
||||
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>.
|
||||
For more details see <xref linkend="cloning-advanced-pg-basebackup-options"/>.
|
||||
</para>
|
||||
</sect2>
|
||||
<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>
|
||||
<para>
|
||||
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>.
|
||||
For more details see <xref linkend="cloning-advanced-pg-basebackup-options"/>.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<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>
|
||||
table?</title>
|
||||
<para>
|
||||
Under some circumstances event notifications can be generated for servers
|
||||
which have not yet been registered; it's also useful to retain a record
|
||||
of events which includes servers removed from the replication cluster
|
||||
which no longer have an entry in the <literal>repmgr.nodes</literal> table.
|
||||
</para>
|
||||
</sect2>
|
||||
<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>
|
||||
table?</title>
|
||||
<para>
|
||||
Under some circumstances event notifications can be generated for servers
|
||||
which have not yet been registered; it's also useful to retain a record
|
||||
of events which includes servers removed from the replication cluster
|
||||
which no longer have an entry in the <literal>repmgr.nodes</literal> table.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<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>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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,
|
||||
even if the string does not contain any characters which need escaping.
|
||||
</para>
|
||||
</sect2>
|
||||
<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>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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,
|
||||
even if the string does not contain any characters which need escaping.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
|
||||
</sect1>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="faq-repmgrd" xreflabel="repmgrd">
|
||||
<title>&repmgrd;</title>
|
||||
<sect1 id="faq-repmgrd" xreflabel="repmgrd">
|
||||
<title>&repmgrd;</title>
|
||||
|
||||
|
||||
<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>
|
||||
<para>
|
||||
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>.
|
||||
</para>
|
||||
<para>
|
||||
Additionally, if <varname>failover</varname> is set to <literal>manual</literal>, the node will never
|
||||
be considered as a promotion candidate.
|
||||
</para>
|
||||
</sect2>
|
||||
<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>
|
||||
<para>
|
||||
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>.
|
||||
</para>
|
||||
<para>
|
||||
Additionally, if <varname>failover</varname> is set to <literal>manual</literal>, the node will never
|
||||
be considered as a promotion candidate.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgrd-delayed-standby" xreflabel="Delayed standby support">
|
||||
<title>Does &repmgrd; support delayed standbys?</title>
|
||||
<para>
|
||||
&repmgrd; can monitor delayed standbys - those set up with
|
||||
<varname>recovery_min_apply_delay</varname> set to a non-zero value
|
||||
in <filename>recovery.conf</filename> - but as it's not currently possible
|
||||
to directly examine the value applied to the standby, &repmgrd;
|
||||
may not be able to properly evaluate the node as a promotion candidate.
|
||||
</para>
|
||||
<para>
|
||||
We recommend that delayed standbys are explicitly excluded from promotion
|
||||
by setting <varname>priority</varname> to <literal>0</literal> in
|
||||
<filename>repmgr.conf</filename>.
|
||||
</para>
|
||||
<para>
|
||||
Note that after registering a delayed standby, &repmgrd; will only start
|
||||
once the metadata added in the primary node has been replicated.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-repmgrd-delayed-standby" xreflabel="Delayed standby support">
|
||||
<title>Does &repmgrd; support delayed standbys?</title>
|
||||
<para>
|
||||
&repmgrd; can monitor delayed standbys - those set up with
|
||||
<varname>recovery_min_apply_delay</varname> set to a non-zero value
|
||||
in <filename>recovery.conf</filename> - but as it's not currently possible
|
||||
to directly examine the value applied to the standby, &repmgrd;
|
||||
may not be able to properly evaluate the node as a promotion candidate.
|
||||
</para>
|
||||
<para>
|
||||
We recommend that delayed standbys are explicitly excluded from promotion
|
||||
by setting <varname>priority</varname> to <literal>0</literal> in
|
||||
<filename>repmgr.conf</filename>.
|
||||
</para>
|
||||
<para>
|
||||
Note that after registering a delayed standby, &repmgrd; will only start
|
||||
once the metadata added in the primary node has been replicated.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgrd-logfile-rotate" xreflabel="repmgrd logfile rotation">
|
||||
<title>How can I get &repmgrd; to rotate its logfile?</title>
|
||||
<para>
|
||||
Configure your system's <literal>logrotate</literal> service to do this; see <xref linkend="repmgrd-log-rotation"/>.
|
||||
</para>
|
||||
<sect2 id="faq-repmgrd-logfile-rotate" xreflabel="repmgrd logfile rotation">
|
||||
<title>How can I get &repmgrd; to rotate its logfile?</title>
|
||||
<para>
|
||||
Configure your system's <literal>logrotate</literal> service to do this; see <xref linkend="repmgrd-log-rotation"/>.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
</sect2>
|
||||
|
||||
<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>
|
||||
<para>
|
||||
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
|
||||
<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
|
||||
be monitored, if desired.
|
||||
</para>
|
||||
</sect2>
|
||||
<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>
|
||||
<para>
|
||||
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
|
||||
<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
|
||||
be monitored, if desired.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgrd-pg-bindir" xreflabel="repmgrd does not apply pg_bindir to promote_command or follow_command">
|
||||
<title>
|
||||
&repmgrd; ignores pg_bindir when executing <varname>promote_command</varname> or <varname>follow_command</varname>
|
||||
</title>
|
||||
<para>
|
||||
<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
|
||||
path; see <xref linkend="repmgrd-automatic-failover-configuration"/> for more details.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-repmgrd-pg-bindir" xreflabel="repmgrd does not apply pg_bindir to promote_command or follow_command">
|
||||
<title>
|
||||
&repmgrd; ignores pg_bindir when executing <varname>promote_command</varname> or <varname>follow_command</varname>
|
||||
</title>
|
||||
<para>
|
||||
<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
|
||||
path; see <xref linkend="repmgrd-automatic-failover-configuration"/> for more details.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="faq-repmgrd-startup-no-upstream" xreflabel="repmgrd does not start if upstream node is not running">
|
||||
<title>
|
||||
&repmgrd; aborts startup with the error "<literal>upstream node must be running before repmgrd can start</literal>"
|
||||
</title>
|
||||
<para>
|
||||
&repmgrd; does this to avoid starting up on a replication cluster
|
||||
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,
|
||||
particularly if &repmgrd; is not running on other nodes.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
The onus is therefore on the adminstrator to manually set the cluster to a stable, healthy state before
|
||||
starting &repmgrd;.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="faq-repmgrd-startup-no-upstream" xreflabel="repmgrd does not start if upstream node is not running">
|
||||
<title>
|
||||
&repmgrd; aborts startup with the error "<literal>upstream node must be running before repmgrd can start</literal>"
|
||||
</title>
|
||||
<para>
|
||||
&repmgrd; does this to avoid starting up on a replication cluster
|
||||
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,
|
||||
particularly if &repmgrd; is not running on other nodes.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
The onus is therefore on the adminstrator to manually set the cluster to a stable, healthy state before
|
||||
starting &repmgrd;.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
</sect1>
|
||||
</appendix>
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
|
||||
<row>
|
||||
<entry>Package name example:</entry>
|
||||
<entry><filename>repmgr10-4.0.4-1.rhel7.x86_64</filename></entry>
|
||||
<entry><filename>repmgr11-4.4.0-1.rhel7.x86_64</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -132,12 +132,12 @@
|
||||
|
||||
<row>
|
||||
<entry>Installation command:</entry>
|
||||
<entry><literal>yum install repmgr10</literal></entry>
|
||||
<entry><literal>yum install repmgr11</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Binary location:</entry>
|
||||
<entry><filename>/usr/pgsql-10/bin</filename></entry>
|
||||
<entry><filename>/usr/pgsql-11/bin</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -147,22 +147,22 @@
|
||||
|
||||
<row>
|
||||
<entry>Configuration file location:</entry>
|
||||
<entry><filename>/etc/repmgr/10/repmgr.conf</filename></entry>
|
||||
<entry><filename>/etc/repmgr/11/repmgr.conf</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Data directory:</entry>
|
||||
<entry><filename>/var/lib/pgsql/10/data</filename></entry>
|
||||
<entry><filename>/var/lib/pgsql/11/data</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>repmgrd service command:</entry>
|
||||
<entry><command>systemctl [start|stop|restart|reload] repmgr10</command></entry>
|
||||
<entry><command>systemctl [start|stop|restart|reload] repmgr11</command></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>repmgrd service file location:</entry>
|
||||
<entry><filename>/usr/lib/systemd/system/repmgr10.service</filename></entry>
|
||||
<entry><filename>/usr/lib/systemd/system/repmgr11.service</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -323,7 +323,7 @@
|
||||
|
||||
<row>
|
||||
<entry>Package name example:</entry>
|
||||
<entry><filename>postgresql-10-repmgr</filename></entry>
|
||||
<entry><filename>postgresql-11-repmgr</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -333,12 +333,12 @@
|
||||
|
||||
<row>
|
||||
<entry>Installation command:</entry>
|
||||
<entry><literal>apt-get install postgresql-10-repmgr</literal></entry>
|
||||
<entry><literal>apt-get install postgresql-11-repmgr</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Binary location:</entry>
|
||||
<entry><filename>/usr/lib/postgresql/10/bin</filename></entry>
|
||||
<entry><filename>/usr/lib/postgresql/11/bin</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@@ -353,12 +353,12 @@
|
||||
|
||||
<row>
|
||||
<entry>Data directory:</entry>
|
||||
<entry><filename>/var/lib/postgresql/10/main</filename></entry>
|
||||
<entry><filename>/var/lib/postgresql/11/main</filename></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>PostgreSQL service command:</entry>
|
||||
<entry><command>systemctl [start|stop|restart|reload] postgresql@10-main</command></entry>
|
||||
<entry><command>systemctl [start|stop|restart|reload] postgresql@11-main</command></entry>
|
||||
|
||||
</row>
|
||||
|
||||
@@ -386,7 +386,7 @@
|
||||
it's recommended to execute <command>pg_ctlcluster</command> (as <literal>root</literal>,
|
||||
either directly or via <command>sudo</command>), e.g.:
|
||||
<programlisting>
|
||||
<command>pg_ctlcluster 10 main [start|stop|restart|reload]</command></programlisting>
|
||||
<command>pg_ctlcluster 11 main [start|stop|restart|reload]</command></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
For pre-<application>systemd</application> systems, <command>pg_ctlcluster</command>
|
||||
|
||||
@@ -15,33 +15,313 @@
|
||||
See also: <xref linkend="upgrading-repmgr"/>
|
||||
</para>
|
||||
|
||||
<sect1 id="release-4.4">
|
||||
<title>Release 4.4</title>
|
||||
<para><emphasis>?? June, 2019</emphasis></para>
|
||||
<!-- remember to update the release date in ../repmgr_version.h.in -->
|
||||
|
||||
<sect2>
|
||||
<title>repmgr client enhancements</title>
|
||||
<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>
|
||||
<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>
|
||||
</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>
|
||||
<link linkend="repmgr-standby-clone"><command>repmgr standby clone</command></link>:
|
||||
prevent a standby from being cloned from a witness server (PostgreSQL 9.6 and later only).
|
||||
<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>
|
||||
|
||||
<listitem>
|
||||
<sect2>
|
||||
<title>Bug fixes</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-witness-register"><command>repmgr witness register</command></link>:
|
||||
prevent a witness server from being registered on the replication cluster primary server
|
||||
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">
|
||||
<title>Release 4.4</title>
|
||||
<para><emphasis>Thu 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>
|
||||
<title>repmgr client enhancements</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-standby-clone"><command>repmgr standby clone</command></link>:
|
||||
prevent a standby from being cloned from a witness server (PostgreSQL 9.6 and later only).
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-witness-register"><command>repmgr witness register</command></link>:
|
||||
prevent a witness server from being registered on the replication cluster primary server
|
||||
(PostgreSQL 9.6 and later only).
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
Registering a witness on the primary node would defeat the purpose of having a witness server,
|
||||
which is intended to remain running even if the cluster's primary goes down.
|
||||
</para>
|
||||
</listitem>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>:
|
||||
note that an active, reachable cluster primary is required for this command;
|
||||
and provide a more helpful error message if no reachable primary could be found.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -75,7 +355,6 @@
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-standby-promote"><command>repmgr standby promote</command></link>:
|
||||
@@ -94,61 +373,61 @@
|
||||
</note>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>:
|
||||
add <option>--repmgrd-force-unpause</option> to unpause all &repmgrd; instances after executing a switchover.
|
||||
This will ensure that any &repmgrd; instances which were paused before the switchover will be
|
||||
unpaused.
|
||||
</para>
|
||||
</listitem>
|
||||
<link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>:
|
||||
add <option>--repmgrd-force-unpause</option> to unpause all &repmgrd; instances after executing a switchover.
|
||||
This will ensure that any &repmgrd; instances which were paused before the switchover will be
|
||||
unpaused.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-daemon-status"><command>repmgr daemon status</command></link>:
|
||||
make output similar to that of
|
||||
<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
|
||||
state.
|
||||
<link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>:
|
||||
make output similar to that of
|
||||
<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
|
||||
state.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>:
|
||||
display each node's timeline ID (PostgreSQL 9.6 and later only).
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</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
|
||||
situations where the cluster is in an unexpected state, and provide a better idea of the
|
||||
actual cluster state.
|
||||
</para>
|
||||
<para>
|
||||
For example, if a cluster has divided somehow and a set of nodes are
|
||||
following a new primary, when running either of these commands, &repmgr;
|
||||
will now show the name of the primary those nodes are actually
|
||||
following, rather than the now outdated node name recorded
|
||||
on the other side of the "split". A warning will also be issued
|
||||
about the unexpected situation.
|
||||
display each node's timeline ID (PostgreSQL 9.6 and later only).
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</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
|
||||
warning if the node is not attached.
|
||||
</para>
|
||||
</listitem>
|
||||
and <link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>:
|
||||
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
|
||||
actual cluster state.
|
||||
</para>
|
||||
<para>
|
||||
For example, if a cluster has divided somehow and a set of nodes are
|
||||
following a new primary, when running either of these commands, &repmgr;
|
||||
will now show the name of the primary those nodes are actually
|
||||
following, rather than the now outdated node name recorded
|
||||
on the other side of the "split". A warning will also be issued
|
||||
about the unexpected situation.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-cluster-show"><command>repmgr cluster show</command></link>
|
||||
and <link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>:
|
||||
check if a node is attached to its advertised upstream node, and issue a
|
||||
warning if the node is not attached.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
@@ -221,23 +500,41 @@
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgr;: when executing <link linkend="repmgr-standby-clone"><command>repmgr standby clone</command></link>
|
||||
with the <option>--upstream-conninfo</option>, ensure that <varname>application_name</varname>
|
||||
is set correctly in <varname>primary_conninfo</varname>.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgr;: when executing <link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>,
|
||||
don't abort if one or more nodes are not reachable <emphasis>and</emphasis>
|
||||
they are marked as inactive.
|
||||
</para>
|
||||
</listitem>
|
||||
they are marked as inactive.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgr;: canonicalize the data directory path when parsing the configuration file, so
|
||||
the provided path matches the path PostgreSQL reports as its data directory.
|
||||
Otherwise, if e.g. the data directory is configured with a trailing slash,
|
||||
<link linkend="repmgr-node-check"><command>repmgr node check --data-directory-config</command></link>
|
||||
will return a spurious error.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: fix memory leak which occurs while the monitored PostgreSQL node is <emphasis>not</emphasis>
|
||||
running.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
|
||||
@@ -271,7 +568,7 @@
|
||||
&repmgr; 4.3 is a major release.
|
||||
</para>
|
||||
<para>
|
||||
For details on how to upgrade an existing &repmgr; instrallation, see
|
||||
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>
|
||||
@@ -281,19 +578,19 @@
|
||||
</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>
|
||||
<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>
|
||||
</para>
|
||||
<para>
|
||||
For further details, see <link linkend="repmgrd-configuration-debian-ubuntu">repmgrd configuration on Debian/Ubuntu</link>.
|
||||
</para>
|
||||
</important>
|
||||
|
||||
<sect2>
|
||||
<title>repmgr client enhancements</title>
|
||||
@@ -340,7 +637,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<link linkend="repmgr-daemon-status"><command>repmgr daemon status</command></link>
|
||||
<link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>
|
||||
additionally displays the node priority and the interval (in seconds) since the
|
||||
&repmgrd; instance last verified its upstream node was available.
|
||||
</para>
|
||||
@@ -358,11 +655,11 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-cluster-show">repmgr cluster show</link></command>:
|
||||
differentiate between unreachable nodes and nodes which are running but rejecting connections.
|
||||
differentiate between unreachable nodes and nodes which are running but rejecting connections.
|
||||
</para>
|
||||
<para>
|
||||
This makes it possible to see whether a node is unreachable at network level,
|
||||
or if it is running but rejecting connections for some reason.
|
||||
This makes it possible to see whether a node is unreachable at network level,
|
||||
or if it is running but rejecting connections for some reason.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
@@ -411,7 +708,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd; will no longer consider nodes where &repmgrd;
|
||||
is not running as promotion candidates.
|
||||
is not running as promotion candidates.
|
||||
</para>
|
||||
<para>
|
||||
Previously, if &repmgrd; was not running on a node, but
|
||||
@@ -449,15 +746,15 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
In a failover situation, &repmgrd; will not attempt to promote a
|
||||
node if another primary has already appeared (e.g. by being promoted manually).
|
||||
GitHub #420.
|
||||
</para>
|
||||
In a failover situation, &repmgrd; will not attempt to promote a
|
||||
node if another primary has already appeared (e.g. by being promoted manually).
|
||||
GitHub #420.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect2>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Bug fixes</title>
|
||||
@@ -467,23 +764,23 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-cluster-show">repmgr cluster show</link></command>:
|
||||
fix display of node IDs with multiple digits.
|
||||
fix display of node IDs with multiple digits.
|
||||
</para>
|
||||
</listitem>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
ensure <command><link linkend="repmgr-primary-unregister">repmgr primary unregister</link></command>
|
||||
behaves correctly when executed on a witness server. GitHub #548.
|
||||
behaves correctly when executed on a witness server. GitHub #548.
|
||||
</para>
|
||||
</listitem>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
ensure <command><link linkend="repmgr-standby-register">repmgr standby register</link></command>
|
||||
fails when <option>--upstream-node-id</option> is the same as the local node ID.
|
||||
fails when <option>--upstream-node-id</option> is the same as the local node ID.
|
||||
</para>
|
||||
</listitem>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -504,7 +801,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgr;: when executing <link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>,
|
||||
verify the standby (promotion candidate) is currently attached to the primary (demotion candidate). GitHub #519.
|
||||
verify the standby (promotion candidate) is currently attached to the primary (demotion candidate). GitHub #519.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
@@ -512,7 +809,7 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<para>
|
||||
&repmgr;: when executing <link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>,
|
||||
avoid a potential race condition when comparing received WAL on the standby to the primary's shutdown location,
|
||||
as the standby's walreceiver may not have yet flushed all received WAL to disk. GitHub #518.
|
||||
as the standby's walreceiver may not have yet flushed all received WAL to disk. GitHub #518.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
@@ -526,11 +823,11 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-node-check">repmgr node check</link></command>
|
||||
will only consider physical replication slots, as the purpose
|
||||
of slot checks is to warn about potential issues with
|
||||
streaming replication standbys which are no longer attached.
|
||||
</para>
|
||||
</listitem>
|
||||
will only consider physical replication slots, as the purpose
|
||||
of slot checks is to warn about potential issues with
|
||||
streaming replication standbys which are no longer attached.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -561,19 +858,19 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<link linkend="upgrading-major-version">Upgrading a major version release</link>.
|
||||
</para>
|
||||
|
||||
<important>
|
||||
<para>
|
||||
On Debian-based systems, including Ubuntu, if using &repmgrd;
|
||||
please ensure that the in the file <filename>/etc/init.d/repmgrd</filename>, the parameter
|
||||
<varname>REPMGRD_OPTS</varname> contains "<literal>--daemonize=false</literal>", e.g.:
|
||||
<programlisting>
|
||||
<important>
|
||||
<para>
|
||||
On Debian-based systems, including Ubuntu, if using &repmgrd;
|
||||
please ensure that the 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 daemon configuration on Debian/Ubuntu</link>.
|
||||
</para>
|
||||
</important>
|
||||
</para>
|
||||
<para>
|
||||
For further details, see <link linkend="repmgrd-configuration-debian-ubuntu">repmgrd daemon configuration on Debian/Ubuntu</link>.
|
||||
</para>
|
||||
</important>
|
||||
|
||||
<sect2>
|
||||
<title>Configuration file changes</title>
|
||||
@@ -705,11 +1002,11 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
repmgr 4.1.1 contains a number of usability enhancements and bug fixes.
|
||||
</para>
|
||||
<para>
|
||||
We recommend upgrading to this version as soon as possible.
|
||||
This release can be installed as a simple package upgrade from repmgr 4.0 ~ 4.1.0;
|
||||
We recommend upgrading to this version as soon as possible.
|
||||
This release can be installed as a simple package upgrade from repmgr 4.0 ~ 4.1.0;
|
||||
&repmgrd; (if running) should be restarted.
|
||||
See <xref linkend="upgrading-repmgr"/> for more details.
|
||||
</para>
|
||||
</para>
|
||||
|
||||
<sect2>
|
||||
<title>repmgr enhancements</title>
|
||||
@@ -971,18 +1268,18 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-witness-unregister">repmgr witness unregister</link></command>
|
||||
can be run on any node, by providing the ID of the witness node with <option>--node-id</option>.
|
||||
(GitHub #472).
|
||||
</para>
|
||||
</listitem>
|
||||
can be run on any node, by providing the ID of the witness node with <option>--node-id</option>.
|
||||
(GitHub #472).
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-standby-switchover">repmgr standby switchover</link></command>
|
||||
will refuse to run if an exclusive backup is taking place on the current primary.
|
||||
(GitHub #476).
|
||||
</para>
|
||||
</listitem>
|
||||
(GitHub #476).
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</para>
|
||||
@@ -1003,9 +1300,9 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: daemonize process by default.
|
||||
In case, for whatever reason, the user does not wish to daemonize the
|
||||
process, provide <option>--daemonize=false</option>.
|
||||
(GitHub #458).
|
||||
In case, for whatever reason, the user does not wish to daemonize the
|
||||
process, provide <option>--daemonize=false</option>.
|
||||
(GitHub #458).
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
@@ -1030,23 +1327,23 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-cluster-cleanup">repmgr cluster cleanup</link></command>:
|
||||
add missing help options. (GitHub #461/#462).
|
||||
</para>
|
||||
</listitem>
|
||||
add missing help options. (GitHub #461/#462).
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Ensure witness node follows new primary after switchover. (GitHub #453).
|
||||
</para>
|
||||
</listitem>
|
||||
Ensure witness node follows new primary after switchover. (GitHub #453).
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-node-check">repmgr node check</link></command> and
|
||||
<command><link linkend="repmgr-node-status">repmgr node status</link></command>:
|
||||
fix witness node handling. (GitHub #451).
|
||||
</para>
|
||||
</listitem>
|
||||
fix witness node handling. (GitHub #451).
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -1066,14 +1363,14 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<title>Release 4.0.6</title>
|
||||
<para><emphasis>Thu June 14, 2018</emphasis></para>
|
||||
<para>
|
||||
&repmgr; 4.0.6 contains a number of bug fixes and usability enhancements.
|
||||
&repmgr; 4.0.6 contains a number of bug fixes and usability enhancements.
|
||||
</para>
|
||||
<para>
|
||||
We recommend upgrading to this version as soon as possible.
|
||||
This release can be installed as a simple package upgrade from repmgr 4.0 ~ 4.0.5;
|
||||
<para>
|
||||
We recommend upgrading to this version as soon as possible.
|
||||
This release can be installed as a simple package upgrade from repmgr 4.0 ~ 4.0.5;
|
||||
&repmgrd; (if running) should be restarted. See <xref linkend="upgrading-repmgr"/>
|
||||
for more details.
|
||||
</para>
|
||||
</para>
|
||||
|
||||
<sect2>
|
||||
<title>Usability enhancements</title>
|
||||
@@ -1091,33 +1388,33 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>:
|
||||
Improve handling of external configuration file copying, including consideration in
|
||||
<option>--dry-run</option> check
|
||||
(GitHub #443)
|
||||
Improve handling of external configuration file copying, including consideration in
|
||||
<option>--dry-run</option> check
|
||||
(GitHub #443)
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
When using <option>--dry-run</option>, force log level to <literal>INFO</literal>
|
||||
to ensure output will always be displayed
|
||||
(GitHub #441)
|
||||
to ensure output will always be displayed
|
||||
(GitHub #441)
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>:
|
||||
Improve documentation of <option>--recovery-conf-only</option> mode
|
||||
(GitHub #438)
|
||||
Improve documentation of <option>--recovery-conf-only</option> mode
|
||||
(GitHub #438)
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-standby-clone">repmgr standby clone</link></command>:
|
||||
Don't require presence of <varname>user</varname> parameter in conninfo string
|
||||
(GitHub #437)
|
||||
Don't require presence of <varname>user</varname> parameter in conninfo string
|
||||
(GitHub #437)
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
@@ -1143,23 +1440,23 @@ REPMGRD_OPTS="--daemonize=false"</programlisting>
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-standby-follow">repmgr standby follow</link></command>:
|
||||
check node has actually connected to new primary before reporting success
|
||||
(GitHub #444)
|
||||
check node has actually connected to new primary before reporting success
|
||||
(GitHub #444)
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<command><link linkend="repmgr-node-rejoin">repmgr node rejoin</link></command>:
|
||||
Fix bug when parsing <option>--config-files</option> parameter
|
||||
(GitHub #442)
|
||||
Fix bug when parsing <option>--config-files</option> parameter
|
||||
(GitHub #442)
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
&repmgrd;: ensure local node is counted as quorum member
|
||||
(GitHub #439)
|
||||
(GitHub #439)
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
|
||||
@@ -52,6 +52,24 @@
|
||||
</itemizedlist>
|
||||
</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">
|
||||
<title>Prerequisites for cloning from Barman</title>
|
||||
<para>
|
||||
@@ -60,8 +78,7 @@
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
<listitem>
|
||||
<para>
|
||||
the <varname>barman_server</varname> setting in <filename>repmgr.conf</filename> is the same as the
|
||||
server configured in Barman;
|
||||
the Barman catalogue must include at least one valid backup for this server;
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
@@ -72,19 +89,68 @@
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
the <varname>restore_command</varname> setting in <filename>repmgr.conf</filename> is configured to
|
||||
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.
|
||||
the <varname>barman_server</varname> setting in <filename>repmgr.conf</filename> is the same as the
|
||||
server configured in Barman.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</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='somedb'</programlisting>
|
||||
</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>
|
||||
<simpara>
|
||||
Barman support is automatically enabled if <varname>barman_server</varname>
|
||||
@@ -94,37 +160,7 @@
|
||||
command line option.
|
||||
</simpara>
|
||||
</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 id="cloning-from-barman-restore-command" xreflabel="Using Barman as a WAL file source">
|
||||
<title>Using Barman as a WAL file source</title>
|
||||
@@ -142,35 +178,28 @@
|
||||
</para>
|
||||
<para>
|
||||
<command>barman-wal-restore</command> is a Python script provided as part of the <literal>barman-cli</literal>
|
||||
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.
|
||||
package (Barman 2.0 ~ 2.7) or as part of the core Barman distribution (Barman 2.8 and later).
|
||||
</para>
|
||||
<para>
|
||||
To use <command>barman-wal-restore</command> with &repmgr;
|
||||
and assuming Barman is located on the <literal>barmansrv</literal> host
|
||||
To use <command>barman-wal-restore</command> with &repmgr;,
|
||||
assuming Barman is located on the host "<literal>barmansrv</literal>"
|
||||
under the "<literal>barman</literal>" user account,
|
||||
and that <command>barman-wal-restore</command> is located as an executable at
|
||||
<filename>/usr/bin/barman-wal-restore</filename>,
|
||||
<filename>repmgr.conf</filename> should include the following lines:
|
||||
<programlisting>
|
||||
barman_host=barmansrv
|
||||
barman_server=somedb
|
||||
restore_command=/usr/bin/barman-wal-restore barmansrv somedb %f %p</programlisting>
|
||||
barman_host='barman@barmansrv'
|
||||
barman_server='somedb'
|
||||
restore_command='/usr/bin/barman-wal-restore barmansrv somedb %f %p'</programlisting>
|
||||
</para>
|
||||
<note>
|
||||
<simpara>
|
||||
<command>barman-wal-restore</command> supports command line switches to
|
||||
control parallelism (<literal>--parallel=N</literal>) and compression (
|
||||
<literal>--bzip2</literal>, <literal>--gzip</literal>).
|
||||
control parallelism (<literal>--parallel=N</literal>) and compression
|
||||
(<literal>--bzip2</literal>, <literal>--gzip</literal>).
|
||||
</simpara>
|
||||
</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>
|
||||
</sect1>
|
||||
|
||||
|
||||
124
doc/configuration-file-optional-settings.xml
Normal file
124
doc/configuration-file-optional-settings.xml
Normal file
@@ -0,0 +1,124 @@
|
||||
<sect1 id="configuration-file-optional-settings" xreflabel="optional configuration file settings">
|
||||
|
||||
<title>Optional configuration file settings</title>
|
||||
|
||||
<indexterm>
|
||||
<primary>repmgr.conf</primary>
|
||||
<secondary>optional settings</secondary>
|
||||
</indexterm>
|
||||
|
||||
<variablelist>
|
||||
|
||||
|
||||
<varlistentry id="repmgr-conf-config-directory" xreflabel="config_directory">
|
||||
<term><varname>config_directory</varname> (<type>string</type>)
|
||||
<indexterm>
|
||||
<primary><varname>config_directory</varname> configuration file parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
If PostgreSQL configuration files are located outside the data
|
||||
directory, specify the directory where the main
|
||||
<filename>postgresql.conf</filename> file is located.
|
||||
</para>
|
||||
<para>
|
||||
This enables explicit provision of an external configuration file
|
||||
directory, which if set will be passed to <command>pg_ctl</command> as the
|
||||
<option>-D</option> parameter. Otherwise <command>pg_ctl</command> will
|
||||
default to using the data directory, which will cause some operations
|
||||
to fail if the configuration files are not present there.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
This is implemented primarily for feature completeness and for
|
||||
development/testing purposes. Users who have installed &repmgr; from
|
||||
a package should <emphasis>not</emphasis> rely on to stop/start/restart PostgreSQL,
|
||||
instead they should set the appropriate <option>service_..._command</option>
|
||||
for their operating system. For more details see
|
||||
<xref linkend="configuration-file-service-commands"/>.
|
||||
</para>
|
||||
</note>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="repmgr-conf-replication-user" xreflabel="replication_user">
|
||||
<term><varname>replication_user</varname> (<type>string</type>)
|
||||
<indexterm>
|
||||
<primary><varname>replication_user</varname> configuration file parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
PostgreSQL user to make replication connections with.
|
||||
If not set defaults, to the user defined in <xref linkend="repmgr-conf-conninfo"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
|
||||
<varlistentry id="repmgr-conf-replication-type" xreflabel="replication_type">
|
||||
<term><varname>replication_type</varname> (<type>string</type>)
|
||||
<indexterm>
|
||||
<primary><varname>replication_type</varname> configuration file parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Must be one of <literal>physical</literal> (for standard streaming replication)
|
||||
or <literal>bdr</literal>.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
Replication type <literal>bdr</literal> can only be used with BDR 2.x
|
||||
</para>
|
||||
<para>
|
||||
BDR 3.x users should use <literal>physical</literal>.
|
||||
</para>
|
||||
</note>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="repmgr-conf-location" xreflabel="location">
|
||||
<term><varname>location</varname> (<type>string</type>)
|
||||
<indexterm>
|
||||
<primary><varname>location</varname> configuration file parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
An arbitrary string defining the location of the node; this
|
||||
is used during failover to check visibility of the
|
||||
current primary node.
|
||||
</para>
|
||||
<para>
|
||||
For more details see <xref linkend="repmgrd-network-split"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="repmgr-conf-use-replication-slots" xreflabel="use_replication_slots">
|
||||
<term><varname>use_replication_slots</varname> (<type>boolean</type>)
|
||||
<indexterm>
|
||||
<primary><varname>use_replication_slots</varname> configuration file parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Whether to use physical replication slots.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
When using replication slots,
|
||||
<varname>max_replication_slots</varname> should be configured for
|
||||
at least the number of standbys which will connect
|
||||
to the primary.
|
||||
</para>
|
||||
</note>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
</variablelist>
|
||||
</sect1>
|
||||
@@ -96,33 +96,6 @@
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For a full list of annotated configuration items, see the file
|
||||
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
For &repmgrd;-specific settings, see <xref linkend="repmgrd-configuration"/>.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
The following parameters in the configuration file can be overridden with
|
||||
command line options:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>-L/--log-level</literal> overrides <literal>log_level</literal> in
|
||||
<filename>repmgr.conf</filename>
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>-b/--pg_bindir</literal> overrides <literal>pg_bindir</literal> in
|
||||
<filename>repmgr.conf</filename>
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</note>
|
||||
|
||||
</sect1>
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
<secondary>format</secondary>
|
||||
</indexterm>
|
||||
|
||||
|
||||
|
||||
<para>
|
||||
<filename>repmgr.conf</filename> is a plain text file with one parameter/value
|
||||
combination per line.
|
||||
@@ -39,14 +41,10 @@
|
||||
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.
|
||||
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>
|
||||
<important>
|
||||
<para>
|
||||
&repmgr; will interpret double-quotes as being part of a string value; only use single quotes
|
||||
to quote parameter values.
|
||||
</para>
|
||||
</important>
|
||||
<para>
|
||||
To embed a single quote in a parameter value, write either two quotes (preferred) or backslash-quote.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Example of a valid <filename>repmgr.conf</filename> file:
|
||||
@@ -56,12 +54,99 @@
|
||||
node_id=1
|
||||
node_name= node1
|
||||
conninfo ='host=node1 dbname=repmgr user=repmgr connect_timeout=2'
|
||||
data_directory = /var/lib/pgsql/11/data</programlisting>
|
||||
data_directory = '/var/lib/pgsql/12/data'</programlisting>
|
||||
|
||||
</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 id="configuration-file-items" xreflabel="configuration file items">
|
||||
|
||||
<title>Configuration file items</title>
|
||||
<para>
|
||||
The following sections document some sections of the configuration file:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara>
|
||||
<xref linkend="configuration-file-settings"/>
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<xref linkend="configuration-file-optional-settings"/>
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<xref linkend="configuration-file-log-settings"/>
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
|
||||
<listitem>
|
||||
<simpara>
|
||||
<xref linkend="configuration-file-service-commands"/>
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</para>
|
||||
<para>
|
||||
For a full list of annotated configuration items, see the file
|
||||
<ulink url="https://raw.githubusercontent.com/2ndQuadrant/repmgr/master/repmgr.conf.sample">repmgr.conf.sample</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
For &repmgrd;-specific settings, see <xref linkend="repmgrd-configuration"/>.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
The following parameters in the configuration file can be overridden with
|
||||
command line options:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>-L/--log-level</literal> overrides <literal>log_level</literal> in
|
||||
<filename>repmgr.conf</filename>
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>-b/--pg_bindir</literal> overrides <literal>pg_bindir</literal> in
|
||||
<filename>repmgr.conf</filename>
|
||||
</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</note>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="configuration-file-location" xreflabel="configuration file location">
|
||||
<title>Configuration file location</title>
|
||||
|
||||
@@ -148,9 +148,19 @@
|
||||
instances in the replication cluster which may potentially become a primary server or
|
||||
(in cascading replication) the upstream server of a standby.
|
||||
</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>.
|
||||
</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>
|
||||
</varlistentry>
|
||||
|
||||
@@ -305,6 +315,7 @@
|
||||
|
||||
&configuration-file;
|
||||
&configuration-file-required-settings;
|
||||
&configuration-file-optional-settings;
|
||||
&configuration-file-log-settings;
|
||||
&configuration-file-service-commands;
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<!ENTITY configuration SYSTEM "configuration.xml">
|
||||
<!ENTITY configuration-file SYSTEM "configuration-file.xml">
|
||||
<!ENTITY configuration-file-required-settings SYSTEM "configuration-file-required-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-service-commands SYSTEM "configuration-file-service-commands.xml">
|
||||
<!ENTITY cloning-standbys SYSTEM "cloning-standbys.xml">
|
||||
@@ -53,11 +54,11 @@
|
||||
<!ENTITY repmgr-cluster-crosscheck SYSTEM "repmgr-cluster-crosscheck.xml">
|
||||
<!ENTITY repmgr-cluster-event SYSTEM "repmgr-cluster-event.xml">
|
||||
<!ENTITY repmgr-cluster-cleanup SYSTEM "repmgr-cluster-cleanup.xml">
|
||||
<!ENTITY repmgr-daemon-status SYSTEM "repmgr-daemon-status.xml">
|
||||
<!ENTITY repmgr-service-status SYSTEM "repmgr-service-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-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-faq SYSTEM "appendix-faq.xml">
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
customers, as the PostgreSQL filesystem layout may be different to the community RPMs.
|
||||
Please contact your support vendor for assistance.
|
||||
</para>
|
||||
<para>
|
||||
See also <link linkend="appendix-faq">FAQ</link> entry
|
||||
<xref linkend="faq-third-party-packages"/>.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
@@ -81,9 +85,9 @@
|
||||
(this enables the 2ndQuadrant repository as a source of &repmgr; packages).
|
||||
</para>
|
||||
<para>
|
||||
For example, for PostgreSQL 10 on CentOS, execute:
|
||||
For example, for PostgreSQL 11 on CentOS, execute:
|
||||
<programlisting>
|
||||
curl https://dl.2ndquadrant.com/default/release/get/10/rpm | sudo bash</programlisting>
|
||||
curl https://dl.2ndquadrant.com/default/release/get/11/rpm | sudo bash</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -99,8 +103,8 @@ curl https://dl.2ndquadrant.com/default/release/get/9.6/rpm | sudo bash</program
|
||||
sudo yum repolist</programlisting>
|
||||
The output should contain two entries like this:
|
||||
<programlisting>
|
||||
2ndquadrant-dl-default-release-pg10/7/x86_64 2ndQuadrant packages (PG10) for 7 - x86_64 4
|
||||
2ndquadrant-dl-default-release-pg10-debug/7/x86_64 2ndQuadrant packages (PG10) for 7 - x86_64 - Debug 3</programlisting>
|
||||
2ndquadrant-dl-default-release-pg11/7/x86_64 2ndQuadrant packages (PG11) for 7 - x86_64 18
|
||||
2ndquadrant-dl-default-release-pg11-debug/7/x86_64 2ndQuadrant packages (PG11) for 7 - x86_64 - Debug 8</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
@@ -108,7 +112,7 @@ sudo yum repolist</programlisting>
|
||||
<para>
|
||||
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
|
||||
<programlisting>
|
||||
sudo yum install repmgr10</programlisting>
|
||||
sudo yum install repmgr11</programlisting>
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
@@ -153,19 +157,23 @@ yum search repmgr</programlisting>
|
||||
To install a specific package version, execute <command>yum --showduplicates list</command>
|
||||
for the package in question:
|
||||
<programlisting>
|
||||
[root@localhost ~]# yum --showduplicates list repmgr10
|
||||
Loaded plugins: fastestmirror
|
||||
Loading mirror speeds from cached hostfile
|
||||
* base: ftp.iij.ad.jp
|
||||
* extras: ftp.iij.ad.jp
|
||||
* updates: ftp.iij.ad.jp
|
||||
Available Packages
|
||||
repmgr10.x86_64 4.0.3-1.rhel7 pgdg10
|
||||
repmgr10.x86_64 4.0.4-1.rhel7 pgdg10
|
||||
repmgr10.x86_64 4.0.5-1.el7 2ndquadrant-repo-10</programlisting>
|
||||
[root@localhost ~]# yum --showduplicates list repmgr11
|
||||
Loaded plugins: fastestmirror
|
||||
Loading mirror speeds from cached hostfile
|
||||
* base: ftp.tsukuba.wide.ad.jp
|
||||
* epel: nrt.edge.kernel.org
|
||||
* extras: ftp.tsukuba.wide.ad.jp
|
||||
* updates: ftp.tsukuba.wide.ad.jp
|
||||
Installed Packages
|
||||
repmgr11.x86_64 4.4.0-1.rhel7 @pgdg11
|
||||
Available Packages
|
||||
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.:
|
||||
<programlisting>
|
||||
[root@localhost ~]# yum install repmgr10-4.0.3-1.rhel7</programlisting>
|
||||
[root@localhost ~]# yum install repmgr11-4.3-1.el7</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -220,13 +228,13 @@ yum search repmgr</programlisting>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<listitem>
|
||||
<para>
|
||||
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>
|
||||
curl https://dl.2ndquadrant.com/default/release/get/deb | sudo bash</programlisting>
|
||||
</para>
|
||||
curl https://dl.2ndquadrant.com/default/release/get/deb | sudo bash</programlisting>
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
This will automatically install the following additional packages, if not already present:
|
||||
@@ -242,20 +250,20 @@ curl https://dl.2ndquadrant.com/default/release/get/deb | sudo bash</programlist
|
||||
</note>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr10</literal>):
|
||||
<listitem>
|
||||
<para>
|
||||
Install the &repmgr; version appropriate for your PostgreSQL version (e.g. <literal>repmgr11</literal>):
|
||||
<programlisting>
|
||||
sudo apt-get install postgresql-10-repmgr</programlisting>
|
||||
</para>
|
||||
sudo apt-get install postgresql-11-repmgr</programlisting>
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
For packages for PostgreSQL 9.6 and earlier, the package name includes
|
||||
a period between major and minor version numbers, e.g.
|
||||
<literal>postgresql-9.6-repmgr</literal>.
|
||||
For packages for PostgreSQL 9.6 and earlier, the package name includes
|
||||
a period between major and minor version numbers, e.g.
|
||||
<literal>postgresql-9.6-repmgr</literal>.
|
||||
</para>
|
||||
</note>
|
||||
</listitem>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
&repmgr; 4.x is compatible with all PostgreSQL versions from 9.3. See
|
||||
&repmgr; &repmgrversion; is compatible with all PostgreSQL versions from 9.3. See
|
||||
section <link linkend="install-compatibility-matrix">&repmgr; compatibility matrix</link>
|
||||
for an overview of version compatibility.
|
||||
</para>
|
||||
@@ -39,13 +39,13 @@
|
||||
|
||||
<note>
|
||||
<simpara>
|
||||
The same "major" &repmgr; version (e.g. <literal>4.2.x</literal>) <emphasis>must</emphasis>
|
||||
The same "major" &repmgr; version (e.g. <literal>&repmgrversion;.x</literal>) <emphasis>must</emphasis>
|
||||
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
|
||||
of incompatibilities.
|
||||
</simpara>
|
||||
<simpara>
|
||||
If different "major" &repmgr; versions (e.g. 3.3.x and 4.1.x)
|
||||
If different "major" &repmgr; versions (e.g. 4.1.x and &repmgrversion;.x)
|
||||
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.
|
||||
</simpara>
|
||||
@@ -109,12 +109,25 @@
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
&repmgr; 5.x
|
||||
</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>
|
||||
<entry>
|
||||
&repmgr; 4.x
|
||||
</entry>
|
||||
<entry>
|
||||
<link linkend="release-4.2">4.2</link> (2018-10-24)
|
||||
<link linkend="release-4.4">4.4</link> (2019-06-27)
|
||||
</entry>
|
||||
<entry>
|
||||
9.3, 9.4, 9.5, 9.6, 10, 11
|
||||
@@ -154,11 +167,26 @@
|
||||
The &repmgr; 2.x and 3.x series are no longer maintained or supported.
|
||||
We strongly recommend upgrading to the latest &repmgr; version.
|
||||
</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>
|
||||
|
||||
</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>
|
||||
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>
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
@@ -177,5 +205,22 @@
|
||||
</listitem>
|
||||
</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>)
|
||||
and will no longer be updated with security or bugfixes.
|
||||
</para>
|
||||
<para>
|
||||
PostgreSQL 9.4. is scheduled for its final release in February 2020
|
||||
(see <ulink url="https://www.postgresql.org/support/versioning/">PostgreSQL Versioning Policy</ulink>).
|
||||
</para>
|
||||
<para>
|
||||
We recommend that users of these versions migrate to a recent PostgreSQL version
|
||||
as soon as possible.
|
||||
</para>
|
||||
</important>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
|
||||
@@ -61,6 +61,9 @@ deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisti
|
||||
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
<listitem>
|
||||
<simpara><literal>flex</literal></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>libedit-dev</literal></simpara>
|
||||
</listitem>
|
||||
@@ -115,6 +118,9 @@ deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisti
|
||||
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
<listitem>
|
||||
<simpara><literal>flex</literal></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>libselinux-devel</literal></simpara>
|
||||
</listitem>
|
||||
@@ -177,7 +183,8 @@ deb-src http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main</programlisti
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There are also tags for each &repmgr; release, e.g. <literal>v4.2.0</literal>.
|
||||
There are also tags for each <ulink url="https://github.com/2ndQuadrant/repmgr/releases">&repmgr; release</ulink>, e.g.
|
||||
<literal><ulink url="https://github.com/2ndQuadrant/repmgr/releases/tag/v4.4.0">v4.4.0</ulink></literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
||||
@@ -254,7 +254,7 @@
|
||||
</para>
|
||||
<programlisting>
|
||||
node_id=1
|
||||
node_name=node1
|
||||
node_name='node1'
|
||||
conninfo='host=node1 user=repmgr dbname=repmgr connect_timeout=2'
|
||||
data_directory='/var/lib/postgresql/data'
|
||||
</programlisting>
|
||||
@@ -265,7 +265,6 @@
|
||||
server. See sections <xref linkend="configuration"/> and <xref linkend="configuration-file"/>
|
||||
for further details about <filename>repmgr.conf</filename>.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
&repmgr; only uses <option>pg_bindir</option> when it executes
|
||||
@@ -368,7 +367,7 @@
|
||||
</para>
|
||||
<programlisting>
|
||||
node_id=2
|
||||
node_name=node2
|
||||
node_name='node2'
|
||||
conninfo='host=node2 user=repmgr dbname=repmgr connect_timeout=2'
|
||||
data_directory='/var/lib/postgresql/data'</programlisting>
|
||||
<para>
|
||||
@@ -478,6 +477,8 @@
|
||||
latest_end_lsn | 0/7000538
|
||||
latest_end_time | 2017-08-28 15:20:56.418735+09
|
||||
slot_name |
|
||||
sender_host | node1
|
||||
sender_port | 5432
|
||||
conninfo | user=repmgr dbname=replication host=node1 application_name=node2
|
||||
</programlisting>
|
||||
Note that the <varname>conninfo</varname> value is that generated in <filename>recovery.conf</filename>
|
||||
@@ -497,11 +498,12 @@
|
||||
<para>
|
||||
Check the node is registered by executing <command>repmgr cluster show</command> on the standby:
|
||||
<programlisting>
|
||||
$ repmgr -f /etc/repmgr.conf cluster show
|
||||
ID | Name | Role | Status | Upstream | Location | Connection string
|
||||
----+-------+---------+-----------+----------+----------+--------------------------------------
|
||||
1 | node1 | primary | * running | | default | host=node1 dbname=repmgr user=repmgr
|
||||
2 | node2 | standby | running | node1 | default | host=node2 dbname=repmgr user=repmgr</programlisting>
|
||||
$ repmgr -f /etc/repmgr.conf cluster show
|
||||
|
||||
ID | Name | Role | Status | Upstream | Location | Priority | Timeline | Connection string
|
||||
----+-------+---------+-----------+----------+----------+----------+----------+--------------------------------------
|
||||
1 | node1 | primary | * running | | default | 100 | 1 | host=node1 dbname=repmgr user=repmgr
|
||||
2 | node2 | standby | running | node1 | default | 100 | 1 | host=node2 dbname=repmgr user=repmgr</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Both nodes are now registered with &repmgr; and the records have been copied to the standby server.
|
||||
|
||||
@@ -233,7 +233,7 @@
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<xref linkend="repmgr-node-status"/>, <xref linkend="repmgr-node-check"/>, <xref linkend="repmgr-daemon-status"/>
|
||||
<xref linkend="repmgr-node-status"/>, <xref linkend="repmgr-node-check"/>, <xref linkend="repmgr-service-status"/>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
|
||||
<refnamediv>
|
||||
<refname>repmgr daemon start</refname>
|
||||
<refpurpose>Start the &repmgrd; daemon</refpurpose>
|
||||
<refpurpose>Start the &repmgrd; daemon on the local node</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
This command starts the &repmgrd; daemon on the
|
||||
This command starts the &repmgrd; service on the
|
||||
local node.
|
||||
</para>
|
||||
<para>
|
||||
@@ -197,7 +197,11 @@
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<xref linkend="repmgr-daemon-stop"/>, <xref linkend="repmgr-daemon-status"/>, <xref linkend="repmgrd-daemon"/>
|
||||
<xref linkend="repmgr-daemon-stop"/>,
|
||||
<xref linkend="repmgrd-daemon"/>,
|
||||
<xref linkend="repmgr-service-status"/>,
|
||||
<xref linkend="repmgr-service-pause"/>,
|
||||
<xref linkend="repmgr-service-unpause"/>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<refnamediv>
|
||||
<refname>repmgr daemon stop</refname>
|
||||
<refpurpose>Stop the &repmgrd; daemon</refpurpose>
|
||||
<refpurpose>Stop the &repmgrd; daemon on the local node</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1>
|
||||
@@ -194,7 +194,11 @@
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<xref linkend="repmgr-daemon-start"/>, <xref linkend="repmgr-daemon-status"/>, <xref linkend="repmgrd-daemon"/>
|
||||
<xref linkend="repmgr-daemon-start"/>,
|
||||
<xref linkend="repmgrd-daemon"/>,
|
||||
<xref linkend="repmgr-service-status"/>,
|
||||
<xref linkend="repmgr-service-pause"/>,
|
||||
<xref linkend="repmgr-service-unpause"/>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@@ -356,7 +356,7 @@
|
||||
<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
|
||||
(rejoin target). This is particularly important if planning to use <application>pg_rewind</application>,
|
||||
which currently (as of PostgreSQL 11) may appear to succeed (or indicate there is no action
|
||||
which currently (as of PostgreSQL 12) 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
|
||||
primary which is behind the standby. &repmgr; will prevent this situation from occurring.
|
||||
</para>
|
||||
|
||||
@@ -114,38 +114,38 @@
|
||||
<para>
|
||||
See what action would be taken for a restart:
|
||||
<programlisting>
|
||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --action=restart --checkpoint --dry-run
|
||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --action=restart --checkpoint --dry-run
|
||||
INFO: a CHECKPOINT would be issued here
|
||||
INFO: would execute server command "sudo service postgresql-11 restart"</programlisting>
|
||||
INFO: would execute server command "sudo service postgresql-12 restart"</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Restart the PostgreSQL instance:
|
||||
<programlisting>
|
||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --action=restart --checkpoint
|
||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --action=restart --checkpoint
|
||||
NOTICE: issuing CHECKPOINT
|
||||
DETAIL: executing server command "sudo service postgresql-11 restart"
|
||||
Redirecting to /bin/systemctl restart postgresql-11.service</programlisting>
|
||||
DETAIL: executing server command "sudo service postgresql-12 restart"
|
||||
Redirecting to /bin/systemctl restart postgresql-12.service</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
List all commands:
|
||||
<programlisting>
|
||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --list-actions
|
||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --list-actions
|
||||
Following commands would be executed for each action:
|
||||
|
||||
start: "sudo service postgresql-11 start"
|
||||
stop: "sudo service postgresql-11 stop"
|
||||
restart: "sudo service postgresql-11 restart"
|
||||
reload: "sudo service postgresql-11 reload"
|
||||
promote: "/usr/pgsql-11/bin/pg_ctl -w -D '/var/lib/pgsql/11/data' promote"</programlisting>
|
||||
start: "sudo service postgresql-12 start"
|
||||
stop: "sudo service postgresql-12 stop"
|
||||
restart: "sudo service postgresql-12 restart"
|
||||
reload: "sudo service postgresql-12 reload"
|
||||
promote: "/usr/pgsql-12/bin/pg_ctl -w -D '/var/lib/pgsql/12/data' promote"</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
List a single command:
|
||||
<programlisting>
|
||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/11/repmgr.conf node service --list-actions --action=promote
|
||||
/usr/pgsql-11/bin/pg_ctl -w -D '/var/lib/pgsql/11/data' promote </programlisting>
|
||||
[postgres@node1 ~]$ repmgr -f /etc/repmgr/12/repmgr.conf node service --list-actions --action=promote
|
||||
/usr/pgsql-12/bin/pg_ctl -w -D '/var/lib/pgsql/12/data' promote </programlisting>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<refentry id="repmgr-daemon-pause">
|
||||
<refentry id="repmgr-service-pause">
|
||||
<indexterm>
|
||||
<primary>repmgr daemon pause</primary>
|
||||
<primary>repmgr service pause</primary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
@@ -9,11 +9,11 @@
|
||||
</indexterm>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>repmgr daemon pause</refentrytitle>
|
||||
<refentrytitle>repmgr service pause</refentrytitle>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>repmgr daemon pause</refname>
|
||||
<refname>repmgr service pause</refname>
|
||||
<refpurpose>Instruct all &repmgrd; instances in the replication cluster to pause failover operations</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
@@ -32,20 +32,29 @@
|
||||
<note>
|
||||
<para>
|
||||
It's important to wait a few seconds after restarting PostgreSQL on any node before running
|
||||
<command>repmgr daemon pause</command>, as the &repmgrd; instance
|
||||
<command>repmgr service pause</command>, as the &repmgrd; instance
|
||||
on the restarted node will take a second or two before it has updated its status.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
<xref linkend="repmgr-daemon-unpause"/> will instruct all previously paused &repmgrd;
|
||||
<xref linkend="repmgr-service-unpause"/> will instruct all previously paused &repmgrd;
|
||||
instances to resume normal failover operation.
|
||||
</para>
|
||||
</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>
|
||||
<title>Execution</title>
|
||||
<para>
|
||||
<command>repmgr daemon pause</command> can be executed on any active node in the
|
||||
<command>repmgr service pause</command> can be executed on any active node in the
|
||||
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
|
||||
It will have no effect on previously paused nodes.
|
||||
</para>
|
||||
@@ -55,7 +64,7 @@
|
||||
<title>Example</title>
|
||||
<para>
|
||||
<programlisting>
|
||||
$ repmgr -f /etc/repmgr.conf daemon pause
|
||||
$ repmgr -f /etc/repmgr.conf service pause
|
||||
NOTICE: node 1 (node1) paused
|
||||
NOTICE: node 2 (node2) paused
|
||||
NOTICE: node 3 (node3) paused</programlisting>
|
||||
@@ -79,7 +88,7 @@ NOTICE: node 3 (node3) paused</programlisting>
|
||||
<refsect1>
|
||||
<title>Exit codes</title>
|
||||
<para>
|
||||
One of the following exit codes will be emitted by <command>repmgr daemon unpause</command>:
|
||||
One of the following exit codes will be emitted by <command>repmgr service unpause</command>:
|
||||
</para>
|
||||
<variablelist>
|
||||
|
||||
@@ -107,7 +116,11 @@ NOTICE: node 3 (node3) paused</programlisting>
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<xref linkend="repmgr-daemon-unpause"/>, <xref linkend="repmgr-daemon-status"/>
|
||||
<xref linkend="repmgr-service-unpause"/>,
|
||||
<xref linkend="repmgr-service-status"/>,
|
||||
<xref linkend="repmgrd-pausing"/>,
|
||||
<xref linkend="repmgr-daemon-start"/>,
|
||||
<xref linkend="repmgr-daemon-stop"/>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
@@ -1,19 +1,19 @@
|
||||
<refentry id="repmgr-daemon-status">
|
||||
<refentry id="repmgr-service-status">
|
||||
<indexterm>
|
||||
<primary>repmgr daemon status</primary>
|
||||
<primary>repmgr service status</primary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
<secondary>displaying daemon status</secondary>
|
||||
<secondary>displaying service status</secondary>
|
||||
</indexterm>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>repmgr daemon status</refentrytitle>
|
||||
<refentrytitle>repmgr service status</refentrytitle>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>repmgr daemon status</refname>
|
||||
<refname>repmgr service status</refname>
|
||||
<refpurpose>display information about the status of &repmgrd; on each node in the cluster</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
@@ -22,21 +22,33 @@
|
||||
<para>
|
||||
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
|
||||
the result of <xref linkend="repmgr-daemon-pause"/> and <xref linkend="repmgr-daemon-unpause"/>
|
||||
the result of <xref linkend="repmgr-service-pause"/> and <xref linkend="repmgr-service-unpause"/>
|
||||
operations.
|
||||
</para>
|
||||
</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>
|
||||
<title>Execution</title>
|
||||
<para>
|
||||
<command>repmgr daemon status</command> can be executed on any active node in the
|
||||
<command>repmgr service status</command> can be executed on any active node in the
|
||||
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
|
||||
</para>
|
||||
<para>
|
||||
If PostgreSQL is not running on a node, &repmgr; will not be able to determine the
|
||||
status of that node's &repmgrd; instance.
|
||||
If a node is not accessible, or PostgreSQL itself is not running on the node,
|
||||
&repmgr; will not be able to determine the status of that node's &repmgrd; instance,
|
||||
and "<literal>n/a</literal>" will be displayed in the node's <literal>repmgrd</literal>
|
||||
column.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
After restarting PostgreSQL on any node, the &repmgrd; instance
|
||||
@@ -51,7 +63,7 @@
|
||||
<title>Examples</title>
|
||||
<para>
|
||||
&repmgrd; running normally on all nodes:
|
||||
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
|
||||
<programlisting>$ repmgr -f /etc/repmgr.conf service status
|
||||
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
||||
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
|
||||
1 | node1 | primary | * running | | running | 96563 | no | n/a
|
||||
@@ -60,8 +72,8 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
&repmgrd; paused on all nodes (using <xref linkend="repmgr-daemon-pause"/>):
|
||||
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
|
||||
&repmgrd; paused on all nodes (using <xref linkend="repmgr-service-pause"/>):
|
||||
<programlisting>$ repmgr -f /etc/repmgr.conf service status
|
||||
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
||||
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
|
||||
1 | node1 | primary | * running | | running | 96563 | yes | n/a
|
||||
@@ -71,7 +83,7 @@
|
||||
|
||||
<para>
|
||||
&repmgrd; not running on one node:
|
||||
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
|
||||
<programlisting>$ repmgr -f /etc/repmgr.conf service status
|
||||
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
||||
----+-------+---------+-----------+----------+-------------+-------+---------+--------------------
|
||||
1 | node1 | primary | * running | | running | 96563 | yes | n/a
|
||||
@@ -89,11 +101,11 @@
|
||||
<term><option>--csv</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
<command>repmgr daemon status</command> accepts an optional parameter <literal>--csv</literal>, which
|
||||
<command>repmgr service status</command> accepts an optional parameter <literal>--csv</literal>, which
|
||||
outputs the replication cluster's status in a simple CSV format, suitable for
|
||||
parsing by scripts, e.g.:
|
||||
<programlisting>
|
||||
$ repmgr -f /etc/repmgr.conf daemon status --csv
|
||||
$ repmgr -f /etc/repmgr.conf service status --csv
|
||||
1,node1,primary,1,1,5722,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>
|
||||
@@ -171,7 +183,7 @@
|
||||
<listitem>
|
||||
<para>
|
||||
Display additional information (<literal>location</literal>, <literal>priority</literal>)
|
||||
about the &repmgr; configuration.
|
||||
about the &repmgr; configuration.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -180,7 +192,7 @@
|
||||
<term><option>--verbose</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Display the full text of any database connection error messages
|
||||
Display the full text of any database connection error messages.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -192,7 +204,12 @@
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<xref linkend="repmgr-daemon-pause"/>, <xref linkend="repmgr-daemon-unpause"/>, <xref linkend="repmgr-cluster-show"/>
|
||||
<xref linkend="repmgr-service-pause"/>,
|
||||
<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>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
@@ -1,6 +1,6 @@
|
||||
<refentry id="repmgr-daemon-unpause">
|
||||
<refentry id="repmgr-service-unpause">
|
||||
<indexterm>
|
||||
<primary>repmgr daemon unpause</primary>
|
||||
<primary>repmgr service unpause</primary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
@@ -8,13 +8,12 @@
|
||||
<secondary>unpausing</secondary>
|
||||
</indexterm>
|
||||
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>repmgr daemon unpause</refentrytitle>
|
||||
<refentrytitle>repmgr service unpause</refentrytitle>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>repmgr daemon unpause</refname>
|
||||
<refname>repmgr service unpause</refname>
|
||||
<refpurpose>Instruct all &repmgrd; instances in the replication cluster to resume failover operations</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
@@ -23,24 +22,33 @@
|
||||
<para>
|
||||
This command can be run on any active node in the replication cluster to instruct all
|
||||
running &repmgrd; instances to "unpause"
|
||||
(following a previous execution of <xref linkend="repmgr-daemon-pause"/>)
|
||||
(following a previous execution of <xref linkend="repmgr-service-pause"/>)
|
||||
and resume normal failover/monitoring operation.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
It's important to wait a few seconds after restarting PostgreSQL on any node before running
|
||||
<command>repmgr daemon pause</command>, as the &repmgrd; instance
|
||||
<command>repmgr service pause</command>, as the &repmgrd; instance
|
||||
on the restarted node will take a second or two before it has updated its status.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
</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>
|
||||
<title>Execution</title>
|
||||
<para>
|
||||
<command>repmgr daemon unpause</command> can be executed on any active node in the
|
||||
<command>repmgr service unpause</command> can be executed on any active node in the
|
||||
replication cluster. A valid <filename>repmgr.conf</filename> file is required.
|
||||
It will have no effect on nodes which are not already paused.
|
||||
</para>
|
||||
@@ -50,7 +58,7 @@
|
||||
<title>Example</title>
|
||||
<para>
|
||||
<programlisting>
|
||||
$ repmgr -f /etc/repmgr.conf daemon unpause
|
||||
$ repmgr -f /etc/repmgr.conf service unpause
|
||||
NOTICE: node 1 (node1) unpaused
|
||||
NOTICE: node 2 (node2) unpaused
|
||||
NOTICE: node 3 (node3) unpaused</programlisting>
|
||||
@@ -74,7 +82,7 @@ NOTICE: node 3 (node3) unpaused</programlisting>
|
||||
<refsect1>
|
||||
<title>Exit codes</title>
|
||||
<para>
|
||||
One of the following exit codes will be emitted by <command>repmgr daemon unpause</command>:
|
||||
One of the following exit codes will be emitted by <command>repmgr service unpause</command>:
|
||||
</para>
|
||||
<variablelist>
|
||||
|
||||
@@ -102,7 +110,11 @@ NOTICE: node 3 (node3) unpaused</programlisting>
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<xref linkend="repmgr-daemon-pause"/>, <xref linkend="repmgr-daemon-status"/>
|
||||
<xref linkend="repmgr-service-pause"/>,
|
||||
<xref linkend="repmgr-service-status"/>,
|
||||
<xref linkend="repmgrd-pausing"/>,
|
||||
<xref linkend="repmgr-daemon-start"/>,
|
||||
<xref linkend="repmgr-daemon-stop"/>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
@@ -18,7 +18,7 @@
|
||||
<para>
|
||||
<command>repmgr standby clone</command> clones a PostgreSQL node from another
|
||||
PostgreSQL node, typically the primary, but optionally from any other node in
|
||||
the cluster or from Barman. It creates the <filename>recovery.conf</filename> file required
|
||||
the cluster or from Barman. It creates the replication configuration required
|
||||
to attach the cloned node to the primary node (or another standby, if cascading replication
|
||||
is in use).
|
||||
</para>
|
||||
@@ -85,15 +85,20 @@
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="repmgr-standby-clone-recovery-conf">
|
||||
<title>Customising recovery.conf</title>
|
||||
<title>Customising replication configuration</title>
|
||||
<indexterm>
|
||||
<primary>recovery.conf</primary>
|
||||
<secondary>customising with "repmgr standby clone"</secondary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>replication configuration</primary>
|
||||
<secondary>customising with "repmgr standby clone"</secondary>
|
||||
</indexterm>
|
||||
|
||||
|
||||
<para>
|
||||
By default, &repmgr; will create a minimal <filename>recovery.conf</filename>
|
||||
By default, &repmgr; will create a minimal replication configuration
|
||||
containing following parameters:
|
||||
</para>
|
||||
|
||||
@@ -119,7 +124,7 @@
|
||||
|
||||
<para>
|
||||
The following additional parameters can be specified in <filename>repmgr.conf</filename>
|
||||
for inclusion in <filename>recovery.conf</filename>:
|
||||
for inclusion in the replication configuration:
|
||||
</para>
|
||||
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
@@ -193,37 +198,50 @@
|
||||
<secondary>generating for a standby cloned by another method</secondary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>replication configuration</primary>
|
||||
<secondary>generating for a standby cloned by another method</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
&repmgr; supports standbys cloned by another method (e.g. using <application>barman</application>'s
|
||||
<command><ulink url="http://docs.pgbarman.org/release/2.5/#recover">barman recover</ulink></command> command).
|
||||
<command><ulink url="https://docs.pgbarman.org/#recover">barman recover</ulink></command> command).
|
||||
</para>
|
||||
<para>
|
||||
To integrate the standby as a &repmgr; node, once the standby has been cloned,
|
||||
ensure the <filename>repmgr.conf</filename>
|
||||
file is created for the node, and that it has been registered using
|
||||
<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>.
|
||||
This will create the <filename>recovery.conf</filename> file needed to attach
|
||||
the node to its upstream, and will also create a replication slot on the
|
||||
the node to its upstream (in PostgreSQL 12 and later: append replication configuration
|
||||
to <filename>postgresql.auto.conf</filename>), and will also create a replication slot on the
|
||||
upstream node if required.
|
||||
</para>
|
||||
<para>
|
||||
Note that the upstream node must be running. An existing
|
||||
Note that the upstream node must be running. In PostgreSQL 11 and earlier, an existing
|
||||
<filename>recovery.conf</filename> will not be overwritten unless the
|
||||
<option>-F/--force</option> option is provided.
|
||||
</para>
|
||||
<para>
|
||||
Execute <command>repmgr standby clone --recovery-conf-only --dry-run</command>
|
||||
to check the prerequisites for creating the <filename>recovery.conf</filename> file,
|
||||
and display the contents of the file without actually creating it.
|
||||
to check the prerequisites for creating the recovery configuration,
|
||||
and display the contents of the configuration which would be added without actually
|
||||
making any changes.
|
||||
</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>
|
||||
@@ -249,8 +267,8 @@
|
||||
</para>
|
||||
<para>
|
||||
If <option>--recovery-conf-only</option> specified, the contents of
|
||||
the generated <filename>recovery.conf</filename> file will be displayed
|
||||
but the file itself not written.
|
||||
the generated recovery configuration will be displayed
|
||||
but not written.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -297,8 +315,16 @@
|
||||
<term><option> --recovery-conf-only</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Create <filename>recovery.conf</filename> file for a previously cloned instance. &repmgr; 4.0.4 and later.
|
||||
Create recovery configuration for a previously cloned instance.
|
||||
</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>
|
||||
</varlistentry>
|
||||
|
||||
@@ -326,9 +352,13 @@
|
||||
<term><option>--upstream-conninfo</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>primary_conninfo</literal> value to write in recovery.conf
|
||||
<literal>primary_conninfo</literal> value to include in the recovery configuration
|
||||
when the intended upstream server does not yet exist.
|
||||
</para>
|
||||
<para>
|
||||
Note that &repmgr; may modify the provided value, in particular to set the
|
||||
correct <literal>application_name</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
@@ -20,49 +20,54 @@
|
||||
("follow target"). Typically this will be the primary, but this
|
||||
command can also be used to attach the standby to another standby.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This command requires a valid
|
||||
<filename>repmgr.conf</filename> file for the standby, either specified
|
||||
explicitly with <literal>-f/--config-file</literal> or located in a
|
||||
This command requires a valid <filename>repmgr.conf</filename> file for the standby,
|
||||
either specified explicitly with <literal>-f/--config-file</literal> or located in a
|
||||
default location; no additional arguments are required.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
By default &repmgr; will attempt to attach the standby to the current primary.
|
||||
If <option>--upstream-node-id</option> is provided, &repmgr; will attempt
|
||||
to attach the standby to the specified node, which can be another standby.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This command will force a restart of the standby server, which must be
|
||||
running.
|
||||
<para>The standby node ("follow candidate") <emphasis>must</emphasis>
|
||||
be running. If the new upstream ("follow target") is not the primary,
|
||||
the cluster primary <emphasis>must</emphasis> be running and accessible from the
|
||||
standby node.
|
||||
</para>
|
||||
|
||||
<tip>
|
||||
<tip>
|
||||
<para>
|
||||
To re-add an inactive node to the replication cluster, use
|
||||
<xref linkend="repmgr-node-rejoin"/>.
|
||||
To re-add an inactive node to the replication cluster, use
|
||||
<xref linkend="repmgr-node-rejoin"/>.
|
||||
</para>
|
||||
</tip>
|
||||
</tip>
|
||||
|
||||
<para>
|
||||
<command>repmgr standby follow</command> will wait up to
|
||||
<varname>standby_follow_timeout</varname> seconds (default: <literal>30</literal>)
|
||||
to verify the standby has actually connected to the new upstream node.
|
||||
</para>
|
||||
<para>
|
||||
By default &repmgr; will attempt to attach the standby to the current primary.
|
||||
If <option>--upstream-node-id</option> is provided, &repmgr; will attempt
|
||||
to attach the standby to the specified node, which can be another standby.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If <option>recovery_min_apply_delay</option> is set for the standby, it
|
||||
will not attach to the new upstream node until it has replayed available
|
||||
WAL.
|
||||
</para>
|
||||
<para>
|
||||
Conversely, if the standby is attached to an upstream standby
|
||||
which has <option>recovery_min_apply_delay</option> set, the upstream
|
||||
standby's replay state may actually be behind that of its new downstream node.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
This command will force a restart of PostgreSQL on the standby node.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>repmgr standby follow</command> will wait up to
|
||||
<varname>standby_follow_timeout</varname> seconds (default: <literal>30</literal>)
|
||||
to verify the standby has actually connected to the new upstream node.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If <option>recovery_min_apply_delay</option> is set for the standby, it
|
||||
will not attach to the new upstream node until it has replayed available
|
||||
WAL.
|
||||
</para>
|
||||
<para>
|
||||
Conversely, if the standby is attached to an upstream standby
|
||||
which has <option>recovery_min_apply_delay</option> set, the upstream
|
||||
standby's replay state may actually be behind that of its new downstream node.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
</refsect1>
|
||||
|
||||
@@ -124,7 +129,7 @@
|
||||
<para>
|
||||
Note that when using &repmgrd;, <option>--upstream-node-id</option>
|
||||
should always be configured;
|
||||
see <link linkend="repmgrd-automatic-failover-configuration">Automatic failover configuration</link>
|
||||
see <link linkend="repmgrd-automatic-failover-configuration">Automatic failover configuration</link>
|
||||
for details.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -166,7 +171,7 @@
|
||||
be possible to follow the new upstream node, and &repmgr; will emit an error
|
||||
message like this:
|
||||
<programlisting>
|
||||
ERROR: this node cannot attach to follow target node 3
|
||||
ERROR: this node cannot attach to follow target node "node3" (ID 3)
|
||||
DETAIL: follow target server's timeline 2 forked off current database system timeline 1 before current recovery point 0/6108880</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
<important>
|
||||
<para>
|
||||
If &repmgrd; is active, you must execute
|
||||
<command><link linkend="repmgr-daemon-pause">repmgr daemon pause</link></command>
|
||||
<command><link linkend="repmgr-service-pause">repmgr service 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 the replication cluster.
|
||||
</para>
|
||||
|
||||
@@ -75,10 +75,22 @@
|
||||
<para>
|
||||
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
|
||||
a complex replication cluster. In this case, by using the <option>-F/--force</option>
|
||||
option and providing the connection parameters to the primary server,
|
||||
the standby can be registered.
|
||||
a complex replication cluster, or if the node was not cloned by &repmgr;.
|
||||
</para>
|
||||
<para>
|
||||
In this case, by using the <option>-F/--force</option>
|
||||
option and providing the connection parameters to the primary server,
|
||||
the standby can be registered even if it has not yet been started.
|
||||
</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>
|
||||
Similarly, with cascading replication it may be necessary to register
|
||||
a standby whose upstream node has not yet been registered - in this case,
|
||||
@@ -96,9 +108,11 @@
|
||||
<title>Registering a node not cloned by repmgr</title>
|
||||
<para>
|
||||
If you've cloned a standby using another method (e.g. <application>barman</application>'s
|
||||
<command>barman recover</command> command), first execute
|
||||
<command><ulink url="https://docs.pgbarman.org/#recover">barman recover</ulink></command>
|
||||
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>
|
||||
to add the <filename>recovery.conf</filename> file, then register the standby as usual.
|
||||
to generate the appropriate replication configuration.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
@@ -119,7 +133,7 @@
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-F</option><option>--force</option></term>
|
||||
<term><option>-F</option>/<option>--force</option></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Overwrite an existing node record
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<abstract>
|
||||
<para>
|
||||
This is the official documentation of &repmgr; &repmgrversion; for
|
||||
use with PostgreSQL 9.3 - PostgreSQL 11.
|
||||
use with PostgreSQL 9.3 - PostgreSQL 12.
|
||||
</para>
|
||||
<para>
|
||||
&repmgr; is being continually developed and we strongly recommend using the
|
||||
@@ -116,11 +116,11 @@
|
||||
&repmgr-cluster-crosscheck;
|
||||
&repmgr-cluster-event;
|
||||
&repmgr-cluster-cleanup;
|
||||
&repmgr-daemon-status;
|
||||
&repmgr-service-status;
|
||||
&repmgr-service-pause;
|
||||
&repmgr-service-unpause;
|
||||
&repmgr-daemon-start;
|
||||
&repmgr-daemon-stop;
|
||||
&repmgr-daemon-pause;
|
||||
&repmgr-daemon-unpause;
|
||||
</part>
|
||||
|
||||
&appendix-release-notes;
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
For more complex replication scenarios,e.g. with multiple datacentres, it may
|
||||
For more complex replication scenarios, e.g. with multiple datacentres, it may
|
||||
be preferable to use location-based failover, which ensures that only nodes
|
||||
in the same location as the primary will ever be promotion candidates;
|
||||
see <xref linkend="repmgrd-network-split"/> for more details.
|
||||
@@ -199,9 +199,10 @@
|
||||
|
||||
<para>
|
||||
The time the primary was last seen by each node can be checked by executing
|
||||
<link linkend="repmgr-daemon-status"><command>repmgr daemon status</command></link>,
|
||||
<link linkend="repmgr-service-status"><command>repmgr service 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.:
|
||||
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
|
||||
<programlisting>$ repmgr -f /etc/repmgr.conf service status
|
||||
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
|
||||
----+-------+---------+-----------+----------+---------+-------+---------+--------------------
|
||||
1 | node1 | primary | * running | | running | 96563 | no | n/a
|
||||
@@ -267,11 +268,12 @@
|
||||
<para>
|
||||
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
|
||||
the local node's WAL receiver before making a failover decision.
|
||||
the local node's WAL receiver, and wait for the WAL receiver on all sibling nodes to be
|
||||
disconnected, before making a failover decision.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
<option>standby_disconnect_on_failover</option> is available from PostgreSQL 9.5 and later.
|
||||
<option>standby_disconnect_on_failover</option> is available with PostgreSQL 9.5 and later.
|
||||
Additionally this requires that the <literal>repmgr</literal> database user is a superuser.
|
||||
</para>
|
||||
</note>
|
||||
@@ -290,6 +292,12 @@
|
||||
plus however many seconds it takes to confirm the WAL receiver is disconnected before
|
||||
&repmgrd; proceeds with the failover decision.
|
||||
</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>
|
||||
Following the failover operation, no matter what the outcome, each node will reconnect its WAL receiver.
|
||||
</para>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
&repmgrd; is a daemon which runs on each PostgreSQL node,
|
||||
&repmgrd; is a daemon process which runs on each PostgreSQL node,
|
||||
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
|
||||
connected to.
|
||||
@@ -77,7 +77,7 @@
|
||||
<listitem>
|
||||
<simpara>
|
||||
<literal>connection</literal> - determines server availability
|
||||
by attempt ingto make a new connection to the upstream node
|
||||
by attempting to make a new connection to the upstream node
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
@@ -222,6 +222,17 @@
|
||||
Normally <option>promote_command</option> is set as &repmgr;'s
|
||||
<command><link linkend="repmgr-standby-promote">repmgr standby promote</link></command> command.
|
||||
</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>
|
||||
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>
|
||||
@@ -508,7 +519,8 @@
|
||||
</indexterm>
|
||||
<para>
|
||||
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> commands, the following
|
||||
and <link linkend="repmgr-daemon-stop"><command>repmgr daemon stop</command></link>
|
||||
commands, the following
|
||||
parameters <emphasis>must</emphasis> be set in <filename>repmgr.conf</filename>:
|
||||
<itemizedlist spacing="compact" mark="bullet">
|
||||
|
||||
@@ -524,10 +536,10 @@
|
||||
|
||||
</para>
|
||||
<para>
|
||||
Example (for &repmgr; with PostgreSQL 11 on CentOS 7):
|
||||
Example (for &repmgr; with PostgreSQL 12 on CentOS 7):
|
||||
<programlisting>
|
||||
repmgrd_service_start_command='sudo systemctl repmgr11 start'
|
||||
repmgrd_service_stop_command='sudo systemctl repmgr11 stop'
|
||||
repmgrd_service_start_command='sudo systemctl repmgr12 start'
|
||||
repmgrd_service_stop_command='sudo systemctl repmgr12 stop'
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
@@ -849,7 +861,7 @@ repmgrd_service_stop_command='sudo systemctl repmgr11 stop'
|
||||
<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> can be used
|
||||
as convenience wrappers to start and stop &repmgrd;.
|
||||
as convenience wrappers to start and stop &repmgrd; on the local node.
|
||||
</para>
|
||||
<important>
|
||||
<para>
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
<secondary>operation</secondary>
|
||||
</indexterm>
|
||||
|
||||
<sect1 id="repmgrd-pausing">
|
||||
<sect1 id="repmgrd-pausing" xreflabel="pausing the repmgrd service">
|
||||
|
||||
<title>Pausing repmgrd</title>
|
||||
<title>Pausing the repmgrd service</title>
|
||||
|
||||
<indexterm>
|
||||
<primary>repmgrd</primary>
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
<note>
|
||||
<para>
|
||||
For major PostgreSQL upgrades, e.g. from PostgreSQL 10 to PostgreSQL 11,
|
||||
For major PostgreSQL upgrades, e.g. from PostgreSQL 11 to PostgreSQL 12,
|
||||
&repmgrd; should be shut down completely and only started up
|
||||
once the &repmgr; packages for the new PostgreSQL major version have been installed.
|
||||
</para>
|
||||
@@ -88,17 +88,21 @@
|
||||
<sect2 id="repmgrd-pausing-execution">
|
||||
<title>Pausing/unpausing &repmgrd;</title>
|
||||
<para>
|
||||
To pause &repmgrd;, execute <link linkend="repmgr-daemon-pause"><command>repmgr daemon pause</command></link>, e.g.:
|
||||
To pause &repmgrd;, execute <link linkend="repmgr-service-pause"><command>repmgr service pause</command></link>
|
||||
(&repmgr; 4.2 - 4.4: <link linkend="repmgr-service-pause"><command>repmgr daemon pause</command></link>),
|
||||
e.g.:
|
||||
<programlisting>
|
||||
$ repmgr -f /etc/repmgr.conf daemon pause
|
||||
$ repmgr -f /etc/repmgr.conf service pause
|
||||
NOTICE: node 1 (node1) paused
|
||||
NOTICE: node 2 (node2) paused
|
||||
NOTICE: node 3 (node3) paused</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The state of &repmgrd; on each node can be checked with
|
||||
<link linkend="repmgr-daemon-status"><command>repmgr daemon status</command></link>, e.g.:
|
||||
<programlisting>$ repmgr -f /etc/repmgr.conf daemon status
|
||||
<link linkend="repmgr-service-status"><command>repmgr service status</command></link>
|
||||
(&repmgr; 4.2 - 4.4: <link linkend="repmgr-service-status"><command>repmgr daemon status</command></link>),
|
||||
e.g.:
|
||||
<programlisting>$ repmgr -f /etc/repmgr.conf service status
|
||||
ID | Name | Role | Status | repmgrd | PID | Paused?
|
||||
----+-------+---------+---------+---------+------+---------
|
||||
1 | node1 | primary | running | running | 7851 | yes
|
||||
@@ -108,8 +112,8 @@ NOTICE: node 3 (node3) paused</programlisting>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If executing a switchover with <link linkend="repmgr-standby-switchover"><command>repmgr standby switchover</command></link>,
|
||||
&repmgr; will automatically pause/unpause &repmgrd; as part of the switchover process.
|
||||
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.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
@@ -117,29 +121,32 @@ NOTICE: node 3 (node3) paused</programlisting>
|
||||
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:
|
||||
<programlisting>
|
||||
[2018-09-20 12:22:21] [WARNING] unable to connect to upstream node "node1" (ID: 1)
|
||||
[2018-09-20 12:22:21] [INFO] checking state of node 1, 1 of 5 attempts
|
||||
[2018-09-20 12:22:21] [INFO] sleeping 1 seconds until next reconnection attempt
|
||||
[2019-08-28 12:22:21] [WARNING] unable to connect to upstream node "node1" (node ID: 1)
|
||||
[2019-08-28 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:24] [INFO] sleeping 1 seconds until next reconnection attempt
|
||||
[2018-09-20 12:22:25] [INFO] checking state of node 1, 5 of 5 attempts
|
||||
[2018-09-20 12:22:25] [WARNING] unable to reconnect to node 1 after 5 attempts
|
||||
[2018-09-20 12:22:25] [NOTICE] node is paused
|
||||
[2018-09-20 12:22:33] [INFO] node "node2" (ID: 2) monitoring upstream node "node1" (ID: 1) in degraded state
|
||||
[2018-09-20 12:22:33] [DETAIL] repmgrd paused by administrator
|
||||
[2018-09-20 12:22:33] [HINT] execute "repmgr daemon unpause" to resume normal failover mode</programlisting>
|
||||
[2019-08-28 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
|
||||
[2019-08-28 12:22:25] [WARNING] unable to reconnect to node 1 after 5 attempts
|
||||
[2019-08-28 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
|
||||
[2019-08-28 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>
|
||||
</para>
|
||||
<para>
|
||||
If the primary becomes available again (e.g. following a software upgrade), &repmgrd;
|
||||
will automatically reconnect, e.g.:
|
||||
<programlisting>
|
||||
[2018-09-20 13:12:41] [NOTICE] reconnected to upstream node 1 after 8 seconds, resuming monitoring</programlisting>
|
||||
[2019-08-28 12:25:41] [NOTICE] reconnected to upstream node 1 after 8 seconds, resuming monitoring</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To unpause &repmgrd;, execute <link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link>, e.g.:
|
||||
To unpause the &repmgrd; service, execute
|
||||
<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>
|
||||
$ repmgr -f /etc/repmgr.conf daemon unpause
|
||||
$ repmgr -f /etc/repmgr.conf service unpause
|
||||
NOTICE: node 1 (node1) unpaused
|
||||
NOTICE: node 2 (node2) unpaused
|
||||
NOTICE: node 3 (node3) unpaused</programlisting>
|
||||
@@ -150,11 +157,11 @@ NOTICE: node 3 (node3) unpaused</programlisting>
|
||||
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
|
||||
<link linkend="repmgr-standby-promote"><command>repmgr standby promote</command></link>,
|
||||
and any standbys attached to the new primary with
|
||||
<link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>.
|
||||
and any standbys attached to the new primary with
|
||||
<link linkend="repmgr-standby-follow"><command>repmgr standby follow</command></link>.
|
||||
</para>
|
||||
<para>
|
||||
This is to prevent <link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link>
|
||||
This is to prevent execution of <link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link>
|
||||
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
|
||||
candidate to the one intended by the administrator.
|
||||
@@ -168,17 +175,23 @@ NOTICE: node 3 (node3) unpaused</programlisting>
|
||||
The pause state of each node will be stored over a PostgreSQL restart.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<link linkend="repmgr-daemon-pause"><command>repmgr daemon pause</command></link> and
|
||||
<link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link> can be
|
||||
executed even if &repmgrd; is not running; in this case,
|
||||
&repmgrd; will start up in whichever pause state has been set.
|
||||
</para>
|
||||
<para>
|
||||
<link linkend="repmgr-service-pause"><command>repmgr service pause</command></link> and
|
||||
<link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link> can be
|
||||
executed even if &repmgrd; is not running; in this case,
|
||||
&repmgrd; will start up in whichever pause state has been set.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
<link linkend="repmgr-daemon-pause"><command>repmgr daemon pause</command></link> and
|
||||
<link linkend="repmgr-daemon-unpause"><command>repmgr daemon unpause</command></link>
|
||||
<emphasis>do not</emphasis> stop/start &repmgrd;.
|
||||
<link linkend="repmgr-service-pause"><command>repmgr service pause</command></link> and
|
||||
<link linkend="repmgr-service-unpause"><command>repmgr service unpause</command></link>
|
||||
<emphasis>do not</emphasis> start/stop &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>
|
||||
</note>
|
||||
</sect2>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<simpara>
|
||||
ability to <link linkend="repmgrd-pausing">pause repmgrd</link>
|
||||
operation on all nodes with a
|
||||
<link linkend="repmgr-daemon-pause"><command>single command</command></link>
|
||||
<link linkend="repmgr-service-pause"><command>single command</command></link>
|
||||
</simpara>
|
||||
</listitem>
|
||||
|
||||
@@ -100,11 +100,11 @@
|
||||
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:
|
||||
<programlisting>
|
||||
[2019-03-15 06:32:05] [NOTICE] repmgrd (repmgrd 4.3) starting up
|
||||
[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-11.pid
|
||||
[2019-03-15 06:32:05] [NOTICE] starting monitoring of node "node2" (ID: 2)
|
||||
[2019-03-15 06:32:05] [INFO] monitoring connection to upstream node "node1" (ID: 1)</programlisting>
|
||||
[2019-08-15 07:14:42] [NOTICE] repmgrd (repmgrd 5.0) starting up
|
||||
[2019-08-15 07:14:42] [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
|
||||
[2019-08-15 07:14:42] [NOTICE] starting monitoring of node "node2" (ID: 2)
|
||||
[2019-08-15 07:14:42] [INFO] monitoring connection to upstream node "node1" (ID: 1)</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
Node ID | Name | Event | OK | Timestamp | Details
|
||||
---------+-------+---------------+----+---------------------+--------------------------------------------------------
|
||||
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-03-14 04:11:47 | monitoring connection to upstream node "node1" (ID: 1)
|
||||
1 | node1 | repmgrd_start | t | 2019-03-14 04:04:31 | monitoring cluster primary "node1" (ID: 1)</programlisting>
|
||||
3 | node3 | repmgrd_start | t | 2019-08-15 07:14:42 | 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)
|
||||
1 | node1 | repmgrd_start | t | 2019-08-15 07:14:39 | monitoring cluster primary "node1" (ID: 1)</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
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>)
|
||||
which has promoted to new primary after failure of the original primary (<literal>node1</literal>).
|
||||
<programlisting>
|
||||
[2019-03-15 06:37:50] [WARNING] unable to connect to upstream node "node1" (ID: 1)
|
||||
[2019-03-15 06:37:50] [INFO] checking state of node 1, 1 of 3 attempts
|
||||
[2019-03-15 06:37:50] [INFO] sleeping 5 seconds until next reconnection attempt
|
||||
[2019-03-15 06:37:55] [INFO] checking state of node 1, 2 of 3 attempts
|
||||
[2019-03-15 06:37:55] [INFO] sleeping 5 seconds until next reconnection attempt
|
||||
[2019-03-15 06:38:00] [INFO] checking state of node 1, 3 of 3 attempts
|
||||
[2019-03-15 06:38:00] [WARNING] unable to reconnect to node 1 after 3 attempts
|
||||
[2019-03-15 06:38:00] [INFO] primary and this node have the same location ("default")
|
||||
[2019-03-15 06:38:00] [INFO] local node's last receive lsn: 0/900CBF8
|
||||
[2019-03-15 06:38:00] [INFO] node 3 last saw primary node 12 second(s) ago
|
||||
[2019-03-15 06:38:00] [INFO] last receive LSN for sibling node "node3" (ID: 3) is: 0/900CBF8
|
||||
[2019-03-15 06:38:00] [INFO] node "node3" (ID: 3) has same LSN as current candidate "node2" (ID: 2)
|
||||
[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-03-15 06:38:00] [NOTICE] promotion candidate is "node2" (ID: 2)
|
||||
[2019-03-15 06:38:00] [NOTICE] this node is the winner, will now promote itself and inform other nodes
|
||||
[2019-03-15 06:38:00] [INFO] promote_command is:
|
||||
"/usr/pgsql-11/bin/repmgr -f /etc/repmgr/11/repmgr.conf standby promote"
|
||||
[2019-08-15 07:27: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-08-15 07:27: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-08-15 07:27: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-08-15 07:28: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-08-15 07:28: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-08-15 07:28: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-08-15 07:28: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-08-15 07:28: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:
|
||||
"/usr/pgsql-12/bin/repmgr -f /etc/repmgr/12/repmgr.conf standby promote"
|
||||
NOTICE: promoting standby to primary
|
||||
DETAIL: promoting server "node2" (ID: 2) using "/usr/pgsql-11/bin/pg_ctl -w -D '/var/lib/pgsql/11/data' promote"
|
||||
DETAIL: promoting server "node2" (ID: 2) using "/usr/pgsql-12/bin/pg_ctl -w -D '/var/lib/pgsql/12/data' promote"
|
||||
NOTICE: waiting up to 60 seconds (parameter "promote_check_timeout") for promotion to complete
|
||||
NOTICE: STANDBY PROMOTE successful
|
||||
DETAIL: server "node2" (ID: 2) was successfully promoted to primary
|
||||
[2019-03-15 06:38:01] [INFO] 3 followers to notify
|
||||
[2019-03-15 06:38:01] [NOTICE] notifying node "node3" (ID: 3) to follow node 2
|
||||
[2019-08-15 07:28:01] [INFO] 3 followers to notify
|
||||
[2019-08-15 07:28:01] [NOTICE] notifying node "node3" (ID: 3) to follow node 2
|
||||
INFO: node 3 received notification to follow node 2
|
||||
[2019-03-15 06:38:01] [INFO] switching to primary monitoring mode
|
||||
[2019-03-15 06:38:01] [NOTICE] monitoring cluster primary "node2" (ID: 2)</programlisting>
|
||||
[2019-08-15 07:28:01] [INFO] switching to primary monitoring mode
|
||||
[2019-08-15 07:28:01] [NOTICE] monitoring cluster primary "node2" (ID: 2)</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
Node ID | Name | Event | OK | Timestamp | Details
|
||||
---------+-------+----------------------------+----+---------------------+-------------------------------------------------------------
|
||||
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-03-15 06:38:02 | standby attached to upstream node "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-03-15 06:38:01 | node 2 promoted to primary; old primary 1 marked as failed
|
||||
2 | node2 | standby_promote | t | 2019-03-15 06:38:01 | server "node2" (ID: 2) was successfully promoted to primary</programlisting>
|
||||
3 | node3 | repmgrd_failover_follow | t | 2019-08-15 07: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)
|
||||
2 | node2 | repmgrd_reload | t | 2019-08-15 07: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 | standby_promote | t | 2019-08-15 07:38:01 | server "node2" (ID: 2) was successfully promoted to primary</programlisting>
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
@@ -317,7 +317,9 @@
|
||||
</para>
|
||||
<para>
|
||||
If &repmgrd; is in use, it's worth double-checking that
|
||||
all nodes are unpaused by executing <command><link linkend="repmgr-daemon-status">repmgr-daemon-status</link></command>.
|
||||
all nodes are unpaused by executing
|
||||
<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>
|
||||
|
||||
<note>
|
||||
|
||||
@@ -216,7 +216,9 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<secondary>checking repmgrd status</secondary>
|
||||
</indexterm>
|
||||
<para>
|
||||
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>
|
||||
From <link linkend="release-4.2">repmgr 4.2</link>, once the upgrade is complete, execute the
|
||||
<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.
|
||||
</para>
|
||||
</sect2>
|
||||
@@ -263,7 +265,7 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<tip>
|
||||
<para>
|
||||
Use <command><link linkend="repmgr-node-check">repmgr node check</link></command>
|
||||
to determine which replacation slots need to be recreated.
|
||||
to determine which replication slots need to be recreated.
|
||||
</para>
|
||||
</tip>
|
||||
|
||||
@@ -417,13 +419,13 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<programlisting>
|
||||
$ ./convert-config.pl /etc/repmgr.conf
|
||||
node_id=2
|
||||
node_name=node2
|
||||
conninfo=host=node2 dbname=repmgr user=repmgr connect_timeout=2
|
||||
node_name='node2'
|
||||
conninfo='host=node2 dbname=repmgr user=repmgr connect_timeout=2'
|
||||
pg_ctl_options='-l /var/log/postgres/startup.log'
|
||||
rsync_options=--exclude=postgresql.local.conf --archive
|
||||
log_level=INFO
|
||||
pg_basebackup_options=--no-slot
|
||||
data_directory=</programlisting>
|
||||
rsync_options='--exclude=postgresql.local.conf --archive'
|
||||
log_level='INFO'
|
||||
pg_basebackup_options='--no-slot'
|
||||
data_directory=''</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The converted file is printed to <literal>STDOUT</literal> and the original file is not
|
||||
@@ -432,8 +434,7 @@ ALTER EXTENSION repmgr UPDATE</programlisting>
|
||||
<para>
|
||||
Please note that the the conversion script will add an empty
|
||||
placeholder parameter for <varname>data_directory</varname>, which
|
||||
is a required parameter in repmgr4 and which <emphasis>must</emphasis>
|
||||
be provided.
|
||||
is a required parameter from &repmgr; 4.
|
||||
</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
@@ -78,8 +78,6 @@ CREATE VIEW repmgr.show_nodes AS
|
||||
LEFT JOIN repmgr.nodes un
|
||||
ON un.node_id = n.upstream_node_id;
|
||||
|
||||
|
||||
/* XXX update upgrade scripts! */
|
||||
CREATE TABLE repmgr.voting_term (
|
||||
term INT NOT NULL
|
||||
);
|
||||
|
||||
@@ -78,8 +78,6 @@ CREATE VIEW repmgr.show_nodes AS
|
||||
LEFT JOIN repmgr.nodes un
|
||||
ON un.node_id = n.upstream_node_id;
|
||||
|
||||
|
||||
/* XXX update upgrade scripts! */
|
||||
CREATE TABLE repmgr.voting_term (
|
||||
term INT NOT NULL
|
||||
);
|
||||
|
||||
@@ -78,8 +78,6 @@ CREATE VIEW repmgr.show_nodes AS
|
||||
LEFT JOIN repmgr.nodes un
|
||||
ON un.node_id = n.upstream_node_id;
|
||||
|
||||
|
||||
/* XXX update upgrade scripts! */
|
||||
CREATE TABLE repmgr.voting_term (
|
||||
term INT NOT NULL
|
||||
);
|
||||
|
||||
@@ -78,8 +78,6 @@ CREATE VIEW repmgr.show_nodes AS
|
||||
LEFT JOIN repmgr.nodes un
|
||||
ON un.node_id = n.upstream_node_id;
|
||||
|
||||
|
||||
/* XXX update upgrade scripts! */
|
||||
CREATE TABLE repmgr.voting_term (
|
||||
term INT NOT NULL
|
||||
);
|
||||
|
||||
5
repmgr--4.4--5.0.sql
Normal file
5
repmgr--4.4--5.0.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- 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;
|
||||
|
||||
@@ -78,8 +78,6 @@ CREATE VIEW repmgr.show_nodes AS
|
||||
LEFT JOIN repmgr.nodes un
|
||||
ON un.node_id = n.upstream_node_id;
|
||||
|
||||
|
||||
/* XXX update upgrade scripts! */
|
||||
CREATE TABLE repmgr.voting_term (
|
||||
term INT NOT NULL
|
||||
);
|
||||
|
||||
224
repmgr--5.0.sql
Normal file
224
repmgr--5.0.sql
Normal file
@@ -0,0 +1,224 @@
|
||||
-- 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
|
||||
);
|
||||
|
||||
@@ -987,7 +987,19 @@ build_cluster_matrix(t_node_matrix_rec ***matrix_rec_dest, int *name_length, Ite
|
||||
make_remote_repmgr_path(&command, cell->node_info);
|
||||
|
||||
appendPQExpBufferStr(&command,
|
||||
" cluster show --csv -L NOTICE --terse\"");
|
||||
" cluster show --csv --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);
|
||||
|
||||
@@ -1175,7 +1187,18 @@ build_cluster_crosscheck(t_node_status_cube ***dest_cube, int *name_length, Item
|
||||
make_remote_repmgr_path(&command, cell->node_info);
|
||||
|
||||
appendPQExpBufferStr(&command,
|
||||
" cluster matrix --csv -L NOTICE --terse");
|
||||
" cluster matrix --csv --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);
|
||||
|
||||
|
||||
@@ -26,478 +26,9 @@
|
||||
#include "repmgr-client-global.h"
|
||||
#include "repmgr-action-daemon.h"
|
||||
|
||||
#define REPMGR_DAEMON_STOP_START_WAIT 15
|
||||
#define REPMGR_DAEMON_STATUS_START_HINT _("use \"repmgr daemon status\" to confirm that repmgrd was successfully started")
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
#define REPMGR_SERVICE_STOP_START_WAIT 15
|
||||
#define REPMGR_SERVICE_STATUS_START_HINT _("use \"repmgr service 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")
|
||||
|
||||
void
|
||||
do_daemon_start(void)
|
||||
@@ -583,12 +114,12 @@ do_daemon_start(void)
|
||||
|
||||
if (runtime_options.no_wait == true || runtime_options.wait == 0)
|
||||
{
|
||||
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
|
||||
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = 0;
|
||||
int timeout = REPMGR_DAEMON_STOP_START_WAIT;
|
||||
int timeout = REPMGR_SERVICE_STOP_START_WAIT;
|
||||
|
||||
if (runtime_options.wait_provided)
|
||||
timeout = runtime_options.wait;
|
||||
@@ -598,7 +129,7 @@ do_daemon_start(void)
|
||||
if (PQstatus(conn) != CONNECTION_OK)
|
||||
{
|
||||
log_notice(_("unable to connect to local node"));
|
||||
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
|
||||
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
|
||||
exit(ERR_DB_CONN);
|
||||
}
|
||||
|
||||
@@ -616,7 +147,7 @@ do_daemon_start(void)
|
||||
PQfinish(conn);
|
||||
log_error(_("repmgrd does not appear to have started after %i seconds"),
|
||||
timeout);
|
||||
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
|
||||
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
|
||||
exit(ERR_REPMGRD_SERVICE);
|
||||
}
|
||||
|
||||
@@ -712,12 +243,12 @@ void do_daemon_stop(void)
|
||||
if (runtime_options.no_wait == true || runtime_options.wait == 0)
|
||||
{
|
||||
if (have_db_connection == true)
|
||||
log_hint(REPMGR_DAEMON_STATUS_STOP_HINT);
|
||||
log_hint(REPMGR_SERVICE_STATUS_STOP_HINT);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = 0;
|
||||
int timeout = REPMGR_DAEMON_STOP_START_WAIT;
|
||||
int timeout = REPMGR_SERVICE_STOP_START_WAIT;
|
||||
/*
|
||||
*
|
||||
*/
|
||||
@@ -732,7 +263,7 @@ void do_daemon_stop(void)
|
||||
log_warning(_("unable to determine repmgrd PID"));
|
||||
|
||||
if (have_db_connection == true)
|
||||
log_hint(REPMGR_DAEMON_STATUS_STOP_HINT);
|
||||
log_hint(REPMGR_SERVICE_STATUS_STOP_HINT);
|
||||
|
||||
exit(ERR_REPMGRD_SERVICE);
|
||||
}
|
||||
@@ -764,7 +295,7 @@ void do_daemon_stop(void)
|
||||
timeout);
|
||||
|
||||
if (have_db_connection == true)
|
||||
log_hint(REPMGR_DAEMON_STATUS_START_HINT);
|
||||
log_hint(REPMGR_SERVICE_STATUS_START_HINT);
|
||||
|
||||
exit(ERR_REPMGRD_SERVICE);
|
||||
}
|
||||
@@ -783,53 +314,29 @@ void do_daemon_help(void)
|
||||
print_help_header();
|
||||
|
||||
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 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("");
|
||||
|
||||
printf(_("DAEMON START\n"));
|
||||
puts("");
|
||||
printf(_(" \"daemon start\" attempts to start repmgrd\n"));
|
||||
printf(_(" \"daemon start\" attempts to start repmgrd on the local node\n"));
|
||||
puts("");
|
||||
printf(_(" --dry-run check prerequisites but don't start repmgrd\n"));
|
||||
printf(_(" -w/--wait wait for repmgrd to start (default: %i seconds)\n"), REPMGR_DAEMON_STOP_START_WAIT);
|
||||
printf(_(" -w/--wait wait for repmgrd to start (default: %i seconds)\n"), REPMGR_SERVICE_STOP_START_WAIT);
|
||||
printf(_(" --no-wait don't wait for repmgrd to start\n"));
|
||||
puts("");
|
||||
|
||||
printf(_("DAEMON STOP\n"));
|
||||
puts("");
|
||||
printf(_(" \"daemon stop\" attempts to stop repmgrd\n"));
|
||||
printf(_(" \"daemon stop\" attempts to stop repmgrd on the local node\n"));
|
||||
puts("");
|
||||
printf(_(" --dry-run check prerequisites but don't stop repmgrd\n"));
|
||||
printf(_(" -w/--wait wait for repmgrd to stop (default: %i seconds)\n"), REPMGR_DAEMON_STOP_START_WAIT);
|
||||
printf(_(" -w/--wait wait for repmgrd to stop (default: %i seconds)\n"), REPMGR_SERVICE_STOP_START_WAIT);
|
||||
printf(_(" --no-wait don't wait for repmgrd to stop\n"));
|
||||
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("");
|
||||
|
||||
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,10 +19,6 @@
|
||||
#ifndef _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_stop(void);
|
||||
|
||||
|
||||
@@ -1833,7 +1833,7 @@ do_node_check_data_directory(PGconn *conn, OutputMode mode, t_node_info *node_in
|
||||
* a superuser connection
|
||||
*/
|
||||
|
||||
if (is_superuser_connection(conn, NULL) == true)
|
||||
if (connection_has_pg_settings(conn) == true)
|
||||
{
|
||||
/* we expect to have a database connection */
|
||||
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 */
|
||||
if (PQserverVersion(conn) >= 100000)
|
||||
{
|
||||
log_hint(_("add the \"%s\" user to group \"pg_read_all_settings\""),
|
||||
log_hint(_("add the \"%s\" user to group \"pg_read_all_settings\" or \"pg_monitor\""),
|
||||
PQuser(conn));
|
||||
}
|
||||
}
|
||||
|
||||
535
repmgr-action-service.c
Normal file
535
repmgr-action-service.c
Normal file
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* 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("");
|
||||
}
|
||||
28
repmgr-action-service.h
Normal file
28
repmgr-action-service.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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,8 +112,10 @@ static void get_barman_property(char *dst, char *name, char *local_repmgr_direct
|
||||
static int get_tablespace_data_barman(char *, TablespaceDataList *);
|
||||
static char *make_barman_ssh_command(char *buf);
|
||||
|
||||
static bool create_recovery_file(t_node_info *node_record, t_conninfo_param_list *recovery_conninfo, char *dest, bool as_file);
|
||||
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 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_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);
|
||||
@@ -133,12 +135,13 @@ static bool parse_data_directory_config(const char *node_check_output);
|
||||
*
|
||||
* Parameters:
|
||||
* --upstream-conninfo
|
||||
* --upstream-node-id
|
||||
* --no-upstream-connection
|
||||
* -F/--force
|
||||
* --dry-run
|
||||
* -c/--fast-checkpoint
|
||||
* --copy-external-config-files
|
||||
* --recovery-min-apply-delay
|
||||
* -R/--remote-user
|
||||
* --replication-user (only required if no upstream record)
|
||||
* --without-barman
|
||||
* --recovery-conf-only
|
||||
@@ -215,7 +218,7 @@ do_standby_clone(void)
|
||||
|
||||
/*
|
||||
* Initialise list of conninfo parameters which will later be used to
|
||||
* create the `primary_conninfo` string in recovery.conf .
|
||||
* create the "primary_conninfo" recovery parameter.
|
||||
*
|
||||
* 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
|
||||
@@ -665,10 +668,21 @@ do_standby_clone(void)
|
||||
|
||||
/* Write the recovery.conf file */
|
||||
|
||||
if (create_recovery_file(&local_node_record, &recovery_conninfo, local_data_directory, true) == false)
|
||||
if (create_recovery_file(&local_node_record,
|
||||
&recovery_conninfo,
|
||||
source_server_version_num,
|
||||
local_data_directory,
|
||||
true) == false)
|
||||
{
|
||||
/* create_recovery_file() will log an error */
|
||||
log_notice(_("unable to create recovery.conf; see preceding error messages"));
|
||||
if (source_server_version_num >= 120000)
|
||||
{
|
||||
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"),
|
||||
local_data_directory);
|
||||
|
||||
@@ -1171,60 +1185,92 @@ _do_create_recovery_conf(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* check if recovery.conf exists */
|
||||
|
||||
snprintf(recovery_file_path, sizeof(recovery_file_path),
|
||||
"%s/%s",
|
||||
local_data_directory,
|
||||
RECOVERY_COMMAND_FILE);
|
||||
|
||||
if (stat(recovery_file_path, &st) == -1)
|
||||
/* check if recovery.conf exists (Pg11 and earlier only) */
|
||||
if (PQserverVersion(upstream_conn) < 120000)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
log_error(_("unable to check for existing \"recovery.conf\" file in \"%s\""),
|
||||
local_data_directory);
|
||||
log_detail("%s", strerror(errno));
|
||||
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);
|
||||
}
|
||||
snprintf(recovery_file_path, sizeof(recovery_file_path),
|
||||
"%s/%s",
|
||||
local_data_directory,
|
||||
RECOVERY_COMMAND_FILE);
|
||||
|
||||
if (runtime_options.dry_run == true)
|
||||
if (stat(recovery_file_path, &st) == -1)
|
||||
{
|
||||
log_warning(_("the existing \"recovery.conf\" file would be overwritten"));
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
log_error(_("unable to check for existing \"recovery.conf\" file in \"%s\""),
|
||||
local_data_directory);
|
||||
log_detail("%s", strerror(errno));
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_warning(_("the existing \"recovery.conf\" file will be overwritten"));
|
||||
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
|
||||
{
|
||||
log_warning(_("the existing \"recovery.conf\" file will be overwritten"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime_options.dry_run == true)
|
||||
{
|
||||
char recovery_conf_contents[MAXLEN] = "";
|
||||
create_recovery_file(&local_node_record, &recovery_conninfo, recovery_conf_contents, false);
|
||||
create_recovery_file(&local_node_record,
|
||||
&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);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!create_recovery_file(&local_node_record, &recovery_conninfo, local_data_directory, true))
|
||||
if (!create_recovery_file(&local_node_record,
|
||||
&recovery_conninfo,
|
||||
PQserverVersion(upstream_conn),
|
||||
local_data_directory,
|
||||
true))
|
||||
{
|
||||
log_error(_("unable to create \"recovery.conf\""));
|
||||
if (PQserverVersion(upstream_conn) >= 120000)
|
||||
{
|
||||
log_error(_("unable to write replication configuration to \"postgresql.auto.conf\""));
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error(_("unable to create \"recovery.conf\""));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_notice(_("\"recovery.conf\" created as \"%s\""), recovery_file_path);
|
||||
if (PQserverVersion(upstream_conn) >= 120000)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -1233,6 +1279,23 @@ _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 */
|
||||
if (slot_creation_required == true)
|
||||
{
|
||||
@@ -2784,12 +2847,6 @@ do_standby_follow(void)
|
||||
|
||||
PQfinish(local_conn);
|
||||
|
||||
if (runtime_options.dry_run == true)
|
||||
{
|
||||
log_info(_("prerequisites for executing STANDBY FOLLOW are met"));
|
||||
exit(SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we'll need a connection to the primary, if the upstream is not a primary.
|
||||
*/
|
||||
@@ -2802,12 +2859,30 @@ do_standby_follow(void)
|
||||
primary_conn = get_primary_connection_quiet(follow_target_conn,
|
||||
&primary_node_id,
|
||||
NULL);
|
||||
|
||||
/*
|
||||
* If follow target is not primary and no other primary could be found,
|
||||
* abort because we won't be able to update the node record.
|
||||
*/
|
||||
if (PQstatus(primary_conn) != CONNECTION_OK)
|
||||
{
|
||||
log_error(_("unable to determine the cluster primary"));
|
||||
log_detail(_("an active primary node is required for \"repmgr standby follow\""));
|
||||
PQfinish(follow_target_conn);
|
||||
exit(ERR_FOLLOW_FAIL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
primary_conn = follow_target_conn;
|
||||
}
|
||||
|
||||
if (runtime_options.dry_run == true)
|
||||
{
|
||||
log_info(_("prerequisites for executing STANDBY FOLLOW are met"));
|
||||
exit(SUCCESS);
|
||||
}
|
||||
|
||||
initPQExpBuffer(&follow_output);
|
||||
|
||||
success = do_standby_follow_internal(
|
||||
@@ -2991,57 +3066,22 @@ do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_n
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise connection parameters to write as `primary_conninfo` */
|
||||
initialize_conninfo_params(&recovery_conninfo, false);
|
||||
|
||||
/* We ignore any application_name set in the primary's conninfo */
|
||||
parse_conninfo_string(follow_target_node_record->conninfo, &recovery_conninfo, &errmsg, true);
|
||||
|
||||
/*
|
||||
* store the original upstream node id so we can delete the
|
||||
* replication slot, if exists
|
||||
*/
|
||||
if (local_node_record.upstream_node_id != UNKNOWN_NODE_ID)
|
||||
{
|
||||
t_conninfo_param_list local_node_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER;
|
||||
bool parse_success;
|
||||
original_upstream_node_id = local_node_record.upstream_node_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
original_upstream_node_id = follow_target_node_record->node_id;
|
||||
}
|
||||
|
||||
initialize_conninfo_params(&local_node_conninfo, false);
|
||||
|
||||
parse_success = parse_conninfo_string(local_node_record.conninfo, &local_node_conninfo, &errmsg, false);
|
||||
|
||||
if (parse_success == false)
|
||||
{
|
||||
/*
|
||||
* this shouldn't happen, but if it does we'll plough on
|
||||
* regardless
|
||||
*/
|
||||
log_warning(_("unable to parse conninfo string \"%s\":\n %s"),
|
||||
local_node_record.conninfo, errmsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *application_name = param_get(&local_node_conninfo, "application_name");
|
||||
|
||||
if (application_name != NULL && strlen(application_name))
|
||||
param_set(&recovery_conninfo, "application_name", application_name);
|
||||
}
|
||||
|
||||
free_conninfo_params(&local_node_conninfo);
|
||||
|
||||
/*
|
||||
* store the original upstream node id so we can delete the
|
||||
* replication slot, if exists
|
||||
*/
|
||||
if (local_node_record.upstream_node_id != UNKNOWN_NODE_ID)
|
||||
{
|
||||
original_upstream_node_id = local_node_record.upstream_node_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
original_upstream_node_id = follow_target_node_record->node_id;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/* Fetch original upstream's record */
|
||||
@@ -3066,6 +3106,12 @@ do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_n
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise connection parameters to write as "primary_conninfo" */
|
||||
initialize_conninfo_params(&recovery_conninfo, false);
|
||||
|
||||
/* We ignore any application_name set in the primary's conninfo */
|
||||
parse_conninfo_string(follow_target_node_record->conninfo, &recovery_conninfo, &errmsg, true);
|
||||
|
||||
/* Set the application name to this node's name */
|
||||
param_set(&recovery_conninfo, "application_name", config_file_options.node_name);
|
||||
|
||||
@@ -3075,7 +3121,11 @@ do_standby_follow_internal(PGconn *primary_conn, PGconn *follow_target_conn, t_n
|
||||
log_notice(_("setting node %i's upstream to node %i"),
|
||||
config_file_options.node_id, follow_target_node_record->node_id);
|
||||
|
||||
if (!create_recovery_file(&local_node_record, &recovery_conninfo, config_file_options.data_directory, true))
|
||||
if (!create_recovery_file(&local_node_record,
|
||||
&recovery_conninfo,
|
||||
PQserverVersion(primary_conn),
|
||||
config_file_options.data_directory,
|
||||
true))
|
||||
{
|
||||
*error_code = general_error_code;
|
||||
return false;
|
||||
@@ -4732,7 +4782,7 @@ do_standby_switchover(void)
|
||||
log_warning(_("unable to unpause repmgrd on %i node(s)"),
|
||||
error_node_count);
|
||||
log_detail(_("errors encountered for following node(s):\n%s"), detail.data);
|
||||
log_hint(_("check node connection and status; unpause manually with \"repmgr daemon unpause\""));
|
||||
log_hint(_("check node connection and status; unpause manually with \"repmgr service unpause\""));
|
||||
|
||||
termPQExpBuffer(&detail);
|
||||
}
|
||||
@@ -4769,6 +4819,7 @@ check_source_server()
|
||||
t_node_info upstream_node_record = T_NODE_INFO_INITIALIZER;
|
||||
RecordStatus record_status = RECORD_NOT_FOUND;
|
||||
ExtensionStatus extension_status = REPMGR_UNKNOWN;
|
||||
t_extension_versions extversions = T_EXTENSION_VERSIONS_INITIALIZER;
|
||||
|
||||
/* Attempt to connect to the upstream server to verify its configuration */
|
||||
log_verbose(LOG_DEBUG, "check_source_server()");
|
||||
@@ -4832,7 +4883,7 @@ check_source_server()
|
||||
* to be used as a standalone clone tool)
|
||||
*/
|
||||
|
||||
extension_status = get_repmgr_extension_status(primary_conn, NULL);
|
||||
extension_status = get_repmgr_extension_status(primary_conn, &extversions);
|
||||
|
||||
if (extension_status != REPMGR_INSTALLED)
|
||||
{
|
||||
@@ -4847,20 +4898,25 @@ check_source_server()
|
||||
exit(ERR_DB_QUERY);
|
||||
}
|
||||
|
||||
/* schema doesn't exist */
|
||||
log_error(_("repmgr extension not found on source node"));
|
||||
|
||||
if (extension_status == REPMGR_AVAILABLE)
|
||||
{
|
||||
log_detail(_("repmgr extension is available but not installed in database \"%s\""),
|
||||
log_error(_("repmgr extension is available but not installed in database \"%s\""),
|
||||
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)
|
||||
{
|
||||
log_detail(_("repmgr extension is not available on the upstream node"));
|
||||
log_error(_("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);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
@@ -4885,6 +4941,13 @@ check_source_server()
|
||||
* later, as this is a precautionary check and we can retrieve the system
|
||||
* 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)
|
||||
{
|
||||
uint64 source_system_identifier = system_identifier(source_conn);
|
||||
@@ -6663,9 +6726,8 @@ make_barman_ssh_command(char *buf)
|
||||
|
||||
|
||||
static int
|
||||
get_tablespace_data_barman
|
||||
(char *tablespace_data_barman,
|
||||
TablespaceDataList *tablespace_list)
|
||||
get_tablespace_data_barman(char *tablespace_data_barman,
|
||||
TablespaceDataList *tablespace_list)
|
||||
{
|
||||
/*
|
||||
* Example: [('main', 24674, '/var/lib/postgresql/tablespaces/9.5/main'),
|
||||
@@ -6939,71 +7001,55 @@ check_recovery_type(PGconn *conn)
|
||||
|
||||
|
||||
/*
|
||||
* Creates a recovery.conf file for a standby
|
||||
* Creates recovery configuration for a standby.
|
||||
*
|
||||
* A database connection pointer is required for escaping primary_conninfo
|
||||
* parameters. When cloning from Barman and --no-upstream-connection ) this
|
||||
* might not be available.
|
||||
* parameters. When cloning from Barman and --no-upstream-connection supplied,
|
||||
* this might not be available.
|
||||
*/
|
||||
bool
|
||||
create_recovery_file(t_node_info *node_record, t_conninfo_param_list *recovery_conninfo, char *dest, bool as_file)
|
||||
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)
|
||||
{
|
||||
PQExpBufferData recovery_file_buf;
|
||||
PQExpBufferData primary_conninfo_buf;
|
||||
char recovery_file_path[MAXPGPATH] = "";
|
||||
FILE *recovery_file;
|
||||
mode_t um;
|
||||
|
||||
/* create file in buffer */
|
||||
initPQExpBuffer(&recovery_file_buf);
|
||||
KeyValueList recovery_config = {NULL, NULL};
|
||||
KeyValueListCell *cell = NULL;
|
||||
|
||||
/* standby_mode = 'on' */
|
||||
appendPQExpBufferStr(&recovery_file_buf,
|
||||
"standby_mode = 'on'\n");
|
||||
initPQExpBuffer(&primary_conninfo_buf);
|
||||
|
||||
/* standby_mode = 'on' (Pg 11 and earlier) */
|
||||
if (server_version_num < 120000)
|
||||
{
|
||||
key_value_list_set(&recovery_config,
|
||||
"standby_mode", "on");
|
||||
}
|
||||
|
||||
/* primary_conninfo = '...' */
|
||||
|
||||
/*
|
||||
* the user specified --upstream-conninfo string - copy that
|
||||
*/
|
||||
if (strlen(runtime_options.upstream_conninfo))
|
||||
{
|
||||
char *escaped = escape_recovery_conf_value(runtime_options.upstream_conninfo);
|
||||
|
||||
appendPQExpBuffer(&recovery_file_buf,
|
||||
"primary_conninfo = '%s'\n",
|
||||
escaped);
|
||||
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
/*
|
||||
* otherwise use the conninfo inferred from the upstream connection and/or
|
||||
* node record
|
||||
*/
|
||||
else
|
||||
{
|
||||
write_primary_conninfo(&recovery_file_buf, recovery_conninfo);
|
||||
}
|
||||
write_primary_conninfo(&primary_conninfo_buf, primary_conninfo);
|
||||
key_value_list_set(&recovery_config,
|
||||
"primary_conninfo", primary_conninfo_buf.data);
|
||||
|
||||
/* recovery_target_timeline = 'latest' */
|
||||
appendPQExpBufferStr(&recovery_file_buf,
|
||||
"recovery_target_timeline = 'latest'\n");
|
||||
key_value_list_set(&recovery_config,
|
||||
"recovery_target_timeline", "latest");
|
||||
|
||||
|
||||
/* recovery_min_apply_delay = ... (optional) */
|
||||
if (config_file_options.recovery_min_apply_delay_provided == true)
|
||||
{
|
||||
appendPQExpBuffer(&recovery_file_buf,
|
||||
"recovery_min_apply_delay = %s\n",
|
||||
config_file_options.recovery_min_apply_delay);
|
||||
key_value_list_set(&recovery_config,
|
||||
"recovery_min_apply_delay", config_file_options.recovery_min_apply_delay);
|
||||
}
|
||||
|
||||
/* primary_slot_name = '...' (optional, for 9.4 and later) */
|
||||
if (config_file_options.use_replication_slots)
|
||||
{
|
||||
appendPQExpBuffer(&recovery_file_buf,
|
||||
"primary_slot_name = %s\n",
|
||||
node_record->slot_name);
|
||||
key_value_list_set(&recovery_config,
|
||||
"primary_slot_name", node_record->slot_name);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7014,9 +7060,8 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *recovery_c
|
||||
{
|
||||
char *escaped = escape_recovery_conf_value(config_file_options.restore_command);
|
||||
|
||||
appendPQExpBuffer(&recovery_file_buf,
|
||||
"restore_command = '%s'\n",
|
||||
escaped);
|
||||
key_value_list_set(&recovery_config,
|
||||
"restore_command", escaped);
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
@@ -7024,33 +7069,84 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *recovery_c
|
||||
if (config_file_options.archive_cleanup_command[0] != '\0')
|
||||
{
|
||||
char *escaped = escape_recovery_conf_value(config_file_options.archive_cleanup_command);
|
||||
appendPQExpBuffer(&recovery_file_buf,
|
||||
"archive_cleanup_command = '%s'\n",
|
||||
escaped);
|
||||
|
||||
key_value_list_set(&recovery_config,
|
||||
"archive_cleanup_command", escaped);
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
if (as_file == true)
|
||||
|
||||
|
||||
|
||||
if (as_file == false)
|
||||
{
|
||||
maxpath_snprintf(recovery_file_path, "%s/%s", dest, RECOVERY_COMMAND_FILE);
|
||||
log_debug("create_recovery_file(): creating \"%s\"...",
|
||||
recovery_file_path);
|
||||
/* create file in buffer */
|
||||
initPQExpBuffer(&recovery_file_buf);
|
||||
|
||||
/* 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)
|
||||
for (cell = recovery_config.head; cell; cell = cell->next)
|
||||
{
|
||||
log_error(_("unable to create recovery.conf file at \"%s\""),
|
||||
recovery_file_path);
|
||||
log_detail("%s", strerror(errno));
|
||||
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;
|
||||
}
|
||||
|
||||
log_debug("recovery file is:\n%s", recovery_file_buf.data);
|
||||
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);
|
||||
log_detail("%s", strerror(errno));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (cell = recovery_config.head; cell; cell = cell->next)
|
||||
{
|
||||
initPQExpBuffer(&recovery_file_buf);
|
||||
appendPQExpBuffer(&recovery_file_buf,
|
||||
"%s = '%s'\n",
|
||||
cell->key, cell->value);
|
||||
|
||||
log_debug("recovery.conf line: %s", recovery_file_buf.data);
|
||||
|
||||
if (fputs(recovery_file_buf.data, recovery_file) == EOF)
|
||||
{
|
||||
@@ -7060,14 +7156,58 @@ create_recovery_file(t_node_info *node_record, t_conninfo_param_list *recovery_c
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(recovery_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
maxlen_snprintf(dest, "%s", recovery_file_buf.data);
|
||||
termPQExpBuffer(&recovery_file_buf);
|
||||
}
|
||||
|
||||
termPQExpBuffer(&recovery_file_buf);
|
||||
|
||||
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\""),
|
||||
STANDBY_SIGNAL_FILE,
|
||||
standby_signal_file_path);
|
||||
log_detail("%s", strerror(errno));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fputs("# created by repmgr\n", file) == EOF)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -7157,8 +7297,7 @@ write_primary_conninfo(PQExpBufferData *dest, t_conninfo_param_list *param_list)
|
||||
|
||||
escaped = escape_recovery_conf_value(conninfo_buf.data);
|
||||
|
||||
appendPQExpBuffer(dest,
|
||||
"primary_conninfo = '%s'\n", escaped);
|
||||
appendPQExpBufferStr(dest, escaped);
|
||||
|
||||
free(escaped);
|
||||
free_conninfo_params(&env_conninfo);
|
||||
|
||||
@@ -260,5 +260,6 @@ 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 void check_shared_library(PGconn *conn);
|
||||
extern bool is_repmgrd_running(PGconn *conn);
|
||||
extern int parse_repmgr_version(const char *version_string);
|
||||
|
||||
#endif /* _REPMGR_CLIENT_GLOBAL_H_ */
|
||||
|
||||
202
repmgr-client.c
202
repmgr-client.c
@@ -33,9 +33,10 @@
|
||||
* NODE SERVICE
|
||||
* NODE CONTROL
|
||||
*
|
||||
* DAEMON STATUS
|
||||
* DAEMON PAUSE
|
||||
* DAEMON UNPAUSE
|
||||
* SERVICE STATUS
|
||||
* SERVICE PAUSE
|
||||
* SERVICE UNPAUSE
|
||||
*
|
||||
* DAEMON START
|
||||
* DAEMON STOP
|
||||
*
|
||||
@@ -57,6 +58,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
#include "repmgr.h"
|
||||
#include "compat.h"
|
||||
#include "controldata.h"
|
||||
@@ -68,11 +70,11 @@
|
||||
#include "repmgr-action-bdr.h"
|
||||
#include "repmgr-action-node.h"
|
||||
#include "repmgr-action-cluster.h"
|
||||
#include "repmgr-action-service.h"
|
||||
#include "repmgr-action-daemon.h"
|
||||
|
||||
#include <storage/fd.h> /* for PG_TEMP_FILE_PREFIX */
|
||||
|
||||
|
||||
/* globally available variables *
|
||||
* ============================ */
|
||||
|
||||
@@ -184,7 +186,7 @@ main(int argc, char **argv)
|
||||
strncpy(runtime_options.username, pw->pw_name, MAXLEN);
|
||||
}
|
||||
|
||||
/* Make getopt emitting errors */
|
||||
/* Make getopt emit errors */
|
||||
opterr = 1;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "?Vb:f:FwWd:h:p:U:R:S:D:ck:L:qtvC:", long_options,
|
||||
@@ -669,33 +671,20 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
/*-----------------------------
|
||||
* options deprecated since 3.3
|
||||
* options deprecated since 4.0
|
||||
*-----------------------------
|
||||
*/
|
||||
case OPT_CHECK_UPSTREAM_CONFIG:
|
||||
item_list_append(&cli_warnings,
|
||||
_("--check-upstream-config is deprecated; use --dry-run instead"));
|
||||
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 */
|
||||
case 'C':
|
||||
item_list_append(&cli_warnings,
|
||||
_("--remote-config-file is no longer required"));
|
||||
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 */
|
||||
option_error_found = true;
|
||||
break;
|
||||
@@ -817,7 +806,6 @@ main(int argc, char **argv)
|
||||
exit_with_cli_errors(&cli_errors, NULL);
|
||||
}
|
||||
|
||||
|
||||
/*----------
|
||||
* Determine the node type and action; following are valid:
|
||||
*
|
||||
@@ -827,7 +815,7 @@ main(int argc, char **argv)
|
||||
* BDR { REGISTER | UNREGISTER } |
|
||||
* NODE { STATUS | CHECK | REJOIN | SERVICE } |
|
||||
* CLUSTER { CROSSCHECK | MATRIX | SHOW | EVENT | CLEANUP }
|
||||
* DAEMON { STATUS | PAUSE | UNPAUSE | START | STOP }
|
||||
* SERVICE { STATUS | PAUSE | UNPAUSE | START | STOP }
|
||||
*
|
||||
* [node] is an optional hostname, provided instead of the -h/--host
|
||||
* option
|
||||
@@ -966,6 +954,22 @@ main(int argc, char **argv)
|
||||
else if (strcasecmp(repmgr_action, "CLEANUP") == 0)
|
||||
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)
|
||||
{
|
||||
if (help_option == true)
|
||||
@@ -974,16 +978,18 @@ main(int argc, char **argv)
|
||||
exit(SUCCESS);
|
||||
}
|
||||
|
||||
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)
|
||||
if (strcasecmp(repmgr_action, "START") == 0)
|
||||
action = DAEMON_START;
|
||||
else if (strcasecmp(repmgr_action, "STOP") == 0)
|
||||
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
|
||||
{
|
||||
@@ -1386,16 +1392,18 @@ main(int argc, char **argv)
|
||||
do_cluster_cleanup();
|
||||
break;
|
||||
|
||||
/* SERVICE */
|
||||
case SERVICE_STATUS:
|
||||
do_service_status();
|
||||
break;
|
||||
case SERVICE_PAUSE:
|
||||
do_service_pause();
|
||||
break;
|
||||
case SERVICE_UNPAUSE:
|
||||
do_service_unpause();
|
||||
break;
|
||||
|
||||
/* 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:
|
||||
do_daemon_start();
|
||||
break;
|
||||
@@ -1906,8 +1914,9 @@ check_cli_parameters(const int action)
|
||||
case WITNESS_UNREGISTER:
|
||||
case NODE_REJOIN:
|
||||
case NODE_SERVICE:
|
||||
case DAEMON_PAUSE:
|
||||
case DAEMON_UNPAUSE:
|
||||
case SERVICE_PAUSE:
|
||||
case SERVICE_UNPAUSE:
|
||||
case SERVICE_STATUS:
|
||||
case DAEMON_START:
|
||||
case DAEMON_STOP:
|
||||
break;
|
||||
@@ -1946,7 +1955,7 @@ check_cli_parameters(const int action)
|
||||
{
|
||||
case CLUSTER_SHOW:
|
||||
case CLUSTER_EVENT:
|
||||
case DAEMON_STATUS:
|
||||
case SERVICE_STATUS:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(&cli_warnings,
|
||||
@@ -1960,7 +1969,7 @@ check_cli_parameters(const int action)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case DAEMON_STATUS:
|
||||
case SERVICE_STATUS:
|
||||
break;
|
||||
default:
|
||||
item_list_append_format(&cli_warnings,
|
||||
@@ -2010,7 +2019,7 @@ check_cli_parameters(const int action)
|
||||
|
||||
/*
|
||||
* Generate formatted node status output for display by "cluster show" and
|
||||
* "daemon status".
|
||||
* "service status".
|
||||
*/
|
||||
bool
|
||||
format_node_status(t_node_info *node_info, PQExpBufferData *node_status, PQExpBufferData *upstream, ItemList *warnings)
|
||||
@@ -2476,12 +2485,13 @@ action_name(const int action)
|
||||
case CLUSTER_CROSSCHECK:
|
||||
return "CLUSTER CROSSCHECK";
|
||||
|
||||
case DAEMON_STATUS:
|
||||
return "DAEMON STATUS";
|
||||
case DAEMON_PAUSE:
|
||||
return "DAEMON PAUSE";
|
||||
case DAEMON_UNPAUSE:
|
||||
return "DAEMON UNPAUSE";
|
||||
case SERVICE_STATUS:
|
||||
return "SERVICE STATUS";
|
||||
case SERVICE_PAUSE:
|
||||
return "SERVICE PAUSE";
|
||||
case SERVICE_UNPAUSE:
|
||||
return "SERVICE UNPAUSE";
|
||||
|
||||
case DAEMON_START:
|
||||
return "DAEMON START";
|
||||
case DAEMON_STOP:
|
||||
@@ -2596,11 +2606,12 @@ do_help(void)
|
||||
printf(_(" %s [OPTIONS] node {status|check|rejoin|service}\n"), progname());
|
||||
printf(_(" %s [OPTIONS] cluster {show|event|matrix|crosscheck|cleanup}\n"), progname());
|
||||
printf(_(" %s [OPTIONS] witness {register|unregister}\n"), progname());
|
||||
printf(_(" %s [OPTIONS] daemon {status|pause|unpause|start|stop}\n"), progname());
|
||||
printf(_(" %s [OPTIONS] service {status|pause|unpause}\n"), progname());
|
||||
printf(_(" %s [OPTIONS] daemon {start|stop}\n"), progname());
|
||||
|
||||
puts("");
|
||||
|
||||
printf(_(" Execute \"%s {primary|standby|bdr|node|cluster|witness|daemon} --help\" to see command-specific options\n"), progname());
|
||||
printf(_(" Execute \"%s {primary|standby|bdr|node|cluster|witness|service} --help\" to see command-specific options\n"), progname());
|
||||
|
||||
puts("");
|
||||
|
||||
@@ -3029,19 +3040,19 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
||||
|
||||
if (*config_file_options.rsync_options == '\0')
|
||||
{
|
||||
appendPQExpBuffer(&rsync_flags, "%s",
|
||||
"--archive --checksum --compress --progress --rsh=ssh");
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
"--archive --checksum --compress --progress --rsh=ssh");
|
||||
}
|
||||
else
|
||||
{
|
||||
appendPQExpBuffer(&rsync_flags, "%s",
|
||||
config_file_options.rsync_options);
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
config_file_options.rsync_options);
|
||||
}
|
||||
|
||||
if (runtime_options.force)
|
||||
{
|
||||
appendPQExpBuffer(&rsync_flags, "%s",
|
||||
" --delete --checksum");
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
" --delete --checksum");
|
||||
}
|
||||
|
||||
if (!remote_user[0])
|
||||
@@ -3067,11 +3078,11 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
||||
if (is_directory)
|
||||
{
|
||||
/* Files which we don't want */
|
||||
appendPQExpBuffer(&rsync_flags, "%s",
|
||||
" --exclude=postmaster.pid --exclude=postmaster.opts --exclude=global/pg_control");
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
" --exclude=postmaster.pid --exclude=postmaster.opts --exclude=global/pg_control");
|
||||
|
||||
appendPQExpBuffer(&rsync_flags, "%s",
|
||||
" --exclude=recovery.conf --exclude=recovery.done");
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
" --exclude=recovery.conf --exclude=recovery.done");
|
||||
|
||||
if (server_version_num >= 90400)
|
||||
{
|
||||
@@ -3079,8 +3090,8 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
||||
* Ideally we'd use PG_AUTOCONF_FILENAME from utils/guc.h, but
|
||||
* that has too many dependencies for a mere client program.
|
||||
*/
|
||||
appendPQExpBuffer(&rsync_flags, "%s",
|
||||
" --exclude=postgresql.auto.conf.tmp");
|
||||
appendPQExpBuffer(&rsync_flags, " --exclude=%s.tmp",
|
||||
PG_AUTOCONF_FILENAME);
|
||||
}
|
||||
|
||||
/* Temporary files which we don't want, if they exist */
|
||||
@@ -3091,17 +3102,17 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
|
||||
|
||||
if (server_version_num >= 100000)
|
||||
{
|
||||
appendPQExpBuffer(&rsync_flags, "%s",
|
||||
" --exclude=pg_wal/*");
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
" --exclude=pg_wal/*");
|
||||
}
|
||||
else
|
||||
{
|
||||
appendPQExpBuffer(&rsync_flags, "%s",
|
||||
" --exclude=pg_xlog/*");
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
" --exclude=pg_xlog/*");
|
||||
}
|
||||
|
||||
appendPQExpBuffer(&rsync_flags, "%s",
|
||||
" --exclude=pg_log/* --exclude=pg_stat_tmp/*");
|
||||
appendPQExpBufferStr(&rsync_flags,
|
||||
" --exclude=pg_log/* --exclude=pg_stat_tmp/*");
|
||||
|
||||
maxlen_snprintf(script, "rsync %s %s:%s/* %s",
|
||||
rsync_flags.data, host_string, remote_path, local_path);
|
||||
@@ -3156,6 +3167,18 @@ make_remote_repmgr_path(PQExpBufferData *output_buf, t_node_info *remote_node_re
|
||||
"%s -f %s ",
|
||||
progname(),
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3869,3 +3892,44 @@ is_repmgrd_running(PGconn *conn)
|
||||
|
||||
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_CROSSCHECK 21
|
||||
#define CLUSTER_EVENT 22
|
||||
#define DAEMON_STATUS 23
|
||||
#define DAEMON_PAUSE 24
|
||||
#define DAEMON_UNPAUSE 25
|
||||
#define SERVICE_STATUS 23
|
||||
#define SERVICE_PAUSE 24
|
||||
#define SERVICE_UNPAUSE 25
|
||||
#define DAEMON_START 26
|
||||
#define DAEMON_STOP 27
|
||||
|
||||
@@ -101,13 +101,9 @@
|
||||
#define OPT_DETAIL 1046
|
||||
#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 */
|
||||
#define OPT_CHECK_UPSTREAM_CONFIG 996
|
||||
#define OPT_NODE 995
|
||||
#define OPT_CHECK_UPSTREAM_CONFIG 999
|
||||
#define OPT_NODE 998
|
||||
|
||||
|
||||
static struct option long_options[] =
|
||||
@@ -157,7 +153,6 @@ static struct option long_options[] =
|
||||
{"copy-external-config-files", optional_argument, NULL, OPT_COPY_EXTERNAL_CONFIG_FILES},
|
||||
{"fast-checkpoint", no_argument, NULL, 'c'},
|
||||
{"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},
|
||||
{"upstream-conninfo", required_argument, NULL, OPT_UPSTREAM_CONNINFO},
|
||||
{"upstream-node-id", required_argument, NULL, OPT_UPSTREAM_NODE_ID},
|
||||
@@ -215,11 +210,8 @@ static struct option long_options[] =
|
||||
|
||||
/* deprecated */
|
||||
{"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" */
|
||||
{"remote-config-file", required_argument, NULL, 'C'},
|
||||
/* legacy alias for -D/--pgdata */
|
||||
{"data-dir", required_argument, NULL, OPT_DATA_DIR},
|
||||
/* replaced by --node-id */
|
||||
{"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;
|
||||
memset(shared_state->repmgrd_pidfile, 0, MAXPGPATH);
|
||||
|
||||
if(repmgrd_pidfile != NULL)
|
||||
if (repmgrd_pidfile != NULL)
|
||||
{
|
||||
strncpy(shared_state->repmgrd_pidfile, repmgrd_pidfile, MAXPGPATH);
|
||||
}
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
# is noted for each item. Where no default value is shown, the
|
||||
# parameter will be treated as empty or false.
|
||||
#
|
||||
# IMPORTANT: string values can be provided as-is, or enclosed in single quotes
|
||||
# (but not double-quotes, which will be interpreted as part of the string),
|
||||
# e.g.:
|
||||
# repmgr parses its configuration file in the same way as PostgreSQL itself
|
||||
# does. In particular, strings must be enclosed in single quotes (although
|
||||
# simple identifiers may be provided as-is).
|
||||
#
|
||||
# node_name=foo
|
||||
# node_name = 'foo'
|
||||
# For details on the configuration file format see the documentation at:
|
||||
#
|
||||
# https://repmgr.org/docs/current/configuration-file.html#CONFIGURATION-FILE-FORMAT
|
||||
#
|
||||
# =============================================================================
|
||||
# Required configuration items
|
||||
@@ -51,7 +52,6 @@
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
||||
# Optional configuration items
|
||||
# =============================================================================
|
||||
|
||||
@@ -68,16 +68,16 @@
|
||||
# Replication settings
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
#replication_user='repmgr' # User to make replication connections with, if not set defaults
|
||||
# to the user defined in "conninfo".
|
||||
#replication_user='repmgr' # User to make replication connections with, if not set
|
||||
# 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
|
||||
|
||||
#location=default # arbitrary string defining the location of the node; this
|
||||
# is used during failover to check visibilty of the
|
||||
# current primary node. See the 'repmgrd' documentation
|
||||
# in README.md for further details.
|
||||
#location='default' # An arbitrary string defining the location of the node; this
|
||||
# is used during failover to check visibility of the
|
||||
# current primary node. For further details see:
|
||||
# https://repmgr.org/docs/current/repmgrd-network-split.html
|
||||
|
||||
#use_replication_slots=no # whether to use physical replication slots
|
||||
# NOTE: when using replication slots,
|
||||
@@ -102,10 +102,10 @@
|
||||
# This is mainly intended for those cases when `repmgr` is executed directly
|
||||
# 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
|
||||
|
||||
#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
|
||||
|
||||
#log_file='' # STDERR can be redirected to an arbitrary file
|
||||
@@ -282,7 +282,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
# These settings are only applied when repmgrd is running. Values shown
|
||||
# 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
|
||||
#
|
||||
# 'automatic': repmgrd will automatically attempt to promote the
|
||||
@@ -340,7 +340,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
# WAL receivers
|
||||
#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.
|
||||
#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
|
||||
# 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.
|
||||
@@ -355,7 +355,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
#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)
|
||||
#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
|
||||
@@ -403,7 +403,7 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
|
||||
# for "promote_command"; do not use "repmgr standby promote"
|
||||
# (or a script which executes "repmgr standby promote") here.
|
||||
|
||||
# Used by "repmgr daemon (start|stop)" to control repmgrd
|
||||
# Used by "repmgr service (start|stop)" to control repmgrd
|
||||
#
|
||||
#repmgrd_service_start_command = ''
|
||||
#repmgrd_service_stop_command = ''
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# repmgr extension
|
||||
comment = 'Replication manager for PostgreSQL'
|
||||
default_version = '4.4'
|
||||
default_version = '5.0'
|
||||
module_pathname = '$libdir/repmgr'
|
||||
relocatable = false
|
||||
schema = repmgr
|
||||
|
||||
37
repmgr.h
37
repmgr.h
@@ -21,6 +21,37 @@
|
||||
#include <config.h>
|
||||
#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_
|
||||
#define _REPMGR_H_
|
||||
|
||||
@@ -51,6 +82,7 @@
|
||||
|
||||
#define UNKNOWN_SERVER_VERSION_NUM -1
|
||||
#define UNKNOWN_BDR_VERSION_NUM -1
|
||||
#define UNKNOWN_REPMGR_VERSION_NUM -1
|
||||
|
||||
#define UNKNOWN_TIMELINE_ID -1
|
||||
#define UNKNOWN_SYSTEM_IDENTIFIER 0
|
||||
@@ -108,6 +140,11 @@
|
||||
#define RECOVERY_COMMAND_FILE "recovery.conf"
|
||||
#endif
|
||||
|
||||
#ifndef STANDBY_SIGNAL_FILE
|
||||
#define STANDBY_SIGNAL_FILE "standby.signal"
|
||||
#define RECOVERY_SIGNAL_FILE "recovery.signal"
|
||||
#endif
|
||||
|
||||
#ifndef TABLESPACE_MAP
|
||||
#define TABLESPACE_MAP "tablespace_map"
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#define REPMGR_VERSION_DATE ""
|
||||
#define REPMGR_VERSION "4.4dev"
|
||||
#define REPMGR_VERSION_NUM 40400
|
||||
#define REPMGR_VERSION "5.0.0"
|
||||
#define REPMGR_VERSION_NUM 50000
|
||||
#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_detail(_("no failover will be carried out"));
|
||||
log_hint(_("execute \"repmgr daemon unpause\" to resume normal failover mode"));
|
||||
log_hint(_("execute \"repmgr service unpause\" to resume normal failover mode"));
|
||||
monitoring_state = MS_DEGRADED;
|
||||
INSTR_TIME_SET_CURRENT(degraded_monitoring_start);
|
||||
}
|
||||
@@ -1710,9 +1710,6 @@ monitor_streaming_standby(void)
|
||||
* has been promoted
|
||||
*/
|
||||
|
||||
NodeInfoListCell *cell;
|
||||
int follow_node_id = UNKNOWN_NODE_ID;
|
||||
|
||||
/* local node has been promoted */
|
||||
if (get_recovery_type(local_conn) == RECTYPE_PRIMARY)
|
||||
{
|
||||
@@ -1802,6 +1799,9 @@ monitor_streaming_standby(void)
|
||||
|
||||
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);
|
||||
for (cell = sibling_nodes.head; cell; cell = cell->next)
|
||||
{
|
||||
@@ -1828,16 +1828,19 @@ monitor_streaming_standby(void)
|
||||
|
||||
if (get_recovery_type(cell->node_info->conn) == RECTYPE_PRIMARY)
|
||||
{
|
||||
follow_node_id = cell->node_info->node_id;
|
||||
follow_node_info = cell->node_info;
|
||||
close_connection(&cell->node_info->conn);
|
||||
break;
|
||||
}
|
||||
close_connection(&cell->node_info->conn);
|
||||
}
|
||||
|
||||
if (follow_node_id != UNKNOWN_NODE_ID)
|
||||
if (follow_node_info != NULL)
|
||||
{
|
||||
follow_new_primary(follow_node_id);
|
||||
log_info(_("node \"%s\" (node ID: %i) detected as primary"),
|
||||
follow_node_info->node_name,
|
||||
follow_node_info->node_id);
|
||||
follow_new_primary(follow_node_info->node_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1881,7 +1884,7 @@ loop:
|
||||
if (PQstatus(local_conn) == CONNECTION_OK && repmgrd_is_paused(local_conn))
|
||||
{
|
||||
log_detail(_("repmgrd paused by administrator"));
|
||||
log_hint(_("execute \"repmgr daemon unpause\" to resume normal failover mode"));
|
||||
log_hint(_("execute \"repmgr service unpause\" to resume normal failover mode"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2083,7 +2086,6 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (got_SIGHUP)
|
||||
{
|
||||
handle_sighup(&local_conn, STANDBY);
|
||||
@@ -2093,13 +2095,34 @@ loop:
|
||||
|
||||
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"),
|
||||
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;
|
||||
/*
|
||||
* It's possible that after a change of upstream, the local node record will not
|
||||
* yet have been updated with the new upstream node ID. Therefore we check the
|
||||
* node record on the upstream, and if that matches "last_known_upstream_node_id",
|
||||
* take that as the correct value.
|
||||
*/
|
||||
|
||||
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\")",
|
||||
@@ -2380,8 +2403,6 @@ monitor_streaming_witness(void)
|
||||
* has been promoted
|
||||
*/
|
||||
|
||||
NodeInfoListCell *cell;
|
||||
int follow_node_id = UNKNOWN_NODE_ID;
|
||||
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
|
||||
|
||||
get_active_sibling_node_records(local_conn,
|
||||
@@ -2391,6 +2412,9 @@ monitor_streaming_witness(void)
|
||||
|
||||
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);
|
||||
for (cell = sibling_nodes.head; cell; cell = cell->next)
|
||||
{
|
||||
@@ -2416,18 +2440,22 @@ monitor_streaming_witness(void)
|
||||
|
||||
if (get_recovery_type(cell->node_info->conn) == RECTYPE_PRIMARY)
|
||||
{
|
||||
follow_node_id = cell->node_info->node_id;
|
||||
follow_node_info = cell->node_info;
|
||||
close_connection(&cell->node_info->conn);
|
||||
break;
|
||||
}
|
||||
close_connection(&cell->node_info->conn);
|
||||
}
|
||||
|
||||
if (follow_node_id != UNKNOWN_NODE_ID)
|
||||
if (follow_node_info != NULL)
|
||||
{
|
||||
witness_follow_new_primary(follow_node_id);
|
||||
log_info(_("node \"%s\" (node ID: %i) detected as primary"),
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -3594,6 +3622,10 @@ follow_new_primary(int new_primary_id)
|
||||
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);
|
||||
|
||||
if (record_status != RECORD_FOUND)
|
||||
@@ -4909,7 +4941,8 @@ check_node_can_follow(PGconn *local_conn, XLogRecPtr local_xlogpos, PGconn *foll
|
||||
*/
|
||||
if (local_xlogpos > follow_target_history->end)
|
||||
{
|
||||
log_error(_("this node cannot attach to follow target node %i"),
|
||||
log_error(_("this node cannot attach to follow target node \"%s\" (ID: %i)"),
|
||||
follow_target_node_info->node_name,
|
||||
follow_target_node_info->node_id);
|
||||
can_follow = false;
|
||||
|
||||
@@ -4921,8 +4954,10 @@ check_node_can_follow(PGconn *local_conn, XLogRecPtr local_xlogpos, PGconn *foll
|
||||
|
||||
if (can_follow == true)
|
||||
{
|
||||
log_info(_("local node %i can attach to follow target node %i"),
|
||||
log_info(_("local node \"%s\" (ID: %i) can attach to follow target node \"%s\" (ID: %i)"),
|
||||
config_file_options.node_name,
|
||||
config_file_options.node_id,
|
||||
follow_target_node_info->node_name,
|
||||
follow_target_node_info->node_id);
|
||||
|
||||
log_detail(_("local node's recovery point: %X/%X; follow target node's fork point: %X/%X"),
|
||||
|
||||
76
strutil.c
76
strutil.c
@@ -29,6 +29,9 @@ static int
|
||||
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||
__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
|
||||
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||
{
|
||||
@@ -164,16 +167,74 @@ item_list_free(ItemList *item_list)
|
||||
void
|
||||
key_value_list_set(KeyValueList *item_list, const char *key, const char *value)
|
||||
{
|
||||
key_value_list_set_format(item_list, key, "%s", value);
|
||||
_key_value_list_set(item_list, false, key, value);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
key_value_list_set_format(KeyValueList *item_list, const char *key, const char *value,...)
|
||||
key_value_list_replace_or_set(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;
|
||||
va_list arglist;
|
||||
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));
|
||||
|
||||
@@ -184,17 +245,14 @@ key_value_list_set_format(KeyValueList *item_list, const char *key, const char *
|
||||
}
|
||||
|
||||
keylen = strlen(key);
|
||||
vallen = strlen(value);
|
||||
|
||||
cell->key = pg_malloc0(keylen + 1);
|
||||
cell->value = pg_malloc0(MAXLEN);
|
||||
cell->value = pg_malloc0(vallen + 1);
|
||||
cell->output_mode = OM_NOT_SET;
|
||||
|
||||
strncpy(cell->key, key, keylen);
|
||||
|
||||
va_start(arglist, value);
|
||||
(void) xvsnprintf(cell->value, MAXLEN, value, arglist);
|
||||
va_end(arglist);
|
||||
|
||||
strncpy(cell->value, value, vallen);
|
||||
|
||||
if (item_list->tail)
|
||||
item_list->tail->next = cell;
|
||||
|
||||
@@ -119,6 +119,9 @@ extern void
|
||||
extern void
|
||||
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
|
||||
key_value_list_set_format(KeyValueList *item_list, const char *key, const char *value,...)
|
||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
|
||||
|
||||
27
sysutils.c
27
sysutils.c
@@ -1,6 +1,8 @@
|
||||
/*
|
||||
* sysutils.c
|
||||
*
|
||||
* Functions which need to be executed on the local system.
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2019
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@@ -115,7 +117,7 @@ bool
|
||||
remote_command(const char *host, const char *user, const char *command, const char *ssh_options, PQExpBufferData *outputbuf)
|
||||
{
|
||||
FILE *fp;
|
||||
char ssh_command[MAXLEN] = "";
|
||||
PQExpBufferData ssh_command;
|
||||
PQExpBufferData ssh_host;
|
||||
|
||||
char output[MAXLEN] = "";
|
||||
@@ -129,24 +131,29 @@ remote_command(const char *host, const char *user, const char *command, const ch
|
||||
|
||||
appendPQExpBufferStr(&ssh_host, host);
|
||||
|
||||
maxlen_snprintf(ssh_command,
|
||||
"ssh -o Batchmode=yes %s %s %s",
|
||||
ssh_options,
|
||||
ssh_host.data,
|
||||
command);
|
||||
initPQExpBuffer(&ssh_command);
|
||||
|
||||
appendPQExpBuffer(&ssh_command,
|
||||
"ssh -o Batchmode=yes %s %s %s",
|
||||
ssh_options,
|
||||
ssh_host.data,
|
||||
command);
|
||||
|
||||
termPQExpBuffer(&ssh_host);
|
||||
|
||||
log_debug("remote_command():\n %s", ssh_command);
|
||||
log_debug("remote_command():\n %s", ssh_command.data);
|
||||
|
||||
fp = popen(ssh_command, "r");
|
||||
fp = popen(ssh_command.data, "r");
|
||||
|
||||
if (fp == NULL)
|
||||
{
|
||||
log_error(_("unable to execute remote command:\n %s"), ssh_command);
|
||||
log_error(_("unable to execute remote command:\n %s"), ssh_command.data);
|
||||
termPQExpBuffer(&ssh_command);
|
||||
return false;
|
||||
}
|
||||
|
||||
termPQExpBuffer(&ssh_command);
|
||||
|
||||
if (outputbuf != NULL)
|
||||
{
|
||||
/* TODO: better error handling */
|
||||
@@ -364,3 +371,5 @@ enable_wal_receiver(PGconn *conn, bool wait_startup)
|
||||
|
||||
return wal_receiver_pid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,5 +28,4 @@ extern bool remote_command(const char *host, const char *user, const char *comma
|
||||
extern pid_t disable_wal_receiver(PGconn *conn);
|
||||
extern pid_t enable_wal_receiver(PGconn *conn, bool wait_startup);
|
||||
|
||||
|
||||
#endif /* _SYSUTILS_H_ */
|
||||
|
||||
Reference in New Issue
Block a user