"standby clone": basic port complete

This commit is contained in:
Ian Barwick
2017-05-02 14:25:08 +09:00
parent 0a553c309b
commit 00fd8e81f8
9 changed files with 609 additions and 50 deletions

View File

@@ -96,7 +96,7 @@ load_config(const char *config_file, bool verbose, bool terse, t_configuration_o
log_notice(_("looking for configuration file in current directory")); log_notice(_("looking for configuration file in current directory"));
} }
snprintf(config_file_path, MAXPGPATH, "./%s", CONFIG_FILE_NAME); maxpath_snprintf(config_file_path, "./%s", CONFIG_FILE_NAME);
canonicalize_path(config_file_path); canonicalize_path(config_file_path);
if (stat(config_file_path, &stat_config) == 0) if (stat(config_file_path, &stat_config) == 0)
@@ -111,7 +111,7 @@ load_config(const char *config_file, bool verbose, bool terse, t_configuration_o
log_notice(_("looking for configuration file in /etc")); log_notice(_("looking for configuration file in /etc"));
} }
snprintf(config_file_path, MAXPGPATH, "/etc/%s", CONFIG_FILE_NAME); maxpath_snprintf(config_file_path, "/etc/%s", CONFIG_FILE_NAME);
if (stat(config_file_path, &stat_config) == 0) if (stat(config_file_path, &stat_config) == 0)
{ {
config_file_found = true; config_file_found = true;
@@ -132,7 +132,7 @@ load_config(const char *config_file, bool verbose, bool terse, t_configuration_o
log_notice(_("looking for configuration file in %s"), sysconf_etc_path); log_notice(_("looking for configuration file in %s"), sysconf_etc_path);
} }
snprintf(config_file_path, MAXPGPATH, "%s/%s", sysconf_etc_path, CONFIG_FILE_NAME); maxpath_snprintf(config_file_path, "%s/%s", sysconf_etc_path, CONFIG_FILE_NAME);
if (stat(config_file_path, &stat_config) == 0) if (stat(config_file_path, &stat_config) == 0)
{ {
config_file_found = true; config_file_found = true;
@@ -486,10 +486,9 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
*/ */
if (known_parameter == true && !strlen(value)) { if (known_parameter == true && !strlen(value)) {
char error_message_buf[MAXLEN] = ""; char error_message_buf[MAXLEN] = "";
snprintf(error_message_buf, maxlen_snprintf(error_message_buf,
MAXLEN, _("\"%s\": no value provided"),
_("\"%s\": no value provided"), name);
name);
item_list_append(error_list, error_message_buf); item_list_append(error_list, error_message_buf);
} }

View File

@@ -1633,6 +1633,41 @@ create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, P
return true; return true;
} }
bool
drop_replication_slot(PGconn *conn, char *slot_name)
{
PQExpBufferData query;
PGresult *res;
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
"SELECT pg_drop_replication_slot('%s')",
slot_name);
log_verbose(LOG_DEBUG, "drop_replication_slot():\n %s", query.data);
res = PQexec(conn, query.data);
termPQExpBuffer(&query);
if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_error(_("unable to drop replication slot \"%s\":\n %s"),
slot_name,
PQerrorMessage(conn));
PQclear(res);
return false;
}
log_verbose(LOG_DEBUG, "replication slot \"%s\" successfully dropped",
slot_name);
return true;
}
int int
get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record) get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record)
{ {
@@ -1650,6 +1685,9 @@ get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record)
log_verbose(LOG_DEBUG, "get_slot_record():\n%s", query.data); log_verbose(LOG_DEBUG, "get_slot_record():\n%s", query.data);
res = PQexec(conn, query.data); res = PQexec(conn, query.data);
termPQExpBuffer(&query);
if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
{ {
log_error(_("unable to query pg_replication_slots:\n %s"), log_error(_("unable to query pg_replication_slots:\n %s"),

View File

@@ -181,7 +181,7 @@ bool create_event_record_extended(PGconn *conn, t_configuration_options *
/* replication slot functions */ /* replication slot functions */
bool create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, PQExpBufferData *error_msg); bool create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, PQExpBufferData *error_msg);
bool drop_replication_slot(PGconn *conn, char *slot_name);
int get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record); int get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record);
/* backup functions */ /* backup functions */

View File

@@ -69,6 +69,8 @@ static char *last_wal_segment = NULL;
static bool pg_start_backup_executed = false; static bool pg_start_backup_executed = false;
static struct BackupLabel backup_label;
/* used by barman mode */ /* used by barman mode */
static char local_repmgr_tmp_directory[MAXPGPATH]; static char local_repmgr_tmp_directory[MAXPGPATH];
static char barman_command_buf[MAXLEN] = ""; static char barman_command_buf[MAXLEN] = "";
@@ -82,6 +84,8 @@ static void check_source_server_via_barman(void);
static void initialise_direct_clone(void); static void initialise_direct_clone(void);
static void config_file_list_init(t_configfile_list *list, int max_size); static void config_file_list_init(t_configfile_list *list, int max_size);
static void config_file_list_add(t_configfile_list *list, const char *file, const char *filename, bool in_data_dir); static void config_file_list_add(t_configfile_list *list, const char *file, const char *filename, bool in_data_dir);
static void copy_configuration_files(void);
static void cleanup_data_directory(void);
static int run_basebackup(void); static int run_basebackup(void);
static int run_file_backup(void); static int run_file_backup(void);
@@ -306,27 +310,64 @@ do_standby_clone(void)
if (mode == pg_basebackup) if (mode == pg_basebackup)
{ {
r = run_basebackup(); r = run_basebackup();
if (r != 0)
{
log_warning(_("standby clone: base backup failed"));
r = ERR_BAD_BASEBACKUP;
}
} }
else else
{ {
r = run_file_backup(); r = run_file_backup();
if (r != 0) }
{
log_warning(_("standby clone: base backup failed"));
r = ERR_BAD_BASEBACKUP;
/* If the backup failed then exit */
if (r != 0)
{
/* If a replication slot was previously created, drop it */
if (config_file_options.use_replication_slots)
{
drop_replication_slot(source_conn, repmgr_slot_name);
} }
log_error(_("unable to take a base backup of the master server"));
log_warning(_("data directory (%s) may need to be cleaned up manually"),
local_data_directory);
PQfinish(source_conn);
exit(r);
}
/*
* If `--copy-external-config-files` was provided, copy any configuration
* files detected to the appropriate location. Any errors encountered
* will not be treated as fatal.
*
* XXX check this won't run in Barman mode
*/
if (runtime_options.copy_external_config_files && config_files.entries)
{
copy_configuration_files();
}
/* Write the recovery.conf file */
create_recovery_file(local_data_directory, &recovery_conninfo);
switch(mode)
{
case rsync:
log_notice(_("standby clone (using rsync) complete"));
break;
case pg_basebackup:
log_notice(_("standby clone (using pg_basebackup) complete"));
break;
case barman:
log_notice(_("standby clone (from Barman) complete"));
break;
} }
} }
void void
check_barman_config(void) check_barman_config(void)
{ {
@@ -678,7 +719,7 @@ initialise_direct_clone(void)
if (!create_pg_dir(local_data_directory, runtime_options.force)) if (!create_pg_dir(local_data_directory, runtime_options.force))
{ {
log_error(_("unable to use directory %s ..."), log_error(_("unable to use directory %s"),
local_data_directory); local_data_directory);
log_hint(_("use -F/--force to force this directory to be overwritten")); log_hint(_("use -F/--force to force this directory to be overwritten"));
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
@@ -1008,10 +1049,15 @@ run_basebackup(void)
/* /*
* As of 9.4, pg_basebackup only ever returns 0 or 1 * As of 9.4, pg_basebackup only ever returns 0 or 1
* XXX check for 10
*/ */
r = system(script); r = system(script);
if (r !=0)
return r;
return r; return r;
} }
@@ -1036,7 +1082,6 @@ run_file_backup(void)
char datadir_list_filename[MAXLEN]; char datadir_list_filename[MAXLEN];
struct BackupLabel backup_label;
if (mode == barman) if (mode == barman)
{ {
@@ -1518,17 +1563,68 @@ run_file_backup(void)
fclose(tablespace_map_file); fclose(tablespace_map_file);
} }
/*
* When using rsync, copy pg_control file last, emulating the base backup
* protocol.
*/
if (mode == rsync)
{
char upstream_control_file[MAXPGPATH] = "";
char local_control_file[MAXPGPATH] = "";
maxlen_snprintf(local_control_file, "%s/global", local_data_directory);
log_info(_("standby clone: local control file '%s'"),
local_control_file);
if (!create_dir(local_control_file))
{
log_error(_("couldn't create directory %s"),
local_control_file);
goto stop_backup;
}
maxlen_snprintf(upstream_control_file, "%s/global/pg_control",
upstream_data_directory);
log_debug("standby clone: upstream control file is \"%s\"",
upstream_control_file);
r = copy_remote_files(runtime_options.host, runtime_options.remote_user,
upstream_control_file, local_control_file,
false, server_version_num);
if (WEXITSTATUS(r))
{
log_warning(_("standby clone: failed copying upstreamcontrol file \"%s\""),
upstream_control_file);
r = ERR_BAD_SSH;
goto stop_backup;
}
}
stop_backup: stop_backup:
if (mode == rsync && pg_start_backup_executed) if (mode == rsync && pg_start_backup_executed)
{ {
log_notice(_("notifying upstream about backup completion...\n")); log_notice(_("notifying upstream about backup completion"));
if (stop_backup(source_conn, last_wal_segment, server_version_num) == false) if (stop_backup(source_conn, last_wal_segment, server_version_num) == false)
{ {
r = ERR_BAD_BASEBACKUP; r = ERR_BAD_BASEBACKUP;
} }
} }
/* clean up copied data directory */
if (mode == rsync)
{
cleanup_data_directory();
}
else if (mode == barman)
{
/* In Barman mode, remove local_repmgr_directory */
rmtree(local_repmgr_tmp_directory, true);
}
return r; return r;
} }
@@ -1545,7 +1641,7 @@ make_barman_ssh_command(char *buf)
maxlen_snprintf(buf, maxlen_snprintf(buf,
"ssh %s barman%s", "ssh %s barman%s",
config_file_options.barman_server, config_file_options.barman_host,
config_opt); config_opt);
return buf; return buf;
@@ -1684,6 +1780,67 @@ config_file_list_add(t_configfile_list *list, const char *file, const char *file
list->entries ++; list->entries ++;
} }
static void
copy_configuration_files(void)
{
int i, r;
t_configfile_info *file;
char *host;
/* get host from upstream record */
host = param_get(&recovery_conninfo, "host");
if (host == NULL)
host = runtime_options.host;
log_verbose(LOG_DEBUG, "fetching configuration files from host \"%s\"", host);
log_notice(_("copying external configuration files from upstream node"));
r = test_ssh_connection(host, runtime_options.remote_user);
if (r != 0)
{
log_error(_("remote host %s is not reachable via SSH - unable to copy external configuration files"),
host);
return;
}
for (i = 0; i < config_files.entries; i++)
{
char dest_path[MAXPGPATH];
file = config_files.files[i];
/*
* Skip files in the data directory - these will be copied during
* the main backup
*/
if (file->in_data_directory == true)
continue;
if (runtime_options.copy_external_config_files_destination == CONFIG_FILE_SAMEPATH)
{
strncpy(dest_path, file->filepath, MAXPGPATH);
}
else
{
snprintf(dest_path, MAXPGPATH,
"%s/%s",
local_data_directory,
file->filename);
}
r = copy_remote_files(runtime_options.host, runtime_options.remote_user,
file->filepath, dest_path, false, server_version_num);
if (WEXITSTATUS(r))
{
log_error(_("standby clone: unable to copy config file \"%s\""),
file->filename);
}
}
return;
}
static int static int
get_tablespace_data(PGconn *upstream_conn, TablespaceDataList *list) get_tablespace_data(PGconn *upstream_conn, TablespaceDataList *list)
@@ -1927,3 +2084,63 @@ read_backup_label(const char *local_data_directory, struct BackupLabel *out_back
return true; return true;
} }
static void
cleanup_data_directory(void)
{
char dirpath[MAXLEN] = "";
if (runtime_options.force)
{
/*
* Remove any WAL files in the target directory which might have
* been left over from previous use of this data directory;
* rsync's --exclude option won't do this.
*/
if (server_version_num >= 100000)
maxlen_snprintf(dirpath, "%s/pg_wal/", local_data_directory);
else
maxlen_snprintf(dirpath, "%s/pg_xlog/", local_data_directory);
if (!rmtree(dirpath, false))
{
log_error(_("unable to empty local WAL directory %s"),
dirpath);
exit(ERR_BAD_RSYNC);
}
}
/*
* Remove any existing replication slot directories from previous use
* of this data directory; this matches the behaviour of a fresh
* pg_basebackup, which would usually result in an empty pg_replslot
* directory.
*
* If the backup label contains a nonzero
* 'MIN FAILOVER SLOT LSN' entry we retain the slots and let
* the server clean them up instead, matching pg_basebackup's
* behaviour when failover slots are enabled.
*
* NOTE: watch out for any changes in the replication
* slot directory name (as of 9.4: "pg_replslot") and
* functionality of replication slots
*/
if (server_version_num >= 90400 &&
backup_label.min_failover_slot_lsn == InvalidXLogRecPtr)
{
maxlen_snprintf(dirpath, "%s/pg_replslot/",
local_data_directory);
log_debug("deleting pg_replslot directory contents");
if (!rmtree(dirpath, false))
{
log_error(_("unable to empty replication slot directory \"%s\""),
dirpath);
exit(ERR_BAD_RSYNC);
}
}
}

View File

@@ -8,6 +8,10 @@
#include "config.h" #include "config.h"
/* values for --copy-external-config-files */
#define CONFIG_FILE_SAMEPATH 1
#define CONFIG_FILE_PGDATA 2
typedef struct typedef struct
{ {
/* configuration metadata */ /* configuration metadata */
@@ -44,12 +48,15 @@ typedef struct
char data_dir[MAXPGPATH]; char data_dir[MAXPGPATH];
/* standby clone options */ /* standby clone options */
bool copy_external_config_files;
int copy_external_config_files_destination;
bool fast_checkpoint; bool fast_checkpoint;
bool rsync_only; bool rsync_only;
bool no_upstream_connection; bool no_upstream_connection;
char recovery_min_apply_delay[MAXLEN]; char recovery_min_apply_delay[MAXLEN];
char replication_user[MAXLEN]; char replication_user[MAXLEN];
char upstream_conninfo[MAXLEN]; char upstream_conninfo[MAXLEN];
bool use_recovery_conninfo_password;
char wal_keep_segments[MAXLEN]; char wal_keep_segments[MAXLEN];
bool without_barman; bool without_barman;
@@ -74,7 +81,7 @@ typedef struct
/* node options */ \ /* node options */ \
UNKNOWN_NODE_ID, "", "", \ UNKNOWN_NODE_ID, "", "", \
/* standby clone options */ \ /* standby clone options */ \
false, false, false, "", "", "", "", false, \ false, CONFIG_FILE_SAMEPATH, false, false, false, "", "", "", false, "", false, \
/* event options */ \ /* event options */ \
false, "", 20 } false, "", 20 }
@@ -116,4 +123,6 @@ extern void print_error_list(ItemList *error_list, int log_level);
extern char * make_pg_path(char *file); extern char * make_pg_path(char *file);
extern bool create_recovery_file(const char *data_dir, t_conninfo_param_list *recovery_conninfo);
#endif #endif

View File

@@ -16,9 +16,10 @@
*/ */
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h>
#include "repmgr.h" #include "repmgr.h"
#include "compat.h"
#include "repmgr-client.h" #include "repmgr-client.h"
#include "repmgr-client-global.h" #include "repmgr-client-global.h"
#include "repmgr-action-master.h" #include "repmgr-action-master.h"
@@ -79,8 +80,69 @@ main(int argc, char **argv)
*/ */
logger_output_mode = OM_COMMAND_LINE; logger_output_mode = OM_COMMAND_LINE;
/*
* Initialize and pre-populate conninfo parameters; these will be
* overwritten if matching command line parameters are provided.
*
* Only some actions will need these, but we need to do this before
* the command line is parsed.
*/
initialize_conninfo_params(&source_conninfo, true); initialize_conninfo_params(&source_conninfo, true);
for (c = 0; c < source_conninfo.size && source_conninfo.keywords[c]; c++)
{
if (strcmp(source_conninfo.keywords[c], "host") == 0 &&
(source_conninfo.values[c] != NULL))
{
strncpy(runtime_options.host, source_conninfo.values[c], MAXLEN);
}
else if (strcmp(source_conninfo.keywords[c], "hostaddr") == 0 &&
(source_conninfo.values[c] != NULL))
{
strncpy(runtime_options.host, source_conninfo.values[c], MAXLEN);
}
else if (strcmp(source_conninfo.keywords[c], "port") == 0 &&
(source_conninfo.values[c] != NULL))
{
strncpy(runtime_options.port, source_conninfo.values[c], MAXLEN);
}
else if (strcmp(source_conninfo.keywords[c], "dbname") == 0 &&
(source_conninfo.values[c] != NULL))
{
strncpy(runtime_options.dbname, source_conninfo.values[c], MAXLEN);
}
else if (strcmp(source_conninfo.keywords[c], "user") == 0 &&
(source_conninfo.values[c] != NULL))
{
strncpy(runtime_options.username, source_conninfo.values[c], MAXLEN);
}
}
/*
* Though libpq will default to the username as dbname, PQconndefaults()
* doesn't return this
*/
if (runtime_options.dbname[0] == '\0')
{
strncpy(runtime_options.dbname, runtime_options.username, MAXLEN);
}
/* set default user for -R/--remote-user */
{
struct passwd *pw = NULL;
pw = getpwuid(geteuid());
if (pw == NULL)
{
fprintf(stderr, _("could not get current user name: %s\n"), strerror(errno));
exit(ERR_BAD_CONFIG);
}
strncpy(runtime_options.username, pw->pw_name, MAXLEN);
}
while ((c = getopt_long(argc, argv, "?Vb:f:Fd:h:p:U:R:S:L:vtD:cr", long_options, while ((c = getopt_long(argc, argv, "?Vb:f:Fd:h:p:U:R:S:L:vtD:cr", long_options,
&optindex)) != -1) &optindex)) != -1)
{ {
@@ -209,6 +271,26 @@ main(int argc, char **argv)
runtime_options.fast_checkpoint = true; runtime_options.fast_checkpoint = true;
break; break;
/* --copy-external-config-files(=[samepath|pgdata]) */
case OPT_COPY_EXTERNAL_CONFIG_FILES:
runtime_options.copy_external_config_files = true;
if (optarg != NULL)
{
if (strcmp(optarg, "samepath") == 0)
{
runtime_options.copy_external_config_files_destination = CONFIG_FILE_SAMEPATH;
}
else if (strcmp(optarg, "pgdata") == 0)
{
runtime_options.copy_external_config_files_destination = CONFIG_FILE_PGDATA;
}
else
{
item_list_append(&cli_errors, _("value provided for '--copy-external-config-files' must be 'samepath' or 'pgdata'"));
}
}
break;
/* -r/--rsync-only */ /* -r/--rsync-only */
case 'r': case 'r':
runtime_options.rsync_only = true; runtime_options.rsync_only = true;
@@ -254,6 +336,10 @@ main(int argc, char **argv)
strncpy(runtime_options.upstream_conninfo, optarg, MAXLEN); strncpy(runtime_options.upstream_conninfo, optarg, MAXLEN);
break; break;
case OPT_USE_RECOVERY_CONNINFO_PASSWORD:
runtime_options.use_recovery_conninfo_password = true;
break;
case OPT_WITHOUT_BARMAN: case OPT_WITHOUT_BARMAN:
runtime_options.without_barman = true; runtime_options.without_barman = true;
break; break;
@@ -1705,3 +1791,187 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
return r; return r;
} }
/*
* Creates a recovery.conf file for a standby
*
* A database connection pointer is required for escaping primary_conninfo
* parameters. When cloning from Barman and --no-upstream-conne ) this might not be
*/
bool
create_recovery_file(const char *data_dir, t_conninfo_param_list *recovery_conninfo)
{
FILE *recovery_file;
char recovery_file_path[MAXPGPATH];
char line[MAXLEN];
mode_t um;
maxpath_snprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_COMMAND_FILE);
/* 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);
return false;
}
log_debug("create_recovery_file(): creating \"%s\"...\n",
recovery_file_path);
/* standby_mode = 'on' */
maxlen_snprintf(line, "standby_mode = 'on'\n");
if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
return false;
log_debug("recovery.conf: %s", line);
/* 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);
maxlen_snprintf(line, "primary_conninfo = '%s'\n",
escaped);
free(escaped);
}
/*
* otherwise use the conninfo inferred from the upstream connection
* and/or node record
*/
else
{
write_primary_conninfo(line, recovery_conninfo);
}
if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
return false;
log_debug("recovery.conf: %s", line);
/* recovery_target_timeline = 'latest' */
maxlen_snprintf(line, "recovery_target_timeline = 'latest'\n");
if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
return false;
log_debug("recovery.conf: %s", line);
/* recovery_min_apply_delay = ... (optional) */
if (*runtime_options.recovery_min_apply_delay)
{
maxlen_snprintf(line, "recovery_min_apply_delay = %s\n",
runtime_options.recovery_min_apply_delay);
if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
return false;
log_debug("recovery.conf: %s", line);
}
/* primary_slot_name = '...' (optional, for 9.4 and later) */
if (config_file_options.use_replication_slots)
{
maxlen_snprintf(line, "primary_slot_name = %s\n",
repmgr_slot_name);
if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
return false;
log_debug("recovery.conf: %s", line);
}
/* If restore_command is set, we use it as restore_command in recovery.conf */
if (strcmp(config_file_options.restore_command, "") != 0)
{
maxlen_snprintf(line, "restore_command = '%s'\n",
config_file_options.restore_command);
if (write_recovery_file_line(recovery_file, recovery_file_path, line) == false)
return false;
log_debug("recovery.conf: %s", line);
}
fclose(recovery_file);
return true;
}
static bool
write_recovery_file_line(FILE *recovery_file, char *recovery_file_path, char *line)
{
if (fputs(line, recovery_file) == EOF)
{
log_error(_("unable to write to recovery file at \"%s\""), recovery_file_path);
fclose(recovery_file);
return false;
}
return true;
}
static void
write_primary_conninfo(char *line, t_conninfo_param_list *param_list)
{
PQExpBufferData conninfo_buf;
bool application_name_provided = false;
int c;
char *escaped;
initPQExpBuffer(&conninfo_buf);
for (c = 0; c < param_list->size && param_list->keywords[c] != NULL; c++)
{
/*
* Skip empty settings and ones which don't make any sense in
* recovery.conf
*/
if (strcmp(param_list->keywords[c], "dbname") == 0 ||
strcmp(param_list->keywords[c], "replication") == 0 ||
(runtime_options.use_recovery_conninfo_password == false &&
strcmp(param_list->keywords[c], "password") == 0) ||
(param_list->values[c] == NULL) ||
(param_list->values[c] != NULL && param_list->values[c][0] == '\0'))
continue;
if (conninfo_buf.len != 0)
appendPQExpBufferChar(&conninfo_buf, ' ');
if (strcmp(param_list->keywords[c], "application_name") == 0)
application_name_provided = true;
appendPQExpBuffer(&conninfo_buf, "%s=", param_list->keywords[c]);
appendConnStrVal(&conninfo_buf, param_list->values[c]);
}
/* `application_name` not provided - default to repmgr node name */
if (application_name_provided == false)
{
if (strlen(config_file_options.node_name))
{
appendPQExpBuffer(&conninfo_buf, " application_name=");
appendConnStrVal(&conninfo_buf, config_file_options.node_name);
}
else
{
appendPQExpBuffer(&conninfo_buf, " application_name=repmgr");
}
}
escaped = escape_recovery_conf_value(conninfo_buf.data);
maxlen_snprintf(line, "primary_conninfo = '%s'\n", escaped);
free(escaped);
termPQExpBuffer(&conninfo_buf);
}

View File

@@ -33,29 +33,31 @@
#define BDR_UNREGISTER 19 #define BDR_UNREGISTER 19
/* command line options without short versions */ /* command line options without short versions */
#define OPT_HELP 1 #define OPT_HELP 1
#define OPT_CHECK_UPSTREAM_CONFIG 2 #define OPT_CHECK_UPSTREAM_CONFIG 2
#define OPT_RECOVERY_MIN_APPLY_DELAY 3 #define OPT_RECOVERY_MIN_APPLY_DELAY 3
#define OPT_COPY_EXTERNAL_CONFIG_FILES 4 #define OPT_COPY_EXTERNAL_CONFIG_FILES 4
#define OPT_CONFIG_ARCHIVE_DIR 5 #define OPT_CONFIG_ARCHIVE_DIR 5
#define OPT_PG_REWIND 6 #define OPT_PG_REWIND 6
#define OPT_PWPROMPT 7 #define OPT_PWPROMPT 7
#define OPT_CSV 8 #define OPT_CSV 8
#define OPT_NODE 9 #define OPT_NODE 9
#define OPT_NODE_ID 10 #define OPT_NODE_ID 10
#define OPT_NODE_NAME 11 #define OPT_NODE_NAME 11
#define OPT_WITHOUT_BARMAN 12 #define OPT_WITHOUT_BARMAN 12
#define OPT_NO_UPSTREAM_CONNECTION 13 #define OPT_NO_UPSTREAM_CONNECTION 13
#define OPT_REGISTER_WAIT 14 #define OPT_REGISTER_WAIT 14
#define OPT_CLUSTER 15 #define OPT_CLUSTER 15
#define OPT_LOG_TO_FILE 16 #define OPT_LOG_TO_FILE 16
#define OPT_UPSTREAM_CONNINFO 17 #define OPT_UPSTREAM_CONNINFO 17
/* XXX deprecate, replace with --use-conninfo-password (--use-recovery-conninfo-password) set */ /* replaces --no-conninfo-password */
#define OPT_NO_CONNINFO_PASSWORD 18 #define OPT_USE_RECOVERY_CONNINFO_PASSWORD 18
#define OPT_REPLICATION_USER 19 #define OPT_REPLICATION_USER 19
#define OPT_EVENT 20 #define OPT_EVENT 20
#define OPT_LIMIT 21 #define OPT_LIMIT 21
#define OPT_ALL 22 #define OPT_ALL 22
/* deprecated since 3.3 */
#define OPT_NO_CONNINFO_PASSWORD 999
static struct option long_options[] = static struct option long_options[] =
@@ -91,12 +93,14 @@ static struct option long_options[] =
{"verbose", no_argument, NULL, 'v'}, {"verbose", no_argument, NULL, 'v'},
/* standby clone options */ /* standby clone options */
{"copy-external-config-files", optional_argument, NULL, OPT_COPY_EXTERNAL_CONFIG_FILES},
{"fast-checkpoint", no_argument, NULL, 'c'}, {"fast-checkpoint", no_argument, NULL, 'c'},
{"rsync-only", no_argument, NULL, 'r'}, {"rsync-only", no_argument, NULL, 'r'},
{"no-upstream-connection", no_argument, NULL, OPT_NO_UPSTREAM_CONNECTION}, {"no-upstream-connection", no_argument, NULL, OPT_NO_UPSTREAM_CONNECTION},
{"recovery-min-apply-delay", required_argument, NULL, OPT_RECOVERY_MIN_APPLY_DELAY}, {"recovery-min-apply-delay", required_argument, NULL, OPT_RECOVERY_MIN_APPLY_DELAY},
{"replication-user", required_argument, NULL, OPT_REPLICATION_USER}, {"replication-user", required_argument, NULL, OPT_REPLICATION_USER},
{"upstream-conninfo", required_argument, NULL, OPT_UPSTREAM_CONNINFO}, {"upstream-conninfo", required_argument, NULL, OPT_UPSTREAM_CONNINFO},
{"use-recovery-conninfo-password", no_argument, NULL, OPT_USE_RECOVERY_CONNINFO_PASSWORD},
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN}, {"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
/* event options */ /* event options */
@@ -104,6 +108,9 @@ static struct option long_options[] =
{"event", required_argument, NULL, OPT_EVENT }, {"event", required_argument, NULL, OPT_EVENT },
{"limit", required_argument, NULL, OPT_LIMIT }, {"limit", required_argument, NULL, OPT_LIMIT },
/* deprecated */
{"no-conninfo-password", no_argument, NULL, OPT_NO_CONNINFO_PASSWORD},
/* not yet handled */ /* not yet handled */
{"wal-keep-segments", required_argument, NULL, 'w'}, {"wal-keep-segments", required_argument, NULL, 'w'},
{"keep-history", required_argument, NULL, 'k'}, {"keep-history", required_argument, NULL, 'k'},
@@ -120,10 +127,10 @@ static struct option long_options[] =
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN}, {"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
{"copy-external-config-files", optional_argument, NULL, OPT_COPY_EXTERNAL_CONFIG_FILES}, {"copy-external-config-files", optional_argument, NULL, OPT_COPY_EXTERNAL_CONFIG_FILES},
{"wait-sync", optional_argument, NULL, OPT_REGISTER_WAIT}, {"wait-sync", optional_argument, NULL, OPT_REGISTER_WAIT},
{"no-conninfo-password", no_argument, NULL, OPT_NO_CONNINFO_PASSWORD},
/* Following options for internal use */ /* Following options for internal use */
{"cluster", required_argument, NULL, OPT_CLUSTER}, {"cluster", required_argument, NULL, OPT_CLUSTER},
{"config-archive-dir", required_argument, NULL, OPT_CONFIG_ARCHIVE_DIR}, {"config-archive-dir", required_argument, NULL, OPT_CONFIG_ARCHIVE_DIR},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
@@ -138,4 +145,7 @@ static void exit_with_errors(void);
static void print_item_list(ItemList *item_list); static void print_item_list(ItemList *item_list);
static void check_cli_parameters(const int action); static void check_cli_parameters(const int action);
static void write_primary_conninfo(char *line, t_conninfo_param_list *param_list);
static bool write_recovery_file_line(FILE *recovery_file, char *recovery_file_path, char *line);
#endif #endif

View File

@@ -26,7 +26,7 @@ xvsnprintf(char *str, size_t size, const char *format, va_list ap)
if (retval >= (int) size) if (retval >= (int) size)
{ {
log_error(_("buffer of size not large enough to format entire string '%s'"), log_error(_("buffer of specified size not large enough to format entire string '%s'"),
str); str);
exit(ERR_STR_OVERFLOW); exit(ERR_STR_OVERFLOW);
} }
@@ -61,6 +61,18 @@ maxlen_snprintf(char *str, const char *format,...)
return retval; return retval;
} }
int
maxpath_snprintf(char *str, const char *format,...)
{
va_list arglist;
int retval;
va_start(arglist, format);
retval = xvsnprintf(str, MAXPGPATH, format, arglist);
va_end(arglist);
return retval;
}
void void
append_where_clause(PQExpBufferData *where_clause, const char *format, ...) append_where_clause(PQExpBufferData *where_clause, const char *format, ...)

View File

@@ -40,6 +40,10 @@ extern int
maxlen_snprintf(char *str, const char *format,...) maxlen_snprintf(char *str, const char *format,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
extern int
maxpath_snprintf(char *str, const char *format,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
extern void extern void
item_list_append(ItemList *item_list, const char *message); item_list_append(ItemList *item_list, const char *message);