standby/witness unregister - enable even if node isn't running

If the `--node` option is provided with the id of the node to unregister,
the action can be executed on any node.

This addresses GitHub #211.
This commit is contained in:
Ian Barwick
2016-08-02 17:00:25 +09:00
parent d0c05e6f46
commit c42437a4f2
4 changed files with 72 additions and 28 deletions

View File

@@ -3,6 +3,9 @@
unless `--verbose` supplied (Ian) unless `--verbose` supplied (Ian)
repmgr: remove deprecated command line options --initdb-no-pwprompt and repmgr: remove deprecated command line options --initdb-no-pwprompt and
-l/--local-port (Ian) -l/--local-port (Ian)
repmgr: add command `witness unregister`
repmgr: enable `standby unregister` / `witness unregister` to be
executed for a node which is not running
3.1.4 2016-07-12 3.1.4 2016-07-12
repmgr: new configuration option for setting "restore_command" repmgr: new configuration option for setting "restore_command"

View File

@@ -940,13 +940,13 @@ 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 the replication cluster. it from the replication cluster.
If the standby is not running, the standby record must be manually If the standby is not running, the command can be executed on another
removed from the `repl_nodes` table with e.g.: node by providing the id of the node to be unregistered using
the command line parameter `--node`, e.g. executing the following
command on the master server will unregister the standby with
id 3:
DELETE FROM repmgr_test.repl_nodes WHERE id = 3; repmgr standby unregister -f /etc/repmgr.conf --node=3
Adjust schema and node ID accordingly. A future `repmgr` release
will make it possible to unregister failed standbys.
Automatic failover with `repmgrd` Automatic failover with `repmgrd`

View File

@@ -200,6 +200,7 @@ main(int argc, char **argv)
{"pg_rewind", optional_argument, NULL, OPT_PG_REWIND}, {"pg_rewind", optional_argument, NULL, OPT_PG_REWIND},
{"pwprompt", optional_argument, NULL, OPT_PWPROMPT}, {"pwprompt", optional_argument, NULL, OPT_PWPROMPT},
{"csv", no_argument, NULL, OPT_CSV}, {"csv", no_argument, NULL, OPT_CSV},
{"node", required_argument, NULL, OPT_NODE},
{"version", no_argument, NULL, 'V'}, {"version", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
@@ -494,6 +495,10 @@ main(int argc, char **argv)
case OPT_CSV: case OPT_CSV:
runtime_options.csv_mode = true; runtime_options.csv_mode = true;
break; break;
case OPT_NODE:
runtime_options.node = repmgr_atoi(optarg, "--node", &cli_errors, false);
break;
default: default:
unknown_option: unknown_option:
{ {
@@ -1394,15 +1399,17 @@ do_standby_unregister(void)
{ {
PGconn *conn; PGconn *conn;
PGconn *master_conn; PGconn *master_conn;
int ret;
int target_node_id;
t_node_info node_info = T_NODE_INFO_INITIALIZER;
bool node_record_deleted; bool node_record_deleted;
log_info(_("connecting to standby database\n")); log_info(_("connecting to database\n"));
conn = establish_db_connection(options.conninfo, true); conn = establish_db_connection(options.conninfo, true);
/* Check we are a standby */ /* Check we are a standby */
ret = is_standby(conn); /* ret = is_standby(conn);
if (ret == 0 || ret == -1) if (ret == 0 || ret == -1)
{ {
log_err(_(ret == 0 ? "this node should be a standby (%s)\n" : log_err(_(ret == 0 ? "this node should be a standby (%s)\n" :
@@ -1410,7 +1417,7 @@ do_standby_unregister(void)
PQfinish(conn); PQfinish(conn);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }*/
/* Check if there is a schema for this cluster */ /* Check if there is a schema for this cluster */
if (check_cluster_schema(conn) == false) if (check_cluster_schema(conn) == false)
@@ -1431,16 +1438,29 @@ do_standby_unregister(void)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
/* if (runtime_options.node)
* Verify that standby and master are supported and compatible server target_node_id = runtime_options.node;
* versions else
*/ target_node_id = options.node;
check_master_standby_version_match(conn, master_conn);
/* Check node exists and is really a standby */
if (!get_node_record(master_conn, options.cluster_name, target_node_id, &node_info))
{
log_err(_("No record found for node %i\n"), target_node_id);
exit(ERR_BAD_CONFIG);
}
if (node_info.type != STANDBY)
{
log_err(_("Node %i is not a standby server\n"), target_node_id);
exit(ERR_BAD_CONFIG);
}
/* Now unregister the standby */ /* Now unregister the standby */
log_info(_("unregistering the standby\n")); log_info(_("unregistering the standby\n"));
node_record_deleted = delete_node_record(master_conn, node_record_deleted = delete_node_record(master_conn,
options.node, target_node_id,
"standby unregister"); "standby unregister");
if (node_record_deleted == false) if (node_record_deleted == false)
@@ -1453,7 +1473,7 @@ do_standby_unregister(void)
/* Log the event */ /* Log the event */
create_event_record(master_conn, create_event_record(master_conn,
&options, &options,
options.node, target_node_id,
"standby_unregister", "standby_unregister",
true, true,
NULL); NULL);
@@ -1463,7 +1483,7 @@ do_standby_unregister(void)
log_info(_("standby unregistration complete\n")); log_info(_("standby unregistration complete\n"));
log_notice(_("standby node correctly unregistered for cluster %s with id %d (conninfo: %s)\n"), log_notice(_("standby node correctly unregistered for cluster %s with id %d (conninfo: %s)\n"),
options.cluster_name, options.node, options.conninfo); options.cluster_name, target_node_id, options.conninfo);
return; return;
} }
@@ -4304,10 +4324,12 @@ do_witness_unregister(void)
{ {
PGconn *conn; PGconn *conn;
PGconn *master_conn; PGconn *master_conn;
int ret;
int target_node_id;
t_node_info node_info = T_NODE_INFO_INITIALIZER;
bool node_record_deleted; bool node_record_deleted;
t_node_info node_info = T_NODE_INFO_INITIALIZER;
log_info(_("connecting to witness database\n")); log_info(_("connecting to witness database\n"));
conn = establish_db_connection(options.conninfo, true); conn = establish_db_connection(options.conninfo, true);
@@ -4331,23 +4353,28 @@ do_witness_unregister(void)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
if (runtime_options.node)
target_node_id = runtime_options.node;
else
target_node_id = options.node;
/* Check node exists and is really a witness */ /* Check node exists and is really a witness */
if (!get_node_record(master_conn, options.cluster_name, options.node, &node_info)) if (!get_node_record(master_conn, options.cluster_name, target_node_id, &node_info))
{ {
log_err(_("No record found for node %i\n"), options.node); log_err(_("No record found for node %i\n"), target_node_id);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
if (node_info.type != WITNESS) if (node_info.type != WITNESS)
{ {
log_err(_("Node %i is not a witness server\n"), options.node); log_err(_("Node %i is not a witness server\n"), target_node_id);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
log_info(_("unregistering the witness server\n")); log_info(_("unregistering the witness server\n"));
node_record_deleted = delete_node_record(master_conn, node_record_deleted = delete_node_record(master_conn,
options.node, target_node_id,
"witness unregister"); "witness unregister");
if (node_record_deleted == false) if (node_record_deleted == false)
@@ -4360,7 +4387,7 @@ do_witness_unregister(void)
/* Log the event */ /* Log the event */
create_event_record(master_conn, create_event_record(master_conn,
&options, &options,
options.node, target_node_id,
"witness_unregister", "witness_unregister",
true, true,
NULL); NULL);
@@ -4370,7 +4397,7 @@ do_witness_unregister(void)
log_info(_("witness unregistration complete\n")); log_info(_("witness unregistration complete\n"));
log_notice(_("witness node correctly unregistered for cluster %s with id %d (conninfo: %s)\n"), log_notice(_("witness node correctly unregistered for cluster %s with id %d (conninfo: %s)\n"),
options.cluster_name, options.node, options.conninfo); options.cluster_name, target_node_id, options.conninfo);
return; return;
} }
@@ -4842,6 +4869,7 @@ check_parameters_for_action(const int action)
item_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:
/* /*
@@ -4858,6 +4886,7 @@ check_parameters_for_action(const int action)
item_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:
/* /*
@@ -4874,6 +4903,7 @@ check_parameters_for_action(const int action)
item_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:
/* /*
@@ -5015,6 +5045,14 @@ check_parameters_for_action(const int action)
} }
} }
if (action != WITNESS_UNREGISTER)
{
if (runtime_options.node)
{
item_list_append(&cli_warnings, _("--node can only be supplied when executing WITNESS UNREGISTER"));
}
}
/* Warn about parameters which apply to CLUSTER SHOW only */ /* Warn about parameters which apply to CLUSTER SHOW only */
if (action != CLUSTER_SHOW) if (action != CLUSTER_SHOW)
{ {
@@ -5024,6 +5062,7 @@ check_parameters_for_action(const int action)
} }
} }
return; return;
} }

View File

@@ -55,7 +55,7 @@
#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
/* Run time options type */ /* Run time options type */
@@ -94,13 +94,15 @@ typedef struct
char config_archive_dir[MAXLEN]; char config_archive_dir[MAXLEN];
/* parameter used by CLUSTER CLEANUP */ /* parameter used by CLUSTER CLEANUP */
int keep_history; int keep_history;
/* paramater used by {STANDBY|WITNESS} UNREGISTER */
int node;
char pg_bindir[MAXLEN]; char pg_bindir[MAXLEN];
char recovery_min_apply_delay[MAXLEN]; char recovery_min_apply_delay[MAXLEN];
} 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, "", "", "", "", "fast", "", 0, "", ""} #define T_RUNTIME_OPTIONS_INITIALIZER { "", "", "", "", "", "", "", DEFAULT_WAL_KEEP_SEGMENTS, false, false, false, false, false, false, false, false, false, false, "", "", "", "", "fast", "", 0, 0, "", ""}
struct BackupLabel struct BackupLabel
{ {