Parse the contents of the "pg_basebackup_options" parameter in repmgr.conf

This is to ensure that when repmgr executes pg_basebackup it doesn't
add any options which would conflict with user-supplied options.

This is related to GitHub #206, where the -S/--slot option has been
added for 9.6 - it's important to check this doesn't conflict with
-X/--xlog-method.

While we're at it, rename the ErrorList handling code to ItemList
etc. so we can use it for generic non-error-related lists.
This commit is contained in:
Ian Barwick
2016-07-26 16:12:43 +09:00
parent 36eb26f86d
commit 02668ee045
7 changed files with 207 additions and 98 deletions

View File

@@ -1,5 +1,6 @@
/* /*
* config.c - Functions to parse the config file * config.c - Functions to parse the config file
*
* Copyright (C) 2ndQuadrant, 2010-2016 * Copyright (C) 2ndQuadrant, 2010-2016
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@@ -26,7 +27,7 @@
static void parse_event_notifications_list(t_configuration_options *options, const char *arg); static void parse_event_notifications_list(t_configuration_options *options, const char *arg);
static void tablespace_list_append(t_configuration_options *options, const char *arg); static void tablespace_list_append(t_configuration_options *options, const char *arg);
static void exit_with_errors(ErrorList *config_errors); static void exit_with_errors(ItemList *config_errors);
const static char *_progname = NULL; const static char *_progname = NULL;
static char config_file_path[MAXPGPATH]; static char config_file_path[MAXPGPATH];
@@ -201,7 +202,7 @@ parse_config(t_configuration_options *options)
char *conninfo_errmsg = NULL; char *conninfo_errmsg = NULL;
/* Collate configuration file errors here for friendlier reporting */ /* Collate configuration file errors here for friendlier reporting */
static ErrorList config_errors = { NULL, NULL }; static ItemList config_errors = { NULL, NULL };
bool node_found = false; bool node_found = false;
@@ -333,7 +334,7 @@ parse_config(t_configuration_options *options)
} }
else else
{ {
error_list_append(&config_errors,_("value for 'failover' must be 'automatic' or 'manual'\n")); item_list_append(&config_errors,_("value for 'failover' must be 'automatic' or 'manual'\n"));
} }
} }
else if (strcmp(name, "priority") == 0) else if (strcmp(name, "priority") == 0)
@@ -406,7 +407,7 @@ parse_config(t_configuration_options *options)
_("no value provided for parameter \"%s\""), _("no value provided for parameter \"%s\""),
name); name);
error_list_append(&config_errors, error_message_buf); item_list_append(&config_errors, error_message_buf);
} }
} }
@@ -415,11 +416,11 @@ parse_config(t_configuration_options *options)
if (node_found == false) if (node_found == false)
{ {
error_list_append(&config_errors, _("\"node\": parameter was not found")); item_list_append(&config_errors, _("\"node\": parameter was not found"));
} }
else if (options->node == 0) else if (options->node == 0)
{ {
error_list_append(&config_errors, _("\"node\": must be greater than zero")); item_list_append(&config_errors, _("\"node\": must be greater than zero"));
} }
if (strlen(options->conninfo)) if (strlen(options->conninfo))
@@ -439,7 +440,7 @@ parse_config(t_configuration_options *options)
_("\"conninfo\": %s"), _("\"conninfo\": %s"),
conninfo_errmsg); conninfo_errmsg);
error_list_append(&config_errors, error_message_buf); item_list_append(&config_errors, error_message_buf);
} }
PQconninfoFree(conninfo_options); PQconninfoFree(conninfo_options);
@@ -770,11 +771,11 @@ reload_config(t_configuration_options *orig_options)
void void
error_list_append(ErrorList *error_list, char *error_message) item_list_append(ItemList *item_list, char *error_message)
{ {
ErrorListCell *cell; ItemListCell *cell;
cell = (ErrorListCell *) pg_malloc0(sizeof(ErrorListCell)); cell = (ItemListCell *) pg_malloc0(sizeof(ItemListCell));
if (cell == NULL) if (cell == NULL)
{ {
@@ -782,19 +783,19 @@ error_list_append(ErrorList *error_list, char *error_message)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
cell->error_message = pg_malloc0(MAXLEN); cell->string = pg_malloc0(MAXLEN);
strncpy(cell->error_message, error_message, MAXLEN); strncpy(cell->string, error_message, MAXLEN);
if (error_list->tail) if (item_list->tail)
{ {
error_list->tail->next = cell; item_list->tail->next = cell;
} }
else else
{ {
error_list->head = cell; item_list->head = cell;
} }
error_list->tail = cell; item_list->tail = cell;
} }
@@ -804,7 +805,7 @@ error_list_append(ErrorList *error_list, char *error_message)
* otherwise exit * otherwise exit
*/ */
int int
repmgr_atoi(const char *value, const char *config_item, ErrorList *error_list, bool allow_negative) repmgr_atoi(const char *value, const char *config_item, ItemList *error_list, bool allow_negative)
{ {
char *endptr; char *endptr;
long longval = 0; long longval = 0;
@@ -853,7 +854,7 @@ repmgr_atoi(const char *value, const char *config_item, ErrorList *error_list, b
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
error_list_append(error_list, error_message_buf); item_list_append(error_list, error_message_buf);
} }
return (int32) longval; return (int32) longval;
@@ -995,15 +996,15 @@ parse_event_notifications_list(t_configuration_options *options, const char *arg
static void static void
exit_with_errors(ErrorList *config_errors) exit_with_errors(ItemList *config_errors)
{ {
ErrorListCell *cell; ItemListCell *cell;
log_err(_("%s: following errors were found in the configuration file.\n"), progname()); log_err(_("%s: following errors were found in the configuration file.\n"), progname());
for (cell = config_errors->head; cell; cell = cell->next) for (cell = config_errors->head; cell; cell = cell->next)
{ {
log_err("%s\n", cell->error_message); log_err("%s\n", cell->string);
} }
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);

View File

@@ -1,5 +1,6 @@
/* /*
* config.h * config.h
*
* Copyright (c) 2ndQuadrant, 2010-2016 * Copyright (c) 2ndQuadrant, 2010-2016
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@@ -92,17 +93,17 @@ typedef struct
*/ */
#define T_CONFIGURATION_OPTIONS_INITIALIZER { "", -1, NO_UPSTREAM_NODE, "", MANUAL_FAILOVER, -1, "", "", "", "", "", "", "", "", "", "", -1, -1, -1, "", "", "", "", "", 0, 0, 0, 0, "", { NULL, NULL }, {NULL, NULL} } #define T_CONFIGURATION_OPTIONS_INITIALIZER { "", -1, NO_UPSTREAM_NODE, "", MANUAL_FAILOVER, -1, "", "", "", "", "", "", "", "", "", "", -1, -1, -1, "", "", "", "", "", 0, 0, 0, 0, "", { NULL, NULL }, {NULL, NULL} }
typedef struct ErrorListCell typedef struct ItemListCell
{ {
struct ErrorListCell *next; struct ItemListCell *next;
char *error_message; char *string;
} ErrorListCell; } ItemListCell;
typedef struct ErrorList typedef struct ItemList
{ {
ErrorListCell *head; ItemListCell *head;
ErrorListCell *tail; ItemListCell *tail;
} ErrorList; } ItemList;
void set_progname(const char *argv0); void set_progname(const char *argv0);
const char * progname(void); const char * progname(void);
@@ -112,10 +113,10 @@ bool reload_config(t_configuration_options *orig_options);
bool parse_config(t_configuration_options *options); bool parse_config(t_configuration_options *options);
void parse_line(char *buff, char *name, char *value); void parse_line(char *buff, char *name, char *value);
char *trim(char *s); char *trim(char *s);
void error_list_append(ErrorList *error_list, char *error_message); void item_list_append(ItemList *item_list, char *error_message);
int repmgr_atoi(const char *s, int repmgr_atoi(const char *s,
const char *config_item, const char *config_item,
ErrorList *error_list, ItemList *error_list,
bool allow_negative); bool allow_negative);
extern bool config_file_found;
#endif #endif

View File

@@ -1,5 +1,6 @@
/* /*
* dbutils.c - Database connection/management functions * dbutils.c - Database connection/management functions
*
* Copyright (C) 2ndQuadrant, 2010-2016 * Copyright (C) 2ndQuadrant, 2010-2016
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify

View File

@@ -1,5 +1,6 @@
/* /*
* dbutils.h * dbutils.h
*
* Copyright (c) 2ndQuadrant, 2010-2016 * Copyright (c) 2ndQuadrant, 2010-2016
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@@ -77,7 +78,7 @@ typedef struct s_replication_slot
bool active; bool active;
} t_replication_slot; } t_replication_slot;
extern char repmgr_schema[MAXLEN];
PGconn *_establish_db_connection(const char *conninfo, PGconn *_establish_db_connection(const char *conninfo,
const bool exit_on_error, const bool exit_on_error,

213
repmgr.c
View File

@@ -1,5 +1,6 @@
/* /*
* repmgr.c - Command interpreter for the repmgr package * repmgr.c - Command interpreter for the repmgr package
*
* Copyright (C) 2ndQuadrant, 2010-2016 * Copyright (C) 2ndQuadrant, 2010-2016
* *
* This module is a command-line utility to easily setup a cluster of * This module is a command-line utility to easily setup a cluster of
@@ -117,7 +118,7 @@ static void do_check_upstream_config(void);
static void do_help(void); static void do_help(void);
static void exit_with_errors(void); static void exit_with_errors(void);
static void print_error_list(ErrorList *error_list, int log_level); static void print_error_list(ItemList *error_list, int log_level);
static bool remote_command(const char *host, const char *user, const char *command, PQExpBufferData *outputbuf); static bool remote_command(const char *host, const char *user, const char *command, PQExpBufferData *outputbuf);
static void format_db_cli_params(const char *conninfo, char *output); static void format_db_cli_params(const char *conninfo, char *output);
@@ -126,6 +127,7 @@ static bool copy_file(const char *old_filename, const char *new_filename);
static bool read_backup_label(const char *local_data_directory, struct BackupLabel *out_backup_label); static bool read_backup_label(const char *local_data_directory, struct BackupLabel *out_backup_label);
static void param_set(const char *param, const char *value); static void param_set(const char *param, const char *value);
static void parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_options *backup_options);
/* Global variables */ /* Global variables */
static PQconninfoOption *opts = NULL; static PQconninfoOption *opts = NULL;
@@ -155,8 +157,8 @@ static char *repmgr_slot_name_ptr = NULL;
static char path_buf[MAXLEN] = ""; static char path_buf[MAXLEN] = "";
/* Collate command line errors and warnings here for friendlier reporting */ /* Collate command line errors and warnings here for friendlier reporting */
ErrorList cli_errors = { NULL, NULL }; ItemList cli_errors = { NULL, NULL };
ErrorList cli_warnings = { NULL, NULL }; ItemList cli_warnings = { NULL, NULL };
static struct BackupLabel backup_label; static struct BackupLabel backup_label;
@@ -228,7 +230,6 @@ main(int argc, char **argv)
exit(1); exit(1);
} }
param_count = 0; param_count = 0;
defs = PQconndefaults(); defs = PQconndefaults();
@@ -417,7 +418,7 @@ main(int argc, char **argv)
PQExpBufferData invalid_log_level; PQExpBufferData invalid_log_level;
initPQExpBuffer(&invalid_log_level); initPQExpBuffer(&invalid_log_level);
appendPQExpBuffer(&invalid_log_level, _("Invalid log level \"%s\" provided"), optarg); appendPQExpBuffer(&invalid_log_level, _("Invalid log level \"%s\" provided"), optarg);
error_list_append(&cli_errors, invalid_log_level.data); item_list_append(&cli_errors, invalid_log_level.data);
termPQExpBuffer(&invalid_log_level); termPQExpBuffer(&invalid_log_level);
} }
break; break;
@@ -439,7 +440,7 @@ main(int argc, char **argv)
PQExpBufferData invalid_mode; PQExpBufferData invalid_mode;
initPQExpBuffer(&invalid_mode); initPQExpBuffer(&invalid_mode);
appendPQExpBuffer(&invalid_mode, _("Invalid pg_ctl shutdown mode \"%s\" provided"), optarg); appendPQExpBuffer(&invalid_mode, _("Invalid pg_ctl shutdown mode \"%s\" provided"), optarg);
error_list_append(&cli_errors, invalid_mode.data); item_list_append(&cli_errors, invalid_mode.data);
termPQExpBuffer(&invalid_mode); termPQExpBuffer(&invalid_mode);
} }
} }
@@ -458,7 +459,7 @@ main(int argc, char **argv)
if (targ < 1) if (targ < 1)
{ {
error_list_append(&cli_errors, _("Invalid value provided for '-r/--recovery-min-apply-delay'")); item_list_append(&cli_errors, _("Invalid value provided for '-r/--recovery-min-apply-delay'"));
break; break;
} }
if (ptr && *ptr) if (ptr && *ptr)
@@ -467,7 +468,7 @@ main(int argc, char **argv)
strcmp(ptr, "min") != 0 && strcmp(ptr, "h") != 0 && strcmp(ptr, "min") != 0 && strcmp(ptr, "h") != 0 &&
strcmp(ptr, "d") != 0) strcmp(ptr, "d") != 0)
{ {
error_list_append(&cli_errors, _("Value provided for '-r/--recovery-min-apply-delay' must be one of ms/s/min/h/d")); item_list_append(&cli_errors, _("Value provided for '-r/--recovery-min-apply-delay' must be one of ms/s/min/h/d"));
break; break;
} }
} }
@@ -500,7 +501,7 @@ main(int argc, char **argv)
initPQExpBuffer(&unknown_option); initPQExpBuffer(&unknown_option);
appendPQExpBuffer(&unknown_option, _("Unknown option '%s'"), argv[optind - 1]); appendPQExpBuffer(&unknown_option, _("Unknown option '%s'"), argv[optind - 1]);
error_list_append(&cli_errors, unknown_option.data); item_list_append(&cli_errors, unknown_option.data);
} }
} }
} }
@@ -526,7 +527,7 @@ main(int argc, char **argv)
PQExpBufferData conninfo_error; PQExpBufferData conninfo_error;
initPQExpBuffer(&conninfo_error); initPQExpBuffer(&conninfo_error);
appendPQExpBuffer(&conninfo_error, _("error parsing conninfo:\n%s"), errmsg); appendPQExpBuffer(&conninfo_error, _("error parsing conninfo:\n%s"), errmsg);
error_list_append(&cli_errors, conninfo_error.data); item_list_append(&cli_errors, conninfo_error.data);
termPQExpBuffer(&conninfo_error); termPQExpBuffer(&conninfo_error);
free(errmsg); free(errmsg);
@@ -614,7 +615,7 @@ main(int argc, char **argv)
PQExpBufferData unknown_mode; PQExpBufferData unknown_mode;
initPQExpBuffer(&unknown_mode); initPQExpBuffer(&unknown_mode);
appendPQExpBuffer(&unknown_mode, _("Unknown server mode '%s'"), server_mode); appendPQExpBuffer(&unknown_mode, _("Unknown server mode '%s'"), server_mode);
error_list_append(&cli_errors, unknown_mode.data); item_list_append(&cli_errors, unknown_mode.data);
} }
} }
@@ -663,14 +664,14 @@ main(int argc, char **argv)
if (action == NO_ACTION) { if (action == NO_ACTION) {
if (server_cmd == NULL) if (server_cmd == NULL)
{ {
error_list_append(&cli_errors, "No server command provided"); item_list_append(&cli_errors, "No server command provided");
} }
else else
{ {
PQExpBufferData unknown_action; PQExpBufferData unknown_action;
initPQExpBuffer(&unknown_action); initPQExpBuffer(&unknown_action);
appendPQExpBuffer(&unknown_action, _("Unknown server command '%s'"), server_cmd); appendPQExpBuffer(&unknown_action, _("Unknown server command '%s'"), server_cmd);
error_list_append(&cli_errors, unknown_action.data); item_list_append(&cli_errors, unknown_action.data);
} }
} }
@@ -686,7 +687,7 @@ main(int argc, char **argv)
appendPQExpBuffer(&additional_host_arg, appendPQExpBuffer(&additional_host_arg,
_("Conflicting parameters: you can't use %s while providing a node separately."), _("Conflicting parameters: you can't use %s while providing a node separately."),
conninfo_provided == true ? "host=" : "-h/--host"); conninfo_provided == true ? "host=" : "-h/--host");
error_list_append(&cli_errors, additional_host_arg.data); item_list_append(&cli_errors, additional_host_arg.data);
} }
else else
{ {
@@ -701,7 +702,7 @@ main(int argc, char **argv)
PQExpBufferData too_many_args; PQExpBufferData too_many_args;
initPQExpBuffer(&too_many_args); initPQExpBuffer(&too_many_args);
appendPQExpBuffer(&too_many_args, _("too many command-line arguments (first extra is \"%s\")"), argv[optind]); appendPQExpBuffer(&too_many_args, _("too many command-line arguments (first extra is \"%s\")"), argv[optind]);
error_list_append(&cli_errors, too_many_args.data); item_list_append(&cli_errors, too_many_args.data);
} }
check_parameters_for_action(action); check_parameters_for_action(action);
@@ -4618,6 +4619,13 @@ run_basebackup(const char *data_dir, int server_version)
int r = 0; int r = 0;
PQExpBufferData params; PQExpBufferData params;
TablespaceListCell *cell; TablespaceListCell *cell;
t_basebackup_options backup_options = T_BASEBACKUP_OPTIONS_INITIALIZER;
/*
* Parse the pg_basebackup_options provided in repmgr.conf - we'll want
* to check later whether certain options were set by the user
*/
parse_pg_basebackup_options(options.pg_basebackup_options, &backup_options);
/* Create pg_basebackup command line options */ /* Create pg_basebackup command line options */
@@ -4678,33 +4686,39 @@ run_basebackup(const char *data_dir, int server_version)
* created a slot with reserved LSN, and will stream from that slot to avoid * created a slot with reserved LSN, and will stream from that slot to avoid
* WAL buildup on the master using the -S/--slot, which requires -X/--xlog-method=stream * WAL buildup on the master using the -S/--slot, which requires -X/--xlog-method=stream
*/ */
{ if (!strlen(backup_options.xlog_method))
/*
* We're going to check first if the user set the xlog method in the repmgr.conf
* file. We don't want to have conflicts with pg_basebackup due to specifying the
* method twice.
*/
const char xlog_short[4] = "-X ";
const char xlog_long[14] = "--xlog-method";
if (strstr(options.pg_basebackup_options, xlog_short) == NULL && strstr(options.pg_basebackup_options, xlog_long) == NULL )
{ {
appendPQExpBuffer(&params, " -X stream"); appendPQExpBuffer(&params, " -X stream");
} }
}
/* /*
* From 9.6, pg_basebackup accepts -S/--slot, which forces WAL streaming to use * From 9.6, pg_basebackup accepts -S/--slot, which forces WAL streaming to use
* the specified replication slot. If replication slot usage is specified, the * the specified replication slot. If replication slot usage is specified, the
* slot will already have been created * slot will already have been created.
* *
* XXX verify that -X/--xlog-method is set to "stream" * NOTE: currently there's no way of disabling the --slot option while using
* --xlog-method=stream - it's hard to imagine a use case for this, so no
* provision has been made for doing it.
*
* NOTE:
* It's possible to set 'pg_basebackup_options' with an invalid combination
* of values for --xlog-method and --slot - we're not checking that, just that
* we're not overriding any user-supplied values
*/ */
if (server_version >= 90600 && options.use_replication_slots) if (server_version >= 90600 && options.use_replication_slots)
{ {
const char slot_short[4] = "-S "; bool slot_add = true;
const char slot_long[7] = "--slot";
if (strstr(options.pg_basebackup_options, slot_short) == NULL && strstr(options.pg_basebackup_options, slot_long) == NULL ) /*
* Check whether 'pg_basebackup_options' in repmgr.conf has the --slot option set,
* or if --xlog-method is set to a value other than "stream" (in which case we can't
* use --slot).
*/
if(strlen(backup_options.slot) || strcmp(backup_options.xlog_method, "stream") != 0) {
slot_add = false;
}
if (slot_add == true)
{ {
appendPQExpBuffer(&params, " -S %s", repmgr_slot_name_ptr); appendPQExpBuffer(&params, " -S %s", repmgr_slot_name_ptr);
} }
@@ -4748,11 +4762,11 @@ check_parameters_for_action(const int action)
*/ */
if (connection_param_provided) if (connection_param_provided)
{ {
error_list_append(&cli_warnings, _("master connection parameters not required when executing MASTER REGISTER")); item_list_append(&cli_warnings, _("master connection parameters not required when executing MASTER REGISTER"));
} }
if (runtime_options.dest_dir[0]) if (runtime_options.dest_dir[0])
{ {
error_list_append(&cli_warnings, _("destination directory not required when executing MASTER REGISTER")); item_list_append(&cli_warnings, _("destination directory not required when executing MASTER REGISTER"));
} }
break; break;
case STANDBY_REGISTER: case STANDBY_REGISTER:
@@ -4764,11 +4778,11 @@ check_parameters_for_action(const int action)
*/ */
if (connection_param_provided) if (connection_param_provided)
{ {
error_list_append(&cli_warnings, _("master connection parameters not required when executing STANDBY REGISTER")); item_list_append(&cli_warnings, _("master connection parameters not required when executing STANDBY REGISTER"));
} }
if (runtime_options.dest_dir[0]) if (runtime_options.dest_dir[0])
{ {
error_list_append(&cli_warnings, _("destination directory not required when executing STANDBY REGISTER")); item_list_append(&cli_warnings, _("destination directory not required when executing STANDBY REGISTER"));
} }
break; break;
case STANDBY_UNREGISTER: case STANDBY_UNREGISTER:
@@ -4780,11 +4794,11 @@ check_parameters_for_action(const int action)
*/ */
if (connection_param_provided) if (connection_param_provided)
{ {
error_list_append(&cli_warnings, _("master connection parameters not required when executing STANDBY UNREGISTER")); item_list_append(&cli_warnings, _("master connection parameters not required when executing STANDBY UNREGISTER"));
} }
if (runtime_options.dest_dir[0]) if (runtime_options.dest_dir[0])
{ {
error_list_append(&cli_warnings, _("destination directory not required when executing STANDBY UNREGISTER")); item_list_append(&cli_warnings, _("destination directory not required when executing STANDBY UNREGISTER"));
} }
break; break;
case STANDBY_PROMOTE: case STANDBY_PROMOTE:
@@ -4797,11 +4811,11 @@ check_parameters_for_action(const int action)
*/ */
if (connection_param_provided) if (connection_param_provided)
{ {
error_list_append(&cli_warnings, _("master connection parameters not required when executing STANDBY PROMOTE")); item_list_append(&cli_warnings, _("master connection parameters not required when executing STANDBY PROMOTE"));
} }
if (runtime_options.dest_dir[0]) if (runtime_options.dest_dir[0])
{ {
error_list_append(&cli_warnings, _("destination directory not required when executing STANDBY PROMOTE")); item_list_append(&cli_warnings, _("destination directory not required when executing STANDBY PROMOTE"));
} }
break; break;
@@ -4818,12 +4832,12 @@ check_parameters_for_action(const int action)
{ {
if (!runtime_options.host[0]) if (!runtime_options.host[0])
{ {
error_list_append(&cli_errors, _("master hostname (-h/--host) required when executing STANDBY FOLLOW with -D/--data-dir option")); item_list_append(&cli_errors, _("master hostname (-h/--host) required when executing STANDBY FOLLOW with -D/--data-dir option"));
} }
if (host_param_provided && !runtime_options.dest_dir[0]) if (host_param_provided && !runtime_options.dest_dir[0])
{ {
error_list_append(&cli_errors, _("local data directory (-D/--data-dir) required when executing STANDBY FOLLOW with -h/--host option")); item_list_append(&cli_errors, _("local data directory (-D/--data-dir) required when executing STANDBY FOLLOW with -h/--host option"));
} }
} }
break; break;
@@ -4838,12 +4852,12 @@ check_parameters_for_action(const int action)
if (strcmp(runtime_options.host, "") == 0) if (strcmp(runtime_options.host, "") == 0)
{ {
error_list_append(&cli_errors, _("master hostname (-h/--host) required when executing STANDBY CLONE")); item_list_append(&cli_errors, _("master hostname (-h/--host) required when executing STANDBY CLONE"));
} }
if (runtime_options.fast_checkpoint && runtime_options.rsync_only) if (runtime_options.fast_checkpoint && runtime_options.rsync_only)
{ {
error_list_append(&cli_warnings, _("-c/--fast-checkpoint has no effect when using -r/--rsync-only")); item_list_append(&cli_warnings, _("-c/--fast-checkpoint has no effect when using -r/--rsync-only"));
} }
config_file_required = false; config_file_required = false;
break; break;
@@ -4854,19 +4868,19 @@ check_parameters_for_action(const int action)
case STANDBY_ARCHIVE_CONFIG: case STANDBY_ARCHIVE_CONFIG:
if (strcmp(runtime_options.config_archive_dir, "") == 0) if (strcmp(runtime_options.config_archive_dir, "") == 0)
{ {
error_list_append(&cli_errors, _("--config-archive-dir required when executing STANDBY ARCHIVE_CONFIG")); item_list_append(&cli_errors, _("--config-archive-dir required when executing STANDBY ARCHIVE_CONFIG"));
} }
break; break;
case STANDBY_RESTORE_CONFIG: case STANDBY_RESTORE_CONFIG:
if (strcmp(runtime_options.config_archive_dir, "") == 0) if (strcmp(runtime_options.config_archive_dir, "") == 0)
{ {
error_list_append(&cli_errors, _("--config-archive-dir required when executing STANDBY RESTORE_CONFIG")); item_list_append(&cli_errors, _("--config-archive-dir required when executing STANDBY RESTORE_CONFIG"));
} }
if (strcmp(runtime_options.dest_dir, "") == 0) if (strcmp(runtime_options.dest_dir, "") == 0)
{ {
error_list_append(&cli_errors, _("-D/--data-dir required when executing STANDBY RESTORE_CONFIG")); item_list_append(&cli_errors, _("-D/--data-dir required when executing STANDBY RESTORE_CONFIG"));
} }
config_file_required = false; config_file_required = false;
@@ -4876,7 +4890,7 @@ check_parameters_for_action(const int action)
/* Require data directory */ /* Require data directory */
if (strcmp(runtime_options.dest_dir, "") == 0) if (strcmp(runtime_options.dest_dir, "") == 0)
{ {
error_list_append(&cli_errors, _("-D/--data-dir required when executing WITNESS CREATE")); item_list_append(&cli_errors, _("-D/--data-dir required when executing WITNESS CREATE"));
} }
/* allow all parameters to be supplied */ /* allow all parameters to be supplied */
break; break;
@@ -4895,27 +4909,27 @@ check_parameters_for_action(const int action)
{ {
if (runtime_options.fast_checkpoint) if (runtime_options.fast_checkpoint)
{ {
error_list_append(&cli_warnings, _("-c/--fast-checkpoint can only be used when executing STANDBY CLONE")); item_list_append(&cli_warnings, _("-c/--fast-checkpoint can only be used when executing STANDBY CLONE"));
} }
if (runtime_options.ignore_external_config_files) if (runtime_options.ignore_external_config_files)
{ {
error_list_append(&cli_warnings, _("--ignore-external-config-files can only be used when executing STANDBY CLONE")); item_list_append(&cli_warnings, _("--ignore-external-config-files can only be used when executing STANDBY CLONE"));
} }
if (*runtime_options.recovery_min_apply_delay) if (*runtime_options.recovery_min_apply_delay)
{ {
error_list_append(&cli_warnings, _("--recovery-min-apply-delay can only be used when executing STANDBY CLONE")); item_list_append(&cli_warnings, _("--recovery-min-apply-delay can only be used when executing STANDBY CLONE"));
} }
if (runtime_options.rsync_only) if (runtime_options.rsync_only)
{ {
error_list_append(&cli_warnings, _("-r/--rsync-only can only be used when executing STANDBY CLONE")); item_list_append(&cli_warnings, _("-r/--rsync-only can only be used when executing STANDBY CLONE"));
} }
if (wal_keep_segments_used) if (wal_keep_segments_used)
{ {
error_list_append(&cli_warnings, _("-w/--wal-keep-segments can only be used when executing STANDBY CLONE")); item_list_append(&cli_warnings, _("-w/--wal-keep-segments can only be used when executing STANDBY CLONE"));
} }
} }
@@ -4924,7 +4938,7 @@ check_parameters_for_action(const int action)
{ {
if (pg_rewind_supplied == true) if (pg_rewind_supplied == true)
{ {
error_list_append(&cli_warnings, _("--pg_rewind can only be used when executing STANDBY SWITCHOVER")); item_list_append(&cli_warnings, _("--pg_rewind can only be used when executing STANDBY SWITCHOVER"));
} }
} }
@@ -4933,7 +4947,7 @@ check_parameters_for_action(const int action)
{ {
if (runtime_options.csv_mode) if (runtime_options.csv_mode)
{ {
error_list_append(&cli_warnings, _("--csv can only be used when executing CLUSTER SHOW")); item_list_append(&cli_warnings, _("--csv can only be used when executing CLUSTER SHOW"));
} }
} }
@@ -5703,9 +5717,9 @@ exit_with_errors(void)
static void static void
print_error_list(ErrorList *error_list, int log_level) print_error_list(ItemList *error_list, int log_level)
{ {
ErrorListCell *cell; ItemListCell *cell;
for (cell = error_list->head; cell; cell = cell->next) for (cell = error_list->head; cell; cell = cell->next)
{ {
@@ -5713,10 +5727,10 @@ print_error_list(ErrorList *error_list, int log_level)
{ {
/* Currently we only need errors and warnings */ /* Currently we only need errors and warnings */
case LOG_ERR: case LOG_ERR:
log_err("%s\n", cell->error_message); log_err("%s\n", cell->string);
break; break;
case LOG_WARNING: case LOG_WARNING:
log_warning("%s\n", cell->error_message); log_warning("%s\n", cell->string);
break; break;
} }
@@ -5906,3 +5920,88 @@ param_set(const char *param, const char *value)
*/ */
} }
static void
parse_pg_basebackup_options(const char *pg_basebackup_options, t_basebackup_options *backup_options)
{
int options_len = strlen(pg_basebackup_options) + 1;
char *options_string = pg_malloc(options_len);
char *options_string_ptr = options_string;
/*
* Add parsed options to this list, then copy to an array
* to pass to getopt
*/
static ItemList option_argv = { NULL, NULL };
char *argv_item;
int c, argc_item = 1;
char **argv_array;
ItemListCell *cell;
int optindex = 0;
static struct option long_options[] =
{
{"slot", required_argument, NULL, 'S'},
{"xlog-method", required_argument, NULL, 'X'},
{NULL, 0, NULL, 0}
};
/* Don't attempt to tokenise an empty string */
if (!strlen(pg_basebackup_options))
return;
/*
* Copy the string before operating on it with strtok()
*/
strncpy(options_string, pg_basebackup_options, options_len);
while ((argv_item = strtok(options_string_ptr, " ")) != NULL)
{
item_list_append(&option_argv, argv_item);
argc_item++;
if (options_string_ptr != NULL)
options_string_ptr = NULL;
}
argv_array = pg_malloc0(sizeof(char *) * (argc_item + 2));
/* Copy a dummy program name to the start of the array */
argv_array[0] = pg_malloc0(1);
strncpy(argv_array[0], "", 4);
c = 1;
for (cell = option_argv.head; cell; cell = cell->next)
{
int argv_len = strlen(cell->string) + 1;
argv_array[c] = pg_malloc0(argv_len);
strncpy(argv_array[c], cell->string, argv_len);
c++;
}
argv_array[c] = NULL;
while ((c = getopt_long(argc_item, argv_array, "S:X:", long_options,
&optindex)) != -1)
{
switch (c)
{
case 'S':
strncpy(backup_options->slot, optarg, MAXLEN);
break;
case 'X':
strncpy(backup_options->xlog_method, optarg, MAXLEN);
break;
}
}
return;
}

View File

@@ -52,7 +52,6 @@
/* Run time options type */ /* Run time options type */
typedef struct typedef struct
{ {
char dbname[MAXLEN]; char dbname[MAXLEN];
char host[MAXLEN]; char host[MAXLEN];
char username[MAXLEN]; char username[MAXLEN];
@@ -110,7 +109,13 @@ struct BackupLabel
XLogRecPtr min_failover_slot_lsn; XLogRecPtr min_failover_slot_lsn;
}; };
extern char repmgr_schema[MAXLEN];
extern bool config_file_found; typedef struct
{
char slot[MAXLEN];
char xlog_method[MAXLEN];
} t_basebackup_options;
#define T_BASEBACKUP_OPTIONS_INITIALIZER { "", "" }
#endif #endif

View File

@@ -1,5 +1,6 @@
/* /*
* repmgrd.c - Replication manager daemon * repmgrd.c - Replication manager daemon
*
* Copyright (C) 2ndQuadrant, 2010-2016 * Copyright (C) 2ndQuadrant, 2010-2016
* *
* This module connects to the nodes of a replication cluster and monitors * This module connects to the nodes of a replication cluster and monitors