Compare commits

..

35 Commits

Author SHA1 Message Date
Ian Barwick
47b7c4ce06 Update HISTORY for minor release 2.0.1 2014-07-16 11:00:58 +09:00
Ian Barwick
99ed9a065e Formatting fixes 2014-07-16 10:58:05 +09:00
Ian Barwick
a87d859e56 Correct year in specfile changelog 2014-07-16 09:58:51 +09:00
Ian Barwick
7350a8bf57 Fix code block formatting 2014-07-16 08:07:07 +09:00
Ian Barwick
75baed233b Convert QUICKSTART file to markdown format
Less effort for more consistent formatting (at least the way
github renders it).
2014-07-16 07:57:00 +09:00
Ian Barwick
5b9ac4585b Formatting fixes 2014-07-07 14:10:00 +09:00
Ian Barwick
2cbee90f35 Fix formatting 2014-07-07 11:51:10 +09:00
Ian Barwick
fa7d8df534 Add a "quickstart" guide
Provides a succinct overview of the steps needed to get repmgr
up and running as.
2014-07-07 11:39:26 +09:00
Ian Barwick
0cbd5d3933 Fix log messages in do_standby_promote()
Initial connection is to current standby, before attempting to
connect to old master.
2014-07-07 11:30:29 +09:00
Ian Barwick
a0e4c99ab4 Typo fixes 2014-07-07 11:10:32 +09:00
Ian Barwick
98c5215871 Change successful standby promotion message to log level 'NOTICE'
Was previously 'ERROR'.
2014-07-07 11:09:07 +09:00
Ian Barwick
e40b9db0a6 Properly specify rsync --exclude directories
Using '--exclude=dirname/*' to explicitly specify directories whose contents
should not be copied. This will result in empty directories being created
on the destination if they exist on the source, but that's not a problem as
they are needed anyway.

Previously the generated rsync command contained '--exclude=pg_log*', which
will break replication on 9.5 as the wildcard expansion prevents the
'pg_logical' directory from being copied.
2014-07-07 10:42:45 +09:00
Ian Barwick
54e62c3d65 Typo fixes and minor wording tweaks for clarity 2014-07-03 15:41:51 +09:00
Abhijit Menon-Sen
bfd482bebc Merge pull request #28 from Nexperteam/rhel-scripts
adapt makefile for RHEL + RHEL specific files
2014-06-26 22:55:56 +05:30
Abhijit Menon-Sen
6a0fc43086 Merge pull request #26 from Nexperteam/master
Makefile: create bindir before instal + force dir
2014-06-26 22:54:09 +05:30
Abhijit Menon-Sen
8f47111072 Merge pull request #31 from riegie/patch-1
Update README.rst
2014-06-26 22:51:52 +05:30
Riegie Godwin Jeyaranchen
0b5b3aaa4b Update README.rst
Fixing a grammar mistake.
2014-06-19 20:53:42 -04:00
Nathan Van Overloop
d8bba0de03 init script: make status call return proper return code 2014-06-06 15:47:33 +02:00
Nathan Van Overloop
73d352b2a2 adapt makefile for RHEL + RHEL specific files 2014-06-06 14:30:37 +02:00
brynhood
143aa57bb8 Makefile: create bindir before instal + force dir
in order to facilitate building of an rpm I've added an / to the end of the dirs.
2014-04-28 14:27:52 +02:00
Abhijit Menon-Sen
5b15fcff5c Merge pull request #24 from PriceChild/patch-1
Typo in example command.
2014-04-08 11:04:09 +05:30
PriceChild
4469de533e Typo in example command. 2014-04-01 16:31:33 +01:00
Christian Kruse
7c89a4d762 Merge pull request #20 from kjoe/master
debian init script and config file documentation fixes
2014-03-24 07:46:56 +01:00
József Kószó
b3c68dead8 debian init script and config file documentation fixes 2014-03-22 22:23:15 +01:00
József Kószó
b9ab9010c0 debian init script and config file documentation fixes 2014-03-22 22:13:33 +01:00
József Kószó
2a6c835a5a debian init script and config file documentation fixes 2014-03-21 14:18:07 +01:00
Christian Kruse
2d48d5aee4 fixing some documentation errors 2014-03-10 15:48:44 +01:00
Christian Kruse
653e11c2a7 basic min_recovery_apply_delay support 2014-03-10 15:41:38 +01:00
Christian Kruse
91c29fe2a2 removed old comment 2014-03-06 18:34:41 +01:00
Christian Kruse
573f1d3b2e no longer use global variable for SQL query buffer 2014-03-06 18:34:41 +01:00
Christian Kruse
0a6ff7faec removed no-longer used variable 2014-03-06 18:34:41 +01:00
Christian Kruse
98b1f8d28a rather big refactoring: use a naming scheme
In the past naming of functions, variables and such didn't really have a
naming scheme. Now they should have.
2014-03-06 18:34:40 +01:00
Christian Kruse
9eba986833 avoid usage of snprintf()
We have a nice little abstraction for snprintf with covering the case
that a string is too big for the target buffer – let's use that!
2014-03-06 18:34:40 +01:00
Christian Kruse
164cf9d08f completely avoid usage of strnlen() 2014-03-06 18:34:40 +01:00
Christian Kruse
d8b8bf0e2a pg_indent'ing all files… 2014-03-06 18:34:40 +01:00
7 changed files with 164 additions and 206 deletions

View File

@@ -1,10 +1,3 @@
2.0.2 2015-02-17
Add "--checksum" in rsync when using "--force" (Jaime)
Use createdb/createuser instead of psql (Jaime)
Fixes to witness creation and monitoring (wamonite)
Use default master port if none supplied (Martín)
Documentation fixes and improvements (Ian)
2.0.1 2014-07-16
Documentation fixes and new QUICKSTART file (Ian)
Explicitly specify directories to ignore when cloning (Ian)

View File

@@ -34,7 +34,7 @@ same PostgreSQL major version, and preferably should be running the same minor
version.
repmgr will work on any Linux or UNIX-like environment capable of running
PostgreSQL. rsync must also be installed.
PostgreSQL. `rsync` must also be installed.
Installation
@@ -82,12 +82,9 @@ Note that repmgr expects a default of 5000 wal_keep_segments, although this
value can be overridden when executing the `repmgr` client.
Additionally, repmgr requires a dedicated PostgreSQL superuser account
and a database in which to store monitoring and replication data. The repmgr
user account will also be used for replication connections from the standby,
so a seperate replication user with the `REPLICATION` privilege is not required.
The database can in principle be any database, including the default `postgres`
one, however it's probably advisable to create a dedicated database for repmgr
usage.
and a database in which to store monitoring and replication data. The
database can in principle be any database, including the default postgres
one, however it's probably advisable to create a dedicated repmgr database.
### repmgr configuration
@@ -110,11 +107,11 @@ identification and database connection information:
resolvable by all nodes on the cluster.
* `pg_bindir`: (optional) location of PostgreSQL binaries, if not in the default $PATH
Note that the configuration file should not be stored inside the PostgreSQL
Note that the configuration file should *not* be stored inside the PostgreSQL
data directory.
Each node configuration needs to be registered with repmgr, either using the
repmgr command line tool, or the repmgrd daemon; for details see below. Details
`repmgr` command line tool, or the `repmgrd` daemon; for details see below. Details
about each node are inserted into the repmgr database (for details see below).
@@ -143,15 +140,14 @@ Master setup
- configure postgresql.conf for replication (see above)
- update pg_hba.conf, e.g.:
- update pg_hba.conf:
```
host repmgr_db repmgr_usr 192.168.1.0/24 trust
host replication repmgr_usr 192.168.1.0/24 trust
host repmgr_usr repmgr_db 192.168.1.0/24 trust
host replication all 192.168.1.0/24 trust
```
Restart the PostgreSQL server after making these changes.
2. Create the repmgr configuration file:
$ cat $HOME/repmgr/repmgr.conf
@@ -194,10 +190,8 @@ Slave/standby setup
-R is the database system user on the master node. At this point it does not matter
if the `repmgr.conf` file is not found.
This will clone the PostgreSQL database files from the master, including its
`postgresql.conf` and `pg_hba.conf` files, and additionally automatically create
the `recovery.conf` file containing the correct parameters to start streaming
from the primary node.
This will clone the PostgreSQL database files from the master, and additionally
create an appropriate `recovery.conf` file.
2. Start the PostgreSQL server

181
repmgr.c
View File

@@ -109,13 +109,15 @@ main(int argc, char **argv)
{"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'},
{NULL, 0, NULL, 0}
};
int optindex;
int c;
int c, targ;
int action = NO_ACTION;
char *ptr = NULL;
progname = get_progname(argv[0]);
@@ -134,7 +136,7 @@ main(int argc, char **argv)
}
while ((c = getopt_long(argc, argv, "d:h:p:U:D:l:f:R:w:k:FWIv", long_options,
while ((c = getopt_long(argc, argv, "d:h:p:U:D:l:f:R:w:k:FWIvr:", long_options,
&optindex)) != -1)
{
switch (c)
@@ -184,6 +186,25 @@ main(int argc, char **argv)
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;
@@ -288,12 +309,6 @@ main(int argc, char **argv)
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);
@@ -1730,53 +1745,6 @@ do_witness_create(void)
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"), 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 postgres %s", options.pg_bindir,
runtime_options.localport,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 postgres --owner=%s %s",
options.pg_bindir, runtime_options.localport,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 "
@@ -1810,19 +1778,18 @@ do_witness_create(void)
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,
/* 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(_("Reload cluster config for witness: %s"), script);
log_info(_("Start cluster for witness: %s"), script);
r = system(script);
if (r != 0)
{
log_err(_("Can't reload cluster for witness server\n"));
log_err(_("Can't start 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)",
@@ -1858,24 +1825,6 @@ do_witness_create(void)
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);
log_debug(_("witness create: %s"), 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);
@@ -1925,6 +1874,7 @@ help(const char *progname)
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)"));
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"));
@@ -1977,6 +1927,19 @@ create_recovery_file(const char *data_dir)
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);
@@ -1987,25 +1950,34 @@ static int
test_ssh_connection(char *host, char *remote_user)
{
char script[MAXLEN];
int r;
int r = 1, i;
/* 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
/* 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_pathes[] = {
"/bin/true",
"/usr/bin/true",
NULL
};
/* Check if we have ssh connectivity to host before trying to rsync */
for(i = 0; truebin_pathes[i] && r != 0; ++i)
{
if (!remote_user[0])
maxlen_snprintf(script, "ssh -o Batchmode=yes %s %s %s",
options.ssh_options, host, TRUEBIN_PATH);
options.ssh_options, host, truebin_pathes[i]);
else
maxlen_snprintf(script, "ssh -o Batchmode=yes %s %s -l %s %s",
options.ssh_options, host, remote_user, TRUEBIN_PATH);
options.ssh_options, host, remote_user,
truebin_pathes[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;
@@ -2028,7 +2000,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 --checksum");
strcat(rsync_flags, " --delete");
if (!remote_user[0])
{
@@ -2396,14 +2368,13 @@ static bool
copy_configuration(PGconn *masterconn, PGconn *witnessconn)
{
char sqlquery[MAXLEN];
PGresult *res1;
PGresult *res2;
PGresult *res;
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)
res = PQexec(witnessconn, sqlquery);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Cannot clean node details in the witness, %s\n",
PQerrorMessage(witnessconn));
@@ -2412,35 +2383,33 @@ copy_configuration(PGconn *masterconn, PGconn *witnessconn)
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)
res = PQexec(masterconn, sqlquery);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "Can't get configuration from master: %s\n",
PQerrorMessage(masterconn));
PQclear(res1);
PQclear(res);
return false;
}
for (i = 0; i < PQntuples(res1); i++)
for (i = 0; i < PQntuples(res); 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));
repmgr_schema, atoi(PQgetvalue(res, i, 0)),
options.cluster_name, PQgetvalue(res, i, 1),
PQgetvalue(res, i, 2),
atoi(PQgetvalue(res, i, 3)),
PQgetvalue(res, i, 4));
res2 = PQexec(witnessconn, sqlquery);
if (!res2 || PQresultStatus(res2) != PGRES_COMMAND_OK)
res = PQexec(witnessconn, sqlquery);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Cannot copy configuration to witness, %s\n",
PQerrorMessage(witnessconn));
PQclear(res2);
PQclear(res);
return false;
}
PQclear(res2);
}
PQclear(res1);
return true;
}

View File

@@ -67,8 +67,10 @@ typedef struct
/* parameter used by CLUSTER CLEANUP */
int keep_history;
char min_recovery_apply_delay[MAXLEN];
} t_runtime_options;
#define T_RUNTIME_OPTIONS_INITIALIZER { "", "", "", "", "", "", DEFAULT_WAL_KEEP_SEGMENTS, false, false, false, false, "", "", 0 }
#define T_RUNTIME_OPTIONS_INITIALIZER { "", "", "", "", "", "", DEFAULT_WAL_KEEP_SEGMENTS, false, false, false, false, "", "", 0, "" }
#endif

View File

@@ -551,7 +551,7 @@ witness_monitor(void)
sqlquery_snprintf(sqlquery,
"INSERT INTO %s.repl_monitor "
"VALUES(%d, %d, '%s'::timestamp with time zone, "
" null, pg_current_xlog_location(), null, "
" pg_current_xlog_location(), null, "
" 0, 0)",
repmgr_schema, primary_options.node, local_options.node,
monitor_witness_timestamp);

View File

@@ -22,7 +22,7 @@
#define _STRUTIL_H_
#include <stdlib.h>
#include "errcode.h"
#include <errcode.h>
#define QUERY_STR_LEN 8192
#define MAXLEN 1024

View File

@@ -1,6 +1,6 @@
#ifndef _VERSION_H_
#define _VERSION_H_
#define REPMGR_VERSION "2.0.2"
#define REPMGR_VERSION "2.1dev"
#endif