Compare commits

...

34 Commits

Author SHA1 Message Date
Ian Barwick
54a4d1e444 README: clarify that the repmgr metadatabase must be part of the replication cluster 2016-10-26 20:28:22 +09:00
Ian Barwick
d4b8c034e9 Update HISTORY 2016-10-24 09:03:46 +09:00
Ian Barwick
b8f4c35810 Merge branch 'master' of github.com:2ndQuadrant/repmgr into REL3_2_STABLE
Bump version to 3.2.1
2016-10-24 08:14:04 +09:00
Ian Barwick
0cde0068dd repmgrd: improve witness failover logging
Log the new master node as INFO rather than DEBUG.
2016-10-20 10:56:16 +09:00
Ian Barwick
20d66df0ef repmgr: prevent involuntary cloning where no repmgr schema present on master 2016-10-19 20:26:55 +09:00
Ian Barwick
3f7c30b84d repmgr: require a valid repmgr cluster name unless -F/--force supplied
Addresses issue mentioned in GitHub #242.
2016-10-19 16:16:12 +09:00
Ian Barwick
a63baf7fcb repmgr: rename local variable config_file_found to remote_config_file_found
We also have a global `config_file_found` - avoid confusion with that.
2016-10-19 15:30:02 +09:00
Ian Barwick
e19c643389 repmgr: refactor check_upstream_config() for clarity
Also ensure the check for sufficient walsenders is only carried out
when using pg_basebackup.
2016-10-19 15:06:21 +09:00
Ian Barwick
f058833451 repmgr: in Barman clone mode, don't try and create the data directory twice
In Barman mode the data directory is created early containing a temporary
directory needed to hold temporary files while cloning from the Barman
server. In other modes we might not know the data directory location until
connecting to the source server, so its creation happens later. In Barman
mode ensure that step is skipped.
2016-10-19 10:00:50 +09:00
Ian Barwick
96c14adfdb repmgr: ensure data directory defaults to that of the source node
As long as -D/--pgdata is not supplied, and barman mode is not used
for cloning.
2016-10-17 16:34:49 +09:00
Ian Barwick
d2c09a1f71 repmgr: clean up runtime options structure
Place elements in a sensible order and split the associated initializer
macro over multiple lines for easier editing.

Also move a few related global variables into to the structure to keep
everything in the same place.
2016-10-11 13:06:09 +09:00
Ian Barwick
2389101ae9 "pg_logical/snapshot" -> "pg_logical/snapshots" 2016-10-11 13:06:04 +09:00
Gianni Ciolli
cbc2841433 When restoring from Barman, create pg_logical subdirectories
Nodes cloned from Barman backups were missing these subdirectories,
and so they were unable to start when promoted.
2016-10-11 13:05:48 +09:00
Ian Barwick
50119056a5 repmgr: clean up runtime options structure
Place elements in a sensible order and split the associated initializer
macro over multiple lines for easier editing.

Also move a few related global variables into to the structure to keep
everything in the same place.
2016-10-11 12:54:56 +09:00
Ian Barwick
a279c42df9 "pg_logical/snapshot" -> "pg_logical/snapshots" 2016-10-11 09:32:55 +09:00
Ian Barwick
f70b6ea136 Merge branch 'fix-barman-mode' of git://github.com/gciolli/repmgr
Fixes GitHub #245.
2016-10-11 09:21:31 +09:00
Ian Barwick
2bc877114c repmgr: simplify LSN parsing
Also silences a compiler warning.
2016-10-10 22:57:24 +09:00
Ian Barwick
e4cb6d7130 repmgr: simplify LSN parsing
Also silences a compiler warning.
2016-10-10 22:56:49 +09:00
Gianni Ciolli
502c056753 When restoring from Barman, create pg_logical subdirectories
Nodes cloned from Barman backups were missing these subdirectories,
and so they were unable to start when promoted.
2016-10-10 10:18:33 +02:00
Ian Barwick
871ec47ff5 Fix repmgr cluster crosscheck output
Show actual node ID rather than incremental number.

Fixes GitHub #244.
2016-10-10 16:20:17 +09:00
Ian Barwick
30c5cc86f3 Update README
Also reorder HISTORY entries.
2016-10-10 15:12:48 +09:00
Ian Barwick
f435abb3ec Update README
Also reorder HISTORY entries.
2016-10-10 15:10:06 +09:00
Ian Barwick
b977b48aee repmgr: standardize SSH-related error messages 2016-10-07 07:48:52 +09:00
Ian Barwick
a217b4d0a9 repmgr: standardize SSH-related error messages 2016-10-07 07:42:15 +09:00
Ian Barwick
108bdeb269 Add 'cluster crosscheck' to help output detail
Per GitHub #243.
2016-10-06 07:39:29 +09:00
Ian Barwick
2dcb75f889 Add 'cluster crosscheck' to help output detail
Per GitHub #243.
2016-10-06 07:38:45 +09:00
Ian Barwick
b509ce6382 Minor README fix 2016-10-05 16:47:37 +09:00
Ian Barwick
1150bf272a Update README
`--ignore-external-config-files` deprecated
2016-10-05 15:09:07 +09:00
Ian Barwick
09ac6cd145 Update history 2016-10-05 13:57:10 +09:00
Ian Barwick
2fae788bc4 Add documentation for repmgrd failover process and failed node fencing
Addresses GitHub #200.
2016-10-05 11:25:36 +09:00
Ian Barwick
eb90f864c9 repmgr: consistent error message style 2016-10-05 10:31:25 +09:00
Ian Barwick
ba89758366 Update barman-wal-restore documentation
Barman 2.0 provides this in a separate, more convenient `barman-cli` package;
document this and add note about previous `barman-wal-restore.py` script.
2016-10-03 15:59:03 +09:00
Ian Barwick
84595fe711 Tweak repmgr.conf.sample
Put `monitor_interval_secs` at the start of the `repmgrd` section, as it's
a very fundamental configuration item.
2016-10-03 15:57:33 +09:00
Ian Barwick
9523894808 Bump dev version number
3.3dev
2016-09-30 15:14:35 +09:00
6 changed files with 246 additions and 124 deletions

13
HISTORY
View File

@@ -1,3 +1,12 @@
3.2.1 2016-10-24
repmgr: require a valid repmgr cluster name unless -F/--force
supplied (Ian)
repmgr: check master server is registered with repmgr before
cloning (Ian)
repmgr: ensure data directory defaults to that of the source node (Ian)
repmgr: various fixes to Barman cloning mode (Gianni, Ian)
repmgr: fix `repmgr cluster crosscheck` output (Ian)
3.2 2016-10-05 3.2 2016-10-05
repmgr: add support for cloning from a Barman backup (Gianni) repmgr: add support for cloning from a Barman backup (Gianni)
repmgr: add commands `standby matrix` and `standby crosscheck` (Gianni) repmgr: add commands `standby matrix` and `standby crosscheck` (Gianni)
@@ -15,12 +24,12 @@
the standby (Ian) the standby (Ian)
repmgr: add option `--copy-external-config-files` for files outside repmgr: add option `--copy-external-config-files` for files outside
of the data directory (Ian) of the data directory (Ian)
repmgr: add configuration options to override the default pg_ctl
commands (Jarkko Oranen, Ian)
repmgr: only require `wal_keep_segments` to be set in certain corner repmgr: only require `wal_keep_segments` to be set in certain corner
cases (Ian) cases (Ian)
repmgr: better support cloning from a node other than the one to repmgr: better support cloning from a node other than the one to
stream from (Ian) stream from (Ian)
repmgrd: add configuration options to override the default pg_ctl
commands (Jarkko Oranen, Ian)
repmgrd: don't start if node is inactive and failover=automatic (Ian) repmgrd: don't start if node is inactive and failover=automatic (Ian)
packaging: improve "repmgr-auto" Debian package (Gianni) packaging: improve "repmgr-auto" Debian package (Gianni)

View File

@@ -8,7 +8,7 @@ replication, and perform administrative tasks such as failover or switchover
operations. operations.
The current `repmgr` version, 3.2, supports all PostgreSQL versions from The current `repmgr` version, 3.2, supports all PostgreSQL versions from
9.3, including the upcoming 9.6. 9.3 to 9.6.
Overview Overview
-------- --------
@@ -121,7 +121,8 @@ views:
status for each node status for each node
The `repmgr` metadata schema can be stored in an existing database or in its own The `repmgr` metadata schema can be stored in an existing database or in its own
dedicated database. dedicated database. Note that the `repmgr` metadata schema cannot reside on a database
server which is not part of the replication cluster managed by `repmgr`.
A dedicated database superuser is required to own the meta-database as well as carry A dedicated database superuser is required to own the meta-database as well as carry
out administrative actions. out administrative actions.
@@ -600,7 +601,7 @@ ensure that:
hostname of the Barman server; hostname of the Barman server;
- the `restore_command` setting in `repmgr.conf` is configured to - the `restore_command` setting in `repmgr.conf` is configured to
use a copy of the `barman-wal-restore` script shipped with the use a copy of the `barman-wal-restore` script shipped with the
`barman-cli package` (see below); `barman-cli` package (see below);
- the Barman catalogue includes at least one valid backup for this - the Barman catalogue includes at least one valid backup for this
server. server.
@@ -1072,8 +1073,9 @@ This will remove the standby record from `repmgr`'s internal metadata
table (`repl_nodes`). A `standby_unregister` event notification will be table (`repl_nodes`). A `standby_unregister` event notification will be
recorded in the `repl_events` table. recorded in the `repl_events` table.
Note that this command will not stop the server itself or remove Note that this command will not stop the server itself or remove it from
it from the replication cluster. the replication cluster. Note that if the standby was using a replication
slot, this will not be removed.
If the standby is not running, the command can be executed on another If the standby is not running, the command can be executed on another
node by providing the id of the node to be unregistered using node by providing the id of the node to be unregistered using

241
repmgr.c
View File

@@ -178,12 +178,6 @@ static bool config_file_required = true;
t_runtime_options runtime_options = T_RUNTIME_OPTIONS_INITIALIZER; t_runtime_options runtime_options = T_RUNTIME_OPTIONS_INITIALIZER;
t_configuration_options options = T_CONFIGURATION_OPTIONS_INITIALIZER; t_configuration_options options = T_CONFIGURATION_OPTIONS_INITIALIZER;
static bool wal_keep_segments_used = false;
static bool conninfo_provided = false;
static bool connection_param_provided = false;
static bool host_param_provided = false;
static bool pg_rewind_supplied = false;
static char *server_mode = NULL; static char *server_mode = NULL;
static char *server_cmd = NULL; static char *server_cmd = NULL;
@@ -365,13 +359,13 @@ main(int argc, char **argv)
case 'd': case 'd':
strncpy(runtime_options.dbname, optarg, MAXLEN); strncpy(runtime_options.dbname, optarg, MAXLEN);
/* we'll set the dbname parameter below if we detect it's not a conninfo string */ /* we'll set the dbname parameter below if we detect it's not a conninfo string */
connection_param_provided = true; runtime_options.connection_param_provided = true;
break; break;
case 'h': case 'h':
strncpy(runtime_options.host, optarg, MAXLEN); strncpy(runtime_options.host, optarg, MAXLEN);
param_set(&source_conninfo, "host", optarg); param_set(&source_conninfo, "host", optarg);
connection_param_provided = true; runtime_options.connection_param_provided = true;
host_param_provided = true; runtime_options.host_param_provided = true;
break; break;
case 'p': case 'p':
repmgr_atoi(optarg, "-p/--port", &cli_errors, false); repmgr_atoi(optarg, "-p/--port", &cli_errors, false);
@@ -379,12 +373,12 @@ main(int argc, char **argv)
strncpy(runtime_options.masterport, strncpy(runtime_options.masterport,
optarg, optarg,
MAXLEN); MAXLEN);
connection_param_provided = true; runtime_options.connection_param_provided = true;
break; break;
case 'U': case 'U':
strncpy(runtime_options.username, optarg, MAXLEN); strncpy(runtime_options.username, optarg, MAXLEN);
param_set(&source_conninfo, "user", optarg); param_set(&source_conninfo, "user", optarg);
connection_param_provided = true; runtime_options.connection_param_provided = true;
break; break;
case 'S': case 'S':
strncpy(runtime_options.superuser, optarg, MAXLEN); strncpy(runtime_options.superuser, optarg, MAXLEN);
@@ -403,7 +397,7 @@ main(int argc, char **argv)
strncpy(runtime_options.wal_keep_segments, strncpy(runtime_options.wal_keep_segments,
optarg, optarg,
MAXLEN); MAXLEN);
wal_keep_segments_used = true; runtime_options.wal_keep_segments_used = true;
break; break;
case 'k': case 'k':
runtime_options.keep_history = repmgr_atoi(optarg, "-k/--keep-history", &cli_errors, false); runtime_options.keep_history = repmgr_atoi(optarg, "-k/--keep-history", &cli_errors, false);
@@ -519,7 +513,7 @@ main(int argc, char **argv)
{ {
strncpy(runtime_options.pg_rewind, optarg, MAXPGPATH); strncpy(runtime_options.pg_rewind, optarg, MAXPGPATH);
} }
pg_rewind_supplied = true; runtime_options.pg_rewind_supplied = true;
break; break;
case OPT_PWPROMPT: case OPT_PWPROMPT:
runtime_options.witness_pwprompt = true; runtime_options.witness_pwprompt = true;
@@ -586,7 +580,7 @@ main(int argc, char **argv)
{ {
char *errmsg = NULL; char *errmsg = NULL;
conninfo_provided = true; runtime_options.conninfo_provided = true;
opts = PQconninfoParse(runtime_options.dbname, &errmsg); opts = PQconninfoParse(runtime_options.dbname, &errmsg);
@@ -620,13 +614,13 @@ main(int argc, char **argv)
(opt->val != NULL && opt->val[0] != '\0')) (opt->val != NULL && opt->val[0] != '\0'))
{ {
strncpy(runtime_options.host, opt->val, MAXLEN); strncpy(runtime_options.host, opt->val, MAXLEN);
host_param_provided = true; runtime_options.host_param_provided = true;
} }
if (strcmp(opt->keyword, "hostaddr") == 0 && if (strcmp(opt->keyword, "hostaddr") == 0 &&
(opt->val != NULL && opt->val[0] != '\0')) (opt->val != NULL && opt->val[0] != '\0'))
{ {
strncpy(runtime_options.host, opt->val, MAXLEN); strncpy(runtime_options.host, opt->val, MAXLEN);
host_param_provided = true; runtime_options.host_param_provided = true;
} }
else if (strcmp(opt->keyword, "port") == 0 && else if (strcmp(opt->keyword, "port") == 0 &&
(opt->val != NULL && opt->val[0] != '\0')) (opt->val != NULL && opt->val[0] != '\0'))
@@ -762,7 +756,7 @@ main(int argc, char **argv)
initPQExpBuffer(&additional_host_arg); initPQExpBuffer(&additional_host_arg);
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"); runtime_options.conninfo_provided == true ? "host=" : "-h/--host");
item_list_append(&cli_errors, additional_host_arg.data); item_list_append(&cli_errors, additional_host_arg.data);
} }
else else
@@ -884,7 +878,7 @@ main(int argc, char **argv)
* the version check for 9.4 or later is done in check_upstream_config() * the version check for 9.4 or later is done in check_upstream_config()
*/ */
if (options.use_replication_slots && wal_keep_segments_used) if (options.use_replication_slots && runtime_options.wal_keep_segments_used)
{ {
log_warning(_("-w/--wal-keep-segments has no effect when replication slots in use\n")); log_warning(_("-w/--wal-keep-segments has no effect when replication slots in use\n"));
} }
@@ -904,6 +898,7 @@ main(int argc, char **argv)
} }
/* Initialise the repmgr schema name */ /* Initialise the repmgr schema name */
if (strlen(repmgr_cluster)) if (strlen(repmgr_cluster))
/* --cluster parameter provided */ /* --cluster parameter provided */
maxlen_snprintf(repmgr_schema, "%s%s", DEFAULT_REPMGR_SCHEMA_PREFIX, maxlen_snprintf(repmgr_schema, "%s%s", DEFAULT_REPMGR_SCHEMA_PREFIX,
@@ -912,6 +907,16 @@ main(int argc, char **argv)
maxlen_snprintf(repmgr_schema, "%s%s", DEFAULT_REPMGR_SCHEMA_PREFIX, maxlen_snprintf(repmgr_schema, "%s%s", DEFAULT_REPMGR_SCHEMA_PREFIX,
options.cluster_name); options.cluster_name);
/*
* If no value for the repmgr_schema provided, continue only under duress.
*/
if (strcmp(repmgr_schema, DEFAULT_REPMGR_SCHEMA_PREFIX) == 0 && !runtime_options.force)
{
log_err(_("unable to determine cluster name - please provide a valid configuration file with -c/--config-file\n"));
log_hint(_("Use -F/--force to continue anyway\n"));
exit(ERR_BAD_CONFIG);
}
/* /*
* Initialise slot name, if required (9.4 and later) * Initialise slot name, if required (9.4 and later)
* *
@@ -1646,7 +1651,7 @@ do_cluster_crosscheck(void)
printf("%*s | Id ", name_length, node_header); printf("%*s | Id ", name_length, node_header);
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
printf("| %2d ", i+1); printf("| %2d ", cube[i]->node_id);
printf("\n"); printf("\n");
for (i = 0; i < name_length; i++) for (i = 0; i < name_length; i++)
@@ -2512,7 +2517,7 @@ do_standby_clone(void)
r = test_ssh_connection(runtime_options.host, runtime_options.remote_user); r = test_ssh_connection(runtime_options.host, runtime_options.remote_user);
if (r != 0) if (r != 0)
{ {
log_err(_("aborting, remote host %s is not reachable.\n"), log_err(_("aborting, remote host %s is not reachable via SSH.\n"),
runtime_options.host); runtime_options.host);
exit(ERR_BAD_SSH); exit(ERR_BAD_SSH);
} }
@@ -2522,9 +2527,14 @@ do_standby_clone(void)
/* /*
* If dest_dir (-D/--pgdata) was provided, this will become the new data * If dest_dir (-D/--pgdata) was provided, this will become the new data
* directory (otherwise repmgr will default to using the same directory * directory (otherwise repmgr will default to using the same directory
* path as on the source host) * path as on the source host).
*
* Note that barman mode requires -D/--pgdata.
*
* If -D/--pgdata is not supplied, and we're not cloning from barman,
* the source host's data directory will be fetched later, after
* we've connected to it.
*/ */
if (runtime_options.dest_dir[0]) if (runtime_options.dest_dir[0])
{ {
target_directory_provided = true; target_directory_provided = true;
@@ -2547,26 +2557,7 @@ do_standby_clone(void)
{ {
strncpy(local_data_directory, runtime_options.dest_dir, MAXPGPATH); strncpy(local_data_directory, runtime_options.dest_dir, MAXPGPATH);
} }
/*
* Otherwise use the same data directory as on the remote host
*/
else
{
strncpy(local_data_directory, master_data_directory, MAXPGPATH);
log_notice(_("setting data directory to: %s\n"), local_data_directory);
log_hint(_("use -D/--data-dir to explicitly specify a data directory\n"));
}
/* Check the local data directory can be used */
if (!create_pg_dir(local_data_directory, runtime_options.force))
{
log_err(_("unable to use directory %s ...\n"),
local_data_directory);
log_hint(_("use -F/--force option to force this directory to be overwritten\n"));
exit(ERR_BAD_CONFIG);
}
/* /*
* Initialise list of conninfo parameters which will later be used * Initialise list of conninfo parameters which will later be used
@@ -2639,7 +2630,7 @@ do_standby_clone(void)
if (!create_pg_dir(local_repmgr_directory, runtime_options.force)) if (!create_pg_dir(local_repmgr_directory, runtime_options.force))
{ {
log_err(_("unable to use directory %s ...\n"), log_err(_("unable to use directory \"%s\" ...\n"),
local_repmgr_directory); local_repmgr_directory);
log_hint(_("use -F/--force option to force this directory to be overwritten\n")); log_hint(_("use -F/--force option to force this directory to be overwritten\n"));
@@ -2738,6 +2729,51 @@ do_standby_clone(void)
primary_conn = source_conn; primary_conn = source_conn;
} }
/*
* Sanity-check that the master node has a repmgr schema - if not
* present, fail with an error (unless -F/--force is used)
*/
if (check_cluster_schema(primary_conn) == false)
{
if (!runtime_options.force)
{
/* schema doesn't exist */
log_err(_("expected repmgr schema '%s' not found on master server\n"), get_repmgr_schema());
log_hint(_("check that the master server was correctly registered\n"));
PQfinish(source_conn);
exit(ERR_BAD_CONFIG);
}
log_warning(_("expected repmgr schema '%s' not found on master server\n"), get_repmgr_schema());
}
/* Fetch the source's data directory */
if (get_pg_setting(source_conn, "data_directory", master_data_directory) == false)
{
log_err(_("Unable to retrieve upstream node's data directory\n"));
log_hint(_("STANDBY CLONE must be run as a database superuser"));
PQfinish(source_conn);
exit(ERR_BAD_CONFIG);
}
/*
* If no target directory was explicitly provided, we'll default to
* the same directory as on the source host.
*/
if (target_directory_provided == false)
{
strncpy(local_data_directory, master_data_directory, MAXPGPATH);
log_notice(_("setting data directory to: \"%s\"\n"), local_data_directory);
log_hint(_("use -D/--data-dir to explicitly specify a data directory\n"));
}
/* /*
* Copy the source connection so that we have some default values, * Copy the source connection so that we have some default values,
* particularly stuff like passwords extracted from PGPASSFILE; * particularly stuff like passwords extracted from PGPASSFILE;
@@ -2898,8 +2934,24 @@ do_standby_clone(void)
} }
} }
if (mode != barman) if (mode != barman)
{ {
/*
* Check the destination data directory can be used
* (in Barman mode, this directory will already have been created)
*/
if (!create_pg_dir(local_data_directory, runtime_options.force))
{
log_err(_("unable to use directory %s ...\n"),
local_data_directory);
log_hint(_("use -F/--force option to force this directory to be overwritten\n"));
exit(ERR_BAD_CONFIG);
}
/* /*
* Check that tablespaces named in any `tablespace_mapping` configuration * Check that tablespaces named in any `tablespace_mapping` configuration
* file parameters exist. * file parameters exist.
@@ -2949,14 +3001,6 @@ do_standby_clone(void)
} }
} }
if (get_pg_setting(source_conn, "data_directory", master_data_directory) == false)
{
log_err(_("Unable to retrieve upstream node's data directory\n"));
log_hint(_("STANDBY CLONE must be run as a database superuser"));
exit(ERR_BAD_CONFIG);
}
/* /*
* Obtain configuration file locations * Obtain configuration file locations
* We'll check to see whether the configuration files are in the data * We'll check to see whether the configuration files are in the data
@@ -3315,14 +3359,14 @@ do_standby_clone(void)
/* Only from 9.5 */ /* Only from 9.5 */
"pg_commit_ts", "pg_commit_ts",
/* Only from 9.4 */ /* Only from 9.4 */
"pg_dynshmem", "pg_logical", "pg_replslot", "pg_dynshmem", "pg_logical", "pg_logical/snapshots", "pg_logical/mappings", "pg_replslot",
/* Already in 9.3 */ /* Already in 9.3 */
"pg_serial", "pg_snapshots", "pg_stat", "pg_stat_tmp", "pg_tblspc", "pg_serial", "pg_snapshots", "pg_stat", "pg_stat_tmp", "pg_tblspc",
"pg_twophase", "pg_xlog", 0 "pg_twophase", "pg_xlog", 0
}; };
const int vers[] = { const int vers[] = {
90500, 90500,
90400, 90400, 90400, 90400, 90400, 90400, 90400, 90400,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 0, 0, 0
}; };
@@ -3656,7 +3700,7 @@ do_standby_clone(void)
file->filepath, dest_path, false, server_version_num); file->filepath, dest_path, false, server_version_num);
if (r != 0) if (r != 0)
{ {
log_err(_("standby clone: unable to copying config file '%s'\n"), log_err(_("standby clone: unable to copy config file '%s'\n"),
file->filename); file->filename);
} }
} }
@@ -3900,29 +3944,31 @@ stop_backup:
exit(retval); exit(retval);
} }
static bool static void
parse_lsn(XLogRecPtr *ptr, const char *str) parse_lsn(XLogRecPtr *ptr, const char *str)
{ {
uint32 high, low; uint32 high, low;
if (sscanf(str, "%x/%x", &high, &low) != 2) if (sscanf(str, "%x/%x", &high, &low) != 2)
return false; return;
*ptr = (((XLogRecPtr)high) << 32) + (XLogRecPtr)low; *ptr = (((XLogRecPtr)high) << 32) + (XLogRecPtr)low;
return true; return;
} }
static XLogRecPtr static XLogRecPtr
parse_label_lsn(const char *label_key, const char *label_value) parse_label_lsn(const char *label_key, const char *label_value)
{ {
XLogRecPtr ptr; XLogRecPtr ptr = InvalidXLogRecPtr;
if (!parse_lsn(&ptr, label_value)) parse_lsn(&ptr, label_value);
/* parse_lsn() will not modify ptr if it can't parse the label value */
if (ptr == InvalidXLogRecPtr)
{ {
log_err(_("Couldn't parse backup label entry \"%s: %s\" as lsn"), log_err(_("Couldn't parse backup label entry \"%s: %s\" as lsn"),
label_key, label_value); label_key, label_value);
return InvalidXLogRecPtr;
} }
return ptr; return ptr;
@@ -4266,7 +4312,7 @@ do_standby_follow(void)
* to determine primary, and carry out some other checks while we're * to determine primary, and carry out some other checks while we're
* at it. * at it.
*/ */
if (host_param_provided == false) if (runtime_options.host_param_provided == false)
{ {
/* We need to connect to check configuration */ /* We need to connect to check configuration */
log_info(_("connecting to standby database\n")); log_info(_("connecting to standby database\n"));
@@ -4560,7 +4606,7 @@ do_standby_switchover(void)
* Add a friendly notice if --pg_rewind supplied for 9.5 and later - we'll * Add a friendly notice if --pg_rewind supplied for 9.5 and later - we'll
* be ignoring it anyway * be ignoring it anyway
*/ */
if (pg_rewind_supplied == true && server_version_num >= 90500) if (runtime_options.pg_rewind_supplied == true && server_version_num >= 90500)
{ {
log_notice(_("--pg_rewind not required for PostgreSQL 9.5 and later\n")); log_notice(_("--pg_rewind not required for PostgreSQL 9.5 and later\n"));
} }
@@ -4610,7 +4656,7 @@ do_standby_switchover(void)
if (r != 0) if (r != 0)
{ {
log_err(_("unable to connect via ssh to host %s, user %s\n"), remote_host, runtime_options.remote_user); log_err(_("unable to connect via SSH to host %s, user %s\n"), remote_host, runtime_options.remote_user);
} }
if (get_pg_setting(remote_conn, "data_directory", remote_data_directory) == false) if (get_pg_setting(remote_conn, "data_directory", remote_data_directory) == false)
@@ -4675,7 +4721,7 @@ do_standby_switchover(void)
else else
{ {
/* 9.3/9.4 - user can use separately-compiled pg_rewind */ /* 9.3/9.4 - user can use separately-compiled pg_rewind */
if (pg_rewind_supplied == true) if (runtime_options.pg_rewind_supplied == true)
{ {
use_pg_rewind = true; use_pg_rewind = true;
@@ -4824,7 +4870,7 @@ do_standby_switchover(void)
else else
{ {
int i; int i;
bool config_file_found = false; bool remote_config_file_found = false;
const char *config_paths[] = { const char *config_paths[] = {
runtime_options.config_file, runtime_options.config_file,
@@ -4834,7 +4880,7 @@ do_standby_switchover(void)
log_verbose(LOG_INFO, _("no remote configuration file provided - checking default locations\n")); log_verbose(LOG_INFO, _("no remote configuration file provided - checking default locations\n"));
for (i = 0; config_paths[i] && config_file_found == false; ++i) for (i = 0; config_paths[i] && remote_config_file_found == false; ++i)
{ {
/* /*
* Don't attempt to check for an empty filename - this might be the case * Don't attempt to check for an empty filename - this might be the case
@@ -4866,13 +4912,13 @@ do_standby_switchover(void)
strncpy(runtime_options.remote_config_file, config_paths[i], MAXLEN); strncpy(runtime_options.remote_config_file, config_paths[i], MAXLEN);
log_verbose(LOG_INFO, _("configuration file \"%s\" found on remote server\n"), log_verbose(LOG_INFO, _("configuration file \"%s\" found on remote server\n"),
runtime_options.remote_config_file); runtime_options.remote_config_file);
config_file_found = true; remote_config_file_found = true;
} }
termPQExpBuffer(&command_output); termPQExpBuffer(&command_output);
} }
if (config_file_found == false) if (remote_config_file_found == false)
{ {
log_err(_("no remote configuration file supplied or found in a default location - terminating\n")); log_err(_("no remote configuration file supplied or found in a default location - terminating\n"));
log_hint(_("specify the remote configuration file with -C/--remote-config-file\n")); log_hint(_("specify the remote configuration file with -C/--remote-config-file\n"));
@@ -6083,6 +6129,7 @@ do_witness_register(PGconn *masterconn)
log_notice(_("configuration has been successfully copied to the witness\n")); log_notice(_("configuration has been successfully copied to the witness\n"));
} }
static void static void
do_witness_unregister(void) do_witness_unregister(void)
{ {
@@ -6254,7 +6301,10 @@ do_help(void)
printf(_(" witness register - registers a witness server\n")); printf(_(" witness register - registers a witness server\n"));
printf(_(" witness unregister - unregisters a witness server\n")); printf(_(" witness unregister - unregisters a witness server\n"));
printf(_(" cluster show - displays information about cluster nodes\n")); printf(_(" cluster show - displays information about cluster nodes\n"));
printf(_(" cluster matrix - displays the cluster's connection matrix\n")); printf(_(" cluster matrix - displays the cluster's connection matrix\n" \
" as seen from the current node\n"));
printf(_(" cluster crosscheck - displays the cluster's connection matrix\n" \
" as seen from all nodes\n"));
printf(_(" cluster cleanup - prunes or truncates monitoring history\n" \ printf(_(" cluster cleanup - prunes or truncates monitoring history\n" \
" (monitoring history creation requires repmgrd\n" \ " (monitoring history creation requires repmgrd\n" \
" with --monitoring-history option)\n")); " with --monitoring-history option)\n"));
@@ -6569,7 +6619,7 @@ run_basebackup(const char *data_dir, int server_version)
* consistency with other applications accepts a conninfo string * consistency with other applications accepts a conninfo string
* under -d/--dbname) * under -d/--dbname)
*/ */
if (conninfo_provided == true) if (runtime_options.conninfo_provided == true)
{ {
appendPQExpBuffer(&params, " -d '%s'", runtime_options.dbname); appendPQExpBuffer(&params, " -d '%s'", runtime_options.dbname);
} }
@@ -6690,7 +6740,7 @@ check_parameters_for_action(const int action)
* parameters are at least useless and could be confusing so * parameters are at least useless and could be confusing so
* reject them * reject them
*/ */
if (connection_param_provided) if (runtime_options.connection_param_provided)
{ {
item_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"));
} }
@@ -6707,7 +6757,7 @@ check_parameters_for_action(const int action)
* need connection parameters to the master because we can detect * need connection parameters to the master because we can detect
* the master in repl_nodes * the master in repl_nodes
*/ */
if (connection_param_provided) if (runtime_options.connection_param_provided)
{ {
item_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"));
} }
@@ -6724,7 +6774,7 @@ check_parameters_for_action(const int action)
* need connection parameters to the master because we can detect * need connection parameters to the master because we can detect
* the master in repl_nodes * the master in repl_nodes
*/ */
if (connection_param_provided) if (runtime_options.connection_param_provided)
{ {
item_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"));
} }
@@ -6742,7 +6792,7 @@ check_parameters_for_action(const int action)
* detect the master in repl_nodes if we can't find it then the * detect the master in repl_nodes if we can't find it then the
* promote action will be cancelled * promote action will be cancelled
*/ */
if (connection_param_provided) if (runtime_options.connection_param_provided)
{ {
item_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"));
} }
@@ -6768,7 +6818,7 @@ check_parameters_for_action(const int action)
item_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 (runtime_options.host_param_provided && !runtime_options.dest_dir[0])
{ {
item_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"));
} }
@@ -6878,7 +6928,7 @@ check_parameters_for_action(const int action)
item_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 (runtime_options.wal_keep_segments_used)
{ {
item_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"));
} }
@@ -6901,7 +6951,7 @@ check_parameters_for_action(const int action)
/* Warn about parameters which apply to STANDBY SWITCHOVER only */ /* Warn about parameters which apply to STANDBY SWITCHOVER only */
if (action != STANDBY_SWITCHOVER) if (action != STANDBY_SWITCHOVER)
{ {
if (pg_rewind_supplied == true) if (runtime_options.pg_rewind_supplied == true)
{ {
item_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"));
} }
@@ -7312,10 +7362,10 @@ check_master_standby_version_match(PGconn *conn, PGconn *master_conn)
/* /*
* check_upstream_config() * check_upstream_config()
* *
* Perform sanity check on upstream server configuration * Perform sanity check on upstream server configuration before starting cloning
* process
* *
* TODO: * TODO:
* - check replication connection is possble
* - check user is qualified to perform base backup * - check user is qualified to perform base backup
*/ */
@@ -7328,14 +7378,33 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error)
t_basebackup_options backup_options = T_BASEBACKUP_OPTIONS_INITIALIZER; t_basebackup_options backup_options = T_BASEBACKUP_OPTIONS_INITIALIZER;
bool xlog_stream = true; bool xlog_stream = true;
enum {
barman,
rsync,
pg_basebackup
} mode;
/*
* Detecting the intended cloning mode
*/
if (runtime_options.rsync_only)
mode = rsync;
else if (strcmp(options.barman_server, "") != 0 && ! runtime_options.without_barman)
mode = barman;
else
mode = pg_basebackup;
/* /*
* Parse `pg_basebackup_options`, if set, to detect whether --xlog-method * Parse `pg_basebackup_options`, if set, to detect whether --xlog-method
* has been set to something other than `stream` (i.e. `fetch`), as * has been set to something other than `stream` (i.e. `fetch`), as
* this will influence some checks * this will influence some checks
*/ */
parse_pg_basebackup_options(options.pg_basebackup_options, &backup_options); parse_pg_basebackup_options(options.pg_basebackup_options, &backup_options);
if (strlen(backup_options.xlog_method) && strcmp(backup_options.xlog_method, "stream") != 0) if (strlen(backup_options.xlog_method) && strcmp(backup_options.xlog_method, "stream") != 0)
xlog_stream = false; xlog_stream = false;
/* Check that WAL level is set correctly */ /* Check that WAL level is set correctly */
if (server_version_num < 90400) if (server_version_num < 90400)
{ {
@@ -7442,7 +7511,7 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error)
* physical replication slots not available or not requested - check if * physical replication slots not available or not requested - check if
* there are any circumstances where `wal_keep_segments` should be set * there are any circumstances where `wal_keep_segments` should be set
*/ */
else if (! runtime_options.without_barman && strcmp(options.barman_server, "") == 0) else if (mode != barman)
{ {
bool check_wal_keep_segments = false; bool check_wal_keep_segments = false;
char min_wal_keep_segments[MAXLEN] = "1"; char min_wal_keep_segments[MAXLEN] = "1";
@@ -7450,7 +7519,7 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error)
/* /*
* -w/--wal-keep-segments was supplied - check against that value * -w/--wal-keep-segments was supplied - check against that value
*/ */
if (wal_keep_segments_used == true) if (runtime_options.wal_keep_segments_used == true)
{ {
check_wal_keep_segments = true; check_wal_keep_segments = true;
strncpy(min_wal_keep_segments, runtime_options.wal_keep_segments, MAXLEN); strncpy(min_wal_keep_segments, runtime_options.wal_keep_segments, MAXLEN);
@@ -7573,7 +7642,12 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error)
config_ok = false; config_ok = false;
} }
if (!runtime_options.rsync_only) /*
* If using pg_basebackup, ensure sufficient replication connections can be made.
* There's no guarantee they'll still be available by the time pg_basebackup
* is executed, but there's nothing we can do about that.
*/
if (mode == pg_basebackup)
{ {
PGconn **connections; PGconn **connections;
@@ -7595,11 +7669,6 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error)
* work out how many replication connections are required (1 or 2) * work out how many replication connections are required (1 or 2)
*/ */
/*
* --xlog-method set by user to something other than "stream" (should be "fetch",
* but we're just checking it's not "stream")
*/
if (xlog_stream == true) if (xlog_stream == true)
min_replication_connections += 1; min_replication_connections += 1;

100
repmgr.h
View File

@@ -64,9 +64,10 @@
#define OPT_CLUSTER 13 #define OPT_CLUSTER 13
/* deprecated command line options */ /* deprecated command line options */
#define OPT_INITDB_NO_PWPROMPT 999 #define OPT_INITDB_NO_PWPROMPT 998
#define OPT_IGNORE_EXTERNAL_CONFIG_FILES 998 #define OPT_IGNORE_EXTERNAL_CONFIG_FILES 999
/* values for --copy-external-config-files */
#define CONFIG_FILE_SAMEPATH 1 #define CONFIG_FILE_SAMEPATH 1
#define CONFIG_FILE_PGDATA 2 #define CONFIG_FILE_PGDATA 2
@@ -74,53 +75,94 @@
/* Run time options type */ /* Run time options type */
typedef struct typedef struct
{ {
/* general repmgr options */
char config_file[MAXPGPATH];
bool verbose;
bool terse;
bool force;
/* options which override setting in repmgr.conf */
char loglevel[MAXLEN];
char pg_bindir[MAXLEN];
/* connection parameters */
char dbname[MAXLEN]; char dbname[MAXLEN];
char host[MAXLEN]; char host[MAXLEN];
char username[MAXLEN]; char username[MAXLEN];
char dest_dir[MAXPGPATH]; char dest_dir[MAXPGPATH];
char config_file[MAXPGPATH];
char remote_user[MAXLEN]; char remote_user[MAXLEN];
char superuser[MAXLEN]; char superuser[MAXLEN];
char masterport[MAXLEN];
bool conninfo_provided;
bool connection_param_provided;
bool host_param_provided;
/* standby clone parameters */
bool wal_keep_segments_used;
char wal_keep_segments[MAXLEN]; char wal_keep_segments[MAXLEN];
bool verbose;
bool terse;
bool force;
bool wait_for_master;
bool ignore_rsync_warn; bool ignore_rsync_warn;
bool witness_pwprompt;
bool rsync_only; bool rsync_only;
bool fast_checkpoint; bool fast_checkpoint;
bool csv_mode;
bool without_barman; bool without_barman;
bool no_upstream_connection; bool no_upstream_connection;
bool copy_external_config_files; bool copy_external_config_files;
int copy_external_config_files_destination; int copy_external_config_files_destination;
bool wait_register_sync; bool wait_register_sync;
int wait_register_sync_seconds; int wait_register_sync_seconds;
char masterport[MAXLEN];
/*
* configuration file parameters which can be overridden on the
* command line
*/
char loglevel[MAXLEN];
/* parameter used by STANDBY SWITCHOVER */
char remote_config_file[MAXLEN];
char pg_rewind[MAXPGPATH];
char pg_ctl_mode[MAXLEN];
/* parameter used by STANDBY {ARCHIVE_CONFIG | RESTORE_CONFIG} */
char config_archive_dir[MAXLEN];
/* parameter used by CLUSTER CLEANUP */
int keep_history;
/* parameter used by {STANDBY|WITNESS} UNREGISTER */
int node;
char pg_bindir[MAXLEN];
char recovery_min_apply_delay[MAXLEN]; char recovery_min_apply_delay[MAXLEN];
/* witness create parameters */
bool witness_pwprompt;
/* standby follow parameters */
bool wait_for_master;
/* cluster {show|matrix|crosscheck} parameters */
bool csv_mode;
/* cluster cleanup parameters */
int keep_history;
/* standby switchover parameters */
char remote_config_file[MAXLEN];
bool pg_rewind_supplied;
char pg_rewind[MAXPGPATH];
char pg_ctl_mode[MAXLEN];
/* standby {archive_config | restore_config} parameters */
char config_archive_dir[MAXLEN];
/* {standby|witness} unregister parameters */
int node;
} t_runtime_options; } t_runtime_options;
#define T_RUNTIME_OPTIONS_INITIALIZER { "", "", "", "", "", "", "", DEFAULT_WAL_KEEP_SEGMENTS, false, false, false, false, false, false, false, false, false, false, false, false, CONFIG_FILE_SAMEPATH, false, 0, "", "", "", "", "fast", "", 0, UNKNOWN_NODE_ID, "", ""} #define T_RUNTIME_OPTIONS_INITIALIZER { \
/* general repmgr options */ \
"", false, false, false, \
/* options which override setting in repmgr.conf */ \
"", "", \
/* connection parameters */ \
"", "", "", "", "", "", "", \
false, false, false, \
/* standby clone parameters */ \
false, DEFAULT_WAL_KEEP_SEGMENTS, false, false, false, false, false, false, \
CONFIG_FILE_SAMEPATH, false, 0, "", \
/* witness create parameters */ \
false, \
/* standby follow parameters */ \
false, \
/* cluster {show|matrix|crosscheck} parameters */ \
false, \
/* cluster cleanup parameters */ \
0, \
/* standby switchover parameters */ \
"", false, "", "fast", \
/* standby {archive_config | restore_config} parameters */ \
"", \
/* {standby|witness} unregister parameters */ \
UNKNOWN_NODE_ID }
struct BackupLabel struct BackupLabel
{ {

View File

@@ -647,7 +647,7 @@ witness_monitor(void)
} }
else else
{ {
log_debug(_("new master found with node ID: %i\n"), master_options.node); log_info(_("new master found with node ID: %i\n"), master_options.node);
connection_ok = true; connection_ok = true;
/* /*

View File

@@ -1,6 +1,6 @@
#ifndef _VERSION_H_ #ifndef _VERSION_H_
#define _VERSION_H_ #define _VERSION_H_
#define REPMGR_VERSION "3.2" #define REPMGR_VERSION "3.2.1"
#endif #endif