"standby register": add sanity check when --upstream-node-id not supplied

If --upstream-node-id was not supplied to "repmgr standby register",
repmgr defaults to the primary node as upstream node. If the local node is
available, we now double-check that it's attached to the primary,
in case the lack of --upstream-node-id was an accidental ommission.

This check is only made when the local node is available.

This behaviour can be overriden with -F/--force (though it's hard to
imagine a scenario where that would be useful).

Addresses GitHub #395.
This commit is contained in:
Ian Barwick
2018-04-05 17:00:17 +09:00
committed by Ian Barwick
parent 94b72382e5
commit 6ac42f1593

View File

@@ -1197,6 +1197,8 @@ do_standby_register(void)
t_node_info primary_node_record = T_NODE_INFO_INITIALIZER; t_node_info primary_node_record = T_NODE_INFO_INITIALIZER;
int primary_node_id = UNKNOWN_NODE_ID; int primary_node_id = UNKNOWN_NODE_ID;
bool dry_run_ok = true;
log_info(_("connecting to local node \"%s\" (ID: %i)"), log_info(_("connecting to local node \"%s\" (ID: %i)"),
config_file_options.node_name, config_file_options.node_name,
config_file_options.node_id); config_file_options.node_id);
@@ -1204,8 +1206,11 @@ do_standby_register(void)
conn = establish_db_connection_quiet(config_file_options.conninfo); conn = establish_db_connection_quiet(config_file_options.conninfo);
/* /*
* if --force provided, don't wait for the node to start, as the * If unable to connect, and --force not provided, wait up to --wait-start
* normal use case will be re-registering an existing node, or * seconds (default: 0) for the node to become reachable.
*
* Not that if --force provided, we don't wait for the node to start, as
* the normal use case will be re-registering an existing node, or
* registering an inactive/not-yet-extant one; we'll do the * registering an inactive/not-yet-extant one; we'll do the
* error handling for those cases in the next code block * error handling for those cases in the next code block
*/ */
@@ -1243,9 +1248,12 @@ do_standby_register(void)
config_file_options.node_id, config_file_options.node_id,
timer); timer);
} }
} }
/*
* If still unable to connect, continue only if -F/--force provided,
* and primary connection parameters provided.
*/
if (PQstatus(conn) != CONNECTION_OK) if (PQstatus(conn) != CONNECTION_OK)
{ {
if (runtime_options.force == false) if (runtime_options.force == false)
@@ -1265,12 +1273,12 @@ do_standby_register(void)
log_error(_("unable to connect to local node \"%s\" (ID: %i)"), log_error(_("unable to connect to local node \"%s\" (ID: %i)"),
config_file_options.node_name, config_file_options.node_name,
config_file_options.node_id); config_file_options.node_id);
log_hint(_("to register an inactive standby, additionally provide the primary connection parameters")); log_hint(_("to register a standby which is not running, additionally provide the primary connection parameters"));
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
} }
/* connection OK - check this is actually a standby */
if (PQstatus(conn) == CONNECTION_OK) else
{ {
check_recovery_type(conn); check_recovery_type(conn);
} }
@@ -1293,7 +1301,6 @@ do_standby_register(void)
primary_conn = establish_db_connection_by_params(&source_conninfo, false); primary_conn = establish_db_connection_by_params(&source_conninfo, false);
} }
/* /*
* no amount of --force will make it possible to register the standby * no amount of --force will make it possible to register the standby
* without a primary server to connect to * without a primary server to connect to
@@ -1368,8 +1375,12 @@ do_standby_register(void)
} }
/* /*
* If an upstream node is defined, check if that node exists and is active * If an upstream node is defined, check if that node exists and is active.
* If it doesn't exist, and --force set, create a minimal inactive record *
* If it doesn't exist, and --force set, create a minimal inactive record,
* in the assumption that the user knows what they are doing (usually some kind
* of provisioning where multiple servers are created in parallel) and will
* create the active record later.
*/ */
if (runtime_options.upstream_node_id != NO_UPSTREAM_NODE) if (runtime_options.upstream_node_id != NO_UPSTREAM_NODE)
{ {
@@ -1493,15 +1504,15 @@ do_standby_register(void)
/* check our standby is connected */ /* check our standby is connected */
if (is_downstream_node_attached(upstream_conn, config_file_options.node_name) == true) if (is_downstream_node_attached(upstream_conn, config_file_options.node_name) == true)
{ {
log_verbose(LOG_INFO, _("local node is attached to upstream")); log_verbose(LOG_INFO, _("local node is attached to specified upstream node %i"), runtime_options.upstream_node_id);
} }
else else
{ {
if (!runtime_options.force) if (!runtime_options.force)
{ {
log_error(_("this node does not appear to be attached to upstream node \"%s\" (ID: %i)"), log_error(_("this node does not appear to be attached to upstream node \"%s\" (ID: %i)"),
config_file_options.node_name, upstream_node_record.node_name,
config_file_options.node_id); upstream_node_record.node_id);
log_detail(_("no record for application name \"%s\" found in \"pg_stat_replication\""), log_detail(_("no record for application name \"%s\" found in \"pg_stat_replication\""),
config_file_options.node_name); config_file_options.node_name);
@@ -1520,24 +1531,82 @@ do_standby_register(void)
} }
} }
if (runtime_options.dry_run == true)
{
log_info(_("all prerequisites for \"standby register\" are met"));
PQfinish(primary_conn);
if (PQstatus(conn) == CONNECTION_OK)
PQfinish(conn);
exit(SUCCESS);
}
/* /*
* populate node record structure with current values (this will overwrite * populate node record structure with current values set in repmgr.conf
* any existing values, which is what we want when updating the record * and/or the command line (this will overwrite any existing values, which
* is what we want when updating the record)
*/ */
init_node_record(&node_record); init_node_record(&node_record);
node_record.type = STANDBY; node_record.type = STANDBY;
/* if --upstream-node-id not provided, set to primary node id */
if (node_record.upstream_node_id == UNKNOWN_NODE_ID)
{
node_record.upstream_node_id = primary_node_id;
}
/*
* If --upstream-node-id not provided, we're defaulting to the primary as
* upstream node. If local node is available, double-check that it's attached
* to the primary, in case --upstream-node-id was an accidental ommission.
*
* Currently we'll only do this for newly registered nodes.
*/
if (runtime_options.upstream_node_id == NO_UPSTREAM_NODE && PQstatus(conn) == CONNECTION_OK)
{
/* only do this if record does not exist */
if (record_status != RECORD_FOUND)
{
log_warning(_("--upstream-node-id not supplied, assuming upstream node is primary (node ID %i)"),
primary_node_id);
/* check our standby is connected */
if (is_downstream_node_attached(primary_conn, config_file_options.node_name) == true)
{
log_verbose(LOG_INFO, _("local node is attached to primary"));
}
else if (runtime_options.force == false)
{
log_error(_("local node not attached to primary node %i"), primary_node_id);
/* TODO: 9.6 and later, display detail from pg_stat_wal_receiver */
log_hint(_("specify the actual upstream node id with --upstream-node-id, or use -F/--force to continue anyway"));
if (runtime_options.dry_run == true)
{
dry_run_ok = false;
}
else
{
PQfinish(primary_conn);
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
}
else
{
log_warning(_("local node not attached to primary node %i"), primary_node_id);
log_notice(_("-F/--force supplied, continuing anyway"));
}
}
}
if (runtime_options.dry_run == true)
{
PQfinish(primary_conn);
if (PQstatus(conn) == CONNECTION_OK)
PQfinish(conn);
if (dry_run_ok == false)
{
log_warning(_("issue(s) encountered; see preceding log messages"));
exit(ERR_BAD_CONFIG);
}
log_info(_("all prerequisites for \"standby register\" are met"));
exit(SUCCESS);
}
/* /*
* node record exists - update it (at this point we have already * node record exists - update it (at this point we have already
@@ -1560,13 +1629,11 @@ do_standby_register(void)
if (record_created == false) if (record_created == false)
{ {
appendPQExpBuffer( appendPQExpBuffer(&details,
&details,
"standby registration failed"); "standby registration failed");
if (runtime_options.force == true) if (runtime_options.force == true)
appendPQExpBuffer( appendPQExpBuffer(&details,
&details,
" (-F/--force option was used)"); " (-F/--force option was used)");
create_event_notification_extended( create_event_notification_extended(