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;
}