Compare commits

..

33 Commits

Author SHA1 Message Date
Jaime Casanova
e479ef4bd1 Add "--checksum" in rsync when using "--force"
If the user don't put that option in rsync_options using of "--force"
could be unsafe.
While the probability of failures because of this are low they aren't
zero.
2015-02-10 20:44:34 -05:00
Jaime Casanova
6390a41953 Options -F -I -v doesn't accept arguments, which means that on
getopt_long shouldn't be marked with the colon (:) character.

This has been wrong since day one, so backpatching all the way until
1.1
2013-01-13 16:40:08 -05:00
Jaime Casanova
d7d91e1c12 Formatting using astyle 2012-12-11 11:54:35 -05:00
Jaime Casanova
d5ec394c54 Make repmgr compatible with FreeBSD.
We need to add an #include and make it use a different path for the
"true" binary.

Maybe we need to make this changes for all BSD systems but having no
evidence of that i prefer to make this only for systems with __FreeBSD__
2012-09-15 17:44:03 -05:00
Jaime Casanova
f6093386a8 When we have more command-line arguments than we should have we
need to show that last value and we should use only optind for that
instead of optind+1
2012-09-15 17:41:42 -05:00
Jaime Casanova
efd50f11ac Fix HISTORY to show from newest to oldest 2012-07-27 11:30:35 -05:00
Jaime Casanova
45a39084ed Prepare release notes for release 2012-07-21 11:56:00 -05:00
Jaime Casanova
94c73a016f Add a release note that was missing 2012-07-05 09:36:42 -05:00
Jaime Casanova
be5cbe4ddd Improve the version message to actually show the repmgr version not
only postgresql's one
2012-06-25 22:53:16 -05:00
Jaime Casanova
30d35d5b4c Names on history file are without surnames when they are well-known
so, keep it that way
2012-06-13 00:48:34 -05:00
Jaime Casanova
fa889a11ac Remove now finished TODO item about having a sanity check for ssh 2012-06-13 00:43:00 -05:00
Jaime Casanova
f4087d0a32 Add a \n in a message 2012-06-12 23:41:31 -05:00
Jaime Casanova
a55d7a4bd3 getMasterConnection() cannot avoid checking the same node that asks
to find the master.
This was a micro optimization based on the fact that all commands
that needed to detect the master were executed from the standby
but now that we have CLUSTER level commands that is not true anymore
2012-06-12 23:23:49 -05:00
Jaime Casanova
5d8cf6abe0 Allow repmgr to obtain tablespace's locations from pg 9.2 and later
in which we no longer have a spclocation column in pg_tablespaces
2012-06-12 10:49:23 -05:00
Jaime Casanova
9caa243354 Moving the 'Starting backup' message to a better place 2012-06-12 09:44:06 -05:00
Jaime Casanova
6880483947 STANDBY CLONE should be run by a SUPERUSER, otherwise we won't be able
to retrieve data_directory and the other parameters we need by
querying the database.
2012-06-12 09:37:03 -05:00
Jaime Casanova
3d89fdadab Fix a typo in a message 2012-06-12 09:28:27 -05:00
Cédric Villemain
6e9e4e05ae Add test_ssh_connection
The feature was written by Jaime and reworked by me to fix
https://github.com/greg2ndQuadrant/repmgr/issues/5
2012-05-09 15:24:38 -05:00
Jaime Casanova
17a160e970 Correct credits 2012-05-09 14:59:00 -05:00
Jaime Casanova
e0e01aa9db Add Carlo to CREDITS 2012-04-27 02:09:48 -05:00
Jaime Casanova
b09eff9f76 Avoid the possibility of a double free. Fix by Carlo Ascani 2012-04-27 02:08:40 -05:00
Jaime Casanova
3c5d82b9ef Complete CREDITS and HISTORY for release 2012-04-27 02:07:42 -05:00
Jaime Casanova
257dbc4f42 Cleanup of patch that introduces write_primary_conninfo() 2012-04-27 01:23:37 -05:00
Jaime Casanova
2a64099163 Added function "write_primary_conninfo" which now adds the username to the primary_conninfo parameter in recovery.conf 2012-04-27 01:10:24 -05:00
Jaime Casanova
41c05bea7b Fix CLUSTER SHOW, that i have broken 2012-04-26 13:58:39 -05:00
Jaime Casanova
7d76d86e19 Add debug information to CLUSTER SHOW y CLUSTER CLEANUP 2012-04-26 13:31:54 -05:00
Jaime Casanova
36d5b5bc24 I need a local connection to get the master of the cluster 2012-04-26 12:29:04 -05:00
Jaime Casanova
c543402d65 A typo that escaped to my previous review 2012-04-26 12:23:24 -05:00
Jaime Casanova
d0959b953e Cleanup patch about CLUSTER CLEANUP 2012-04-26 12:21:41 -05:00
Jaime Casanova
0660bded0b Fix a switch in which a "break" was missing that makes always that --force option was used end up in the default section and error. 2012-04-19 12:21:49 -05:00
Jaime Casanova
209a0c64d2 Add documentation about both CLUSTER SHOW and CLUSTER CLEANUP commands 2012-04-14 21:56:58 -05:00
Jaime Casanova
fd76ec6283 Adds a CLUSTER CLEANUP command to clean monitor's history,
also include a --keep-history (-k) option to indicate how many
days of history to keep
2012-04-14 21:34:06 -05:00
Jaime Casanova
7d579cf71f Add CLUSTER SHOW command to show the current nodes configured 2012-04-14 21:11:51 -05:00
11 changed files with 342 additions and 95 deletions

View File

@@ -10,3 +10,5 @@ Hannu Krosing <hannu@2ndQuadrant.com>
Cédric Villemain <cedric@2ndquadrant.com>
Charles Duffy <charles@dyfis.net>
Daniel Farina <daniel@heroku.com>
Marco Nenciarini <marco.nenciarini@2ndquadrant.it>
Carlo Ascani <carlo.ascani@2ndquadrant.it>

32
HISTORY
View File

@@ -1,5 +1,21 @@
1.0.0 2010-12-05
First public release
1.2.0 2012-07-27
Test ssh connection before trying to rsync (Cédric)
Add CLUSTER SHOW command (Carlo)
Add CLUSTER CLEANUP command (Jaime)
Add function write_primary_conninfo (Marco)
Teach repmgr how to get tablespace's location in different pg version (Jaime)
Improve version message (Carlo)
1.1.1 2012-04-18
Add --ignore-rsync-warning (Cédric)
Add strnlen for compatibility with OS X (Greg)
Improve performance of repl_status view (Jaime)
Remove last argument from log_err (Jaime, Reported by Jeroen Dekkers)
Complete documentation about possible error conditions (Jaime)
Document how to clean history (Jaime)
1.1.0 2011-03-09
Make options -U, -R and -p not mandatory (Jaime)
1.1.0b1 2011-02-24
Fix missing "--force" option in help (Greg Smith)
@@ -28,13 +44,5 @@
Map old verbose flag into a useful setting for the new logger (Greg)
Document repmgrd startup restrictions and log info about them (Greg)
1.1.0 2011-03-09
Make options -U, -R and -p not mandatory (Jaime)
1.1.1 2012-04-18
Add --ignore-rsync-warning (Cédric)
Add strnlen for compatibility with OS X (Greg)
Improve performance of repl_status view (Jaime)
Remove last argument from log_err (Jaime, Reported by Jeroen Dekkers)
Complete documentation about possible error conditions (Jaime)
Document how to clean history (Jaime)
1.0.0 2010-12-05
First public release

View File

@@ -862,6 +862,7 @@ The output from this program looks like this::
Usage:
repmgr [OPTIONS] master {register}
repmgr [OPTIONS] standby {register|clone|promote|follow}
repmgr [OPTIONS] cluster {show|cleanup}
General options:
--help show this help, then exit
@@ -881,6 +882,7 @@ The output from this program looks like this::
-w, --wal-keep-segments=VALUE minimum value for the GUC wal_keep_segments (default: 5000)
-F, --force force potentially dangerous operations to happen
-I, --ignore-rsync-warning Ignore partial transfert warning
-k, --keep-history keeps indicated number of days of history
repmgr performs some tasks like clone a node, promote it or making follow another node and then exits.
COMMANDS:
@@ -889,6 +891,8 @@ The output from this program looks like this::
standby clone [node] - allows creation of a new standby
standby promote - allows manual promotion of a specific standby into a new master in the event of a failover
standby follow - allows the standby to re-point itself to a new master
cluster show - print node informations
cluster cleanup - cleans monitor's history
The ``--verbose`` option can be useful in troubleshooting issues with
the program.
@@ -959,6 +963,26 @@ its port if is different from the default one.
./repmgr standby follow
* cluster show
* Shows the role (standby/master) and connection string for all nodes configured
in the cluster or "FAILED" if the node doesn't respond. This allow us to know
which nodes are alive and which one needs attention and to have a notion of the
structure of clusters we just have access to. Example::
./repmgr cluster show
* cluster cleanup
* Cleans the monitor's history from repmgr tables. This avoids the repl_monitor table
to grow excesivelly which in turns affects repl_status view performance, also
keeps controlled the space in disk used by repmgr. This command can be used manually
or in a cron to make it periodically.
There is also a --keep-history (-k) option to indicate how many days of history we
want to keep, so the command will clean up history older than "keep-history" days. Example::
./repmgr cluster cleanup -k 2
repmgrd Daemon
--------------

7
TODO
View File

@@ -12,10 +12,3 @@ Known issues in repmgr
* After running repmgrd as a regular foreground application, hitting
control-C causes the program to crash.
Planned feature improvements
============================
* Before running ``pg_start_backup()``, a sanity check that there is a
a working ssh connection to the destination would help find
configuration errors before disturbing the database.

View File

@@ -129,10 +129,10 @@ mkdir_p(char *path, mode_t omode)
{
struct stat sb;
mode_t numask,
oumask;
oumask;
int first,
last,
retval;
last,
retval;
char *p;
p = path;

View File

@@ -202,7 +202,7 @@ get_cluster_size(PGconn *conn)
* connection string is placed there.
*/
PGconn *
getMasterConnection(PGconn *standby_conn, int id, char *cluster,
getMasterConnection(PGconn *standby_conn, char *cluster,
int *master_id, char *master_conninfo_out)
{
PGconn *master_conn = NULL;
@@ -242,8 +242,8 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster,
cluster);
sqlquery_snprintf(sqlquery, "SELECT * FROM %s.repl_nodes "
" WHERE cluster = '%s' and id <> %d",
schema_quoted, cluster, id);
" WHERE cluster = '%s'",
schema_quoted, cluster);
res1 = PQexec(standby_conn, sqlquery);
if (PQresultStatus(res1) != PGRES_TUPLES_OK)

View File

@@ -31,7 +31,7 @@ char *pg_version(PGconn *conn, char* major_version);
bool guc_setted(PGconn *conn, const char *parameter, const char *op,
const char *value);
const char *get_cluster_size(PGconn *conn);
PGconn *getMasterConnection(PGconn *standby_conn, int id, char *cluster,
PGconn *getMasterConnection(PGconn *standby_conn, char *cluster,
int *master_id, char *master_conninfo_out);
#endif

340
repmgr.c
View File

@@ -7,7 +7,7 @@
*
* Commands implemented are.
* MASTER REGISTER, STANDBY REGISTER, STANDBY CLONE, STANDBY FOLLOW,
* STANDBY PROMOTE
* STANDBY PROMOTE, CLUSTER SHOW, CLUSTER CLEANUP
*
* 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
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
@@ -35,6 +36,7 @@
#include "config.h"
#include "check_dir.h"
#include "strutil.h"
#include "version.h"
#define RECOVERY_FILE "recovery.conf"
#define RECOVERY_DONE_FILE "recovery.done"
@@ -45,19 +47,25 @@
#define STANDBY_CLONE 3
#define STANDBY_PROMOTE 4
#define STANDBY_FOLLOW 5
#define CLUSTER_SHOW 6
#define CLUSTER_CLEANUP 7
static void help(const char *progname);
static bool create_recovery_file(const char *data_dir, char *master_conninfo);
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 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 help(const char* progname);
static void do_cluster_show(void);
static void do_cluster_cleanup(void);
static void usage(void);
/* Global variables */
@@ -71,7 +79,7 @@ bool need_a_node = true;
bool require_password = false;
/* Initialization of runtime options */
t_runtime_options runtime_options = { "", "", "", "", "", "", DEFAULT_WAL_KEEP_SEGMENTS, false, false, false, "" };
t_runtime_options runtime_options = { "", "", "", "", "", "", DEFAULT_WAL_KEEP_SEGMENTS, false, false, false, "", 0 };
t_configuration_options options = { "", -1, "", "", "" };
static char *server_mode = NULL;
@@ -90,6 +98,7 @@ main(int argc, char **argv)
{"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'},
{"ignore-rsync-warning", no_argument, NULL, 'I'},
{"verbose", no_argument, NULL, 'v'},
@@ -111,13 +120,13 @@ main(int argc, char **argv)
}
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
{
printf("%s (PostgreSQL) " PG_VERSION "\n", progname);
printf("%s %s (PostgreSQL %s)\n", progname, REPMGR_VERSION, PG_VERSION);
exit(SUCCESS);
}
}
while ((c = getopt_long(argc, argv, "d:h:p:U:D:f:R:w:F:I:v", long_options,
while ((c = getopt_long(argc, argv, "d:h:p:U:D:f:R:w:k:FIv", long_options,
&optindex)) != -1)
{
switch (c)
@@ -148,6 +157,12 @@ main(int argc, char **argv)
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;
@@ -166,7 +181,8 @@ main(int argc, char **argv)
/*
* Now we need to obtain the action, this comes in one of these forms:
* MASTER REGISTER |
* STANDBY {REGISTER | CLONE [node] | PROMOTE | FOLLOW [node]}
* STANDBY {REGISTER | CLONE [node] | PROMOTE | FOLLOW [node]} |
* CLUSTER {SHOW | CLEANUP}
*
* the node part is optional, if we receive it then we shouldn't
* have received a -h option
@@ -174,8 +190,8 @@ main(int argc, char **argv)
if (optind < argc)
{
server_mode = argv[optind++];
if (strcasecmp(server_mode, "STANDBY") != 0 &&
strcasecmp(server_mode, "MASTER") != 0)
if (strcasecmp(server_mode, "STANDBY") != 0 && strcasecmp(server_mode, "MASTER") != 0 &&
strcasecmp(server_mode, "CLUSTER") != 0 )
{
usage();
exit(ERR_BAD_CONFIG);
@@ -204,13 +220,21 @@ main(int argc, char **argv)
action = STANDBY_PROMOTE;
else if (strcasecmp(server_cmd, "FOLLOW") == 0)
action = STANDBY_FOLLOW;
else
else if (strcasecmp(server_mode, "CLUSTER") == 0)
{
usage();
exit(ERR_BAD_CONFIG);
if(strcasecmp(server_cmd, "SHOW") == 0)
action = CLUSTER_SHOW;
else if(strcasecmp(server_cmd, "CLEANUP") == 0)
action = CLUSTER_CLEANUP;
}
}
if (action == NO_ACTION)
{
usage();
exit(ERR_BAD_CONFIG);
}
/* For some actions we still can receive a last argument */
if (action == STANDBY_CLONE)
{
@@ -232,7 +256,7 @@ main(int argc, char **argv)
break;
default:
log_err(_("%s: too many command-line arguments (first extra is \"%s\")\n"),
progname, argv[optind + 1]);
progname, argv[optind]);
usage();
exit(ERR_BAD_CONFIG);
}
@@ -314,6 +338,12 @@ main(int argc, char **argv)
case STANDBY_FOLLOW:
do_standby_follow();
break;
case CLUSTER_SHOW:
do_cluster_show();
break;
case CLUSTER_CLEANUP:
do_cluster_cleanup();
break;
default:
usage();
exit(ERR_BAD_CONFIG);
@@ -323,6 +353,114 @@ main(int argc, char **argv)
return 0;
}
static void
do_cluster_show(void)
{
PGconn *conn;
PGconn *node_conn = NULL;
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 = establishDBConnection(options.conninfo, true);
sqlquery_snprintf(sqlquery, "SELECT conninfo FROM %s.repl_nodes;", repmgr_schema);
log_debug("cluster show: %s\n", sqlquery);
res = PQexec(conn, sqlquery);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_err(_("Can't get nodes informations, have you regitered them?\n%s\n"), PQerrorMessage(conn));
PQclear(res);
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
printf("Role | Connection String \n");
for (i = 0; i < PQntuples(res); i++)
{
node_conn = establishDBConnection(PQgetvalue(res, i, 0), false);
if (PQstatus(node_conn) != CONNECTION_OK)
strcpy(node_role, " FAILED");
else if (is_standby(node_conn))
strcpy(node_role, " standby");
else
strcpy(node_role, "* master");
printf("%-10s", node_role);
printf("| %s\n", PQgetvalue(res, i, 0));
PQfinish(node_conn);
}
PQclear(res);
PQfinish(conn);
}
static void
do_cluster_cleanup(void)
{
int master_id;
PGconn *conn;
PGconn *master_conn;
PGresult *res;
char sqlquery[QUERY_STR_LEN];
/* I need a connection to my local db to know what node is the master */
log_info(_("%s connecting to database\n"), progname);
conn = establishDBConnection(options.conninfo, true);
/* check if there is a master in this cluster */
log_info(_("%s connecting to master database\n"), progname);
master_conn = getMasterConnection(conn, options.cluster_name,
&master_id, NULL);
if (!master_conn)
{
log_err(_("cluster cleanup: cannot connect to master\n"));
PQfinish(conn);
exit(ERR_DB_CON);
}
/* I don't need a local connection anymore */
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);
}
log_debug("cluster cleanup: %s\n", sqlquery);
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);
log_debug("cluster cleanup: %s\n", sqlquery);
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)
{
@@ -477,8 +615,7 @@ do_master_register(void)
int id;
/* Ensure there isn't any other master already registered */
master_conn = getMasterConnection(conn, options.node,
options.cluster_name, &id,NULL);
master_conn = getMasterConnection(conn, options.cluster_name, &id,NULL);
if (master_conn != NULL)
{
PQfinish(master_conn);
@@ -597,7 +734,7 @@ do_standby_register(void)
/* check if there is a master in this cluster */
log_info(_("%s connecting to master database\n"), progname);
master_conn = getMasterConnection(conn, options.node, options.cluster_name,
master_conn = getMasterConnection(conn, options.cluster_name,
&master_id, NULL);
if (!master_conn)
{
@@ -804,10 +941,17 @@ do_standby_clone(void)
* Check if the tablespace locations exists and that we can write to
* them.
*/
sqlquery_snprintf(sqlquery,
"SELECT spclocation "
" FROM pg_tablespace "
"WHERE spcname NOT IN ('pg_default', 'pg_global')");
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);
@@ -861,6 +1005,7 @@ do_standby_clone(void)
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
break;
default:
/* Trouble accessing directory */
log_err(_("%s: could not access directory \"%s\": %s\n"),
@@ -871,7 +1016,14 @@ do_standby_clone(void)
}
}
log_notice("Starting backup...\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);
PQclear(res);
PQfinish(conn);
exit(ERR_DB_CON);
}
/* Get the data directory full path and the configuration files location */
sqlquery_snprintf(sqlquery,
@@ -887,6 +1039,16 @@ do_standby_clone(void)
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
/* 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);
PQclear(res);
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
for (i = 0; i < PQntuples(res); i++)
{
if (strcmp(PQgetvalue(res, i, 0), "data_directory") == 0)
@@ -902,6 +1064,8 @@ do_standby_clone(void)
}
PQclear(res);
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
@@ -993,10 +1157,17 @@ do_standby_clone(void)
* find and appropiate rsync option but besides we could someday make all
* these rsync happen concurrently
*/
sqlquery_snprintf(sqlquery,
"SELECT spclocation "
" FROM pg_tablespace "
" WHERE spcname NOT IN ('pg_default', 'pg_global')");
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)
@@ -1067,7 +1238,7 @@ stop_backup:
last_wal_segment = PQgetvalue(res, 0, 0);
/* don't show this message if rsync failed */
if (r == 0)
if (r == 0 && 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);
@@ -1150,7 +1321,7 @@ do_standby_promote(void)
}
/* we also need to check if there isn't any master already */
old_master_conn = getMasterConnection(conn, options.node, options.cluster_name,
old_master_conn = getMasterConnection(conn, options.cluster_name,
&old_master_id, NULL);
if (old_master_conn != NULL)
{
@@ -1254,8 +1425,7 @@ do_standby_follow(void)
/* we also need to check if there is any master in the cluster */
log_info(_("%s connecting to master database\n"), progname);
master_conn = getMasterConnection(conn, options.node,
options.cluster_name, &master_id,(char *) &master_conninfo);
master_conn = getMasterConnection(conn, options.cluster_name, &master_id,(char *) &master_conninfo);
if (master_conn == NULL)
{
PQfinish(conn);
@@ -1301,7 +1471,7 @@ do_standby_follow(void)
strncpy(runtime_options.masterport, PQport(master_conn), MAXLEN);
PQfinish(master_conn);
log_info(_("%s Changing standby's master"),progname);
log_info(_("%s Changing standby's master\n"),progname);
/* Get the data directory full path */
sqlquery_snprintf(sqlquery, "SELECT setting "
@@ -1351,6 +1521,7 @@ void help(const char *progname)
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"));
@@ -1367,6 +1538,7 @@ void help(const char *progname)
printf(_(" -w, --wal-keep-segments=VALUE minimum value for the GUC wal_keep_segments (default: 5000)\n"));
printf(_(" -F, --force force potentially dangerous operations to happen\n"));
printf(_(" -I, --ignore-rsync-warning Ignore partial transfert warning\n"));
printf(_(" -k, --keep-history=VALUE keeps indicated number of days of history\n"));
printf(_("\n%s performs some tasks like clone a node, promote it "), progname);
printf(_("or making follow another node and then exits.\n"));
@@ -1377,6 +1549,8 @@ void help(const char *progname)
printf(_(" standby promote - allows manual promotion of a specific standby into a "));
printf(_("new master in the event of a failover\n"));
printf(_(" standby follow - allows the standby to re-point itself to a new master\n"));
printf(_(" cluster show - print node informations\n"));
printf(_(" cluster cleanup - cleans monitor's history\n"));
}
@@ -1409,41 +1583,7 @@ create_recovery_file(const char *data_dir, char *master_conninfo)
return false;
}
maxlen_snprintf(line, "primary_conninfo = 'host=%s port=%s'\n", runtime_options.host,
(runtime_options.masterport[0]) ? runtime_options.masterport : "5432");
/*
* Template a password into the connection string in recovery.conf
* if a full connection string is not already provided.
*
* Sometimes this is passed by the user explicitly, and otherwise
* we try to get it into the environment.
*
* XXX: This is pretty dirty, at least push this up to the caller rather
* than hitting environment variables at this level.
*/
if (master_conninfo == NULL)
{
char *password = getenv("PGPASSWORD");
if (password != NULL)
{
maxlen_snprintf(line,
"primary_conninfo = 'host=%s port=%s password=%s'\n",
runtime_options.host,
(runtime_options.masterport[0]) ? runtime_options.masterport : "5432",
password);
}
else
{
if (require_password)
{
log_err(_("%s: PGPASSWORD not set, but having one is required\n"),
progname);
exit(ERR_BAD_PASSWORD);
}
}
}
write_primary_conninfo(line);
if (fputs(line, recovery_file) == EOF)
{
@@ -1458,6 +1598,31 @@ create_recovery_file(const char *data_dir, char *master_conninfo)
return true;
}
static int
test_ssh_connection(char *host, char *remote_user)
{
char script[MAXLEN];
int r;
/* On some OS, true is located in a different place than in Linux */
#ifdef __FreeBSD__
#define TRUEBIN_PATH "/usr/bin/true"
#else
#define TRUEBIN_PATH "/bin/true"
#endif
/* Check if we have ssh connectivity to host before trying to rsync */
if (!remote_user[0])
maxlen_snprintf(script, "ssh -o Batchmode=yes %s %s", host, TRUEBIN_PATH);
else
maxlen_snprintf(script, "ssh -o Batchmode=yes %s -l %s %s", host, remote_user, TRUEBIN_PATH);
log_debug(_("command is: %s"), script);
r = system(script);
if (r != 0)
log_info(_("Cannot connect to the remote host (%s)\n"), host);
return r;
}
static int
copy_remote_files(char *host, char *remote_user, char *remote_path,
@@ -1476,7 +1641,7 @@ copy_remote_files(char *host, char *remote_user, char *remote_path,
maxlen_snprintf(rsync_flags, "%s", options.rsync_options);
if (runtime_options.force)
strcat(rsync_flags, " --delete");
strcat(rsync_flags, " --delete --checksum");
if (!remote_user[0])
{
@@ -1652,7 +1817,52 @@ check_parameters_for_action(const int action)
}
need_a_node = false;
break;
case CLUSTER_SHOW:
/* allow all parameters to be supplied */
break;
case CLUSTER_CLEANUP:
/* allow all parameters to be supplied */
break;
}
return ok;
}
/* 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 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);
}
maxlen_snprintf(conn_buf, "port=%s%s%s%s",
(runtime_options.masterport[0]) ? runtime_options.masterport : "5432", host_buf, user_buf, password_buf);
maxlen_snprintf(line, "primary_conninfo = '%s'", conn_buf);
}

View File

@@ -59,6 +59,8 @@ typedef struct
char masterport[MAXLEN];
/* parameter used by CLUSTER CLEANUP */
int keep_history;
} t_runtime_options;
#endif

View File

@@ -30,6 +30,7 @@
#include "config.h"
#include "log.h"
#include "strutil.h"
#include "version.h"
#include "libpq/pqsignal.h"
@@ -116,7 +117,7 @@ main(int argc, char **argv)
}
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
{
printf("%s (PostgreSQL) " PG_VERSION "\n", progname);
printf("%s %s (PostgreSQL %s)\n", progname, REPMGR_VERSION, PG_VERSION);
exit(SUCCESS);
}
}
@@ -185,7 +186,7 @@ main(int argc, char **argv)
/* I need the id of the primary as well as a connection to it */
log_info(_("%s Connecting to primary for cluster '%s'\n"),
progname, local_options.cluster_name);
primaryConn = getMasterConnection(myLocalConn, local_options.node,
primaryConn = getMasterConnection(myLocalConn,
local_options.cluster_name,
&primary_options.node,NULL);
if (primaryConn == NULL)
@@ -269,7 +270,7 @@ MonitorExecute(void)
log_err(_("We couldn't reconnect to master. Now checking if another node has been promoted.\n"));
for (connection_retries = 0; connection_retries < 6; connection_retries++)
{
primaryConn = getMasterConnection(myLocalConn, local_options.node,
primaryConn = getMasterConnection(myLocalConn,
local_options.cluster_name, &primary_options.node,NULL);
if (PQstatus(primaryConn) == CONNECTION_OK)
{
@@ -456,7 +457,10 @@ checkNodeConfiguration(char *conninfo)
exit(ERR_BAD_CONFIG);
}
}
PQclear(res);
else
{
PQclear(res);
}
}

4
version.h Normal file
View File

@@ -0,0 +1,4 @@
#ifndef _VERSION_H_
#define _VERSION_H_
#define REPMGR_VERSION "1.2.0"
#endif