From c42437a4f2908c6c9e826a480b29ccc6edd73f44 Mon Sep 17 00:00:00 2001 From: Ian Barwick Date: Tue, 2 Aug 2016 17:00:25 +0900 Subject: [PATCH] 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. --- HISTORY | 3 +++ README.md | 12 ++++----- repmgr.c | 79 +++++++++++++++++++++++++++++++++++++++++-------------- repmgr.h | 6 +++-- 4 files changed, 72 insertions(+), 28 deletions(-) diff --git a/HISTORY b/HISTORY index 7dd1bd44..190459be 100644 --- a/HISTORY +++ b/HISTORY @@ -3,6 +3,9 @@ unless `--verbose` supplied (Ian) repmgr: remove deprecated command line options --initdb-no-pwprompt and -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 repmgr: new configuration option for setting "restore_command" diff --git a/README.md b/README.md index 3185074c..3d65c399 100644 --- a/README.md +++ b/README.md @@ -940,13 +940,13 @@ recorded in the `repl_events` table. Note that this command will not stop the server itself or remove it from the replication cluster. -If the standby is not running, the standby record must be manually -removed from the `repl_nodes` table with e.g.: +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 +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; - -Adjust schema and node ID accordingly. A future `repmgr` release -will make it possible to unregister failed standbys. + repmgr standby unregister -f /etc/repmgr.conf --node=3 Automatic failover with `repmgrd` diff --git a/repmgr.c b/repmgr.c index c1edc2b7..facc0fe9 100644 --- a/repmgr.c +++ b/repmgr.c @@ -200,6 +200,7 @@ main(int argc, char **argv) {"pg_rewind", optional_argument, NULL, OPT_PG_REWIND}, {"pwprompt", optional_argument, NULL, OPT_PWPROMPT}, {"csv", no_argument, NULL, OPT_CSV}, + {"node", required_argument, NULL, OPT_NODE}, {"version", no_argument, NULL, 'V'}, {NULL, 0, NULL, 0} }; @@ -494,6 +495,10 @@ main(int argc, char **argv) case OPT_CSV: runtime_options.csv_mode = true; break; + case OPT_NODE: + runtime_options.node = repmgr_atoi(optarg, "--node", &cli_errors, false); + break; + default: unknown_option: { @@ -1394,15 +1399,17 @@ do_standby_unregister(void) { PGconn *conn; PGconn *master_conn; - int ret; + + int target_node_id; + t_node_info node_info = T_NODE_INFO_INITIALIZER; bool node_record_deleted; - log_info(_("connecting to standby database\n")); + log_info(_("connecting to database\n")); conn = establish_db_connection(options.conninfo, true); /* Check we are a standby */ - ret = is_standby(conn); +/* ret = is_standby(conn); if (ret == 0 || ret == -1) { log_err(_(ret == 0 ? "this node should be a standby (%s)\n" : @@ -1410,7 +1417,7 @@ do_standby_unregister(void) PQfinish(conn); exit(ERR_BAD_CONFIG); - } + }*/ /* Check if there is a schema for this cluster */ if (check_cluster_schema(conn) == false) @@ -1431,16 +1438,29 @@ do_standby_unregister(void) exit(ERR_BAD_CONFIG); } - /* - * Verify that standby and master are supported and compatible server - * versions - */ - check_master_standby_version_match(conn, master_conn); + if (runtime_options.node) + target_node_id = runtime_options.node; + else + target_node_id = options.node; + + /* 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 */ log_info(_("unregistering the standby\n")); node_record_deleted = delete_node_record(master_conn, - options.node, + target_node_id, "standby unregister"); if (node_record_deleted == false) @@ -1453,7 +1473,7 @@ do_standby_unregister(void) /* Log the event */ create_event_record(master_conn, &options, - options.node, + target_node_id, "standby_unregister", true, NULL); @@ -1463,7 +1483,7 @@ do_standby_unregister(void) log_info(_("standby unregistration complete\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; } @@ -4304,10 +4324,12 @@ do_witness_unregister(void) { PGconn *conn; PGconn *master_conn; - int ret; + + int target_node_id; + t_node_info node_info = T_NODE_INFO_INITIALIZER; bool node_record_deleted; - t_node_info node_info = T_NODE_INFO_INITIALIZER; + log_info(_("connecting to witness database\n")); conn = establish_db_connection(options.conninfo, true); @@ -4331,23 +4353,28 @@ do_witness_unregister(void) 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 */ - 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); } 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); } log_info(_("unregistering the witness server\n")); node_record_deleted = delete_node_record(master_conn, - options.node, + target_node_id, "witness unregister"); if (node_record_deleted == false) @@ -4360,7 +4387,7 @@ do_witness_unregister(void) /* Log the event */ create_event_record(master_conn, &options, - options.node, + target_node_id, "witness_unregister", true, NULL); @@ -4370,7 +4397,7 @@ do_witness_unregister(void) log_info(_("witness unregistration complete\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; } @@ -4842,6 +4869,7 @@ check_parameters_for_action(const int action) item_list_append(&cli_warnings, _("destination directory not required when executing MASTER REGISTER")); } break; + 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")); } break; + 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")); } break; + 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 */ if (action != CLUSTER_SHOW) { @@ -5024,6 +5062,7 @@ check_parameters_for_action(const int action) } } + return; } diff --git a/repmgr.h b/repmgr.h index 10adc4b5..e10aa86b 100644 --- a/repmgr.h +++ b/repmgr.h @@ -55,7 +55,7 @@ #define OPT_PG_REWIND 6 #define OPT_PWPROMPT 7 #define OPT_CSV 8 - +#define OPT_NODE 9 /* Run time options type */ @@ -94,13 +94,15 @@ typedef struct char config_archive_dir[MAXLEN]; /* parameter used by CLUSTER CLEANUP */ int keep_history; + /* paramater used by {STANDBY|WITNESS} UNREGISTER */ + int node; char pg_bindir[MAXLEN]; char recovery_min_apply_delay[MAXLEN]; } 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 {