diff --git a/dbutils.c b/dbutils.c index ba03c4c1..9b82c203 100644 --- a/dbutils.c +++ b/dbutils.c @@ -652,7 +652,7 @@ guc_set_typed(PGconn *conn, const char *parameter, const char *op, " WHERE name = '%s' AND setting::%s %s '%s'::%s", parameter, datatype, op, value, datatype); - log_verbose(LOG_DEBUG, "guc_set_typed():\n%s\n", query.data); + log_verbose(LOG_DEBUG, "guc_set_typed():\n%s", query.data); res = PQexec(conn, query.data); diff --git a/repmgr-action-standby.c b/repmgr-action-standby.c index 9f7f2b28..26eec735 100644 --- a/repmgr-action-standby.c +++ b/repmgr-action-standby.c @@ -266,9 +266,12 @@ check_source_server() { int server_version_num = UNKNOWN_SERVER_VERSION_NUM; char cluster_size[MAXLEN]; + t_node_info node_record = T_NODE_INFO_INITIALIZER; + int query_result; + t_extension_status extension_status; /* Attempt to connect to the upstream server to verify its configuration */ - log_info(_("connecting to upstream node\n")); + log_info(_("connecting to upstream node")); source_conn = establish_db_connection_by_params((const char**)source_conninfo.keywords, (const char**)source_conninfo.values, @@ -280,131 +283,150 @@ check_source_server() */ if (PQstatus(source_conn) != CONNECTION_OK) { - if (mode != barman) + if (mode == barman) + { + return; + } + else { PQfinish(source_conn); exit(ERR_DB_CON); } } + + /* + * If a connection was established, perform some sanity checks on the + * provided upstream connection + */ + + + /* Verify that upstream node is a supported server version */ + log_verbose(LOG_INFO, _("connected to upstream node, checking its state")); + + server_version_num = check_server_version(source_conn, "master", true, NULL); + + check_upstream_config(source_conn, server_version_num, true); + + if (get_cluster_size(source_conn, cluster_size) == false) + exit(ERR_DB_QUERY); + + log_info(_("successfully connected to source node")); + log_detail(_("current installation size is %s"), + cluster_size); + + /* + * If --recovery-min-apply-delay was passed, check that + * we're connected to PostgreSQL 9.4 or later + */ + // XXX should this be a config file parameter? + if (*runtime_options.recovery_min_apply_delay) + { + if (server_version_num < 90400) + { + log_error(_("PostgreSQL 9.4 or greater required for --recovery-min-apply-delay\n")); + PQfinish(source_conn); + exit(ERR_BAD_CONFIG); + } + } + + /* + * If the upstream node is a standby, try to connect to the primary too so we + * can write an event record + */ + if (is_standby(source_conn)) + { + primary_conn = get_master_connection(source_conn, NULL, NULL); + + // XXX check this worked? + } else { - /* - * If a connection was established, perform some sanity checks on the - * provided upstream connection - */ - t_node_info upstream_node_record = T_NODE_INFO_INITIALIZER; - int query_result; - t_extension_status extension_status; + primary_conn = source_conn; + } - /* Verify that upstream node is a supported server version */ - log_verbose(LOG_INFO, _("connected to upstream node, checking its state\n")); + /* + * Sanity-check that the master node has a repmgr schema - if not + * present, fail with an error unless -F/--force is used (to enable + * repmgr to be used as a standalone clone tool) + */ - server_version_num = check_server_version(source_conn, "master", true, NULL); + extension_status = get_repmgr_extension_status(primary_conn); - check_upstream_config(source_conn, server_version_num, true); - - if (get_cluster_size(source_conn, cluster_size) == false) - exit(ERR_DB_QUERY); - - log_info(_("Successfully connected to source node. Current installation size is %s"), - cluster_size); - - /* - * If --recovery-min-apply-delay was passed, check that - * we're connected to PostgreSQL 9.4 or later - */ - // XXX should this be a config file parameter? - if (*runtime_options.recovery_min_apply_delay) + if (extension_status != REPMGR_INSTALLED) + { + if (!runtime_options.force) { - if (server_version_num < 90400) - { - log_error(_("PostgreSQL 9.4 or greater required for --recovery-min-apply-delay\n")); - PQfinish(source_conn); - exit(ERR_BAD_CONFIG); - } - } - - /* - * If the upstream node is a standby, try to connect to the primary too so we - * can write an event record - */ - if (is_standby(source_conn)) - { - primary_conn = get_master_connection(source_conn, NULL, NULL); - - // XXX check this worked? - } - else - { - primary_conn = source_conn; - } - - /* - * Sanity-check that the master node has a repmgr schema - if not - * present, fail with an error unless -F/--force is used (to enable - * repmgr to be used as a standalone clone tool) - */ - - extension_status = get_repmgr_extension_status(primary_conn); - - if (extension_status != REPMGR_INSTALLED) - { - if (!runtime_options.force) - { - /* schema doesn't exist */ - log_error(_("repmgr extension not found on upstream server")); - log_hint(_("check that the upstream server is part of a repmgr cluster")); - PQfinish(source_conn); - exit(ERR_BAD_CONFIG); - } - - log_warning(_("repmgr extension not found on upstream server")); - } - - /* Fetch the source's data directory */ - if (get_pg_setting(source_conn, "data_directory", upstream_data_directory) == false) - { - log_error(_("unable to retrieve upstream node's data directory")); - log_hint(_("STANDBY CLONE must be run as a database superuser")); + /* schema doesn't exist */ + log_error(_("repmgr extension not found on upstream server")); + log_hint(_("check that the upstream server is part of a repmgr cluster")); PQfinish(source_conn); exit(ERR_BAD_CONFIG); } - /* - * If no target directory was explicitly provided, we'll default to - * the same directory as on the source host. - */ - if (local_data_directory_provided == false) - { - strncpy(local_data_directory, upstream_data_directory, MAXPGPATH); - - log_notice(_("setting data directory to: \"%s\""), local_data_directory); - log_hint(_("use -D/--pgdata to explicitly specify a data directory")); - } - - /* - * Copy the source connection so that we have some default values, - * particularly stuff like passwords extracted from PGPASSFILE; - * these will be overridden from the upstream conninfo, if provided. - */ - conn_to_param_list(source_conn, &recovery_conninfo); - - /* - * Attempt to find the upstream node record - */ - if (config_file_options.upstream_node_id == NO_UPSTREAM_NODE) - upstream_node_id = get_master_node_id(source_conn); - else - upstream_node_id = config_file_options.upstream_node_id; - - query_result = get_node_record(source_conn, upstream_node_id, &upstream_node_record); - - if (query_result) - { - upstream_record_found = true; - strncpy(recovery_conninfo_str, upstream_node_record.conninfo, MAXLEN); - } + log_warning(_("repmgr extension not found on upstream server")); } + + /* Fetch the source's data directory */ + if (get_pg_setting(source_conn, "data_directory", upstream_data_directory) == false) + { + log_error(_("unable to retrieve upstream node's data directory")); + log_hint(_("STANDBY CLONE must be run as a database superuser")); + PQfinish(source_conn); + exit(ERR_BAD_CONFIG); + } + + /* + * If no target data directory was explicitly provided, we'll default to + * the source host's data directory. + */ + if (local_data_directory_provided == false) + { + strncpy(local_data_directory, upstream_data_directory, MAXPGPATH); + + log_notice(_("setting data directory to: \"%s\""), local_data_directory); + log_hint(_("use -D/--pgdata to explicitly specify a data directory")); + } + + /* + * Copy the source connection so that we have some default values, + * particularly stuff like passwords extracted from PGPASSFILE; + * these will be overridden from the upstream conninfo, if provided. + * + * XXX only allow passwords if --use-conninfo-password + */ + conn_to_param_list(source_conn, &recovery_conninfo); + + /* + * Attempt to find the upstream node record + */ + if (config_file_options.upstream_node_id == NO_UPSTREAM_NODE) + upstream_node_id = get_master_node_id(source_conn); + else + upstream_node_id = config_file_options.upstream_node_id; + + query_result = get_node_record(source_conn, upstream_node_id, &node_record); + + if (query_result) + { + upstream_record_found = true; + strncpy(recovery_conninfo_str, node_record.conninfo, MAXLEN); + } + + /* + * check that there's no existing node record with the same name but + * different ID + */ + query_result = get_node_record_by_name(source_conn, config_file_options.node_name, &node_record); + + if (query_result) + { + log_error(_("another node (node_id: %i) already exists with node_name \"%s\""), + node_record.node_id, + config_file_options.node_name); + PQfinish(source_conn); + exit(ERR_BAD_CONFIG); + } + } diff --git a/repmgr-client-global.h b/repmgr-client-global.h index 4d0f593d..7b7596f4 100644 --- a/repmgr-client-global.h +++ b/repmgr-client-global.h @@ -28,8 +28,13 @@ typedef struct bool terse; bool verbose; - /* connection options */ + /* standard connection options */ + char dbname[MAXLEN]; char host[MAXLEN]; + char username[MAXLEN]; + char port[MAXLEN]; + + /* other connection options */ char remote_user[MAXLEN]; char superuser[MAXLEN]; @@ -62,8 +67,10 @@ typedef struct "", false, "", \ /* logging options */ \ "", false, false, false, \ - /* connection options */ \ - "", "", "", \ + /* database connection options */ \ + "", "", "", "", \ + /* other connection options */ \ + "", "", \ /* node options */ \ UNKNOWN_NODE_ID, "", "", \ /* standby clone options */ \ diff --git a/repmgr-client.c b/repmgr-client.c index a30ad42b..0723727e 100644 --- a/repmgr-client.c +++ b/repmgr-client.c @@ -74,7 +74,9 @@ main(int argc, char **argv) */ logger_output_mode = OM_COMMAND_LINE; - while ((c = getopt_long(argc, argv, "?Vf:Fb:S:L:vtD:cr", long_options, + initialize_conninfo_params(&source_conninfo, true); + + while ((c = getopt_long(argc, argv, "?Vb:f:Fd:h:p:U:R:S:L:vtD:cr", long_options, &optindex)) != -1) { /* @@ -107,21 +109,37 @@ main(int argc, char **argv) /* general configuration options * ----------------------------- */ - /* -f/--config-file */ - case 'f': - strncpy(runtime_options.config_file, optarg, MAXLEN); - break; - /* -F/--force */ - case 'F': - runtime_options.force = true; - break; /* -b/--pg_bindir */ case 'b': strncpy(runtime_options.pg_bindir, optarg, MAXLEN); break; - /* connection options */ - /* ------------------ */ + /* -f/--config-file */ + case 'f': + strncpy(runtime_options.config_file, optarg, MAXLEN); + break; + + /* -F/--force */ + case 'F': + runtime_options.force = true; + break; + + /* database connection options */ + /* --------------------------- */ + + /* + * These are the standard database connection options; with the + * exception of -d/--dbname (which could be a conninfo string) + * we'll also set these values in "source_conninfo" (overwriting + * preset values from environment variables). + * XXX check this is same as psql + */ + /* -d/--dbname */ + case 'd': + strncpy(runtime_options.dbname, optarg, MAXLEN); + /* dbname will be set in source_conninfo later after checking if it's a conninfo string */ + runtime_options.connection_param_provided = true; + break; /* -h/--host */ case 'h': @@ -131,6 +149,25 @@ main(int argc, char **argv) runtime_options.host_param_provided = true; break; + case 'p': + (void) repmgr_atoi(optarg, "-p/--port", &cli_errors, false); + param_set(&source_conninfo, "port", optarg); + strncpy(runtime_options.port, + optarg, + MAXLEN); + runtime_options.connection_param_provided = true; + break; + + /* -U/--user */ + case 'U': + strncpy(runtime_options.username, optarg, MAXLEN); + param_set(&source_conninfo, "user", optarg); + runtime_options.connection_param_provided = true; + break; + + /* other connection options */ + /* ------------------------ */ + /* -R/--remote_user */ case 'R': strncpy(runtime_options.remote_user, optarg, MAXLEN); @@ -162,18 +199,22 @@ main(int argc, char **argv) /* standby clone options * * --------------------- */ + /* -c/--fast-checkpoint */ case 'c': runtime_options.fast_checkpoint = true; break; + /* -r/--rsync-only */ case 'r': runtime_options.rsync_only = true; break; + /* --no-upstream-connection */ case OPT_NO_UPSTREAM_CONNECTION: runtime_options.no_upstream_connection = true; break; + /* --recovery-min-apply-delay */ case OPT_RECOVERY_MIN_APPLY_DELAY: { char *ptr = NULL; @@ -324,6 +365,12 @@ main(int argc, char **argv) if (strcasecmp(repmgr_action, "REGISTER") == 0) action = MASTER_REGISTER; } + else if(strcasecmp(repmgr_node_type, "STANDBY") == 0) + { + if (strcasecmp(repmgr_action, "CLONE") == 0) + action = STANDBY_CLONE; + } + else if(strcasecmp(repmgr_node_type, "CLUSTER") == 0) { if (strcasecmp(repmgr_action, "EVENT") == 0) diff --git a/repmgr-client.h b/repmgr-client.h index f6405595..a1fbe78c 100644 --- a/repmgr-client.h +++ b/repmgr-client.h @@ -11,14 +11,14 @@ -#define NO_ACTION 0 /* Dummy default action */ -#define MASTER_REGISTER 1 -#define STANDBY_REGISTER 2 -#define STANDBY_UNREGISTER 3 -#define STANDBY_CLONE 4 -#define STANDBY_PROMOTE 5 -#define STANDBY_FOLLOW 6 -#define STANDBY_SWITCHOVER 7 +#define NO_ACTION 0 /* Dummy default action */ +#define MASTER_REGISTER 1 +#define STANDBY_REGISTER 2 +#define STANDBY_UNREGISTER 3 +#define STANDBY_CLONE 4 +#define STANDBY_PROMOTE 5 +#define STANDBY_FOLLOW 6 +#define STANDBY_SWITCHOVER 7 #define STANDBY_ARCHIVE_CONFIG 8 #define STANDBY_RESTORE_CONFIG 9 #define WITNESS_CREATE 10 @@ -50,7 +50,7 @@ #define OPT_CLUSTER 15 #define OPT_LOG_TO_FILE 16 #define OPT_UPSTREAM_CONNINFO 17 -/* XXX deprecate, replace with --use-conninfo-password */ +/* XXX deprecate, replace with --use-conninfo-password (--use-recovery-conninfo-password) set */ #define OPT_NO_CONNINFO_PASSWORD 18 #define OPT_REPLICATION_USER 19 #define OPT_EVENT 20 @@ -70,9 +70,12 @@ static struct option long_options[] = {"pg_bindir", required_argument, NULL, 'b'}, /* connection options */ + {"dbname", required_argument, NULL, 'd'}, {"host", required_argument, NULL, 'h'}, + {"port", required_argument, NULL, 'p'}, {"remote-user", required_argument, NULL, 'R'}, {"superuser", required_argument, NULL, 'S'}, + {"username", required_argument, NULL, 'U'}, /* node options */ {"pgdata", required_argument, NULL, 'D'}, @@ -102,9 +105,6 @@ static struct option long_options[] = {"limit", required_argument, NULL, OPT_LIMIT }, /* not yet handled */ - {"dbname", required_argument, NULL, 'd'}, - {"port", required_argument, NULL, 'p'}, - {"username", required_argument, NULL, 'U'}, {"wal-keep-segments", required_argument, NULL, 'w'}, {"keep-history", required_argument, NULL, 'k'}, {"wait", no_argument, NULL, 'W'},