mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-22 14:46:29 +00:00
Convert configuration file parsing to use flex
Previously, repmgr was using a very simple ad-hoc string-based parser,
which had various limitations and allowed configuration files to be
created in a way which could cause confusion and/or unexpected
behaviour.
For example, it accepted strings enclosed in single quotes, but treated
strings enclosed in double quotes literally. A node_name defined thusly:
node_name="somenode"
would result in the literal value '"somenode"' being used, which could
lead to unobvious errors along the lines of:
no record found for ""somenode""
The configuration file parser has been adapted from the one used by
PostgreSQL itself, so behaves more-or-less identically (though some
functions such as file inclusion are not supported in repmgr).
This makes configuration parsing more robust and consistent;
additionally, error reporting will be more precise.
Note this does mean that some repmgr.conf items previously accepted
as valid by repmgr will now be rejected; in particular this includes
strings containing spaces which are not enclosed in single quotes.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -53,3 +53,6 @@ repmgr
|
||||
repmgrd
|
||||
repmgr4
|
||||
repmgrd4
|
||||
|
||||
# generated files
|
||||
configfile-scan.c
|
||||
|
||||
3
HISTORY
3
HISTORY
@@ -1,3 +1,6 @@
|
||||
4.5 2019-??-??
|
||||
general: parse configuration file using flex (Ian)
|
||||
|
||||
4.4 2019-06-27
|
||||
repmgr: improve "daemon status" output (Ian)
|
||||
repmgr: add "--siblings-follow" option to "standby promote" (Ian)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Makefile.global.in
|
||||
# @configure_input@
|
||||
|
||||
|
||||
# Can only be built using pgxs
|
||||
USE_PGXS=1
|
||||
|
||||
@@ -29,3 +30,11 @@ include $(PGXS)
|
||||
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'$@' $<
|
||||
|
||||
@@ -54,14 +54,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
|
||||
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) -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
|
||||
|
||||
repmgr: $(REPMGR_CLIENT_OBJS)
|
||||
|
||||
344
configfile-scan.l
Normal file
344
configfile-scan.l
Normal file
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
%}
|
||||
|
||||
%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
|
||||
ProcessConfigFile(FILE *fp, const char *config_file, 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 */
|
||||
|
||||
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 */
|
||||
}
|
||||
706
configfile.c
706
configfile.c
@@ -266,12 +266,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,365 +462,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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
(void) ProcessConfigFile(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"));
|
||||
}
|
||||
@@ -919,6 +560,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
|
||||
|
||||
@@ -317,6 +317,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 +344,7 @@ 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 ProcessConfigFile(FILE *fp, const char *config_file, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
|
||||
|
||||
#endif /* _REPMGR_CONFIGFILE_H_ */
|
||||
|
||||
@@ -24,6 +24,33 @@
|
||||
<sect2>
|
||||
<title>General enhancements</title>
|
||||
<para>
|
||||
<itemizedlist>
|
||||
|
||||
<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>
|
||||
<note>
|
||||
<para>
|
||||
This change makes configuration file parsing somewhat stricter
|
||||
than previously. When upgrading, be sure to check your
|
||||
configuration file syntax.
|
||||
<!-- XXX add notes in upgrade section -->
|
||||
</para>
|
||||
<para>
|
||||
In particular, all string values containing spaces
|
||||
<emphasis>must</emphasis> be contained within single quotes.
|
||||
</para>
|
||||
</note>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
Reference in New Issue
Block a user