diff --git a/check_dir.c b/check_dir.c index 44083885..30d93f4f 100644 --- a/check_dir.c +++ b/check_dir.c @@ -98,7 +98,7 @@ create_dir(char *dir) if (mkdir_p(dir, 0700) == 0) return true; - log_err(_("Could not create directory \"%s\": %s\n"), + log_err(_("unable to create directory \"%s\": %s\n"), dir, strerror(errno)); return false; @@ -255,7 +255,7 @@ create_pg_dir(char *dir, bool force) if (!create_dir(dir)) { - log_err(_("couldn't create directory \"%s\"...\n"), + log_err(_("unable to create directory \"%s\"...\n"), dir); return false; } @@ -267,7 +267,7 @@ create_pg_dir(char *dir, bool force) if (!set_dir_permissions(dir)) { - log_err(_("could not change permissions of directory \"%s\": %s\n"), + log_err(_("unable to change permissions of directory \"%s\": %s\n"), dir, strerror(errno)); return false; } diff --git a/config.c b/config.c index 5534d258..bef2b10d 100644 --- a/config.c +++ b/config.c @@ -100,11 +100,11 @@ parse_config(const char *config_file, t_configuration_options *options) { if(config_file_provided) { - log_err(_("Unable to open provided configuration file '%s' - terminating\n"), config_file_buf); + log_err(_("unable to open provided configuration file '%s' - terminating\n"), config_file_buf); exit(ERR_BAD_CONFIG); } - log_notice(_("No configuration file provided and default file '%s' not found - " + log_notice(_("no configuration file provided and default file '%s' not found - " "continuing with default values\n"), DEFAULT_CONFIG_FILE); return false; @@ -182,7 +182,7 @@ parse_config(const char *config_file, t_configuration_options *options) options->failover = AUTOMATIC_FAILOVER; else { - log_warning(_("value for failover option is incorrect, it should be automatic or manual. Defaulting to manual.\n")); + log_warning(_("Value for failover option is incorrect, it should be 'automatic' or 'manual'. Defaulting to manual.\n")); options->failover = MANUAL_FAILOVER; } } @@ -345,30 +345,30 @@ reload_config(char *config_file, t_configuration_options * orig_options) /* * Re-read the configuration file: repmgr.conf */ - log_info(_("Reloading configuration file and updating repmgr tables\n")); + log_info(_("reloading configuration file and updating repmgr tables\n")); parse_config(config_file, &new_options); if (new_options.node == -1) { - log_warning(_("Cannot load new configuration, will keep current one.\n")); + log_warning(_("unable to load new configuration, retaining current configuration.\n")); return false; } if (strcmp(new_options.cluster_name, orig_options->cluster_name) != 0) { - log_warning(_("Cannot change cluster name, will keep current configuration.\n")); + log_warning(_("unable to change cluster name, retaining current configuration.\n")); return false; } if (new_options.node != orig_options->node) { - log_warning(_("Cannot change node number, will keep current configuration.\n")); + log_warning(_("unable to change node ID, retaining current configuration.\n")); return false; } if (strcmp(new_options.node_name, orig_options->node_name) != 0) { - log_warning(_("Cannot change standby name, will keep current configuration.\n")); + log_warning(_("unable to change standby name, keeping current configuration .\n")); return false; } @@ -380,19 +380,19 @@ reload_config(char *config_file, t_configuration_options * orig_options) if (new_options.master_response_timeout <= 0) { - log_warning(_("New value for master_response_timeout is not valid. Should be greater than zero.\n")); + log_warning(_("New value for 'master_response_timeout' is not valid. Should be greater than zero.\n")); return false; } if (new_options.reconnect_attempts < 0) { - log_warning(_("New value for reconnect_attempts is not valid. Should be greater or equal than zero.\n")); + log_warning(_("New value for 'reconnect_attempts' is not valid. Should be greater or equal than zero.\n")); return false; } if (new_options.reconnect_intvl < 0) { - log_warning(_("New value for reconnect_interval is not valid. Should be greater or equal than zero.\n")); + log_warning(_("New value for 'reconnect_interva'l is not valid. Should be greater or equal than zero.\n")); return false; } @@ -402,7 +402,7 @@ reload_config(char *config_file, t_configuration_options * orig_options) conn = establish_db_connection(new_options.conninfo, false); if (!conn || (PQstatus(conn) != CONNECTION_OK)) { - log_warning(_("conninfo string is not valid, will keep current configuration.\n")); + log_warning(_("'conninfo' string is not valid, retaining current configuration.\n")); return false; } PQfinish(conn); @@ -557,7 +557,7 @@ reload_config(char *config_file, t_configuration_options * orig_options) } else { - log_debug(_("reload_config(): configuration has not changed")); + log_debug(_("reload_config(): configuration has not changed\n")); } return config_changed; @@ -582,7 +582,7 @@ tablespace_list_append(t_configuration_options *options, const char *arg) cell = (TablespaceListCell *) malloc(sizeof(TablespaceListCell)); if(cell == NULL) { - log_err(_("Unable to allocate memory. Terminating.\n")); + log_err(_("unable to allocate memory. Terminating.\n")); exit(ERR_BAD_CONFIG); } diff --git a/dbutils.c b/dbutils.c index 87be06f8..dfdb9e1d 100644 --- a/dbutils.c +++ b/dbutils.c @@ -39,14 +39,14 @@ establish_db_connection(const char *conninfo, const bool exit_on_error) strcpy(connection_string, conninfo); strcat(connection_string, " fallback_application_name='repmgr'"); - log_debug(_("Connecting to: '%s'\n"), connection_string); + log_debug(_("connecting to: '%s'\n"), connection_string); conn = PQconnectdb(connection_string); /* Check to see that the backend connection was successfully made */ if ((PQstatus(conn) != CONNECTION_OK)) { - log_err(_("Connection to database failed: %s\n"), + log_err(_("connection to database failed: %s\n"), PQerrorMessage(conn)); if (exit_on_error) @@ -69,7 +69,7 @@ establish_db_connection_by_params(const char *keywords[], const char *values[], /* Check to see that the backend connection was successfully made */ if ((PQstatus(conn) != CONNECTION_OK)) { - log_err(_("Connection to database failed: %s\n"), + log_err(_("connection to database failed: %s\n"), PQerrorMessage(conn)); if (exit_on_error) { @@ -253,7 +253,7 @@ get_server_version(PGconn *conn, char *server_version) if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Unable to determine server version number:\n%s"), + log_err(_("unable to determine server version number:\n%s"), PQerrorMessage(conn)); PQclear(res); return -1; @@ -344,7 +344,7 @@ get_cluster_size(PGconn *conn, char *size) res = PQexec(conn, sqlquery); if (res == NULL || PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Get cluster size PQexec failed: %s"), + log_err(_("get_cluster_size(): PQexec failed: %s"), PQerrorMessage(conn)); PQclear(res); @@ -450,7 +450,7 @@ get_primary_connection(PGconn *standby_conn, char *cluster, if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Unable to get conninfo for primary server: %s\n"), + log_err(_("unable to get conninfo for master server: %s\n"), PQerrorMessage(standby_conn)); PQclear(res); return NULL; @@ -458,7 +458,7 @@ get_primary_connection(PGconn *standby_conn, char *cluster, if(!PQntuples(res)) { - log_notice(_("No primary server record found")); + log_notice(_("no master server record found")); PQclear(res); return NULL; } @@ -475,7 +475,7 @@ get_primary_connection(PGconn *standby_conn, char *cluster, if (PQstatus(primary_conn) != CONNECTION_OK) { - log_err(_("Unable to connect to primary node: %s\n"), + log_err(_("unable to connect to master node: %s\n"), PQerrorMessage(primary_conn)); return NULL; } @@ -526,7 +526,7 @@ get_upstream_connection(PGconn *standby_conn, char *cluster, int node_id, if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Unable to get conninfo for upstream server: %s\n"), + log_err(_("unable to get conninfo for upstream server: %s\n"), PQerrorMessage(standby_conn)); PQclear(res); return NULL; @@ -534,7 +534,7 @@ get_upstream_connection(PGconn *standby_conn, char *cluster, int node_id, if(!PQntuples(res)) { - log_notice(_("No upstream server record found")); + log_notice(_("no record found for upstream server")); PQclear(res); return NULL; } @@ -551,7 +551,7 @@ get_upstream_connection(PGconn *standby_conn, char *cluster, int node_id, if (PQstatus(upstream_conn) != CONNECTION_OK) { - log_err(_("Unable to connect to upstream node: %s\n"), + log_err(_("unable to connect to upstream node: %s\n"), PQerrorMessage(upstream_conn)); return NULL; } @@ -606,7 +606,7 @@ get_master_connection(PGconn *standby_conn, char *cluster, res1 = PQexec(standby_conn, sqlquery); if (PQresultStatus(res1) != PGRES_TUPLES_OK) { - log_err(_("Can't get nodes info: %s\n"), + log_err(_("unable to retrieve node records: %s\n"), PQerrorMessage(standby_conn)); PQclear(res1); return NULL; @@ -633,7 +633,7 @@ get_master_connection(PGconn *standby_conn, char *cluster, if (PQresultStatus(res2) != PGRES_TUPLES_OK) { - log_err(_("Can't get recovery state from this node: %s\n"), + log_err(_("unable to retrieve recovery state from this node: %s\n"), PQerrorMessage(master_conn)); PQclear(res2); PQfinish(master_conn); @@ -814,7 +814,7 @@ create_replication_slot(PGconn *conn, char *slot_name) res = PQexec(conn, sqlquery); if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Unable to create slot '%s' on the primary node: %s\n"), + log_err(_("unable to create slot '%s' on the primary node: %s\n"), slot_name, PQerrorMessage(conn)); PQclear(res); @@ -842,7 +842,7 @@ start_backup(PGconn *conn, char *first_wal_segment) res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Can't start backup: %s\n"), PQerrorMessage(conn)); + log_err(_("unable to start backup: %s\n"), PQerrorMessage(conn)); PQclear(res); return false; } @@ -873,7 +873,7 @@ stop_backup(PGconn *conn, char *last_wal_segment) res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Can't stop backup: %s\n"), PQerrorMessage(conn)); + log_err(_("unable to stop backup: %s\n"), PQerrorMessage(conn)); PQclear(res); return false; } @@ -908,7 +908,7 @@ set_config_bool(PGconn *conn, const char *config_param, bool state) if (PQresultStatus(res) != PGRES_COMMAND_OK) { - log_err("Unable to set '%s': %s\n", config_param, PQerrorMessage(conn)); + log_err("unable to set '%s': %s\n", config_param, PQerrorMessage(conn)); PQclear(res); return false; } diff --git a/repmgr-orig.c b/repmgr-orig.c new file mode 100644 index 00000000..c8d09934 --- /dev/null +++ b/repmgr-orig.c @@ -0,0 +1,2571 @@ +/* + * repmgr.c - Command interpreter for the repmgr + * Copyright (C) 2ndQuadrant, 2010-2015 + * + * This module is a command-line utility to easily setup a cluster of + * hot standby servers for an HA environment + * + * Commands implemented are. + * MASTER REGISTER + * STANDBY REGISTER, STANDBY CLONE, STANDBY FOLLOW, STANDBY PROMOTE + * CLUSTER SHOW, CLUSTER CLEANUP + * WITNESS CREATE + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "repmgr.h" + +#include +#include +#include +#include +#include + +#include "log.h" +#include "config.h" +#include "check_dir.h" +#include "strutil.h" +#include "version.h" + +#define RECOVERY_FILE "recovery.conf" +#define RECOVERY_DONE_FILE "recovery.done" + +#define NO_ACTION 0 /* Not a real action, just to initialize */ +#define MASTER_REGISTER 1 +#define STANDBY_REGISTER 2 +#define STANDBY_CLONE 3 +#define STANDBY_PROMOTE 4 +#define STANDBY_FOLLOW 5 +#define WITNESS_CREATE 6 +#define CLUSTER_SHOW 7 +#define CLUSTER_CLEANUP 8 + +static bool create_recovery_file(const char *data_dir); +static int test_ssh_connection(char *host, char *remote_user); +static int copy_remote_files(char *host, char *remote_user, char *remote_path, + char *local_path, bool is_directory); +static bool check_parameters_for_action(const int action); +static bool create_schema(PGconn *conn); +static bool copy_configuration(PGconn *masterconn, PGconn *witnessconn); +static void write_primary_conninfo(char *line); + +static void do_master_register(void); +static void do_standby_register(void); +static void do_standby_clone(void); +static void do_standby_promote(void); +static void do_standby_follow(void); +static void do_witness_create(void); +static void do_cluster_show(void); +static void do_cluster_cleanup(void); + +static void usage(void); +static void help(const char *progname); + +/* Global variables */ +static const char *progname; +static const char *keywords[6]; +static const char *values[6]; +char repmgr_schema[MAXLEN]; +bool need_a_node = true; + +/* XXX This should be mapped into a command line option */ +bool require_password = false; + +/* Initialization of runtime options */ +t_runtime_options runtime_options = T_RUNTIME_OPTIONS_INITIALIZER; +t_configuration_options options = T_CONFIGURATION_OPTIONS_INITIALIZER; + +static char *server_mode = NULL; +static char *server_cmd = NULL; + +int +main(int argc, char **argv) +{ + static struct option long_options[] = + { + {"dbname", required_argument, NULL, 'd'}, + {"host", required_argument, NULL, 'h'}, + {"port", required_argument, NULL, 'p'}, + {"username", required_argument, NULL, 'U'}, + {"superuser", required_argument, NULL, 'S'}, + {"dest-dir", required_argument, NULL, 'D'}, + {"local-port", required_argument, NULL, 'l'}, + {"config-file", required_argument, NULL, 'f'}, + {"remote-user", required_argument, NULL, 'R'}, + {"wal-keep-segments", required_argument, NULL, 'w'}, + {"keep-history", required_argument, NULL, 'k'}, + {"force", no_argument, NULL, 'F'}, + {"wait", no_argument, NULL, 'W'}, + {"ignore-rsync-warning", no_argument, NULL, 'I'}, + {"min-recovery-apply-delay", required_argument, NULL, 'r'}, + {"verbose", no_argument, NULL, 'v'}, + {"initdb-no-pwprompt", no_argument, NULL, 1}, + {NULL, 0, NULL, 0} + }; + + int optindex; + int c, targ; + int action = NO_ACTION; + char *ptr = NULL; + + progname = get_progname(argv[0]); + + if (argc > 1) + { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) + { + help(progname); + exit(SUCCESS); + } + if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) + { + printf("%s %s (PostgreSQL %s)\n", progname, REPMGR_VERSION, PG_VERSION); + exit(SUCCESS); + } + } + + + while ((c = getopt_long(argc, argv, "d:h:p:U:S:D:l:f:R:w:k:FWIvr:", long_options, + &optindex)) != -1) + { + switch (c) + { + case 'd': + strncpy(runtime_options.dbname, optarg, MAXLEN); + break; + case 'h': + strncpy(runtime_options.host, optarg, MAXLEN); + break; + case 'p': + if (atoi(optarg) > 0) + strncpy(runtime_options.masterport, optarg, MAXLEN); + break; + case 'U': + strncpy(runtime_options.username, optarg, MAXLEN); + break; + case 'S': + strncpy(runtime_options.superuser, optarg, MAXLEN); + break; + case 'D': + strncpy(runtime_options.dest_dir, optarg, MAXFILENAME); + break; + case 'l': + if (atoi(optarg) > 0) + strncpy(runtime_options.localport, optarg, MAXLEN); + break; + case 'f': + strncpy(runtime_options.config_file, optarg, MAXLEN); + break; + case 'R': + strncpy(runtime_options.remote_user, optarg, MAXLEN); + break; + case 'w': + if (atoi(optarg) > 0) + strncpy(runtime_options.wal_keep_segments, optarg, MAXLEN); + break; + case 'k': + if (atoi(optarg) > 0) + runtime_options.keep_history = atoi(optarg); + else + runtime_options.keep_history = 0; + break; + case 'F': + runtime_options.force = true; + break; + case 'W': + runtime_options.wait_for_master = true; + break; + case 'I': + runtime_options.ignore_rsync_warn = true; + break; + case 'r': + targ = strtol(optarg, &ptr, 10); + + if(targ < 0) { + usage(); + exit(ERR_BAD_CONFIG); + } + if(ptr && *ptr) { + if(strcmp(ptr, "ms") != 0 && strcmp(ptr, "s") != 0 && + strcmp(ptr, "min") != 0 && strcmp(ptr, "h") != 0 && + strcmp(ptr, "d") != 0) + { + usage(); + exit(ERR_BAD_CONFIG); + } + } + + strncpy(runtime_options.min_recovery_apply_delay, optarg, MAXLEN); + break; + case 'v': + runtime_options.verbose = true; + break; + case 1: + runtime_options.initdb_no_pwprompt = true; + break; + default: + usage(); + exit(ERR_BAD_CONFIG); + } + } + + /* + * Now we need to obtain the action, this comes in one of these forms: + * MASTER REGISTER | STANDBY {REGISTER | CLONE [node] | PROMOTE | FOLLOW + * [node]} | WITNESS CREATE CLUSTER {SHOW | CLEANUP} + * + * the node part is optional, if we receive it then we shouldn't have + * received a -h option + */ + if (optind < argc) + { + server_mode = argv[optind++]; + if (strcasecmp(server_mode, "STANDBY") != 0 && + strcasecmp(server_mode, "MASTER") != 0 && + strcasecmp(server_mode, "WITNESS") != 0 && + strcasecmp(server_mode, "CLUSTER") != 0) + { + usage(); + exit(ERR_BAD_CONFIG); + } + } + + if (optind < argc) + { + server_cmd = argv[optind++]; + /* check posibilities for all server modes */ + if (strcasecmp(server_mode, "MASTER") == 0) + { + if (strcasecmp(server_cmd, "REGISTER") == 0) + action = MASTER_REGISTER; + } + else if (strcasecmp(server_mode, "STANDBY") == 0) + { + if (strcasecmp(server_cmd, "REGISTER") == 0) + action = STANDBY_REGISTER; + else if (strcasecmp(server_cmd, "CLONE") == 0) + action = STANDBY_CLONE; + else if (strcasecmp(server_cmd, "PROMOTE") == 0) + action = STANDBY_PROMOTE; + else if (strcasecmp(server_cmd, "FOLLOW") == 0) + action = STANDBY_FOLLOW; + } + else if (strcasecmp(server_mode, "CLUSTER") == 0) + { + if (strcasecmp(server_cmd, "SHOW") == 0) + action = CLUSTER_SHOW; + else if (strcasecmp(server_cmd, "CLEANUP") == 0) + action = CLUSTER_CLEANUP; + } + else if (strcasecmp(server_mode, "WITNESS") == 0) + if (strcasecmp(server_cmd, "CREATE") == 0) + action = WITNESS_CREATE; + } + + if (action == NO_ACTION) + { + usage(); + exit(ERR_BAD_CONFIG); + } + + /* For some actions we still can receive a last argument */ + if (action == STANDBY_CLONE) + { + if (optind < argc) + { + if (runtime_options.host[0]) + { + log_err(_("Conflicting parameters: you can't use -h while providing a node separately.\n")); + usage(); + exit(ERR_BAD_CONFIG); + } + strncpy(runtime_options.host, argv[optind++], MAXLEN); + } + } + + if (optind < argc) + { + log_err(_("%s: too many command-line arguments (first extra is \"%s\")\n"), + progname, argv[optind]); + usage(); + exit(ERR_BAD_CONFIG); + } + + if (!check_parameters_for_action(action)) + exit(ERR_BAD_CONFIG); + + if (!runtime_options.dbname[0]) + { + if (getenv("PGDATABASE")) + strncpy(runtime_options.dbname, getenv("PGDATABASE"), MAXLEN); + else if (getenv("PGUSER")) + strncpy(runtime_options.dbname, getenv("PGUSER"), MAXLEN); + else + strncpy(runtime_options.dbname, DEFAULT_DBNAME, MAXLEN); + } + + /* We check that port number is not null */ + if (!runtime_options.masterport[0]) + { + strncpy(runtime_options.masterport, DEFAULT_MASTER_PORT, MAXLEN); + } + + /* Read the configuration file, normally repmgr.conf */ + if (!runtime_options.config_file[0]) + strncpy(runtime_options.config_file, DEFAULT_CONFIG_FILE, MAXLEN); + + if (runtime_options.verbose) + printf(_("Opening configuration file: %s\n"), + runtime_options.config_file); + + /* + * XXX Do not read config files for action where it is not required (clone + * for example). + */ + parse_config(runtime_options.config_file, &options); + + keywords[2] = "user"; + values[2] = (runtime_options.username[0]) ? runtime_options.username : NULL; + keywords[3] = "dbname"; + values[3] = runtime_options.dbname; + keywords[4] = "application_name"; + values[4] = (char *) progname; + keywords[5] = NULL; + values[5] = NULL; + + /* + * Initialize the logger. If verbose command line parameter was input, + * make sure that the log level is at least INFO. This is mainly useful + * for STANDBY CLONE. That doesn't require a configuration file where a + * logging level might be specified at, but it often requires detailed + * logging to troubleshoot problems. + */ + logger_init(&options, progname, options.loglevel, options.logfacility); + if (runtime_options.verbose) + logger_min_verbose(LOG_INFO); + + /* + * Node configuration information is not needed for all actions, with + * STANDBY CLONE being the main exception. + */ + if (need_a_node) + { + if (options.node == -1) + { + log_err(_("Node information is missing. " + "Check the configuration file.\n")); + exit(ERR_BAD_CONFIG); + } + } + + /* Prepare the repmgr schema variable */ + maxlen_snprintf(repmgr_schema, "%s%s", DEFAULT_REPMGR_SCHEMA_PREFIX, + options.cluster_name); + + switch (action) + { + case MASTER_REGISTER: + do_master_register(); + break; + case STANDBY_REGISTER: + do_standby_register(); + break; + case STANDBY_CLONE: + do_standby_clone(); + break; + case STANDBY_PROMOTE: + do_standby_promote(); + break; + case STANDBY_FOLLOW: + do_standby_follow(); + break; + case WITNESS_CREATE: + do_witness_create(); + break; + case CLUSTER_SHOW: + do_cluster_show(); + break; + case CLUSTER_CLEANUP: + do_cluster_cleanup(); + break; + default: + usage(); + exit(ERR_BAD_CONFIG); + } + logger_shutdown(); + + return 0; +} + +static void +do_cluster_show(void) +{ + PGconn *conn; + PGresult *res; + char sqlquery[QUERY_STR_LEN]; + char node_role[MAXLEN]; + int i; + + /* We need to connect to check configuration */ + log_info(_("%s connecting to database\n"), progname); + conn = establish_db_connection(options.conninfo, true); + + sqlquery_snprintf(sqlquery, "SELECT conninfo, witness FROM %s.repl_nodes;", + repmgr_schema); + res = PQexec(conn, sqlquery); + + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Can't get nodes information, have you registered them?\n%s\n"), + PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + PQfinish(conn); + + printf("Role | Connection String \n"); + for (i = 0; i < PQntuples(res); i++) + { + conn = establish_db_connection(PQgetvalue(res, i, 0), false); + if (PQstatus(conn) != CONNECTION_OK) + strcpy(node_role, " FAILED"); + else if (strcmp(PQgetvalue(res, i, 1), "t") == 0) + strcpy(node_role, " witness"); + else if (is_standby(conn)) + strcpy(node_role, " standby"); + else + strcpy(node_role, "* master"); + + printf("%-10s", node_role); + printf("| %s\n", PQgetvalue(res, i, 0)); + + PQfinish(conn); + } + + PQclear(res); +} + +static void +do_cluster_cleanup(void) +{ + int master_id; + PGconn *conn = NULL; + PGconn *master_conn = NULL; + PGresult *res; + char sqlquery[QUERY_STR_LEN]; + + /* We need to connect to check configuration */ + log_info(_("%s connecting to database\n"), progname); + conn = establish_db_connection(options.conninfo, true); + + /* check if there is a master in this cluster */ + log_info(_("%s connecting to master database\n"), progname); + master_conn = get_master_connection(conn, repmgr_schema, options.cluster_name, + &master_id, NULL); + if (!master_conn) + { + log_err(_("cluster cleanup: cannot connect to master\n")); + PQfinish(conn); + exit(ERR_DB_CON); + } + PQfinish(conn); + + if (runtime_options.keep_history > 0) + { + sqlquery_snprintf(sqlquery, "DELETE FROM %s.repl_monitor " + " WHERE age(now(), last_monitor_time) >= '%d days'::interval;", + repmgr_schema, runtime_options.keep_history); + } + else + { + sqlquery_snprintf(sqlquery, "TRUNCATE TABLE %s.repl_monitor;", + repmgr_schema); + } + res = PQexec(master_conn, sqlquery); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_err(_("cluster cleanup: Couldn't clean history\n%s\n"), + PQerrorMessage(master_conn)); + PQclear(res); + PQfinish(master_conn); + exit(ERR_BAD_CONFIG); + } + PQclear(res); + + /* + * Let's VACUUM the table to avoid autovacuum to be launched in an + * unexpected hour + */ + sqlquery_snprintf(sqlquery, "VACUUM %s.repl_monitor;", repmgr_schema); + res = PQexec(master_conn, sqlquery); + + /* XXX There is any need to check this VACUUM happens without problems? */ + + PQclear(res); + PQfinish(master_conn); +} + + +static void +do_master_register(void) +{ + PGconn *conn; + PGresult *res; + char sqlquery[QUERY_STR_LEN], + *ret_ver; + + bool schema_exists = false; + char schema_quoted[MAXLEN]; + char master_version[MAXVERSIONSTR]; + int ret; + + conn = establish_db_connection(options.conninfo, true); + + /* master should be v9 or better */ + log_info(_("%s connecting to master database\n"), progname); + ret_ver = pg_version(conn, master_version); + if (ret_ver == NULL || strcmp(master_version, "") == 0) + { + PQfinish(conn); + if (ret_ver != NULL) + log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"), + progname); + return; + } + + /* Check we are a master */ + log_info(_("%s connected to master, checking its state\n"), progname); + ret = is_standby(conn); + + if (ret) + { + log_err(_(ret == 1 ? "Trying to register a standby node as a master\n" : + "Connection to node lost!\n")); + + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* + * Assemble a quoted schema name XXX This is not currently used due to a + * merge conflict, but probably should be + */ + if (false) + { + char *identifier = PQescapeIdentifier(conn, repmgr_schema, + strlen(repmgr_schema)); + + maxlen_snprintf(schema_quoted, "%s", identifier); + PQfreemem(identifier); + } + + /* Check if there is a schema for this cluster */ + sqlquery_snprintf(sqlquery, + "SELECT 1 FROM pg_namespace " + "WHERE nspname = '%s'", repmgr_schema); + log_debug(_("master register: %s\n"), sqlquery); + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Can't get info about schemas: %s\n"), PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + if (PQntuples(res) > 0) /* schema exists */ + { + if (!runtime_options.force) /* and we are not forcing so error */ + { + log_notice(_("Schema %s already exists.\n"), repmgr_schema); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + schema_exists = true; + } + PQclear(res); + + if (!schema_exists) + { + log_info(_("master register: creating database objects inside the %s schema\n"), + repmgr_schema); + + /* ok, create the schema */ + if (!create_schema(conn)) + return; + } + else + { + PGconn *master_conn; + int id; + + if (runtime_options.force) + { + sqlquery_snprintf(sqlquery, "DELETE FROM %s.repl_nodes " + " WHERE id = %d", + repmgr_schema, options.node); + log_debug(_("master register: %s\n"), sqlquery); + + res = PQexec(conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_warning(_("Cannot delete node details, %s\n"), + PQerrorMessage(conn)); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + PQclear(res); + } + + /* Ensure there isn't any other master already registered */ + master_conn = get_master_connection(conn, repmgr_schema, + options.cluster_name, &id, NULL); + if (master_conn != NULL) + { + PQfinish(master_conn); + log_warning(_("There is a master already in cluster %s\n"), + options.cluster_name); + exit(ERR_BAD_CONFIG); + } + } + + /* Now register the master */ + + sqlquery_snprintf(sqlquery, "INSERT INTO %s.repl_nodes (id, cluster, name, conninfo, priority) " + "VALUES (%d, '%s', '%s', '%s', %d)", + repmgr_schema, options.node, options.cluster_name, options.node_name, + options.conninfo, options.priority); + log_debug(_("master register: %s\n"), sqlquery); + + res = PQexec(conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_warning(_("Cannot insert node details, %s\n"), + PQerrorMessage(conn)); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + PQclear(res); + + PQfinish(conn); + log_notice(_("Master node correctly registered for cluster %s with id %d (conninfo: %s)\n"), + options.cluster_name, options.node, options.conninfo); + return; +} + + +static void +do_standby_register(void) +{ + PGconn *conn; + PGconn *master_conn; + int master_id, + ret; + + PGresult *res; + char sqlquery[QUERY_STR_LEN], + *ret_ver; + char schema_quoted[MAXLEN]; + + char master_version[MAXVERSIONSTR]; + char standby_version[MAXVERSIONSTR]; + + /* XXX: A lot of copied code from do_master_register! Refactor */ + + log_info(_("%s connecting to standby database\n"), progname); + conn = establish_db_connection(options.conninfo, true); + + /* should be v9 or better */ + log_info(_("%s connected to standby, checking its state\n"), progname); + ret_ver = pg_version(conn, standby_version); + if (ret_ver == NULL || strcmp(standby_version, "") == 0) + { + PQfinish(conn); + if (ret_ver != NULL) + log_err(_("%s needs standby to be PostgreSQL 9.0 or better\n"), + progname); + exit(ERR_BAD_CONFIG); + } + + /* Check we are a standby */ + ret = is_standby(conn); + if (ret == 0 || ret == -1) + { + log_err(_(ret == 0 ? "repmgr: This node should be a standby (%s)\n" : + "repmgr: connection to node (%s) lost\n"), options.conninfo); + + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* + * Assemble a quoted schema name XXX This is not currently used due to a + * merge conflict, but probably should be + */ + if (false) + { + char *identifier = PQescapeIdentifier(conn, repmgr_schema, + strlen(repmgr_schema)); + + maxlen_snprintf(schema_quoted, "%s", identifier); + PQfreemem(identifier); + } + + /* Check if there is a schema for this cluster */ + sqlquery_snprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = '%s'", + repmgr_schema); + log_debug(_("standby register: %s\n"), sqlquery); + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Can't get info about tablespaces: %s\n"), + PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + if (PQntuples(res) == 0) + { + /* schema doesn't exist */ + log_err(_("Schema %s doesn't exists.\n"), repmgr_schema); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + PQclear(res); + + /* check if there is a master in this cluster */ + log_info(_("%s connecting to master database\n"), progname); + master_conn = get_master_connection(conn, repmgr_schema, options.cluster_name, + &master_id, NULL); + if (!master_conn) + { + log_err(_("A master must be defined before configuring a slave\n")); + exit(ERR_BAD_CONFIG); + } + + /* master should be v9 or better */ + log_info(_("%s connected to master, checking its state\n"), progname); + ret_ver = pg_version(master_conn, master_version); + if (ret_ver == NULL || strcmp(master_version, "") == 0) + { + PQfinish(conn); + PQfinish(master_conn); + if (ret_ver != NULL) + log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"), + progname); + exit(ERR_BAD_CONFIG); + } + + /* master and standby version should match */ + if (strcmp(master_version, standby_version) != 0) + { + PQfinish(conn); + PQfinish(master_conn); + log_err(_("%s needs versions of both master (%s) and standby (%s) to match.\n"), + progname, master_version, standby_version); + exit(ERR_BAD_CONFIG); + } + + /* Now register the standby */ + log_info(_("%s registering the standby\n"), progname); + if (runtime_options.force) + { + sqlquery_snprintf(sqlquery, "DELETE FROM %s.repl_nodes " + " WHERE id = %d", + repmgr_schema, options.node); + + log_debug(_("standby register: %s\n"), sqlquery); + + res = PQexec(master_conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_err(_("Cannot delete node details, %s\n"), + PQerrorMessage(master_conn)); + PQfinish(master_conn); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + PQclear(res); + } + + sqlquery_snprintf(sqlquery, "INSERT INTO %s.repl_nodes(id, cluster, name, conninfo, priority) " + "VALUES (%d, '%s', '%s', '%s', %d)", + repmgr_schema, options.node, options.cluster_name, options.node_name, + options.conninfo, options.priority); + log_debug(_("standby register: %s\n"), sqlquery); + + res = PQexec(master_conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_err(_("Cannot insert node details, %s\n"), + PQerrorMessage(master_conn)); + PQfinish(master_conn); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + log_info(_("%s registering the standby complete\n"), progname); + PQfinish(master_conn); + PQfinish(conn); + log_notice(_("Standby node correctly registered for cluster %s with id %d (conninfo: %s)\n"), + options.cluster_name, options.node, options.conninfo); + return; +} + + +static void +do_standby_clone(void) +{ + PGconn *conn; + PGresult *res; + char sqlquery[QUERY_STR_LEN], + *ret; + const char *cluster_size; + + int r = 0, + retval = SUCCESS; + int i,j, + is_standby_retval; + bool flag_success = false; + bool test_mode = false; + + char tblspc_dir[MAXFILENAME]; + + char master_data_directory[MAXFILENAME]; + char local_data_directory[MAXFILENAME]; + char master_xlog_directory[MAXFILENAME]; + char local_xlog_directory[MAXFILENAME]; + char master_stats_temp_directory[MAXFILENAME]; + char local_stats_temp_directory[MAXFILENAME]; + + char master_control_file[MAXFILENAME]; + char local_control_file[MAXFILENAME]; + char master_config_file[MAXFILENAME]; + char local_config_file[MAXFILENAME]; + char master_hba_file[MAXFILENAME]; + char local_hba_file[MAXFILENAME]; + char master_ident_file[MAXFILENAME]; + char local_ident_file[MAXFILENAME]; + + char *first_wal_segment = NULL; + const char *last_wal_segment = NULL; + + char master_version[MAXVERSIONSTR]; + + /* + * if dest_dir has been provided, we copy everything in the same path if + * dest_dir is set and the master have tablespace, repmgr will stop + * because it is more complex to remap the path for the tablespaces and it + * does not look useful at the moment + */ + if (runtime_options.dest_dir[0]) + { + test_mode = true; + log_notice(_("%s Destination directory %s provided, try to clone everything in it.\n"), + progname, runtime_options.dest_dir); + } + + /* Connection parameters for master only */ + keywords[0] = "host"; + values[0] = runtime_options.host; + keywords[1] = "port"; + values[1] = runtime_options.masterport; + + /* We need to connect to check configuration and start a backup */ + log_info(_("%s connecting to master database\n"), progname); + conn = establish_db_connection_by_params(keywords, values, true); + + /* primary should be v9 or better */ + log_info(_("%s connected to master, checking its state\n"), progname); + ret = pg_version(conn, master_version); + if (ret == NULL || strcmp(master_version, "") == 0) + { + PQfinish(conn); + if (ret != NULL) + log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"), + progname); + exit(ERR_BAD_CONFIG); + } + + /* Check we are cloning a primary node */ + is_standby_retval = is_standby(conn); + if (is_standby_retval) + { + log_err(_(is_standby_retval == 1 ? "The command should clone a primary node\n" : + "Connection to node lost!\n")); + + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* And check if it is well configured */ + i = guc_set(conn, "wal_level", "=", "hot_standby"); + if (i == 0 || i == -1) + { + if (i == 0) + { + /* We could be using PG 9.4 with log_level logical, which is good enough for + hot standby replication. + We should check if the wal_level is set to that value, in which case we are + good to proceed. + No need to check if we are in 9.4 first, as the query used in guc_set will just + return zero rows if on < 9.4, and so will work anyway. + */ + j = guc_set(conn, "wal_level", "=", "logical"); + if (j == 0 || j == -1) + { + PQfinish(conn); + if (j == 0) + log_err(_("%s needs parameter 'wal_level' to be set to at least 'hot_standby'\n"), + progname); + exit(ERR_BAD_CONFIG); + } + } + else if (i == -1) + { + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + } + + i = guc_set_typed(conn, "wal_keep_segments", ">=", + runtime_options.wal_keep_segments, "integer"); + if (i == 0 || i == -1) + { + PQfinish(conn); + if (i == 0) + log_err(_("%s needs parameter 'wal_keep_segments' to be set to %s or greater (see the '-w' option or edit the postgresql.conf of the PostgreSQL master.)\n"), + progname, runtime_options.wal_keep_segments); + exit(ERR_BAD_CONFIG); + } + + i = guc_set(conn, "archive_mode", "=", "on"); + if (i == 0 || i == -1) + { + PQfinish(conn); + if (i == 0) + log_err(_("%s needs parameter 'archive_mode' to be set to 'on'\n"), + progname); + exit(ERR_BAD_CONFIG); + } + + i = guc_set(conn, "hot_standby", "=", "on"); + if (i == 0 || i == -1) + { + PQfinish(conn); + if (i == 0) + log_err(_("%s needs parameter 'hot_standby' to be set to 'on'\n"), + progname); + exit(ERR_BAD_CONFIG); + } + + /* + * Check if the tablespace locations exists and that we can write to them. + */ + if (strcmp(master_version, "9.0") == 0 || + strcmp(master_version, "9.1") == 0) + sqlquery_snprintf(sqlquery, + "SELECT spclocation " + " FROM pg_tablespace " + "WHERE spcname NOT IN ('pg_default', 'pg_global')"); + else + sqlquery_snprintf(sqlquery, + "SELECT pg_tablespace_location(oid) spclocation " + " FROM pg_tablespace " + "WHERE spcname NOT IN ('pg_default', 'pg_global')"); + + log_debug("standby clone: %s\n", sqlquery); + + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Can't get info about tablespaces: %s\n"), PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + for (i = 0; i < PQntuples(res); i++) + { + if (test_mode) + { + log_err("Can't clone in test mode when master have tablespace\n"); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + strncpy(tblspc_dir, PQgetvalue(res, i, 0), MAXFILENAME); + + /* + * Check this directory could be used for tablespace this will create + * the directory a bit too early XXX build an array of tablespace to + * create later in the backup + */ + if (!create_pg_dir(tblspc_dir, runtime_options.force)) + { + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + } + PQclear(res); + + /* Get the data directory full path and the configuration files location */ + sqlquery_snprintf(sqlquery, + "SELECT name, setting " + " FROM pg_settings " + " WHERE name IN ('data_directory', 'config_file', 'hba_file', 'ident_file', 'stats_temp_directory')"); + log_debug(_("standby clone: %s\n"), sqlquery); + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Can't get info about data directory and configuration files: %s\n"), + PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* We need all 5 parameters, and they can be retrieved only by superusers */ + if (PQntuples(res) != 5) + { + log_err("%s: STANDBY CLONE should be run by a SUPERUSER\n", progname); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + for (i = 0; i < PQntuples(res); i++) + { + if (strcmp(PQgetvalue(res, i, 0), "data_directory") == 0) + strncpy(master_data_directory, PQgetvalue(res, i, 1), MAXFILENAME); + else if (strcmp(PQgetvalue(res, i, 0), "config_file") == 0) + strncpy(master_config_file, PQgetvalue(res, i, 1), MAXFILENAME); + else if (strcmp(PQgetvalue(res, i, 0), "hba_file") == 0) + strncpy(master_hba_file, PQgetvalue(res, i, 1), MAXFILENAME); + else if (strcmp(PQgetvalue(res, i, 0), "ident_file") == 0) + strncpy(master_ident_file, PQgetvalue(res, i, 1), MAXFILENAME); + else if (strcmp(PQgetvalue(res, i, 0), "stats_temp_directory") == 0) + strncpy(master_stats_temp_directory, PQgetvalue(res, i, 1), + MAXFILENAME); + else + log_warning(_("unknown parameter: %s\n"), PQgetvalue(res, i, 0)); + } + PQclear(res); + + cluster_size = get_cluster_size(conn); + if (cluster_size == NULL) + exit(ERR_DB_QUERY); + log_info(_("Successfully connected to primary. Current installation size is %s\n"), + cluster_size); + + /* + * XXX master_xlog_directory should be discovered from master + * configuration but it is not possible via SQL. We need to use a command + * via ssh + */ + maxlen_snprintf(master_xlog_directory, "%s/pg_xlog", master_data_directory); + if (test_mode) + { + strncpy(local_data_directory, runtime_options.dest_dir, MAXFILENAME); + strncpy(local_config_file, runtime_options.dest_dir, MAXFILENAME); + strncpy(local_hba_file, runtime_options.dest_dir, MAXFILENAME); + strncpy(local_ident_file, runtime_options.dest_dir, MAXFILENAME); + maxlen_snprintf(local_stats_temp_directory, "%s/pg_stat_tmp", + runtime_options.dest_dir); + maxlen_snprintf(local_xlog_directory, "%s/pg_xlog", + runtime_options.dest_dir); + } + else + { + strncpy(local_data_directory, master_data_directory, MAXFILENAME); + strncpy(local_config_file, master_config_file, MAXFILENAME); + strncpy(local_hba_file, master_hba_file, MAXFILENAME); + strncpy(local_ident_file, master_ident_file, MAXFILENAME); + strncpy(local_stats_temp_directory, master_stats_temp_directory, + MAXFILENAME); + strncpy(local_xlog_directory, master_xlog_directory, MAXFILENAME); + } + + r = test_ssh_connection(runtime_options.host, runtime_options.remote_user); + if (r != 0) + { + log_err(_("%s: Aborting, remote host %s is not reachable.\n"), + progname, runtime_options.host); + PQfinish(conn); + exit(ERR_BAD_SSH); + } + + log_notice(_("Starting backup...\n")); + + /* + * in pg 9.1 default is to wait for a sync standby to ack, avoid that by + * turning off sync rep for this session + */ + sqlquery_snprintf(sqlquery, "SET synchronous_commit TO OFF"); + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_err("Can't set synchronous_commit: %s\n", PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* + * inform the master we will start a backup and get the first XLog + * filename so we can say to the user we need those files + */ + sqlquery_snprintf( + sqlquery, + "SELECT pg_xlogfile_name(pg_start_backup('repmgr_standby_clone_%ld'))", + time(NULL)); + log_debug(_("standby clone: %s\n"), sqlquery); + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Can't start backup: %s\n"), PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + if (runtime_options.verbose) + { + char *first_wal_seg_pq = PQgetvalue(res, 0, 0); + size_t buf_sz = strlen(first_wal_seg_pq); + + first_wal_segment = malloc(buf_sz + 1); + xsnprintf(first_wal_segment, buf_sz + 1, "%s", first_wal_seg_pq); + } + + PQclear(res); + + /* Check the directory could be used as a PGDATA dir */ + if (!create_pg_dir(local_data_directory, runtime_options.force)) + { + log_err(_("%s: couldn't use directory %s ...\nUse --force option to force\n"), + progname, local_data_directory); + r = ERR_BAD_CONFIG; + retval = ERR_BAD_CONFIG; + goto stop_backup; + } + + /* + * 1) first move global/pg_control + * + * 2) then move data_directory ommiting the files we have already moved + * and pg_xlog content + * + * 3) finally We need to backup configuration files (that could be on + * other directories, debian like systems likes to do that), so look at + * config_file, hba_file and ident_file but we can omit external_pid_file + * ;) + * + * On error we need to return but before that execute pg_stop_backup() + */ + + /* need to create the global sub directory */ + maxlen_snprintf(master_control_file, "%s/global/pg_control", + master_data_directory); + maxlen_snprintf(local_control_file, "%s/global", local_data_directory); + log_info(_("standby clone: master control file '%s'\n"), + master_control_file); + if (!create_dir(local_control_file)) + { + log_err(_("%s: couldn't create directory %s ...\n"), + progname, local_control_file); + goto stop_backup; + } + + log_info(_("standby clone: master control file '%s'\n"), + master_control_file); + r = copy_remote_files(runtime_options.host, runtime_options.remote_user, + master_control_file, local_control_file, + false); + if (r != 0) + { + log_warning(_("standby clone: failed copying master control file '%s'\n"), + master_control_file); + goto stop_backup; + } + + log_info(_("standby clone: master data directory '%s'\n"), + master_data_directory); + r = copy_remote_files(runtime_options.host, runtime_options.remote_user, + master_data_directory, local_data_directory, + true); + if (r != 0) + { + log_warning(_("standby clone: failed copying master data directory '%s'\n"), + master_data_directory); + goto stop_backup; + } + + /* + * Copy tablespace locations, i'm doing this separately because i couldn't + * find and appropiate rsync option but besides we could someday make all + * these rsync happen concurrently XXX We may not do that if we are in + * test_mode but it does not hurt too much (except if a tablespace is + * created during the test) + */ + if (strcmp(master_version, "9.0") == 0 || + strcmp(master_version, "9.1") == 0) + sqlquery_snprintf(sqlquery, + "SELECT spclocation " + " FROM pg_tablespace " + " WHERE spcname NOT IN ('pg_default', 'pg_global')"); + else + sqlquery_snprintf(sqlquery, + "SELECT pg_tablespace_location(oid) spclocation " + " FROM pg_tablespace " + " WHERE spcname NOT IN ('pg_default', 'pg_global')"); + + log_debug("standby clone: %s\n", sqlquery); + + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Can't get info about tablespaces: %s\n"), + PQerrorMessage(conn)); + PQclear(res); + goto stop_backup; + } + for (i = 0; i < PQntuples(res); i++) + { + strncpy(tblspc_dir, PQgetvalue(res, i, 0), MAXFILENAME); + log_info(_("standby clone: master tablespace '%s'\n"), tblspc_dir); + r = copy_remote_files(runtime_options.host, runtime_options.remote_user, + tblspc_dir, tblspc_dir, + true); + if (r != 0) + { + log_warning(_("standby clone: failed copying tablespace directory '%s'\n"), + tblspc_dir); + PQclear(res); + goto stop_backup; + } + } + PQclear(res); + + log_info(_("standby clone: master config file '%s'\n"), master_config_file); + r = copy_remote_files(runtime_options.host, runtime_options.remote_user, + master_config_file, local_config_file, + false); + if (r != 0) + { + log_warning(_("standby clone: failed copying master config file '%s'\n"), + master_config_file); + goto stop_backup; + } + + log_info(_("standby clone: master hba file '%s'\n"), master_hba_file); + r = copy_remote_files(runtime_options.host, runtime_options.remote_user, + master_hba_file, local_hba_file, + false); + if (r != 0) + { + log_warning(_("standby clone: failed copying master hba file '%s'\n"), + master_hba_file); + goto stop_backup; + } + + log_info(_("standby clone: master ident file '%s'\n"), master_ident_file); + r = copy_remote_files(runtime_options.host, runtime_options.remote_user, + master_ident_file, local_ident_file, + false); + if (r != 0) + { + log_warning(_("standby clone: failed copying master ident file '%s'\n"), + master_ident_file); + goto stop_backup; + } + + /* we success so far, flag that to allow a better HINT */ + flag_success = true; + +stop_backup: + + /* + * Inform the master that we have finished the backup. + */ + log_notice(_("Finishing backup...\n")); + sqlquery_snprintf(sqlquery, "SELECT pg_xlogfile_name(pg_stop_backup())"); + log_debug(_("standby clone: %s\n"), sqlquery); + + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Can't stop backup: %s\n"), PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + exit(retval); + } + last_wal_segment = PQgetvalue(res, 0, 0); + + if (runtime_options.verbose) + log_info(_("%s requires primary to keep WAL files %s until at least %s\n"), + progname, first_wal_segment, last_wal_segment); + + /* Finished with the database connection now */ + PQclear(res); + PQfinish(conn); + + /* + * Only free the first_wal_segment since it was copied out of the + * pqresult. + */ + free(first_wal_segment); + first_wal_segment = NULL; + + /* If the rsync failed then exit */ + if (r != 0) + { + log_err(_("Couldn't rsync the master...\nYou have to cleanup the destination directory (%s) manually!\n"), + local_data_directory); + exit(ERR_BAD_RSYNC); + } + + /* + * We need to create the pg_xlog sub directory too. + */ + if (!create_dir(local_xlog_directory)) + { + log_err(_("%s: couldn't create directory %s, you will need to do it manually...\n"), + progname, local_xlog_directory); + r = ERR_NEEDS_XLOG; /* continue, but eventually exit returning + * error */ + } + + /* Finally, write the recovery.conf file */ + create_recovery_file(local_data_directory); + + /* + * We don't start the service yet because we still may want to move the + * directory + */ + log_notice(_("%s standby clone complete\n"), progname); + + /* HINT message : what to do next ? */ + if (flag_success) + { + log_notice("HINT: You can now start your postgresql server\n"); + if (test_mode) + { + log_notice(_("for example : pg_ctl -D %s start\n"), + local_data_directory); + } + else + { + log_notice("for example : /etc/init.d/postgresql start\n"); + } + } + exit(r); +} + + +static void +do_standby_promote(void) +{ + PGconn *conn; + PGresult *res; + char sqlquery[QUERY_STR_LEN], + *ret; + char script[MAXLEN]; + + PGconn *old_master_conn; + int old_master_id; + + int r, + retval; + char data_dir[MAXLEN]; + char recovery_file_path[MAXFILENAME]; + char recovery_done_path[MAXFILENAME]; + + char standby_version[MAXVERSIONSTR]; + + /* We need to connect to check configuration */ + log_info(_("%s connecting to standby database\n"), progname); + conn = establish_db_connection(options.conninfo, true); + + /* we need v9 or better */ + log_info(_("%s connected to standby, checking its state\n"), progname); + ret = pg_version(conn, standby_version); + if (ret == NULL || strcmp(standby_version, "") == 0) + { + if (ret != NULL) + log_err(_("%s needs standby to be PostgreSQL 9.0 or better\n"), + progname); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* Check we are in a standby node */ + retval = is_standby(conn); + if (retval == 0 || retval == -1) + { + log_err(_(retval == 0 ? "%s: The command should be executed on a standby node\n" : + "%s: connection to node lost!\n"), progname); + + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* we also need to check if there isn't any master already */ + old_master_conn = get_master_connection(conn, repmgr_schema, + options.cluster_name, &old_master_id, NULL); + if (old_master_conn != NULL) + { + log_err(_("There is a master already in this cluster\n")); + PQfinish(old_master_conn); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + log_notice(_("%s: Promoting standby\n"), progname); + + /* Get the data directory full path and the last subdirectory */ + sqlquery_snprintf(sqlquery, "SELECT setting " + " FROM pg_settings WHERE name = 'data_directory'"); + log_debug(_("standby promote: %s\n"), sqlquery); + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Can't get info about data directory: %s\n"), + PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + strcpy(data_dir, PQgetvalue(res, 0, 0)); + PQclear(res); + PQfinish(conn); + + log_info(_("%s: Marking recovery done\n"), progname); + maxlen_snprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_FILE); + maxlen_snprintf(recovery_done_path, "%s/%s", data_dir, RECOVERY_DONE_FILE); + rename(recovery_file_path, recovery_done_path); + + /* + * Restart and wait for the server to finish starting, so that the check + * below will find an active server rather than one starting up. This may + * hang for up the default timeout (60 seconds). + */ + log_notice(_("%s: restarting server using %s/pg_ctl\n"), progname, + options.pg_bindir); + maxlen_snprintf(script, "%s/pg_ctl %s -D %s -w -m fast restart", + options.pg_bindir, options.pgctl_options, data_dir); + r = system(script); + if (r != 0) + { + log_err(_("Can't restart PostgreSQL server\n")); + exit(ERR_NO_RESTART); + } + + /* reconnect to check we got promoted */ + log_info(_("%s connecting to now restarted database\n"), progname); + conn = establish_db_connection(options.conninfo, true); + retval = is_standby(conn); + if (retval) + { + log_err(_(retval == 1 ? + "%s: STANDBY PROMOTE failed, this is still a standby node.\n" : + "%s: connection to node lost!\n"), progname); + } + else + { + log_notice(_("%s: STANDBY PROMOTE successful. You should REINDEX any hash indexes you have.\n"), + progname); + } + PQfinish(conn); + return; +} + + +static void +do_standby_follow(void) +{ + PGconn *conn; + PGresult *res; + char sqlquery[QUERY_STR_LEN], + *ret; + char script[MAXLEN]; + char master_conninfo[MAXLEN]; + PGconn *master_conn; + int master_id; + + int r, + retval; + char data_dir[MAXLEN]; + + char master_version[MAXVERSIONSTR]; + char standby_version[MAXVERSIONSTR]; + + /* We need to connect to check configuration */ + log_info(_("%s connecting to standby database\n"), progname); + conn = establish_db_connection(options.conninfo, true); + + /* Check we are in a standby node */ + log_info(_("%s connected to standby, checking its state\n"), progname); + retval = is_standby(conn); + if (retval == 0 || retval == -1) + { + log_err(_(retval == 0 ? "%s: The command should be executed in a standby node\n" : + "%s: connection to node lost!\n"), progname); + + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* should be v9 or better */ + ret = pg_version(conn, standby_version); + if (ret == NULL || strcmp(standby_version, "") == 0) + { + if (ret != NULL) + log_err(_("%s needs standby to be PostgreSQL 9.0 or better\n"), + progname); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* + * we also need to check if there is any master in the cluster or wait for + * one to appear if we have set the wait option + */ + log_info(_("%s discovering new master...\n"), progname); + + do + { + if (!is_pgup(conn, options.master_response_timeout)) + { + conn = establish_db_connection(options.conninfo, true); + } + + master_conn = get_master_connection(conn, repmgr_schema, + options.cluster_name, &master_id, (char *) &master_conninfo); + } + while (master_conn == NULL && runtime_options.wait_for_master); + + if (master_conn == NULL) + { + log_err(_("There isn't a master to follow in this cluster\n")); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + + /* Check we are going to point to a master */ + retval = is_standby(master_conn); + if (retval) + { + log_err(_(retval == 1 ? "%s: The node to follow should be a master\n" : + "%s: connection to node lost!\n"), progname); + + PQfinish(conn); + PQfinish(master_conn); + exit(ERR_BAD_CONFIG); + } + + /* should be v9 or better */ + log_info(_("%s connected to master, checking its state\n"), progname); + ret = pg_version(master_conn, master_version); + if (ret == NULL || strcmp(master_version, "") == 0) + { + if (ret != NULL) + log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"), + progname); + PQfinish(conn); + PQfinish(master_conn); + exit(ERR_BAD_CONFIG); + } + + /* master and standby version should match */ + if (strcmp(master_version, standby_version) != 0) + { + log_err(_("%s needs versions of both master (%s) and standby (%s) to match.\n"), + progname, master_version, standby_version); + PQfinish(conn); + PQfinish(master_conn); + exit(ERR_BAD_CONFIG); + } + + /* + * set the host and masterport variables with the master ones before + * closing the connection because we will need them to recreate the + * recovery.conf file + */ + strncpy(runtime_options.host, PQhost(master_conn), MAXLEN); + strncpy(runtime_options.masterport, PQport(master_conn), MAXLEN); + strncpy(runtime_options.username, PQuser(master_conn), MAXLEN); + PQfinish(master_conn); + + log_info(_("%s Changing standby's master\n"), progname); + + /* Get the data directory full path */ + sqlquery_snprintf(sqlquery, "SELECT setting " + " FROM pg_settings WHERE name = 'data_directory'"); + log_debug(_("standby follow: %s\n"), sqlquery); + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Can't get info about data directory: %s\n"), + PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + strcpy(data_dir, PQgetvalue(res, 0, 0)); + PQclear(res); + PQfinish(conn); + + /* write the recovery.conf file */ + if (!create_recovery_file(data_dir)) + exit(ERR_BAD_CONFIG); + + /* Finally, restart the service */ + maxlen_snprintf(script, "%s/pg_ctl %s -w -D %s -m fast restart", + options.pg_bindir, options.pgctl_options, data_dir); + r = system(script); + if (r != 0) + { + log_err(_("Can't restart service\n")); + exit(ERR_NO_RESTART); + } + + return; +} + + +static void +do_witness_create(void) +{ + PGconn *masterconn; + PGconn *witnessconn; + PGresult *res; + char sqlquery[QUERY_STR_LEN], + *ret; + + char script[MAXLEN]; + char buf[MAXLEN]; + FILE *pg_conf = NULL; + + int r = 0, + retval; + int i; + + char master_version[MAXVERSIONSTR]; + + char master_hba_file[MAXLEN]; + + /* Connection parameters for master only */ + keywords[0] = "host"; + values[0] = runtime_options.host; + keywords[1] = "port"; + values[1] = runtime_options.masterport; + + /* We need to connect to check configuration and copy it */ + masterconn = establish_db_connection_by_params(keywords, values, true); + if (!masterconn) + { + log_err(_("%s: could not connect to master\n"), progname); + exit(ERR_DB_CON); + } + + /* primary should be v9 or better */ + ret = pg_version(masterconn, master_version); + if (ret == NULL || strcmp(master_version, "") == 0) + { + if (ret != NULL) + log_err(_("%s needs master to be PostgreSQL 9.0 or better\n"), + progname); + PQfinish(masterconn); + exit(ERR_BAD_CONFIG); + } + + /* Check we are connecting to a primary node */ + retval = is_standby(masterconn); + if (retval) + { + log_err(_(retval == 1 ? + "The command should not run on a standby node\n" : + "Connection to node lost!\n")); + + PQfinish(masterconn); + exit(ERR_BAD_CONFIG); + } + + log_info(_("Successfully connected to primary.\n")); + + r = test_ssh_connection(runtime_options.host, runtime_options.remote_user); + if (r != 0) + { + log_err(_("%s: Aborting, remote host %s is not reachable.\n"), + progname, runtime_options.host); + PQfinish(masterconn); + exit(ERR_BAD_SSH); + } + + /* Check this directory could be used as a PGDATA dir */ + if (!create_pg_dir(runtime_options.dest_dir, runtime_options.force)) + { + log_err(_("witness create: couldn't create data directory (\"%s\") for witness"), + runtime_options.dest_dir); + exit(ERR_BAD_CONFIG); + } + + + /* + * To create a witness server we need to: 1) initialize the cluster 2) + * register the witness in repl_nodes 3) copy configuration from master + */ + + /* Create the cluster for witness */ + if (!runtime_options.superuser[0]) + strncpy(runtime_options.superuser, "postgres", MAXLEN); + + sprintf(script, "%s/pg_ctl %s -D %s init -o \"%s-U %s\"", options.pg_bindir, + options.pgctl_options, runtime_options.dest_dir, + runtime_options.initdb_no_pwprompt ? "" : "-W ", + runtime_options.superuser); + log_info("Initialize cluster for witness: %s.\n", script); + + r = system(script); + if (r != 0) + { + log_err("Can't initialize cluster for witness server\n"); + PQfinish(masterconn); + exit(ERR_BAD_CONFIG); + } + + /* + * default port for the witness is 5499, but user can provide a different + * one + */ + xsnprintf(buf, sizeof(buf), "%s/postgresql.conf", runtime_options.dest_dir); + pg_conf = fopen(buf, "a"); + if (pg_conf == NULL) + { + log_err(_("%s: could not open \"%s\" for adding extra config: %s\n"), + progname, buf, strerror(errno)); + PQfinish(masterconn); + exit(ERR_BAD_CONFIG); + } + + xsnprintf(buf, sizeof(buf), "\n#Configuration added by %s\n", progname); + fputs(buf, pg_conf); + + if (!runtime_options.localport[0]) + strncpy(runtime_options.localport, "5499", MAXLEN); + xsnprintf(buf, sizeof(buf), "port = %s\n", runtime_options.localport); + fputs(buf, pg_conf); + + xsnprintf(buf, sizeof(buf), "shared_preload_libraries = 'repmgr_funcs'\n"); + fputs(buf, pg_conf); + + xsnprintf(buf, sizeof(buf), "listen_addresses = '*'\n"); + fputs(buf, pg_conf); + + fclose(pg_conf); + + + /* start new instance */ + sprintf(script, "%s/pg_ctl %s -w -D %s start", options.pg_bindir, + options.pgctl_options, runtime_options.dest_dir); + log_info(_("Start cluster for witness: %s\n"), script); + r = system(script); + if (r != 0) + { + log_err(_("Can't start cluster for witness server\n")); + PQfinish(masterconn); + exit(ERR_BAD_CONFIG); + } + + /* check if we need to create a user */ + if (runtime_options.username[0] && runtime_options.localport[0] && strcmp(runtime_options.username,"postgres")!=0 ) + { + /* create required user needs to be superuser to create untrusted language function in c */ + sprintf(script, "%s/createuser -p %s --superuser --login -U %s %s", options.pg_bindir, + runtime_options.localport, runtime_options.superuser, runtime_options.username); + log_info("Create user for witness db: %s.\n", script); + + r = system(script); + if (r != 0) + { + log_err("Can't create user for witness server\n"); + PQfinish(masterconn); + exit(ERR_BAD_CONFIG); + } + } + + /* check if we need to create a database */ + if(runtime_options.dbname[0] && strcmp(runtime_options.dbname,"postgres")!=0 && runtime_options.localport[0]) + { + /* create required db */ + sprintf(script, "%s/createdb -p %s -U %s --owner=%s %s", + options.pg_bindir, runtime_options.localport, runtime_options.superuser, runtime_options.username, runtime_options.dbname); + log_info("Create database for witness db: %s.\n", script); + + r = system(script); + if (r != 0) + { + log_err("Can't create database for witness server\n"); + PQfinish(masterconn); + exit(ERR_BAD_CONFIG); + } + } + + /* Get the pg_hba.conf full path */ + sqlquery_snprintf(sqlquery, "SELECT name, setting " + " FROM pg_settings " + " WHERE name IN ('hba_file')"); + log_debug(_("witness create: %s\n"), sqlquery); + res = PQexec(masterconn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + log_err(_("Can't get info about pg_hba.conf: %s\n"), + PQerrorMessage(masterconn)); + PQclear(res); + PQfinish(masterconn); + exit(ERR_DB_QUERY); + } + for (i = 0; i < PQntuples(res); i++) + { + if (strcmp(PQgetvalue(res, i, 0), "hba_file") == 0) + strcpy(master_hba_file, PQgetvalue(res, i, 1)); + else + log_err(_("unknown parameter: %s"), PQgetvalue(res, i, 0)); + } + PQclear(res); + + r = copy_remote_files(runtime_options.host, runtime_options.remote_user, + master_hba_file, runtime_options.dest_dir, + false); + if (r != 0) + { + log_err(_("Can't rsync the pg_hba.conf file from master\n")); + PQfinish(masterconn); + exit(ERR_BAD_CONFIG); + } + + /* reload to adapt for changed pg_hba.conf */ + sprintf(script, "%s/pg_ctl %s -w -D %s reload", options.pg_bindir, + options.pgctl_options, runtime_options.dest_dir); + log_info(_("Reload cluster config for witness: %s"), script); + r = system(script); + if (r != 0) + { + log_err(_("Can't reload cluster for witness server\n")); + PQfinish(masterconn); + exit(ERR_BAD_CONFIG); + } + + /* register ourselves in the master */ + sqlquery_snprintf(sqlquery, "INSERT INTO %s.repl_nodes(id, cluster, name, conninfo, priority, witness) " + "VALUES (%d, '%s', '%s', '%s', %d, true)", + repmgr_schema, options.node, options.cluster_name, + options.node_name, options.conninfo, options.priority); + + log_debug(_("witness create: %s"), sqlquery); + res = PQexec(masterconn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_err(_("Cannot insert node details, %s\n"), + PQerrorMessage(masterconn)); + PQfinish(masterconn); + exit(ERR_DB_QUERY); + } + + /* establish a connection to the witness, and create the schema */ + witnessconn = establish_db_connection(options.conninfo, true); + + log_info(_("Starting copy of configuration from master...\n")); + + if (!create_schema(witnessconn)) + { + PQfinish(masterconn); + PQfinish(witnessconn); + exit(ERR_BAD_CONFIG); + } + + /* copy configuration from master, only repl_nodes is needed */ + if (!copy_configuration(masterconn, witnessconn)) + { + PQfinish(masterconn); + PQfinish(witnessconn); + exit(ERR_BAD_CONFIG); + } + + /* drop superuser powers if needed */ + if (runtime_options.username[0] && runtime_options.localport[0] && strcmp(runtime_options.username,"postgres")!=0 ) + { + sqlquery_snprintf(sqlquery, "ALTER ROLE %s NOSUPERUSER", runtime_options.username); + log_info("Drop superuser powers on user for witness db: %s.\n", sqlquery); + + res = PQexec(witnessconn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_err(_("Cannot alter user privileges, %s\n"), + PQerrorMessage(witnessconn)); + PQfinish(masterconn); + PQfinish(witnessconn); + exit(ERR_DB_QUERY); + } + } + PQfinish(masterconn); + PQfinish(witnessconn); + + log_notice(_("Configuration has been successfully copied to the witness\n")); +} + + + +static void +usage(void) +{ + fprintf(stderr, _("\n\n%s: Replicator manager \n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); +} + + + +static void +help(const char *progname) +{ + printf(_("\n%s: Replicator manager \n"), progname); + printf(_("Usage:\n")); + printf(_(" %s [OPTIONS] master {register}\n"), progname); + printf(_(" %s [OPTIONS] standby {register|clone|promote|follow}\n"), + progname); + printf(_(" %s [OPTIONS] cluster {show|cleanup}\n"), progname); + printf(_("\nGeneral options:\n")); + printf(_(" --help show this help, then exit\n")); + printf(_(" --version output version information, then exit\n")); + printf(_(" --verbose output verbose activity information\n")); + printf(_("\nConnection options:\n")); + printf(_(" -d, --dbname=DBNAME database to connect to\n")); + printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); + printf(_(" -p, --port=PORT database server port\n")); + printf(_(" -U, --username=USERNAME database user name to connect as\n")); + printf(_("\nConfiguration options:\n")); + printf(_(" -D, --data-dir=DIR local directory where the files will be\n" \ + " copied to\n")); + printf(_(" -l, --local-port=PORT standby or witness server local port\n")); + printf(_(" -f, --config-file=PATH path to the configuration file\n")); + printf(_(" -R, --remote-user=USERNAME database server username for rsync\n")); + printf(_(" -S, --superuser=USERNAME superuser username for witness database\n" \ + " (default: postgres)\n")); + printf(_(" -w, --wal-keep-segments=VALUE minimum value for the GUC\n" \ + " wal_keep_segments (default: 5000)\n")); + printf(_(" -I, --ignore-rsync-warning ignore rsync partial transfer warning\n")); + printf(_(" -k, --keep-history=VALUE keeps indicated number of days of\n" \ + " history\n")); + printf(_(" -F, --force force potentially dangerous operations\n" \ + " to happen\n")); + printf(_(" -W, --wait wait for a master to appear\n")); + printf(_(" -r, --min-recovery-apply-delay=VALUE enable recovery time delay, value has to be a valid time atom (e.g. 5min)\n")); + printf(_(" --initdb-no-pwprompt don't require superuser password when running initdb\n")); + printf(_("\n%s performs some tasks like clone a node, promote it or making follow\n"), progname); + printf(_("another node and then exits.\n\n")); + printf(_("COMMANDS:\n")); + printf(_(" master register - registers the master in a cluster\n")); + printf(_(" standby register - registers a standby in a cluster\n")); + printf(_(" standby clone [node] - allows creation of a new standby\n")); + printf(_(" standby promote - allows manual promotion of a specific standby into\n" \ + " a new master in the event of a failover\n")); + printf(_(" standby follow - allows the standby to re-point itself to a new\n" \ + " master\n")); + printf(_(" cluster show - print node information\n")); + printf(_(" cluster cleanup - cleans monitor's history\n")); +} + + +/* + * Creates a recovery file for a standby. + */ +static bool +create_recovery_file(const char *data_dir) +{ + FILE *recovery_file; + char recovery_file_path[MAXLEN]; + char line[MAXLEN]; + + maxlen_snprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_FILE); + + recovery_file = fopen(recovery_file_path, "w"); + if (recovery_file == NULL) + { + log_err(_("could not create recovery.conf file, it could be necessary to create it manually\n")); + return false; + } + + maxlen_snprintf(line, "standby_mode = 'on'\n"); + if (fputs(line, recovery_file) == EOF) + { + log_err(_("recovery file could not be written, it could be necessary to create it manually\n")); + fclose(recovery_file); + return false; + } + + write_primary_conninfo(line); + + if (fputs(line, recovery_file) == EOF) + { + log_err(_("recovery file could not be written, it could be necessary to create it manually\n")); + fclose(recovery_file); + return false; + } + + if(*runtime_options.min_recovery_apply_delay) + { + maxlen_snprintf(line, "\nmin_recovery_apply_delay = %s\n", + runtime_options.min_recovery_apply_delay); + + if (fputs(line, recovery_file) == EOF) + { + log_err(_("recovery file could not be written, it could be necessary to create it manually\n")); + fclose(recovery_file); + return false; + } + } + + /* FreeFile(recovery_file); */ + fclose(recovery_file); + + return true; +} + +static int +test_ssh_connection(char *host, char *remote_user) +{ + char script[MAXLEN]; + int r = 1, i; + + /* On some OS, true is located in a different place than in Linux + * we have to try them all until all alternatives are gone or we + * found `true' because the target OS may differ from the source + * OS + */ + const char *truebin_paths[] = { + "/bin/true", + "/usr/bin/true", + NULL + }; + + /* Check if we have ssh connectivity to host before trying to rsync */ + for(i = 0; truebin_paths[i] && r != 0; ++i) + { + if (!remote_user[0]) + maxlen_snprintf(script, "ssh -o Batchmode=yes %s %s %s", + options.ssh_options, host, truebin_paths[i]); + else + maxlen_snprintf(script, "ssh -o Batchmode=yes %s %s -l %s %s", + options.ssh_options, host, remote_user, + truebin_paths[i]); + + log_debug(_("command is: %s\n"), script); + r = system(script); + } + + if (r != 0) + log_info(_("Can not connect to the remote host (%s)\n"), host); + return r; +} + +static int +copy_remote_files(char *host, char *remote_user, char *remote_path, + char *local_path, bool is_directory) +{ + char script[MAXLEN]; + char rsync_flags[MAXLEN]; + char host_string[MAXLEN]; + int r; + + if (*options.rsync_options == '\0') + maxlen_snprintf( + rsync_flags, "%s", + "--archive --checksum --compress --progress --rsh=ssh"); + else + maxlen_snprintf(rsync_flags, "%s", options.rsync_options); + + if (runtime_options.force) + strcat(rsync_flags, " --delete --checksum"); + + if (!remote_user[0]) + { + maxlen_snprintf(host_string, "%s", host); + } + else + { + maxlen_snprintf(host_string, "%s@%s", remote_user, host); + } + + if (is_directory) + { + strcat(rsync_flags, + " --exclude=pg_xlog/* --exclude=pg_log/* --exclude=pg_control --exclude=*.pid"); + maxlen_snprintf(script, "rsync %s %s:%s/* %s", + rsync_flags, host_string, remote_path, local_path); + } + else + { + maxlen_snprintf(script, "rsync %s %s:%s %s", + rsync_flags, host_string, remote_path, local_path); + } + + log_info(_("rsync command line: '%s'\n"), script); + + r = system(script); + + /* + * If we are transfering a directory (data directory, tablespace + * directories) then we can ignore some rsync warnings. If we get some of + * those errors, we treat them as 0 only if passed the + * --ignore-rsync-warning command-line option. + * + * List of ignorable rsync errors: 24 Partial transfer due to vanished + * source files + */ + if ((WEXITSTATUS(r) == 24) && is_directory) + { + if (runtime_options.ignore_rsync_warn) + { + r = 0; + log_info(_("rsync partial transfer warning ignored\n")); + } + else + log_warning(_("rsync completed with return code 24: " + "\"Partial transfer due to vanished source files\".\n" + "This can happen because of normal operation " + "on the master server, but it may indicate an " + "unexpected change during cloning. If you are certain " + "no changes were made to the master, try cloning " + "again using \"repmgr --force --ignore-rsync-warning\".")); + } + if (r != 0) + log_err(_("Can't rsync from remote file or directory (%s:%s)\n"), + host_string, remote_path); + + return r; +} + + +/* + * Tries to avoid useless or conflicting parameters + */ +static bool +check_parameters_for_action(const int action) +{ + bool ok = true; + + switch (action) + { + case MASTER_REGISTER: + + /* + * To register a master we only need the repmgr.conf all other + * parameters are at least useless and could be confusing so + * reject them + */ + if (runtime_options.host[0] || runtime_options.masterport[0] || + runtime_options.username[0] || runtime_options.dbname[0]) + { + log_err(_("You can't use connection parameters to the master when issuing a MASTER REGISTER command.\n")); + usage(); + ok = false; + } + if (runtime_options.dest_dir[0]) + { + log_err(_("You don't need a destination directory for MASTER REGISTER command\n")); + usage(); + ok = false; + } + break; + case STANDBY_REGISTER: + + /* + * To register a standby we only need the repmgr.conf we don't + * need connection parameters to the master because we can detect + * the master in repl_nodes + */ + if (runtime_options.host[0] || runtime_options.masterport[0] || + runtime_options.username[0] || runtime_options.dbname[0]) + { + log_err(_("You can't use connection parameters to the master when issuing a STANDBY REGISTER command.\n")); + usage(); + ok = false; + } + if (runtime_options.dest_dir[0]) + { + log_err(_("You don't need a destination directory for STANDBY REGISTER command\n")); + usage(); + ok = false; + } + break; + case STANDBY_PROMOTE: + + /* + * To promote a standby we only need the repmgr.conf we don't want + * connection parameters to the master because we will try to + * detect the master in repl_nodes if we can't find it then the + * promote action will be cancelled + */ + if (runtime_options.host[0] || runtime_options.masterport[0] || + runtime_options.username[0] || runtime_options.dbname[0]) + { + log_err(_("You can't use connection parameters to the master when issuing a STANDBY PROMOTE command.\n")); + usage(); + ok = false; + } + if (runtime_options.dest_dir[0]) + { + log_err(_("You don't need a destination directory for STANDBY PROMOTE command\n")); + usage(); + ok = false; + } + break; + case STANDBY_FOLLOW: + + /* + * To make a standby follow a master we only need the repmgr.conf + * we don't want connection parameters to the new master because + * we will try to detect the master in repl_nodes if we can't find + * it then the follow action will be cancelled + */ + if (runtime_options.host[0] || runtime_options.masterport[0] || + runtime_options.username[0] || runtime_options.dbname[0]) + { + log_err(_("You can't use connection parameters to the master when issuing a STANDBY FOLLOW command.\n")); + usage(); + ok = false; + } + if (runtime_options.dest_dir[0]) + { + log_err(_("You don't need a destination directory for STANDBY FOLLOW command\n")); + usage(); + ok = false; + } + break; + case STANDBY_CLONE: + + /* + * Issue a friendly notice that the configuration file is not + * necessary nor read at all in when performing a STANDBY CLONE + * action. + */ + if (runtime_options.config_file[0]) + { + log_notice(_("Only command line parameters for the connection " + "to the master are used when issuing a STANDBY CLONE command. " + "The passed configuration file is neither required nor used for " + "its node configuration portions\n\n")); + } + + /* + * To clone a master into a standby we need connection parameters + * repmgr.conf is useless because we don't have a server running + * in the standby; warn the user, but keep going. + */ + if (runtime_options.host == NULL) + { + log_notice(_("You need to use connection parameters to " + "the master when issuing a STANDBY CLONE command.")); + ok = false; + } + need_a_node = false; + break; + case WITNESS_CREATE: + /* allow all parameters to be supplied */ + break; + case CLUSTER_SHOW: + /* allow all parameters to be supplied */ + break; + case CLUSTER_CLEANUP: + /* allow all parameters to be supplied */ + break; + } + + return ok; +} + + + +static bool +create_schema(PGconn *conn) +{ + char sqlquery[QUERY_STR_LEN]; + PGresult *res; + + sqlquery_snprintf(sqlquery, "CREATE SCHEMA %s", repmgr_schema); + log_debug(_("master register: %s\n"), sqlquery); + res = PQexec(conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_err(_("Cannot create the schema %s: %s\n"), + repmgr_schema, PQerrorMessage(conn)); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + PQclear(res); + + /* + * to avoid confusion of the time_lag field and provide a consistent UI we + * use these functions for providing the latest update timestamp + */ + sqlquery_snprintf(sqlquery, + "CREATE FUNCTION %s.repmgr_update_last_updated() RETURNS TIMESTAMP WITH TIME ZONE " + "AS '$libdir/repmgr_funcs', 'repmgr_update_last_updated' " + " LANGUAGE C STRICT", repmgr_schema); + res = PQexec(conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + fprintf(stderr, "Cannot create the function repmgr_update_last_updated: %s\n", + PQerrorMessage(conn)); + return false; + } + PQclear(res); + + + sqlquery_snprintf(sqlquery, + "CREATE FUNCTION %s.repmgr_get_last_updated() RETURNS TIMESTAMP WITH TIME ZONE " + "AS '$libdir/repmgr_funcs', 'repmgr_get_last_updated' " + "LANGUAGE C STRICT", repmgr_schema); + res = PQexec(conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + fprintf(stderr, "Cannot create the function repmgr_get_last_updated: %s\n", + PQerrorMessage(conn)); + return false; + } + PQclear(res); + + + /* ... the tables */ + sqlquery_snprintf(sqlquery, "CREATE TABLE %s.repl_nodes ( " + " id integer primary key, " + " cluster text not null, " + " name text not null, " + " conninfo text not null, " + " priority integer not null, " + " witness boolean not null default false)", repmgr_schema); + log_debug(_("master register: %s\n"), sqlquery); + res = PQexec(conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_err(_("Cannot create the table %s.repl_nodes: %s\n"), + repmgr_schema, PQerrorMessage(conn)); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + PQclear(res); + + sqlquery_snprintf(sqlquery, "CREATE TABLE %s.repl_monitor ( " + " primary_node INTEGER NOT NULL, " + " standby_node INTEGER NOT NULL, " + " last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, " + " last_apply_time TIMESTAMP WITH TIME ZONE, " + " last_wal_primary_location TEXT NOT NULL, " + " last_wal_standby_location TEXT, " + " replication_lag BIGINT NOT NULL, " + " apply_lag BIGINT NOT NULL) ", repmgr_schema); + log_debug(_("master register: %s\n"), sqlquery); + res = PQexec(conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_err(_("Cannot create the table %s.repl_monitor: %s\n"), + repmgr_schema, PQerrorMessage(conn)); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + PQclear(res); + + /* a view */ + sqlquery_snprintf(sqlquery, "CREATE VIEW %s.repl_status AS " + " SELECT primary_node, standby_node, name AS standby_name, last_monitor_time, " + " last_wal_primary_location, last_wal_standby_location, " + " pg_size_pretty(replication_lag) replication_lag, " + " age(now(), last_apply_time) AS replication_time_lag, " + " pg_size_pretty(apply_lag) apply_lag, " + " age(now(), CASE WHEN pg_is_in_recovery() THEN %s.repmgr_get_last_updated() ELSE last_monitor_time END) AS communication_time_lag " + " FROM %s.repl_monitor JOIN %s.repl_nodes ON standby_node = id " + " WHERE (standby_node, last_monitor_time) IN (SELECT standby_node, MAX(last_monitor_time) " + " FROM %s.repl_monitor GROUP BY 1)", + repmgr_schema, repmgr_schema, repmgr_schema, + repmgr_schema, repmgr_schema); + log_debug(_("master register: %s\n"), sqlquery); + + res = PQexec(conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_err(_("Cannot create the view %s.repl_status: %s\n"), + repmgr_schema, PQerrorMessage(conn)); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + PQclear(res); + + /* an index to improve performance of the view */ + sqlquery_snprintf(sqlquery, "CREATE INDEX idx_repl_status_sort " + " ON %s.repl_monitor (last_monitor_time, standby_node) ", + repmgr_schema); + log_debug(_("master register: %s\n"), sqlquery); + res = PQexec(conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + log_err(_("Can't index table %s.repl_monitor: %s\n"), + repmgr_schema, PQerrorMessage(conn)); + PQfinish(conn); + exit(ERR_BAD_CONFIG); + } + PQclear(res); + + /* + * XXX Here we MUST try to load the repmgr_function.sql not hardcode it + * here + */ + sqlquery_snprintf(sqlquery, + "CREATE OR REPLACE FUNCTION %s.repmgr_update_standby_location(text) RETURNS boolean " + "AS '$libdir/repmgr_funcs', 'repmgr_update_standby_location' " + "LANGUAGE C STRICT ", repmgr_schema); + res = PQexec(conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + fprintf(stderr, "Cannot create the function repmgr_update_standby_location: %s\n", + PQerrorMessage(conn)); + return false; + } + PQclear(res); + + sqlquery_snprintf(sqlquery, + "CREATE OR REPLACE FUNCTION %s.repmgr_get_last_standby_location() RETURNS text " + "AS '$libdir/repmgr_funcs', 'repmgr_get_last_standby_location' " + "LANGUAGE C STRICT ", repmgr_schema); + res = PQexec(conn, sqlquery); + if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) + { + fprintf(stderr, "Cannot create the function repmgr_get_last_standby_location: %s\n", + PQerrorMessage(conn)); + return false; + } + PQclear(res); + + return true; +} + + +static bool +copy_configuration(PGconn *masterconn, PGconn *witnessconn) +{ + char sqlquery[MAXLEN]; + PGresult *res1; + PGresult *res2; + int i; + + sqlquery_snprintf(sqlquery, "TRUNCATE TABLE %s.repl_nodes", repmgr_schema); + log_debug("copy_configuration: %s\n", sqlquery); + res1 = PQexec(witnessconn, sqlquery); + if (!res1 || PQresultStatus(res1) != PGRES_COMMAND_OK) + { + fprintf(stderr, "Cannot clean node details in the witness, %s\n", + PQerrorMessage(witnessconn)); + return false; + } + + sqlquery_snprintf(sqlquery, "SELECT id, name, conninfo, priority, witness FROM %s.repl_nodes", + repmgr_schema); + res1 = PQexec(masterconn, sqlquery); + if (PQresultStatus(res1) != PGRES_TUPLES_OK) + { + fprintf(stderr, "Can't get configuration from master: %s\n", + PQerrorMessage(masterconn)); + PQclear(res1); + return false; + } + for (i = 0; i < PQntuples(res1); i++) + { + sqlquery_snprintf(sqlquery, "INSERT INTO %s.repl_nodes(id, cluster, name, conninfo, priority, witness) " + "VALUES (%d, '%s', '%s', '%s', %d, '%s')", + repmgr_schema, atoi(PQgetvalue(res1, i, 0)), + options.cluster_name, PQgetvalue(res1, i, 1), + PQgetvalue(res1, i, 2), + atoi(PQgetvalue(res1, i, 3)), + PQgetvalue(res1, i, 4)); + + res2 = PQexec(witnessconn, sqlquery); + if (!res2 || PQresultStatus(res2) != PGRES_COMMAND_OK) + { + fprintf(stderr, "Cannot copy configuration to witness, %s\n", + PQerrorMessage(witnessconn)); + PQclear(res2); + return false; + } + PQclear(res2); + } + PQclear(res1); + + return true; +} + +/* This function uses global variables to determine connection settings. Special + * usage of the PGPASSWORD variable is handled, but strongly discouraged */ +static void +write_primary_conninfo(char *line) +{ + char host_buf[MAXLEN] = ""; + char conn_buf[MAXLEN] = ""; + char user_buf[MAXLEN] = ""; + char appname_buf[MAXLEN] = ""; + char password_buf[MAXLEN] = ""; + + /* Environment variable for password (UGLY, please use .pgpass!) */ + const char *password = getenv("PGPASSWORD"); + + if (password != NULL) + { + maxlen_snprintf(password_buf, " password=%s", password); + } + else if (require_password) + { + log_err(_("%s: PGPASSWORD not set, but having one is required\n"), + progname); + exit(ERR_BAD_PASSWORD); + } + + if (runtime_options.host[0]) + { + maxlen_snprintf(host_buf, " host=%s", runtime_options.host); + } + + if (runtime_options.username[0]) + { + maxlen_snprintf(user_buf, " user=%s", runtime_options.username); + } + + if (options.node_name[0]) + { + maxlen_snprintf(appname_buf, " application_name=%s", options.node_name); + } + + maxlen_snprintf(conn_buf, "port=%s%s%s%s%s", + (runtime_options.masterport[0]) ? runtime_options.masterport : "5432", + host_buf, user_buf, password_buf, + appname_buf); + + maxlen_snprintf(line, "primary_conninfo = '%s'", conn_buf); + +} diff --git a/repmgr.c b/repmgr.c index 5dc86494..f13062f3 100644 --- a/repmgr.c +++ b/repmgr.c @@ -416,7 +416,7 @@ main(int argc, char **argv) if (runtime_options.verbose && runtime_options.config_file[0]) { - log_notice(_("Opening configuration file: %s\n"), + log_notice(_("opening configuration file: %s\n"), runtime_options.config_file); } @@ -571,7 +571,7 @@ do_cluster_show(void) int i; /* We need to connect to check configuration */ - log_info(_("%s connecting to database\n"), progname); + log_info(_("connecting to database\n")); conn = establish_db_connection(options.conninfo, true); sqlquery_snprintf(sqlquery, @@ -582,7 +582,8 @@ do_cluster_show(void) if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Can't get nodes information, have you registered them?\n%s\n"), + // ZZZ + log_err(_("can't get nodes information, have you registered them?\n%s\n"), PQerrorMessage(conn)); PQclear(res); PQfinish(conn); @@ -621,11 +622,11 @@ do_cluster_cleanup(void) char sqlquery[QUERY_STR_LEN]; /* We need to connect to check configuration */ - log_info(_("%s connecting to database\n"), progname); + log_info(_("connecting to database\n")); conn = establish_db_connection(options.conninfo, true); /* check if there is a master in this cluster */ - log_info(_("%s connecting to master database\n"), progname); + log_info(_("connecting to master database\n")); master_conn = get_master_connection(conn, options.cluster_name, NULL, NULL); if (!master_conn) @@ -688,17 +689,17 @@ do_master_register(void) conn = establish_db_connection(options.conninfo, true); /* Verify that master is a supported server version */ - log_info(_("%s connecting to master database\n"), progname); + log_info(_("connecting to master database\n")); check_server_version(conn, "master", true, NULL); /* Check we are a master */ - log_info(_("%s connected to master, checking its state\n"), progname); + log_info(_("connected to master, checking its state\n")); ret = is_standby(conn); if (ret) { - log_err(_(ret == 1 ? "Trying to register a standby node as a master\n" : - "Connection to node lost!\n")); + log_err(_(ret == 1 ? "server is in standby mode and cannot be registered as a master\n" : + "connection to node lost!\n")); PQfinish(conn); exit(ERR_BAD_CONFIG); @@ -710,7 +711,7 @@ do_master_register(void) /* If schema exists and force option not selected, raise an error */ if(schema_exists && !runtime_options.force) { - log_notice(_("Schema '%s' already exists.\n"), get_repmgr_schema()); + log_notice(_("schema '%s' already exists.\n"), get_repmgr_schema()); PQfinish(conn); exit(ERR_BAD_CONFIG); } @@ -734,7 +735,7 @@ do_master_register(void) if (master_conn != NULL) { PQfinish(master_conn); - log_warning(_("There is a master already in cluster %s\n"), + log_warning(_("there is a master already in cluster %s\n"), options.cluster_name); exit(ERR_BAD_CONFIG); } @@ -788,7 +789,7 @@ do_master_register(void) PQfinish(conn); - log_notice(_("Master node correctly registered for cluster %s with id %d (conninfo: %s)\n"), + log_notice(_("master node correctly registered for cluster %s with id %d (conninfo: %s)\n"), options.cluster_name, options.node, options.conninfo); return; } @@ -809,7 +810,7 @@ do_standby_register(void) bool record_created; - log_info(_("%s connecting to standby database\n"), progname); + log_info(_("connecting to standby database\n")); conn = establish_db_connection(options.conninfo, true); /* Verify that standby is a supported server version */ @@ -819,8 +820,8 @@ do_standby_register(void) ret = is_standby(conn); if (ret == 0 || ret == -1) { - log_err(_(ret == 0 ? "repmgr: This node should be a standby (%s)\n" : - "repmgr: connection to node (%s) lost\n"), options.conninfo); + log_err(_(ret == 0 ? "this node should be a standby (%s)\n" : + "connection to node (%s) lost\n"), options.conninfo); PQfinish(conn); exit(ERR_BAD_CONFIG); @@ -830,23 +831,23 @@ do_standby_register(void) if (check_cluster_schema(conn) == false) { /* schema doesn't exist */ - log_err(_("Schema '%s' doesn't exist.\n"), get_repmgr_schema()); + log_err(_("schema '%s' doesn't exist.\n"), get_repmgr_schema()); PQfinish(conn); exit(ERR_BAD_CONFIG); } /* check if there is a master in this cluster */ - log_info(_("%s connecting to master database\n"), progname); + log_info(_("connecting to master database\n")); master_conn = get_master_connection(conn, options.cluster_name, NULL, NULL); if (!master_conn) { - log_err(_("A master must be defined before configuring a slave\n")); + log_err(_("a master must be defined before configuring a slave\n")); exit(ERR_BAD_CONFIG); } /* Verify that master is a supported server version */ - log_info(_("%s connected to master, checking its state\n"), progname); + log_info(_("connected to master, checking its state\n")); master_version_num = check_server_version(conn, "master", false, master_version); if(master_version_num < 0) { @@ -860,13 +861,13 @@ do_standby_register(void) { PQfinish(conn); PQfinish(master_conn); - log_err(_("%s needs versions of both master (%s) and standby (%s) to match.\n"), - progname, master_version, standby_version); + log_err(_("PostgreSQL versions on master (%s) and standby (%s) must match.\n"), + master_version, standby_version); exit(ERR_BAD_CONFIG); } /* Now register the standby */ - log_info(_("%s registering the standby\n"), progname); + log_info(_("registering the standby\n")); if (runtime_options.force) { bool node_record_deleted = delete_node_record(master_conn, @@ -918,8 +919,8 @@ do_standby_register(void) PQfinish(master_conn); PQfinish(conn); - log_info(_("%s registering the standby complete\n"), progname); - log_notice(_("Standby node correctly registered for cluster %s with id %d (conninfo: %s)\n"), + log_info(_("standby registration complete\n")); + log_notice(_("standby node correctly registered for cluster %s with id %d (conninfo: %s)\n"), options.cluster_name, options.node, options.conninfo); return; } @@ -976,8 +977,8 @@ do_standby_clone(void) if (runtime_options.dest_dir[0]) { target_directory_provided = true; - log_notice(_("%s Destination directory '%s' provided\n"), - progname, runtime_options.dest_dir); + log_notice(_("destination directory '%s' provided\n"), + runtime_options.dest_dir); } /* Connection parameters for master only */ @@ -987,11 +988,11 @@ do_standby_clone(void) values[1] = runtime_options.masterport; /* Connect to check configuration */ - log_info(_("%s connecting to upstream node\n"), progname); + log_info(_("connecting to upstream node\n")); upstream_conn = establish_db_connection_by_params(keywords, values, true); /* Verify that upstream node is a supported server version */ - log_info(_("%s connected to upstream node, checking its state\n"), progname); + log_info(_("connected to upstream node, checking its state\n")); server_version_num = check_server_version(upstream_conn, "master", true, NULL); check_upstream_config(upstream_conn, server_version_num, true); @@ -1020,7 +1021,7 @@ do_standby_clone(void) if(get_server_version(upstream_conn, NULL) < 90400) { - log_err(_("In PostgreSQL 9.3, tablespace mapping can only be used in conjunction with --rsync-only\n")); + log_err(_("in PostgreSQL 9.3, tablespace mapping can only be used in conjunction with --rsync-only\n")); PQfinish(upstream_conn); exit(ERR_BAD_CONFIG); } @@ -1035,7 +1036,7 @@ do_standby_clone(void) res = PQexec(upstream_conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Unable to execute tablespace query: %s\n"), PQerrorMessage(upstream_conn)); + log_err(_("unable to execute tablespace query: %s\n"), PQerrorMessage(upstream_conn)); PQclear(res); PQfinish(upstream_conn); exit(ERR_BAD_CONFIG); @@ -1043,7 +1044,7 @@ do_standby_clone(void) if (PQntuples(res) == 0) { - log_err(_("No tablespace matching path '%s' found\n"), cell->old_dir); + log_err(_("no tablespace matching path '%s' found\n"), cell->old_dir); PQclear(res); PQfinish(upstream_conn); exit(ERR_BAD_CONFIG); @@ -1077,7 +1078,7 @@ do_standby_clone(void) res = PQexec(upstream_conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Can't get info about data directory and configuration files: %s\n"), + log_err(_("can't get info about data directory and configuration files: %s\n"), PQerrorMessage(upstream_conn)); PQclear(res); PQfinish(upstream_conn); @@ -1087,7 +1088,7 @@ do_standby_clone(void) /* We need all 4 parameters, and they can be retrieved only by superusers */ if (PQntuples(res) != 4) { - log_err("%s: STANDBY CLONE should be run by a SUPERUSER\n", progname); + log_err("STANDBY CLONE should be run by a SUPERUSER\n"); PQclear(res); PQfinish(upstream_conn); exit(ERR_BAD_CONFIG); @@ -1154,7 +1155,7 @@ do_standby_clone(void) strncpy(local_ident_file, master_ident_file, MAXFILENAME); } - log_notice(_("Starting backup...\n")); + log_notice(_("starting backup...\n")); /* * When using rsync only, we need to check the SSH connection early @@ -1164,8 +1165,8 @@ do_standby_clone(void) r = test_ssh_connection(runtime_options.host, runtime_options.remote_user); if (r != 0) { - log_err(_("%s: Aborting, remote host %s is not reachable.\n"), - progname, runtime_options.host); + log_err(_("aborting, remote host %s is not reachable.\n"), + runtime_options.host); retval = ERR_BAD_SSH; goto stop_backup; } @@ -1176,8 +1177,8 @@ do_standby_clone(void) /* ZZZ maybe check tablespace, xlog dirs too */ if (!create_pg_dir(local_data_directory, runtime_options.force)) { - log_err(_("%s: couldn't use directory %s ...\nUse --force option to force\n"), - progname, local_data_directory); + log_err(_("unable to use directory %s ...\nUse --force option to force\n"), + local_data_directory); r = ERR_BAD_CONFIG; retval = ERR_BAD_CONFIG; goto stop_backup; @@ -1233,7 +1234,8 @@ do_standby_clone(void) res = PQexec(upstream_conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Unable to execute tablespace query: %s\n"), PQerrorMessage(upstream_conn)); + log_err(_("unable to execute tablespace query: %s\n"), + PQerrorMessage(upstream_conn)); PQclear(res); PQfinish(upstream_conn); exit(ERR_BAD_CONFIG); @@ -1271,7 +1273,8 @@ do_standby_clone(void) if(mapping_found == true) { appendPQExpBuffer(&tblspc_dir_dst, "%s", cell->new_dir); - log_debug(_("Mapping source tablespace '%s' (OID %s) to '%s'\n"), tblspc_dir_src.data, tblspc_oid.data, tblspc_dir_dst.data); + log_debug(_("mapping source tablespace '%s' (OID %s) to '%s'\n"), + tblspc_dir_src.data, tblspc_oid.data, tblspc_dir_dst.data); } else { @@ -1293,16 +1296,15 @@ do_standby_clone(void) appendPQExpBuffer(&tblspc_symlink, "%s/pg_tblspc/%s", local_data_directory, tblspc_oid.data); - log_debug(_("symlink: %s\n"), tblspc_symlink.data); if (unlink(tblspc_symlink.data) < 0 && errno != ENOENT) { - log_err(_("Unable to remove tablespace symlink %s\n"), tblspc_symlink.data); + log_err(_("unable to remove tablespace symlink %s\n"), tblspc_symlink.data); exit(ERR_BAD_CONFIG); } if (symlink(tblspc_dir_dst.data, tblspc_symlink.data) < 0) { - log_err(_("Unable to create tablespace symlink from %s to %s\n"), tblspc_symlink.data, tblspc_dir_dst.data); + log_err(_("unable to create tablespace symlink from %s to %s\n"), tblspc_symlink.data, tblspc_dir_dst.data); exit(ERR_BAD_CONFIG); } @@ -1339,12 +1341,12 @@ do_standby_clone(void) if(config_file_copy_required == true) { - log_notice(_("Copying configuration files from master\n")); + log_notice(_("copying configuration files from master\n")); r = test_ssh_connection(runtime_options.host, runtime_options.remote_user); if (r != 0) { - log_err(_("%s: Aborting, remote host %s is not reachable.\n"), - progname, runtime_options.host); + log_err(_("aborting, remote host %s is not reachable.\n"), + runtime_options.host); retval = ERR_BAD_SSH; goto stop_backup; } @@ -1425,8 +1427,8 @@ do_standby_clone(void) if (!create_dir(local_control_file)) { - log_err(_("%s: couldn't create directory %s ...\n"), - progname, local_control_file); + log_err(_("couldn't create directory %s ...\n"), + local_control_file); goto stop_backup; } @@ -1451,7 +1453,7 @@ stop_backup: if(runtime_options.rsync_only) { - log_notice(_("Notifying master about backup completion...\n")); + log_notice(_("notifying master about backup completion...\n")); if(stop_backup(upstream_conn, last_wal_segment) == false) { r = ERR_BAD_BASEBACKUP; @@ -1462,8 +1464,8 @@ stop_backup: /* If the backup failed then exit */ if (r != 0) { - log_err(_("Unable to take a base backup of the master server\n")); - log_warning(_("The destination directory (%s) will need to be cleaned up manually\n"), + log_err(_("unable to take a base backup of the master server\n")); + log_warning(_("destination directory (%s) may need to be cleaned up manually\n"), local_data_directory); PQfinish(upstream_conn); exit(retval); @@ -1488,11 +1490,11 @@ stop_backup: if(runtime_options.rsync_only) { - log_notice(_("%s standby clone (using rsync) complete\n"), progname); + log_notice(_("standby clone (using rsync) complete\n")); } else { - log_notice(_("%s standby clone (using pg_basebackup) complete\n"), progname); + log_notice(_("standby clone (using pg_basebackup) complete\n")); } @@ -1502,7 +1504,7 @@ stop_backup: * - provide a custom pg_ctl command */ - log_notice("HINT: You can now start your postgresql server\n"); + log_notice(_("HINT: you can now start your PostgreSQL server\n")); if (target_directory_provided) { log_notice(_("for example : pg_ctl -D %s start\n"), @@ -1510,7 +1512,7 @@ stop_backup: } else { - log_notice("for example : /etc/init.d/postgresql start\n"); + log_notice(_("for example : /etc/init.d/postgresql start\n")); } /* Log the event */ @@ -1587,11 +1589,11 @@ do_standby_promote(void) bool record_created; /* We need to connect to check configuration */ - log_info(_("%s connecting to standby database\n"), progname); + log_info(_("connecting to standby database\n")); conn = establish_db_connection(options.conninfo, true); /* Verify that standby is a supported server version */ - log_info(_("%s connected to standby, checking its state\n"), progname); + log_info(_("connected to standby, checking its state\n")); check_server_version(conn, "standby", true, NULL); @@ -1599,8 +1601,8 @@ do_standby_promote(void) retval = is_standby(conn); if (retval == 0 || retval == -1) { - log_err(_(retval == 0 ? "%s: The command should be executed on a standby node\n" : - "%s: connection to node lost!\n"), progname); + log_err(_(retval == 0 ? "this command should be executed on a standby node\n" : + "connection to node lost!\n")); PQfinish(conn); exit(ERR_BAD_CONFIG); @@ -1611,13 +1613,13 @@ do_standby_promote(void) options.cluster_name, NULL, NULL); if (old_master_conn != NULL) { - log_err(_("This cluster already has an active master server\n")); + log_err(_("this cluster already has an active master server\n")); PQfinish(old_master_conn); PQfinish(conn); exit(ERR_BAD_CONFIG); } - log_notice(_("%s: Promoting standby\n"), progname); + log_notice(_("promoting standby\n")); /* Get the data directory */ success = get_pg_setting(conn, "data_directory", data_dir); @@ -1625,7 +1627,7 @@ do_standby_promote(void) if (success == false) { - log_err(_("Unable to determine data directory\n")); + log_err(_("unable to determine data directory\n")); exit(ERR_BAD_CONFIG); } @@ -1638,19 +1640,19 @@ do_standby_promote(void) */ maxlen_snprintf(script, "%s -D %s promote", make_pg_path("pg_ctl"), data_dir); - log_notice(_("%s: promoting server using '%s'\n"), progname, + log_notice(_("promoting server using '%s'\n"), script); r = system(script); if (r != 0) { - log_err(_("Unable to promote server from standby to master\n")); + log_err(_("unable to promote server from standby to master\n")); exit(ERR_NO_RESTART); } /* reconnect to check we got promoted */ - log_info(_("%s reconnecting to promoted server\n"), progname); + log_info(_("reconnecting to promoted server\n")); conn = establish_db_connection(options.conninfo, true); for(i = 0; i < promote_check_timeout; i += promote_check_interval) @@ -1679,8 +1681,8 @@ do_standby_promote(void) details.data); /* XXX exit with error? */ log_err(_(retval == 1 ? - "%s: STANDBY PROMOTE failed, this is still a standby node.\n" : - "%s: connection to node lost!\n"), progname); + "STANDBY PROMOTE failed, this is still a standby node.\n" : + "connection to node lost!\n")); } else { @@ -1690,8 +1692,7 @@ do_standby_promote(void) "Node %i was successfully promoted to master", options.node); - log_notice(_("%s: STANDBY PROMOTE successful. You should REINDEX any hash indexes you have.\n"), - progname); + log_notice(_("STANDBY PROMOTE successful. You should REINDEX any hash indexes you have.\n")); /* Log the event */ record_created = create_event_record(conn, options.node, @@ -1735,9 +1736,9 @@ do_standby_follow(void) /* We need to connect to check configuration */ - log_info(_("%s connecting to standby database\n"), progname); + log_info(_("connecting to standby database\n")); conn = establish_db_connection(options.conninfo, true); - log_info(_("%s connected to standby, checking its state\n"), progname); + log_info(_("connected to standby, checking its state\n")); /* Verify that standby is a supported server version */ standby_version_num = check_server_version(conn, "standby", true, standby_version); @@ -1746,8 +1747,8 @@ do_standby_follow(void) retval = is_standby(conn); if (retval == 0 || retval == -1) { - log_err(_(retval == 0 ? "%s: The command should be executed in a standby node\n" : - "%s: connection to node lost!\n"), progname); + log_err(_(retval == 0 ? "this command should be executed on a standby node\n" : + "connection to node lost!\n")); PQfinish(conn); exit(ERR_BAD_CONFIG); @@ -1757,7 +1758,7 @@ do_standby_follow(void) * we also need to check if there is any master in the cluster or wait for * one to appear if we have set the wait option */ - log_info(_("%s discovering new master...\n"), progname); + log_info(_("discovering new master...\n")); do { @@ -1773,7 +1774,7 @@ do_standby_follow(void) if (master_conn == NULL) { - log_err(_("There isn't a master to follow in this cluster\n")); + log_err(_("there isn't a master to follow in this cluster\n")); PQfinish(conn); exit(ERR_BAD_CONFIG); } @@ -1782,8 +1783,8 @@ do_standby_follow(void) retval = is_standby(master_conn); if (retval) { - log_err(_(retval == 1 ? "%s: The node to follow should be a master\n" : - "%s: connection to node lost!\n"), progname); + log_err(_(retval == 1 ? "the node to follow should be a master\n" : + "connection to node lost!\n")); PQfinish(conn); PQfinish(master_conn); @@ -1791,7 +1792,7 @@ do_standby_follow(void) } /* Verify that master is a supported server version */ - log_info(_("%s connected to master, checking its state\n"), progname); + log_info(_("connected to master, checking its state\n")); master_version_num = check_server_version(conn, "master", false, master_version); if(master_version_num < 0) { @@ -1805,8 +1806,8 @@ do_standby_follow(void) { PQfinish(conn); PQfinish(master_conn); - log_err(_("%s needs versions of both master (%s) and standby (%s) to match.\n"), - progname, master_version, standby_version); + log_err(_("PostgreSQL versions on master (%s) and standby (%s) must match.\n"), + master_version, standby_version); exit(ERR_BAD_CONFIG); } @@ -1820,7 +1821,7 @@ do_standby_follow(void) strncpy(runtime_options.username, PQuser(master_conn), MAXLEN); PQfinish(master_conn); - log_info(_("%s Changing standby's master\n"), progname); + log_info(_("changing standby's master\n")); /* Get the data directory full path */ success = get_pg_setting(conn, "data_directory", data_dir); @@ -1828,7 +1829,7 @@ do_standby_follow(void) if (success == false) { - log_err(_("Unable to determine data directory\n")); + log_err(_("unable to determine data directory\n")); exit(ERR_BAD_CONFIG); } @@ -1840,13 +1841,13 @@ do_standby_follow(void) maxlen_snprintf(script, "%s %s -w -D %s -m fast restart", make_pg_path("pg_ctl"), options.pgctl_options, data_dir); - log_notice(_("%s: restarting server using '%s'\n"), progname, + log_notice(_("restarting server using '%s'\n"), script); r = system(script); if (r != 0) { - log_err(_("Can't restart server\n")); + log_err(_("unable to restart server\n")); exit(ERR_NO_RESTART); } @@ -1884,7 +1885,7 @@ do_witness_create(void) if (!masterconn) { /* No event logging possible as we can't connect to the master */ - log_err(_("%s: could not connect to master\n"), progname); + log_err(_("unable to connect to master\n")); exit(ERR_DB_CON); } @@ -1900,8 +1901,8 @@ do_witness_create(void) appendPQExpBuffer(&errmsg, "%s", _(retval == 1 ? - "Provided upstream node is not a master" : - "Connection to upstream node lost")); + "provided upstream node is not a master" : + "connection to upstream node lost")); log_err("%s\n", errmsg.data); @@ -1914,7 +1915,7 @@ do_witness_create(void) exit(ERR_BAD_CONFIG); } - log_info(_("Successfully connected to master.\n")); + log_info(_("successfully connected to master.\n")); r = test_ssh_connection(runtime_options.host, runtime_options.remote_user); if (r != 0) @@ -1922,8 +1923,8 @@ do_witness_create(void) PQExpBufferData errmsg; initPQExpBuffer(&errmsg); appendPQExpBuffer(&errmsg, - _("%s: unable to connect to remote host '%s' via SSH"), - progname, runtime_options.host); + _("unable to connect to remote host '%s' via SSH"), + runtime_options.host); log_err("%s\n", errmsg.data); create_event_record(masterconn, @@ -1941,8 +1942,8 @@ do_witness_create(void) PQExpBufferData errmsg; initPQExpBuffer(&errmsg); appendPQExpBuffer(&errmsg, - _("%s: ouldn't create witness server data directory (\"%s\")"), - progname, runtime_options.host); + _("unable to create witness server data directory (\"%s\")"), + runtime_options.host); log_err("%s\n", errmsg.data); create_event_record(masterconn, options.node, @@ -1967,12 +1968,12 @@ do_witness_create(void) options.pgctl_options, runtime_options.dest_dir, runtime_options.initdb_no_pwprompt ? "" : "-W ", runtime_options.superuser); - log_info("Initialize cluster for witness: %s.\n", script); + log_info(_("initializing cluster for witness: %s.\n"), script); r = system(script); if (r != 0) { - char *errmsg = "Unable to initialize cluster for witness server"; + char *errmsg = _("unable to initialize cluster for witness server"); log_err("%s\n", errmsg); create_event_record(masterconn, options.node, @@ -1994,8 +1995,7 @@ do_witness_create(void) PQExpBufferData errmsg; initPQExpBuffer(&errmsg); appendPQExpBuffer(&errmsg, - _("%s: could not open \"%s\" for adding extra config: %s\n"), - progname, + _("unable to open \"%s\" to add additional configuration items: %s\n"), buf, strerror(errno)); log_err("%s\n", errmsg.data); @@ -2031,11 +2031,11 @@ do_witness_create(void) sprintf(script, "%s %s -w -D %s start", make_pg_path("pg_ctl"), options.pgctl_options, runtime_options.dest_dir); - log_info(_("Start cluster for witness: %s"), script); + log_info(_("starting witness server: %s"), script); r = system(script); if (r != 0) { - char *errmsg = _("Unable to start cluster for witness server"); + char *errmsg = _("unable to start witness server"); log_err("%s\n", errmsg); create_event_record(masterconn, @@ -2055,12 +2055,12 @@ do_witness_create(void) sprintf(script, "%s -p %s --superuser --login -U %s %s", make_pg_path("createuser"), runtime_options.localport, runtime_options.superuser, runtime_options.username); - log_info("Create user for witness db: %s.\n", script); + log_info(_("creating user for witness db: %s.\n"), script); r = system(script); if (r != 0) { - char *errmsg = _("Unable to create user for witness server"); + char *errmsg = _("unable to create user for witness server"); log_err("%s\n", errmsg); create_event_record(masterconn, @@ -2080,7 +2080,7 @@ do_witness_create(void) sprintf(script, "%s -p %s -U %s --owner=%s %s", make_pg_path("createdb"), runtime_options.localport, runtime_options.superuser, runtime_options.username, runtime_options.dbname); - log_info("Create database for witness db: %s.\n", script); + log_info("creating database for witness db: %s.\n", script); r = system(script); if (r != 0) @@ -2104,7 +2104,7 @@ do_witness_create(void) if (success == false) { - char *errmsg = _("Unable to retrieve location of pg_hba.conf"); + char *errmsg = _("unable to retrieve location of pg_hba.conf"); log_err("%s\n", errmsg); create_event_record(masterconn, @@ -2120,7 +2120,7 @@ do_witness_create(void) master_hba_file, runtime_options.dest_dir, false, -1); if (r != 0) { - char *errmsg = _("Unable to copy pg_hba.conf from master"); + char *errmsg = _("unable to copy pg_hba.conf from master"); log_err("%s\n", errmsg); create_event_record(masterconn, @@ -2137,11 +2137,11 @@ do_witness_create(void) sprintf(script, "%s %s -w -D %s reload", make_pg_path("pg_ctl"), options.pgctl_options, runtime_options.dest_dir); - log_info(_("Reload cluster config for witness: %s"), script); + log_info(_("reloading witness server configuration: %s"), script); r = system(script); if (r != 0) { - char *errmsg = _("Unable reload witness server"); + char *errmsg = _("unable to reload witness server"); log_err("%s\n", errmsg); create_event_record(masterconn, @@ -2182,7 +2182,7 @@ do_witness_create(void) /* establish a connection to the witness, and create the schema */ witnessconn = establish_db_connection(options.conninfo, true); - log_info(_("Starting copy of configuration from master...\n")); + log_info(_("starting copy of configuration from master...\n")); if (!create_schema(witnessconn)) { @@ -2190,7 +2190,7 @@ do_witness_create(void) options.node, "witness_create", false, - "Unable to create schema on witness"); + _("unable to create schema on witness")); PQfinish(masterconn); PQfinish(witnessconn); exit(ERR_BAD_CONFIG); @@ -2203,7 +2203,7 @@ do_witness_create(void) options.node, "witness_create", false, - "Unable to copy configuration from master"); + _("Unable to copy configuration from master")); PQfinish(masterconn); PQfinish(witnessconn); exit(ERR_BAD_CONFIG); @@ -2213,13 +2213,15 @@ do_witness_create(void) if (runtime_options.username[0] && runtime_options.localport[0] && strcmp(runtime_options.username,"postgres")!=0 ) { sqlquery_snprintf(sqlquery, "ALTER ROLE %s NOSUPERUSER", runtime_options.username); - log_info("Drop superuser powers on user for witness db: %s.\n", sqlquery); + log_info(_("revoking superuser status on user %s: %s.\n"), + runtime_options.username, sqlquery); log_debug(_("witness create: %s\n"), sqlquery); res = PQexec(witnessconn, sqlquery); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - log_err(_("Cannot alter user privileges, %s\n"), + log_err(_("unable to alter user privileges for user %s: %s\n"), + runtime_options.username, PQerrorMessage(witnessconn)); PQfinish(masterconn); PQfinish(witnessconn); @@ -2243,7 +2245,7 @@ do_witness_create(void) PQfinish(masterconn); PQfinish(witnessconn); - log_notice(_("Configuration has been successfully copied to the witness\n")); + log_notice(_("configuration has been successfully copied to the witness\n")); } @@ -2315,7 +2317,7 @@ create_recovery_file(const char *data_dir) recovery_file = fopen(recovery_file_path, "w"); if (recovery_file == NULL) { - log_err(_("Unable to create recovery.conf file at '%s'\n"), recovery_file_path); + log_err(_("unable to create recovery.conf file at '%s'\n"), recovery_file_path); return false; } @@ -2364,7 +2366,7 @@ write_recovery_file_line(FILE *recovery_file, char *recovery_file_path, char *li { if (fputs(line, recovery_file) == EOF) { - log_err(_("Unable to write to recovery file at '%s'\n"), recovery_file_path); + log_err(_("unable to write to recovery file at '%s'\n"), recovery_file_path); fclose(recovery_file); return false; } @@ -2406,7 +2408,7 @@ test_ssh_connection(char *host, char *remote_user) } if (r != 0) - log_info(_("Can not connect to the remote host (%s)\n"), host); + log_info(_("unable to connect to remote host (%s)\n"), host); return r; } @@ -2494,12 +2496,12 @@ copy_remote_files(char *host, char *remote_user, char *remote_path, rsync_flags.data, host_string, remote_path, local_path); } - log_info(_("rsync command line: '%s'\n"), script); + log_info(_("rsync command line: '%s'\n"), script); r = system(script); if (r != 0) - log_err(_("Can't rsync from remote file (%s:%s)\n"), + log_err(_("unable to rsync from remote host (%s:%s)\n"), host_string, remote_path); return r; @@ -2547,7 +2549,7 @@ run_basebackup() termPQExpBuffer(¶ms); - log_info(_("Executing: '%s'\n"), script); + log_info(_("executing: '%s'\n"), script); /* * As of 9.4, pg_basebackup et al only ever return 0 or 1 @@ -2577,11 +2579,11 @@ check_parameters_for_action(const int action) if (runtime_options.host[0] || runtime_options.masterport[0] || runtime_options.username[0] || runtime_options.dbname[0]) { - error_list_append(_("You can't use connection parameters to the master when issuing a MASTER REGISTER command.")); + error_list_append(_("master connection parameters not required when executing MASTER REGISTER.")); } if (runtime_options.dest_dir[0]) { - error_list_append(_("You don't need a destination directory for MASTER REGISTER command")); + error_list_append(_("destination directory not required when executing MASTER REGISTER.")); } break; case STANDBY_REGISTER: @@ -2594,11 +2596,11 @@ check_parameters_for_action(const int action) if (runtime_options.host[0] || runtime_options.masterport[0] || runtime_options.username[0] || runtime_options.dbname[0]) { - error_list_append(_("You can't use connection parameters to the master when issuing a STANDBY REGISTER command.")); + error_list_append(_("master connection parameters not required when executing STANDBY REGISTER.")); } if (runtime_options.dest_dir[0]) { - error_list_append(_("You don't need a destination directory for STANDBY REGISTER command")); + error_list_append(_("destination directory not required when executing STANDBY REGISTER.")); } break; case STANDBY_PROMOTE: @@ -2612,11 +2614,11 @@ check_parameters_for_action(const int action) if (runtime_options.host[0] || runtime_options.masterport[0] || runtime_options.username[0] || runtime_options.dbname[0]) { - error_list_append(_("You can't use connection parameters to the master when issuing a STANDBY PROMOTE command.")); + error_list_append(_("master connection parameters not required when executing STANDBY PROMOTE.")); } if (runtime_options.dest_dir[0]) { - error_list_append(_("You don't need a destination directory for STANDBY PROMOTE command")); + error_list_append(_("destination directory not required when executing STANDBY PROMOTE.")); } break; case STANDBY_FOLLOW: @@ -2630,11 +2632,11 @@ check_parameters_for_action(const int action) if (runtime_options.host[0] || runtime_options.masterport[0] || runtime_options.username[0] || runtime_options.dbname[0]) { - error_list_append(_("You can't use connection parameters to the master when issuing a STANDBY FOLLOW command.")); + error_list_append(_("master connection parameters not required when executing STANDBY FOLLOW.")); } if (runtime_options.dest_dir[0]) { - error_list_append(_("You don't need a destination directory for STANDBY FOLLOW command")); + error_list_append(_("destination directory not required when executing STANDBY FOLLOW.")); } break; case STANDBY_CLONE: @@ -2649,8 +2651,7 @@ check_parameters_for_action(const int action) */ if (runtime_options.host == NULL) { - log_notice(_("You need to use connection parameters to " - "the master when issuing a STANDBY CLONE command.")); + log_notice(_("master connection parameters required when executing STANDBY CLONE.")); } need_a_node = false; break; @@ -2679,7 +2680,7 @@ create_schema(PGconn *conn) res = PQexec(conn, sqlquery); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - log_err(_("Cannot create the schema %s: %s\n"), + log_err(_("unable to create the schema %s: %s\n"), get_repmgr_schema(), PQerrorMessage(conn)); PQfinish(conn); exit(ERR_BAD_CONFIG); @@ -2700,7 +2701,7 @@ create_schema(PGconn *conn) res = PQexec(conn, sqlquery); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - fprintf(stderr, "Cannot create the function repmgr_update_last_updated: %s\n", + log_err(_("unable to create the function repmgr_update_last_updated: %s\n"), PQerrorMessage(conn)); return false; } @@ -2717,7 +2718,7 @@ create_schema(PGconn *conn) res = PQexec(conn, sqlquery); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - fprintf(stderr, "Cannot create the function repmgr_get_last_updated: %s\n", + log_err(_("unable to create the function repmgr_get_last_updated: %s\n"), PQerrorMessage(conn)); return false; } @@ -2743,7 +2744,7 @@ create_schema(PGconn *conn) res = PQexec(conn, sqlquery); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - log_err(_("Cannot create the table %s.repl_nodes: %s\n"), + log_err(_("unable to create table '%s.repl_nodes': %s\n"), get_repmgr_schema_quoted(conn), PQerrorMessage(conn)); PQfinish(conn); exit(ERR_BAD_CONFIG); @@ -2765,7 +2766,7 @@ create_schema(PGconn *conn) res = PQexec(conn, sqlquery); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - log_err(_("Cannot create the table %s.repl_monitor: %s\n"), + log_err(_("unable to create table '%s.repl_monitor': %s\n"), get_repmgr_schema_quoted(conn), PQerrorMessage(conn)); PQfinish(conn); exit(ERR_BAD_CONFIG); @@ -2799,7 +2800,7 @@ create_schema(PGconn *conn) res = PQexec(conn, sqlquery); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - log_err(_("Cannot create the view %s.repl_status: %s\n"), + log_err(_("unable to create view %s.repl_status: %s\n"), get_repmgr_schema_quoted(conn), PQerrorMessage(conn)); PQfinish(conn); exit(ERR_BAD_CONFIG); @@ -2816,7 +2817,7 @@ create_schema(PGconn *conn) res = PQexec(conn, sqlquery); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - log_err(_("Can't index table %s.repl_monitor: %s\n"), + log_err(_("unable to create index 'idx_repl_status_sort' on '%s.repl_monitor': %s\n"), get_repmgr_schema_quoted(conn), PQerrorMessage(conn)); PQfinish(conn); exit(ERR_BAD_CONFIG); @@ -2838,7 +2839,7 @@ create_schema(PGconn *conn) res = PQexec(conn, sqlquery); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { - log_err(_("Cannot create the table %s.repl_events: %s\n"), + log_err(_("unable to create table '%s.repl_events': %s\n"), get_repmgr_schema_quoted(conn), PQerrorMessage(conn)); PQfinish(conn); exit(ERR_BAD_CONFIG); @@ -2909,8 +2910,7 @@ write_primary_conninfo(char *line) } else if (require_password) { - log_err(_("%s: PGPASSWORD not set, but having one is required\n"), - progname); + log_err(_("password required but none provided and PGPASSWORD not set\n")); exit(ERR_BAD_PASSWORD); } @@ -2967,7 +2967,7 @@ check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char * if(server_version_num < MIN_SUPPORTED_VERSION_NUM) { if (server_version_num > 0) - log_err(_("%s needs %s to be PostgreSQL %s or better\n"), + log_err(_("%s requires %s to be PostgreSQL %s or later\n"), progname, server_type, MIN_SUPPORTED_VERSION @@ -3007,7 +3007,7 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error) if(server_version_num < 90300) { i = guc_set(conn, "wal_level", "=", "hot_standby"); - wal_error_message = "needs parameter 'wal_level' to be set to 'hot_standby'"; + wal_error_message = _("parameter 'wal_level' must be set to 'hot_standby'"); } else { @@ -3017,7 +3017,7 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error) }; int j = 0; - wal_error_message = "needs parameter 'wal_level' to be set to 'hot_standby' or 'logical'"; + wal_error_message = _("parameter 'wal_level' must be set to 'hot_standby' or 'logical'"); for(; j < 2; j++) { @@ -3032,9 +3032,9 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error) if (i == 0 || i == -1) { if (i == 0) - log_err(_("%s %s\n"), - progname, + log_err("%s\n", wal_error_message); + if(exit_on_error == true) { PQfinish(conn); @@ -3049,7 +3049,7 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error) /* Does the server support physical replication slots? */ if(server_version_num < 90400) { - log_err(_("Server version must be 9.4 or later to enable replication slots\n")); + log_err(_("server version must be 9.4 or later to enable replication slots\n")); if(exit_on_error == true) { @@ -3069,7 +3069,7 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error) if (i == 0) { log_err(_("parameter 'max_replication_slots' must be set to at least 1 to enable replication slots\n")); - + log_notice(_("HINT: 'max_replication_slots' should be set to at least the number of expected standbys\n")); if(exit_on_error == true) { PQfinish(conn); @@ -3094,8 +3094,8 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error) { if (i == 0) { - log_err(_("%s needs parameter 'wal_keep_segments' to be set to %s or greater (see the '-w' option or edit the postgresql.conf of the upstream server.)\n"), - progname, runtime_options.wal_keep_segments); + log_err(_("parameter 'wal_keep_segments' must be be set to %s or greater (see the '-w' option or edit the postgresql.conf of the upstream server.)\n"), + runtime_options.wal_keep_segments); if(server_version_num >= 90400) { log_notice(_("HINT: in PostgreSQL 9.4 and later, replication slots can be used, which " @@ -3119,8 +3119,8 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error) if (i == 0 || i == -1) { if (i == 0) - log_err(_("%s needs parameter 'archive_mode' to be set to 'on'\n"), - progname); + log_err(_("parameter 'archive_mode' must be set to 'on'\n")); + if(exit_on_error == true) { PQfinish(conn); @@ -3134,8 +3134,7 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error) if (i == 0 || i == -1) { if (i == 0) - log_err(_("%s needs parameter 'hot_standby' to be set to 'on'\n"), - progname); + log_err(_("parameter 'hot_standby' must be set to 'on'\n")); if(exit_on_error == true) { @@ -3150,8 +3149,10 @@ check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error) if (i == 0 || i == -1) { if (i == 0) - log_err(_("%s needs parameter 'max_wal_senders' to be set to be at least 1\n"), - progname); + { + log_err(_("parameter 'max_wal_senders' must be set to be at least 1\n")); + log_notice(_("HINT: 'max_wal_senders' should be set to at least the number of expected standbys\n")); + } if(exit_on_error == true) { @@ -3184,11 +3185,11 @@ do_check_upstream_config(void) values[2] = runtime_options.dbname; /* We need to connect to check configuration and start a backup */ - log_info(_("%s connecting to upstream server\n"), progname); + log_info(_("connecting to upstream server\n")); conn = establish_db_connection_by_params(keywords, values, true); /* Verify that upstream server is a supported server version */ - log_info(_("%s connected to upstream server, checking its state\n"), progname); + log_info(_("connected to upstream server, checking its state\n")); server_version_num = check_server_version(conn, "upstream server", false, NULL); config_ok = check_upstream_config(conn, server_version_num, false); @@ -3221,7 +3222,7 @@ error_list_append(char *error_message) if(cell == NULL) { - log_err(_("Unable to allocate memory. Terminating.\n")); + log_err(_("unable to allocate memory; terminating.\n")); exit(ERR_BAD_CONFIG); } diff --git a/repmgrd.c b/repmgrd.c index 383315da..3502f8e8 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -261,17 +261,17 @@ main(int argc, char **argv) maxlen_snprintf(repmgr_schema, "%s%s", DEFAULT_REPMGR_SCHEMA_PREFIX, local_options.cluster_name); - log_info(_("%s Connecting to database '%s'\n"), progname, + log_info(_("connecting to database '%s'\n"), local_options.conninfo); my_local_conn = establish_db_connection(local_options.conninfo, true); /* Verify that server is a supported version */ - log_info(_("%s connected to database, checking its state\n"), progname); + log_info(_("connected to database, checking its state\n")); server_version_num = get_server_version(my_local_conn, NULL); if(server_version_num < MIN_SUPPORTED_VERSION_NUM) { if (server_version_num > 0) - log_err(_("%s requires PostgreSQL %s or better\n"), + log_err(_("%s requires PostgreSQL %s or later\n"), progname, MIN_SUPPORTED_VERSION ); @@ -283,11 +283,11 @@ main(int argc, char **argv) if(node_info.node_id == -1) { - log_err(_("Node %i is not registered\n"), local_options.node); + log_err(_("node %i is not registered\n"), local_options.node); terminate(ERR_BAD_CONFIG); } - log_debug("Node id is %i, upstream is %i\n", node_info.node_id, node_info.upstream_node_id); + log_debug("node id is %i, upstream is %i\n", node_info.node_id, node_info.upstream_node_id); /* * MAIN LOOP This loops cycles at startup and once per failover and @@ -332,8 +332,7 @@ main(int argc, char **argv) startup_event_logged = true; } - log_info(_("%s Starting continuous primary connection check\n"), - progname); + log_info(_("starting continuous primary connection check\n")); /* * Check that primary is still alive, and standbies are @@ -399,8 +398,8 @@ main(int argc, char **argv) case STANDBY: /* We need the node id of the primary server as well as a connection to it */ - log_info(_("%s Connecting to primary for cluster '%s'\n"), - progname, local_options.cluster_name); + log_info(_("connecting to master for cluster '%s'\n"), + local_options.cluster_name); primary_conn = get_master_connection(my_local_conn, local_options.cluster_name, @@ -437,13 +436,11 @@ main(int argc, char **argv) */ if (node_info.type == WITNESS) { - log_info(_("%s Starting continuous witness node monitoring\n"), - progname); + log_info(_("starting continuous witness node monitoring\n")); } else if (node_info.type == STANDBY) { - log_info(_("%s Starting continuous standby node monitoring\n"), - progname); + log_info(_("starting continuous standby node monitoring\n")); } do @@ -480,11 +477,11 @@ main(int argc, char **argv) } while (!failover_done); break; default: - log_err(_("%s: Unrecognized mode for node %d\n"), progname, + log_err(_("unrecognized mode for node %d\n"), local_options.node); } - log_debug(_("end of main loop\n")); + log_debug(_("end of main loop\n")); // ZZZ failover_done = false; @@ -525,11 +522,11 @@ witness_monitor(void) if(connection_ok == false) { int connection_retries; - log_debug(_("Old primary node ID: %i\n"), primary_options.node); + log_debug(_("old primary node ID: %i\n"), primary_options.node); /* We need to wait a while for the new primary to be promoted */ log_info( - _("Waiting %i seconds for a new master to be promoted...\n"), + _("waiting %i seconds for a new master to be promoted...\n"), local_options.master_response_timeout ); @@ -539,7 +536,7 @@ witness_monitor(void) for (connection_retries = 0; connection_retries < local_options.reconnect_attempts; connection_retries++) { log_info( - _("Attempt %i of %i to determine new master...\n"), + _("attempt %i of %i to determine new master...\n"), connection_retries + 1, local_options.reconnect_attempts ); @@ -549,7 +546,7 @@ witness_monitor(void) if (PQstatus(primary_conn) != CONNECTION_OK) { log_warning( - _("Unable to determine a valid master server; waiting %i seconds to retry...\n"), + _("unable to determine a valid master server; waiting %i seconds to retry...\n"), local_options.reconnect_intvl ); PQfinish(primary_conn); @@ -557,7 +554,7 @@ witness_monitor(void) } else { - log_debug(_("New master found with node ID: %i\n"), primary_options.node); + log_debug(_("new master found with node ID: %i\n"), primary_options.node); connection_ok = true; /* @@ -575,7 +572,7 @@ witness_monitor(void) if(connection_ok == false) { - log_err(_("Unable to determine a valid master server, exiting...\n")); + log_err(_("unable to determine a valid master server, exiting...\n")); terminate(ERR_DB_CON); } @@ -632,9 +629,9 @@ witness_monitor(void) * Execute the query asynchronously, but don't check for a result. We will * check the result next time we pause for a monitor step. */ - log_debug("witness_monitor: %s\n", sqlquery); + log_debug("witness_monitor: %s\n", sqlquery); // ZZZ if (PQsendQuery(primary_conn, sqlquery) == 0) - log_warning(_("Query could not be sent to primary. %s\n"), + log_warning(_("query could not be sent to master: %s\n"), PQerrorMessage(primary_conn)); } @@ -680,7 +677,7 @@ standby_monitor(void) if (!check_connection(my_local_conn, "standby")) { set_local_node_failed(); - log_err(_("Failed to connect to local node, exiting!\n")); + log_err(_("failed to connect to local node, terminating!\n")); terminate(1); } @@ -712,7 +709,7 @@ standby_monitor(void) if (local_options.failover == MANUAL_FAILOVER) { - log_err(_("We couldn't reconnect to %s. Now checking if another node has been promoted.\n"), type); + log_err(_("Unable to reconnect to %s. Now checking if another node has been promoted.\n"), type); for (connection_retries = 0; connection_retries < local_options.reconnect_attempts; connection_retries++) { @@ -724,14 +721,14 @@ standby_monitor(void) * Connected, we can continue the process so break the * loop */ - log_err(_("Connected to node %d, continue monitoring.\n"), + log_err(_("connected to node %d, continuing monitoring.\n"), primary_options.node); break; } else { log_err( - _("We haven't found a new master, waiting %i seconds before retry...\n"), + _("no new master found, waiting %i seconds before retry...\n"), local_options.retry_promote_interval_secs ); @@ -741,7 +738,8 @@ standby_monitor(void) if (PQstatus(primary_conn) != CONNECTION_OK) { - log_err(_("We couldn't reconnect for long enough, exiting...\n")); + log_err(_("Unable to reconnet to master after %i attempts, terminating...\n"), + local_options.reconnect_attempts); terminate(ERR_DB_CON); } } @@ -760,18 +758,18 @@ standby_monitor(void) if(upstream_node.type == PRIMARY) { - log_debug(_("Primary node %i failure detected; attempting to promote a standby\n"), + log_debug(_("failure detected on master node (%i); attempting to promote a standby\n"), node_info.upstream_node_id); do_primary_failover(); } else { - log_debug(_("Failure on upstream node %i detected; attempting to reconnect to new upstream node\n"), + log_debug(_("failure detected on upstream node %i; attempting to reconnect to new upstream node\n"), node_info.upstream_node_id); if(!do_upstream_standby_failover(upstream_node)) { - log_err(_("Unable to reconnect to new upstream node,terminating...\n")); + log_err(_("unable to reconnect to new upstream node, terminating...\n")); terminate(1); } } @@ -805,7 +803,7 @@ standby_monitor(void) break; case -1: - log_err(_("Standby node disappeared, trying to reconnect...\n")); + log_err(_("standby node has disappeared, trying to reconnect...\n")); did_retry = true; if (!check_connection(my_local_conn, "standby")) @@ -820,7 +818,7 @@ standby_monitor(void) if (did_retry) { - log_info(_("standby connection got back up again!\n")); + log_info(_("standby connection recovered!\n")); } /* Fast path for the case where no history is requested */ @@ -855,7 +853,7 @@ standby_monitor(void) if(PQntuples(res) == 0) { - log_err(_("standby_monitor(): no active primary found\n")); + log_err(_("standby_monitor(): no active master found\n")); PQclear(res); return; } @@ -865,7 +863,7 @@ standby_monitor(void) if(active_primary_id != primary_options.node) { - log_notice(_("Connecting to active cluster primary (node %i)...\n"), active_primary_id); \ + log_notice(_("connecting to active master (node %i)...\n"), active_primary_id); \ if(primary_conn != NULL) { PQfinish(primary_conn); @@ -950,7 +948,7 @@ standby_monitor(void) */ log_debug("standby_monitor: %s\n", sqlquery); if (PQsendQuery(primary_conn, sqlquery) == 0) - log_warning(_("Query could not be sent to primary. %s\n"), + log_warning(_("query could not be sent to primary. %s\n"), PQerrorMessage(primary_conn)); } @@ -1010,7 +1008,7 @@ do_primary_failover(void) res = PQexec(my_local_conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Unable to retrieve node records: %s\n"), PQerrorMessage(my_local_conn)); + log_err(_("unable to retrieve node records: %s\n"), PQerrorMessage(my_local_conn)); PQclear(res); PQfinish(my_local_conn); terminate(ERR_DB_QUERY); @@ -1020,7 +1018,7 @@ do_primary_failover(void) * total nodes that are registered */ total_nodes = PQntuples(res); - log_debug(_("%s: there are %d nodes registered\n"), progname, total_nodes); + log_debug(_("there are %d nodes registered\n"), total_nodes); /* * Build an array with the nodes and indicate which ones are visible and @@ -1052,8 +1050,8 @@ do_primary_failover(void) nodes[i].xlog_location = InvalidXLogRecPtr; - log_debug(_("%s: node=%d conninfo=\"%s\" type=%s\n"), - progname, nodes[i].node_id, nodes[i].conninfo_str, + log_debug(_("node=%d conninfo=\"%s\" type=%s\n"), + nodes[i].node_id, nodes[i].conninfo_str, PQgetvalue(res, i, 2)); node_conn = establish_db_connection(nodes[i].conninfo_str, false); @@ -1074,7 +1072,7 @@ do_primary_failover(void) } PQclear(res); - log_debug(_("Total nodes counted: registered=%d, visible=%d\n"), + log_debug(_("total nodes counted: registered=%d, visible=%d\n"), total_nodes, visible_nodes); /* @@ -1083,9 +1081,9 @@ do_primary_failover(void) */ if (visible_nodes < (total_nodes / 2.0)) { - log_err(_("Can't reach most of the nodes.\n" + log_err(_("Unable to reach most of the nodes.\n" "Let the other standby servers decide which one will be the primary.\n" - "Manual action will be needed to re-add this node to the cluster.\n")); + "Manual action will be needed to re-add this node to the cluster.\n")); terminate(ERR_FAILOVER_FAIL); } @@ -1123,9 +1121,9 @@ do_primary_failover(void) res = PQexec(node_conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_info(_("Can't get node's last standby location: %s\n"), + log_info(_("unable to retrieve node's last standby location: %s\n"), PQerrorMessage(node_conn)); - log_info(_("Connection details: %s\n"), nodes[i].conninfo_str); + log_debug(_("connection details: %s\n"), nodes[i].conninfo_str); PQclear(res); PQfinish(node_conn); terminate(ERR_FAILOVER_FAIL); @@ -1141,7 +1139,7 @@ do_primary_failover(void) /* If position is 0/0, error */ if(xlog_recptr == InvalidXLogRecPtr) { - log_info(_("InvalidXLogRecPtr detected on standby node %i\n"), nodes[i].node_id); + log_err(_("InvalidXLogRecPtr detected on standby node %i\n"), nodes[i].node_id); terminate(ERR_FAILOVER_FAIL); } @@ -1168,7 +1166,7 @@ do_primary_failover(void) /* Wait for each node to come up and report a valid LSN */ for (i = 0; i < total_nodes; i++) { - log_debug(_("is_ready check for node %i\n"), nodes[i].node_id); + log_debug(_("is_ready check for node %i\n"), nodes[i].node_id); // ZZZ /* * ensure witness server is marked as ready, and skip * LSN check @@ -1238,10 +1236,10 @@ do_primary_failover(void) if(*PQgetvalue(res, 0, 0) == '\0') { log_crit( - _("Unable to obtain LSN from node %i"), nodes[i].node_id + _("unable to obtain LSN from node %i"), nodes[i].node_id ); log_info( - _("Please check that 'shared_preload_libraries=repmgr_funcs' is set\n") + _("please check that 'shared_preload_libraries=repmgr_funcs' is set in postgresql.conf\n") ); PQclear(res); @@ -1253,13 +1251,13 @@ do_primary_failover(void) * Very unlikely to happen; in the absence of any better * strategy keep checking */ - log_warning(_("Unable to parse LSN \"%s\"\n"), + log_warning(_("unable to parse LSN \"%s\"\n"), PQgetvalue(res, 0, 0)); } else { log_debug( - _("Invalid LSN returned from node %i: '%s'\n"), + _("invalid LSN returned from node %i: '%s'\n"), nodes[i].node_id, PQgetvalue(res, 0, 0) ); @@ -1332,8 +1330,7 @@ do_primary_failover(void) /* Terminate if no candidate found */ if (!candidate_found) { - log_err(_("%s: No suitable candidate for promotion found; terminating.\n"), - progname); + log_err(_("no suitable candidate for promotion found; terminating.\n")); terminate(ERR_FAILOVER_FAIL); } @@ -1347,8 +1344,8 @@ do_primary_failover(void) sleep(5); if (verbose) - log_info(_("%s: This node is the best candidate to be the new primary, promoting...\n"), - progname); + log_info(_("this node is the best candidate to be the new master, promoting...\n")); + log_debug(_("promote command is: \"%s\"\n"), local_options.promote_command); @@ -1360,8 +1357,7 @@ do_primary_failover(void) r = system(local_options.promote_command); if (r != 0) { - log_err(_("%s: promote command failed. You could check and try it manually.\n"), - progname); + log_err(_("promote command failed. You could check and try it manually.\n")); /* * At this point there's no valid primary we can write to, @@ -1378,7 +1374,7 @@ do_primary_failover(void) if(update_node_record_set_primary(my_local_conn, node_info.node_id, failed_primary.node_id) == false) { appendPQExpBuffer(&event_details, - _("Unable to update node record for node %i (promoted to master following failure of node %i)"), + _("unable to update node record for node %i (promoted to master following failure of node %i)"), node_info.node_id, failed_primary.node_id); @@ -1395,7 +1391,7 @@ do_primary_failover(void) node_info = get_node_info(my_local_conn, local_options.cluster_name, local_options.node); appendPQExpBuffer(&event_details, - _("Node %i promoted to master; old master %i marked as failed"), + _("node %i promoted to master; old master %i marked as failed"), node_info.node_id, failed_primary.node_id); @@ -1417,8 +1413,8 @@ do_primary_failover(void) sleep(10); if (verbose) - log_info(_("%s: Node %d is the best candidate to be the new primary, we should follow it...\n"), - progname, best_candidate.node_id); + log_info(_("node %d is the best candidate to be the new primary, we should follow it...\n"), + best_candidate.node_id); log_debug(_("follow command is: \"%s\"\n"), local_options.follow_command); /* @@ -1462,8 +1458,7 @@ do_primary_failover(void) r = system(local_options.follow_command); if (r != 0) { - log_err(_("%s: follow command failed. You could check and try it manually.\n"), - progname); + log_err(_("follow command failed. You could check and try it manually.\n")); terminate(ERR_BAD_CONFIG); } @@ -1555,14 +1550,14 @@ do_upstream_standby_failover(t_node_info upstream_node) if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Unable to query cluster primary: %s\n"), PQerrorMessage(primary_conn)); + log_err(_("unable to query cluster master: %s\n"), PQerrorMessage(primary_conn)); PQclear(res); return false; } if(PQntuples(res) == 0) { - log_err(_("No node with id %i found"), upstream_node_id); + log_err(_("no node with id %i found"), upstream_node_id); PQclear(res); return false; } @@ -1580,7 +1575,7 @@ do_upstream_standby_failover(t_node_info upstream_node) */ if(strcmp(PQgetvalue(res, 0, 4), "primary") == 0) { - log_err(_("Unable to find active upstream node\n")); + log_err(_("unable to find active upstream node\n")); PQclear(res); return false; } @@ -1591,7 +1586,7 @@ do_upstream_standby_failover(t_node_info upstream_node) { upstream_node_id = atoi(PQgetvalue(res, 0, 0)); - log_notice(_("Found active upstream node with id %i\n"), upstream_node_id); + log_notice(_("found active upstream node with id %i\n"), upstream_node_id); PQclear(res); break; } @@ -1608,8 +1603,7 @@ do_upstream_standby_failover(t_node_info upstream_node) if (r != 0) { // ZZZ fail - log_err(_("%s: follow command failed. You could check and try it manually.\n"), - progname); + log_err(_("follow command failed. You could check and try it manually.\n")); terminate(ERR_BAD_CONFIG); } @@ -1639,8 +1633,7 @@ check_connection(PGconn *conn, const char *type) { if (!is_pgup(conn, local_options.master_response_timeout)) { - log_warning(_("%s: Connection to %s has been lost, trying to recover... %i seconds before failover decision\n"), - progname, + log_warning(_("connection to %s has been lost, trying to recover... %i seconds before failover decision\n"), type, (local_options.reconnect_intvl * (local_options.reconnect_attempts - connection_retries))); /* wait local_options.reconnect_intvl seconds between retries */ @@ -1650,8 +1643,7 @@ check_connection(PGconn *conn, const char *type) { if (connection_retries > 0) { - log_info(_("%s: Connection to %s has been restored.\n"), - progname, type); + log_info(_("connection to %s has been restored.\n"), type); } return true; } @@ -1659,8 +1651,7 @@ check_connection(PGconn *conn, const char *type) if (!is_pgup(conn, local_options.master_response_timeout)) { - log_err(_("%s: Unable to reconnect to %s after %i seconds...\n"), - progname, + log_err(_("unable to reconnect to %s after %i seconds...\n"), type, local_options.master_response_timeout ); @@ -1710,7 +1701,7 @@ set_local_node_failed(void) res = PQexec(primary_conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { - log_err(_("Unable to obtain active primary record: %s\n"), + log_err(_("unable to obtain record for active master: %s\n"), PQerrorMessage(primary_conn)); return false; @@ -1718,7 +1709,7 @@ set_local_node_failed(void) if(!PQntuples(res)) { - log_err(_("No active primary record found\n")); + log_err(_("no active master record found\n")); return false; } @@ -1728,18 +1719,18 @@ set_local_node_failed(void) if(active_primary_node_id != primary_options.node) { - log_notice(_("Current active primary is %i; attempting to connect\n"), + log_notice(_("current active master is %i; attempting to connect\n"), active_primary_node_id); PQfinish(primary_conn); primary_conn = establish_db_connection(primary_conninfo, false); if(PQstatus(primary_conn) != CONNECTION_OK) { - log_err(_("Unable to connect to active primary\n")); + log_err(_("unable to connect to active master\n")); return false; } - log_notice(_("Connection to new primary was successful\n")); + log_notice(_("Connection to new master was successful\n")); } @@ -1756,14 +1747,14 @@ set_local_node_failed(void) res = PQexec(primary_conn, sqlquery); if (PQresultStatus(res) != PGRES_COMMAND_OK) { - log_err(_("Unable to set local node %i as inactive on primary: %s\n"), + log_err(_("unable to set local node %i as inactive on primary: %s\n"), node_info.node_id, PQerrorMessage(primary_conn)); return false; } - log_notice(_("Marking this node (%i) as inactive on primary\n"), node_info.node_id); + log_notice(_("marking this node (%i) as inactive on primary\n"), node_info.node_id); return true; } @@ -1774,8 +1765,8 @@ check_cluster_configuration(PGconn *conn) PGresult *res; char sqlquery[QUERY_STR_LEN]; - log_info(_("%s Checking cluster configuration with schema '%s'\n"), - progname, get_repmgr_schema()); + log_info(_("checking cluster configuration with schema '%s'\n"), get_repmgr_schema()); + sqlquery_snprintf(sqlquery, "SELECT oid FROM pg_class " " WHERE oid = '%s.repl_nodes'::regclass ", @@ -1797,7 +1788,7 @@ check_cluster_configuration(PGconn *conn) */ if (PQntuples(res) == 0) { - log_err(_("The replication cluster is not configured\n")); + log_err(_("the replication cluster is not configured\n")); PQclear(res); terminate(ERR_BAD_CONFIG); } @@ -1814,8 +1805,8 @@ check_node_configuration(void) /* * Check if this node has an entry in `repl_nodes` */ - log_info(_("%s Checking node %d in cluster '%s'\n"), - progname, local_options.node, local_options.cluster_name); + log_info(_("checking node %d in cluster '%s'\n"), + local_options.node, local_options.cluster_name); sqlquery_snprintf(sqlquery, "SELECT COUNT(*) " @@ -1850,8 +1841,8 @@ check_node_configuration(void) } /* Adding the node */ - log_info(_("%s Adding node %d to cluster '%s'\n"), - progname, local_options.node, local_options.cluster_name); + log_info(_("adding node %d to cluster '%s'\n"), + local_options.node, local_options.cluster_name); sqlquery_snprintf(sqlquery, "INSERT INTO %s.repl_nodes" " (id, cluster, name, conninfo, priority, witness) " @@ -1864,7 +1855,7 @@ check_node_configuration(void) if (!PQexec(primary_conn, sqlquery)) { - log_err(_("Cannot insert node details, %s\n"), + log_err(_("unable to insert node details, %s\n"), PQerrorMessage(primary_conn)); terminate(ERR_BAD_CONFIG); } @@ -1893,7 +1884,7 @@ lsn_to_xlogrecptr(char *lsn, bool *format_ok) { if(format_ok != NULL) *format_ok = false; - log_err(_("wrong log location format: %s\n"), lsn); + log_err(_("incorrect log location format: %s\n"), lsn); return 0; }