From 7b976ef2df0be371aae5f6c5da77257b80c7a362 Mon Sep 17 00:00:00 2001 From: Ian Barwick Date: Fri, 16 Jun 2017 00:05:18 +0900 Subject: [PATCH] repmgr standby follow: initial code --- dbutils.c | 2 +- repmgr-action-standby.c | 121 +++++++++++++++++++++++++++++++++------- repmgr-client-global.h | 3 +- repmgr-client.c | 5 ++ repmgr-client.h | 2 +- 5 files changed, 109 insertions(+), 24 deletions(-) diff --git a/dbutils.c b/dbutils.c index abadc49c..9a4294e9 100644 --- a/dbutils.c +++ b/dbutils.c @@ -950,7 +950,7 @@ get_master_connection(PGconn *conn, node_id = atoi(PQgetvalue(res, i, 0)); strncpy(remote_conninfo, PQgetvalue(res, i, 1), MAXCONNINFO); log_verbose(LOG_INFO, - _("checking role of cluster node '%i'"), + _("checking role of node '%i'"), node_id); remote_conn = establish_db_connection(remote_conninfo, false); diff --git a/repmgr-action-standby.c b/repmgr-action-standby.c index 966dc496..25c2b0d2 100644 --- a/repmgr-action-standby.c +++ b/repmgr-action-standby.c @@ -63,7 +63,7 @@ static void check_barman_config(void); static void check_source_server(void); static void check_source_server_via_barman(void); static void check_master_standby_version_match(PGconn *conn, PGconn *master_conn); - +static void check_recovery_type(PGconn *conn); static void initialise_direct_clone(void); static void config_file_list_init(t_configfile_list *list, int max_size); @@ -589,25 +589,7 @@ do_standby_register(void) if (PQstatus(conn) == CONNECTION_OK) { - t_recovery_type recovery_type = get_recovery_type(conn); - - if (recovery_type != RECTYPE_STANDBY) - { - if (recovery_type == RECTYPE_MASTER) - { - log_error(_("this node should be a standby (%s)"), - config_file_options.conninfo); - PQfinish(conn); - exit(ERR_BAD_CONFIG); - } - else - { - log_error(_("connection to node (%s) lost"), - config_file_options.conninfo); - PQfinish(conn); - exit(ERR_DB_CONN); - } - } + check_recovery_type(conn); } /* check if there is a master in this cluster */ @@ -1227,10 +1209,82 @@ do_standby_promote(void) return; } + +/* + * Follow a new primary. + * + * This function has two "modes": + * 1) no primary info provided - determine primary from standby metadata + * 2) primary info provided - use that info to connect to the primary. + * + * (2) is mainly for when a node has been stopped as part of a switchover + * and needs to be started with recovery.conf correctly configured. + */ + void do_standby_follow(void) { - puts("not implemented"); + PGconn *local_conn; + char data_dir[MAXPGPATH]; + + log_verbose(LOG_DEBUG, "do_standby_follow()"); + + /* + * If -h/--host wasn't provided, attempt to connect to standby + * to determine primary, and carry out some other checks while we're + * at it. + */ + if (runtime_options.host_param_provided == false) + { + bool success; + PGconn *master_conn = NULL; + char master_conninfo[MAXLEN]; + int master_id = UNKNOWN_NODE_ID; + int timer; + + local_conn = establish_db_connection(config_file_options.conninfo, true); + + log_verbose(LOG_INFO, _("connected to local node")); + + check_recovery_type(local_conn); + + success = get_pg_setting(local_conn, "data_directory", data_dir); + + if (success == false) + { + log_error(_("unable to determine data directory")); + PQfinish(local_conn); + exit(ERR_BAD_CONFIG); + } + + /* + * Attempt to connect to master. + * + * If --wait provided, loop for up `master_response_timeout` + * seconds before giving up + */ + + for (timer = 0; timer < config_file_options.master_response_timeout; timer++) + { + master_conn = get_master_connection(local_conn, + &master_id, + (char *) &master_conninfo); + + if (PQstatus(master_conn) == CONNECTION_OK || runtime_options.wait == false) + { + break; + } + } + + if (PQstatus(master_conn) != CONNECTION_OK) + { + log_error(_("unable to determine master node")); + PQfinish(local_conn); + exit(ERR_BAD_CONFIG); + } + + puts("OK"); + } return; } @@ -2669,3 +2723,28 @@ check_master_standby_version_match(PGconn *conn, PGconn *master_conn) exit(ERR_BAD_CONFIG); } } + + +static void +check_recovery_type(PGconn *conn) +{ + t_recovery_type recovery_type = get_recovery_type(conn); + + if (recovery_type != RECTYPE_STANDBY) + { + if (recovery_type == RECTYPE_MASTER) + { + log_error(_("this node should be a standby (%s)"), + config_file_options.conninfo); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + else + { + log_error(_("connection to node (%s) lost"), + config_file_options.conninfo); + PQfinish(conn); + exit(ERR_DB_CONN); + } + } +} diff --git a/repmgr-client-global.h b/repmgr-client-global.h index c712c8a4..608b40fe 100644 --- a/repmgr-client-global.h +++ b/repmgr-client-global.h @@ -29,6 +29,7 @@ typedef struct bool dry_run; bool force; char pg_bindir[MAXLEN]; /* overrides setting in repmgr.conf */ + bool wait; /* logging options */ char loglevel[MAXLEN]; /* overrides setting in repmgr.conf */ @@ -79,7 +80,7 @@ typedef struct /* configuration metadata */ \ false, false, false, false, false, \ /* general configuration options */ \ - "", false, false, "", \ + "", false, false, "", false, \ /* logging options */ \ "", false, false, false, \ /* database connection options */ \ diff --git a/repmgr-client.c b/repmgr-client.c index 109a6636..c99b82c5 100644 --- a/repmgr-client.c +++ b/repmgr-client.c @@ -204,6 +204,11 @@ main(int argc, char **argv) runtime_options.force = true; break; + /* -W/--wait */ + case 'W': + runtime_options.wait = true; + break; + /* database connection options */ /* --------------------------- */ diff --git a/repmgr-client.h b/repmgr-client.h index 569f7a28..eb430408 100644 --- a/repmgr-client.h +++ b/repmgr-client.h @@ -73,6 +73,7 @@ static struct option long_options[] = {"dry-run", no_argument, NULL, OPT_DRY_RUN}, {"force", no_argument, NULL, 'F'}, {"pg_bindir", required_argument, NULL, 'b'}, + {"wait", no_argument, NULL, 'W'}, /* connection options */ {"dbname", required_argument, NULL, 'd'}, @@ -119,7 +120,6 @@ static struct option long_options[] = /* not yet handled */ {"keep-history", required_argument, NULL, 'k'}, - {"wait", no_argument, NULL, 'W'}, {"mode", required_argument, NULL, 'm'}, {"remote-config-file", required_argument, NULL, 'C'}, {"check-upstream-config", no_argument, NULL, OPT_CHECK_UPSTREAM_CONFIG},