mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-27 00:46:29 +00:00
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:
3
HISTORY
3
HISTORY
@@ -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"
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -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`
|
||||||
|
|||||||
79
repmgr.c
79
repmgr.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
repmgr.h
6
repmgr.h
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user