From c7f49541a3a0a9fdcad7a75d8b9868a0fe8769be Mon Sep 17 00:00:00 2001 From: Ian Barwick Date: Mon, 8 May 2017 23:37:53 +0900 Subject: [PATCH] Add "standby unregister" --- dbutils.c | 31 ++++++++++++++++ dbutils.h | 4 +- repmgr-action-standby.c | 82 +++++++++++++++++++++++++++++++++++++++++ repmgr-action-standby.h | 1 + repmgr-client.c | 8 +++- 5 files changed, 124 insertions(+), 2 deletions(-) diff --git a/dbutils.c b/dbutils.c index ba239719..0cdcc6df 100644 --- a/dbutils.c +++ b/dbutils.c @@ -1360,6 +1360,37 @@ _create_update_node_record(PGconn *conn, char *action, t_node_info *node_info) return true; } + +bool +delete_node_record(PGconn *conn, int node) +{ + PQExpBufferData query; + PGresult *res; + + initPQExpBuffer(&query); + + appendPQExpBuffer(&query, + "DELETE FROM repmgr.nodes " + " WHERE node_id = %d", + node); + + log_verbose(LOG_DEBUG, "delete_node_record():\n %s", query.data); + + res = PQexec(conn, query.data); + + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_error(_("unable to delete node record:\n %s"), + PQerrorMessage(conn)); + PQclear(res); + return false; + } + + PQclear(res); + return true; + +} + /* ====================== */ /* event record functions */ /* ====================== */ diff --git a/dbutils.h b/dbutils.h index d990d5a0..3420b64b 100644 --- a/dbutils.h +++ b/dbutils.h @@ -132,6 +132,8 @@ PGconn *establish_db_connection_by_params(const char *keywords[], const char *values[], const bool exit_on_error); +PGconn *get_master_connection(PGconn *standby_conn, int *master_id, char *master_conninfo_out); + bool is_superuser_connection(PGconn *conn, t_connection_user *userinfo); /* conninfo manipulation functions */ @@ -164,7 +166,6 @@ bool get_pg_setting(PGconn *conn, const char *setting, char *output); bool get_cluster_size(PGconn *conn, char *size); int get_server_version(PGconn *conn, char *server_version); int is_standby(PGconn *conn); -PGconn *get_master_connection(PGconn *standby_conn, int *master_id, char *master_conninfo_out); int get_master_node_id(PGconn *conn); /* extension functions */ @@ -182,6 +183,7 @@ int get_node_record_by_name(PGconn *conn, const char *node_name, t_node_info * bool create_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info); bool update_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info); +bool delete_node_record(PGconn *conn, int node); /* event record functions */ bool create_event_record(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details); diff --git a/repmgr-action-standby.c b/repmgr-action-standby.c index bbfe399c..4c12bde6 100644 --- a/repmgr-action-standby.c +++ b/repmgr-action-standby.c @@ -930,6 +930,88 @@ do_standby_register(void) } +void +do_standby_unregister(void) +{ + PGconn *conn; + PGconn *master_conn; + + int target_node_id; + t_node_info node_info = T_NODE_INFO_INITIALIZER; + + bool node_record_deleted; + + log_info(_("connecting to local standby")); + conn = establish_db_connection(config_file_options.conninfo, true); + + /* check if there is a master in this cluster */ + log_info(_("connecting to master database")); + + master_conn = get_master_connection(conn, NULL, NULL); + + if (PQstatus(master_conn) != CONNECTION_OK) + { + log_error(_("unable to connect to master server")); + log_detail("%s", PQerrorMessage(conn)); + exit(ERR_BAD_CONFIG); + } + + /* + * if --node-id was specified, unregister that node rather than the + * current one - this enables inactive nodes to be unregistered. + */ + if (runtime_options.node_id != UNKNOWN_NODE_ID) + target_node_id = runtime_options.node_id; + else + target_node_id = config_file_options.node_id; + + /* Check node exists and is really a standby */ + + if (!get_node_record(master_conn, target_node_id, &node_info)) + { + log_error(_("no record found for node %i"), target_node_id); + PQfinish(master_conn); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + if (node_info.type != STANDBY) + { + log_error(_("node %i is not a standby server"), target_node_id); + PQfinish(master_conn); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* Now unregister the standby */ + log_notice(_("unregistering node %i"), target_node_id); + node_record_deleted = delete_node_record(master_conn, + target_node_id); + + if (node_record_deleted == false) + { + PQfinish(master_conn); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* Log the event */ + create_event_record(master_conn, + &config_file_options, + target_node_id, + "standby_unregister", + true, + NULL); + + PQfinish(master_conn); + PQfinish(conn); + + log_info(_("standby unregistration complete")); + + return; + +} + static void check_source_server() { diff --git a/repmgr-action-standby.h b/repmgr-action-standby.h index fd2438a4..ead97c9b 100644 --- a/repmgr-action-standby.h +++ b/repmgr-action-standby.h @@ -8,6 +8,7 @@ extern void do_standby_clone(void); extern void do_standby_register(void); +extern void do_standby_unregister(void); typedef struct { diff --git a/repmgr-client.c b/repmgr-client.c index 7224c212..db4ce955 100644 --- a/repmgr-client.c +++ b/repmgr-client.c @@ -11,7 +11,8 @@ * [ MASTER | PRIMARY ] REGISTER * * STANDBY CLONE - * STANDBY REGISTER (wip) + * STANDBY REGISTER + * STANDBY UNREGISTER (wip) * * CLUSTER EVENT */ @@ -558,6 +559,8 @@ main(int argc, char **argv) action = STANDBY_CLONE; else if(strcasecmp(repmgr_action, "REGISTER") == 0) action = STANDBY_REGISTER; + else if(strcasecmp(repmgr_action, "UNREGISTER") == 0) + action = STANDBY_UNREGISTER; } else if(strcasecmp(repmgr_node_type, "CLUSTER") == 0) @@ -814,6 +817,9 @@ main(int argc, char **argv) case STANDBY_REGISTER: do_standby_register(); break; + case STANDBY_UNREGISTER: + do_standby_unregister(); + break; case CLUSTER_EVENT: do_cluster_event();