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
16 changed files with 235 additions and 403 deletions

28
HISTORY
View File

@@ -1,22 +1,10 @@
2.0.3 2015-04-16
Add -S/--superuser option for witness database creation (Ian)
Add -c/--fast-checkpoint option for cloning (Christoph)
Add option "--initdb-no-pwprompt" (Ian)
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)
Fix log level for some log messages (Ian)
RHEL/CentOS specfile, init script and Makefile fixes (Nathan Van Overloop)
2.0.1 2014-07-16
Documentation fixes and new QUICKSTART file (Ian)
Explicitly specify directories to ignore when cloning (Ian)
Fix log level for some log messages (Ian)
RHEL/CentOS specfile, init script and Makefile fixes (Nathan Van Overloop)
Debian init script and config file documentation fixes (József Kószó)
Typo fixes (Riegie Godwin Jeyaranchen, PriceChild)
Typo fixes (Riegie Godwin Jeyaranchen, PriceChild)
2.0stable 2014-01-30
Documentation fixes (Christian)
@@ -37,7 +25,7 @@
Add a ssh_options parameter (Jay Taylor)
2.0beta1 2012-07-27
Make CLONE command try to make an exact copy including $PGDATA location (Cedric)
Make CLONE command try to make an exact copy including $PGDATA location (Cedric)
Add detection of master failure (Jaime)
Add the notion of a witness server (Jaime)
Add autofailover capabilities (Jaime)
@@ -64,7 +52,7 @@
1.1.0 2011-03-09
Make options -U, -R and -p not mandatory (Jaime)
1.1.0b1 2011-02-24
1.1.0b1 2011-02-24
Fix missing "--force" option in help (Greg Smith)
Correct warning message for wal_keep_segments (Bas van Oostveen)
Add Debian build/usage docs (Bas, Hannu Krosing, Cedric Villemain)

View File

@@ -1,7 +1,7 @@
repmgr: Quickstart guide
========================
`repmgr` is an open-source tool suite for mananaging replication and failover
repmgr is an open-source tool suite for mananaging replication and failover
among multiple PostgreSQL server nodes. It enhances PostgreSQL's built-in
hot-standby capabilities with a set of administration tools for monitoring
replication, setting up standby servers and performing failover/switchover
@@ -14,14 +14,14 @@ covering setup on a variety of different systems, see the README.rst file.
Conceptual Overview
-------------------
`repmgr` provides two binaries:
repmgr provides two binaries:
- `repmgr`: a command-line client to manage replication and `repmgr` configuration
- `repmgr`: a command-line client to manage replication and repmgr configuration
- `repmgrd`: an optional daemon process which runs on standby nodes to monitor
replication and node status
Each PostgreSQL node requires a `repmgr.conf` configuration file; additionally
it must be "registered" using the `repmgr` command-line client. `repmgr` stores
Each PostgreSQL node requires a repmgr configuration file; additionally
it must be "registered" using the repmgr command-line client. repmgr stores
information about managed nodes in a custom schema on the node's current master
database.
@@ -29,31 +29,31 @@ database.
Requirements
------------
`repmgr` works with PostgreSQL 9.0 and later. All server nodes must be running the
repmgr works with PostgreSQL 9.0 and later. All server nodes must be running the
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
repmgr will work on any Linux or UNIX-like environment capable of running
PostgreSQL. `rsync` must also be installed.
Installation
------------
`repmgr` must be installed on each PostgreSQL server node.
repmgr must be installed on each PostgreSQL server node.
* Packages
- RPM packages for RedHat-based distributions are available from PGDG
- Debian/Ubuntu provide .deb packages.
It is also possible to build .deb packages directly from the `repmgr` source;
It is also possible to build .deb packages directly from the repmgr source;
see README.rst for further details.
* Source installation
- `repmgr` source code is hosted at github (https://github.com/2ndQuadrant/repmgr);
- repmgr source code is hosted at github (https://github.com/2ndQuadrant/repmgr);
tar.gz files can be downloaded from https://github.com/2ndQuadrant/repmgr/releases .
`repmgr` can be built easily using PGXS:
repmgr can be built easily using PGXS:
sudo make USE_PGXS=1 install
@@ -64,7 +64,7 @@ Configuration
### Server configuration
Password-less SSH logins must be enabled for the database system user (typically `postgres`)
between all server nodes to enable `repmgr` to copy required files.
between all server nodes to enable repmgr to copy required files.
### PostgreSQL configuration
@@ -78,21 +78,18 @@ following settings:
wal_keep_segments = 5000 # in logfile segments, 16MB each; 0 disables
hot_standby = on # "on" allows queries during recovery
Note that `repmgr` expects a default of 5000 wal_keep_segments, although this
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.
Additionally, repmgr requires a dedicated PostgreSQL superuser account
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
Each PostgreSQL node requires a `repmgr.conf` configuration file containing
Each PostgreSQL node requires a repmgr configuration file containing
identification and database connection information:
cluster=test
@@ -111,14 +108,11 @@ identification and database connection information:
* `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
data directory. The configuration file can be specified with the
`-f, --config-file=PATH` option and can have any arbitrary name. If no
configuration file is specified, `repmgr` will search for `repmgr.conf`
in the current working directory.
data directory.
Each node configuration needs to be registered with `repmgr`, either using the
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
about each node are inserted into the `repmgr` database (for details see below).
about each node are inserted into the repmgr database (for details see below).
Replication setup and monitoring
@@ -144,17 +138,17 @@ Master setup
CREATE DATABASE repmgr_db OWNER repmgr_usr;
```
- configure `postgresql.conf` for replication (see above)
- 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:
Restart the PostgreSQL server after making these changes.
2. Create the repmgr configuration file:
$ cat $HOME/repmgr/repmgr.conf
cluster=test
@@ -163,10 +157,7 @@ Master setup
conninfo='host=repmgr_node1 user=repmgr_usr dbname=repmgr_db'
pg_bindir=/path/to/postgres/bin
(For an annotated `repmgr.conf` file, see `repmgr.conf.sample` in the
repository's root directory).
3. Register the master node with `repmgr`:
3. Register the master node with repmgr:
$ repmgr -f $HOME/repmgr/repmgr.conf --verbose master register
[2014-07-04 10:43:42] [INFO] repmgr mgr connecting to master database
@@ -178,9 +169,9 @@ Master setup
Slave/standby setup
-------------------
1. Use `repmgr` to clone the master:
1. Use repmgr to clone the master:
$ repmgr -D $PGDATA -d repmgr_db -U repmgr_usr -R postgres --verbose standby clone 192.168.1.2
$ repmgr -f $HOME/repmgr/repmgr.conf -D $PGDATA -d repmgr_db -U repmgr_usr -R postgres --verbose standby clone 192.168.1.2
Opening configuration file: ./repmgr.conf
[2014-07-04 10:49:00] [ERROR] Did not find the configuration file './repmgr.conf', continuing
[2014-07-04 10:49:00] [INFO] repmgr connecting to master database
@@ -199,14 +190,12 @@ 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
3. Create the `repmgr` configuration file:
3. Create the repmgr configuration file:
$ cat $HOME/repmgr/repmgr.conf
cluster=test
@@ -215,7 +204,7 @@ Slave/standby setup
conninfo='host=repmgr_node2 user=repmgr_usr dbname=repmgr_db'
pg_bindir=/path/to/postgres/bin
4. Register the master node with `repmgr`:
4. Register the master node with repmgr:
$ repmgr -f $HOME/repmgr/repmgr.conf --verbose standby register
Opening configuration file: /path/to/repmgr/repmgr.conf
@@ -264,8 +253,8 @@ To promote a standby to master, on the standby execute e.g.:
repmgr -f $HOME/repmgr/repmgr.conf --verbose standby promote
`repmgr` will attempt to connect to the current master to verify that it
is not available (if it is, `repmgr` will not promote the standby).
repmgr will attempt to connect to the current master to verify that it
is not available (if it is, repmgr will not promote the standby).
Other standby servers need to be told to follow the new master with:
@@ -278,7 +267,7 @@ automated failover.
repmgr database schema
----------------------
`repmgr` creates a small schema for its own use in the database specified in
repmgr creates a small schema for its own use in the database specified in
each node's conninfo configuration parameter. This database can in principle
be any database. The schema name is the global `cluster` name prefixed
with `repmgr_`, so for the example setup above the schema name is
@@ -295,10 +284,3 @@ and one view, `repl_status`, which summarizes the latest monitoring information
for each node.
Further reading
---------------
* http://blog.2ndquadrant.com/announcing-repmgr-2-0/
* http://blog.2ndquadrant.com/managing-useful-clusters-repmgr/
* http://blog.2ndquadrant.com/easier_postgresql_90_clusters/

View File

@@ -427,7 +427,7 @@ system you already have superuser access to.
Clearing the PostgreSQL installation on the Standby
---------------------------------------------------
To setup a new streaming replica, start by removing any PostgreSQL
To setup a new streaming replica, startin by removing any PostgreSQL
installation on the existing standby nodes.
* Stop any server on "node2" and "node3". You can confirm the database

View File

@@ -4,7 +4,7 @@ Version: 2.0
Release: 2
License: GPLv3
Group: System Environment/Daemons
URL: http://repmgr.org
URL: http://repmgr.org
Packager: Nathan Van Overloop <nathan.van.overloop@nexperteam.be>
Vendor: 2ndQuadrant Limited
Distribution: centos
@@ -32,7 +32,7 @@ export PATH=$PATH:/usr/pgsql-9.3/bin/
%clean
[ "%{buildroot}" != "/" ] && %{__rm} -rf %{buildroot}
%files
%defattr(-,root,root)
@@ -45,7 +45,7 @@ export PATH=$PATH:/usr/pgsql-9.3/bin/
/usr/pgsql-9.3/share/contrib/repmgr_funcs.sql
/usr/pgsql-9.3/share/contrib/uninstall_repmgr.sql
/usr/pgsql-9.3/share/contrib/uninstall_repmgr_funcs.sql
%attr(0755,root,root)/etc/init.d/repmgrd
%attr(0755,root,root)/etc/init.d/repmgrd
%attr(0644,root,root)/etc/sysconfig/repmgrd
%attr(0644,root,root)/etc/repmgr/repmgr.conf.sample
@@ -54,3 +54,4 @@ export PATH=$PATH:/usr/pgsql-9.3/bin/
- fix witness creation to create db and user if needed
* Fri Apr 04 2014 Nathan Van Overloop <nathan.van.overloop@nexperteam.be> 2.0.1
- initial build for RHEL6

View File

@@ -1,114 +1,89 @@
#!/bin/sh
#!/bin/bash
#
# chkconfig: - 75 16
# description: Enable repmgrd replication management and monitoring daemon for PostgreSQL
# processname: repmgrd
# pidfile="/var/run/${NAME}.pid"
# repmgrd Start up the repmgrd daemon
# repmrgd (replication manager daemon)
#
# chkconfig: - 75 16
# description: repmgrd is the repliation manager daemon \
# The repmgrd replication management and monitoring daemon for PostgreSQL.
### BEGIN INIT INFO
# Provides: repmgrd
# Required-Start: $local_fs $remote_fs $network $syslog postgresql
# Required-Stop: $local_fs $remote_fs $network $syslog postgresql
# Should-Start: $syslog postgresql-9.3
# Should-Stop: $syslog postgresql-9.3
# Short-Description: start and stop repmrgd
# Description: Enable repmgrd replication management and monitoring daemon for PostgreSQL
# this is used to monitor a postgresql cluster.
### END INIT INFO
# Source function library.
INITD=/etc/rc.d/init.d
. $INITD/functions
. /etc/init.d/functions
# Get function listing for cross-distribution logic.
TYPESET=`typeset -f|grep "declare"`
# Get network config.
# Source networking configuration.
. /etc/sysconfig/network
DESC="PostgreSQL replication management and monitoring daemon"
NAME=repmgrd
REPMGRD_ENABLED=no
prog=repmgrd
REPMGRD_ENABLED=yes
REPMGRD_OPTS=
REPMGRD_USER=postgres
REPMGRD_BIN=/usr/pgsql-9.3/bin/repmgrd
REPMGRD_PIDFILE=/var/run/repmgrd.pid
REPMGRD_LOCK=/var/lock/subsys/${NAME}
REPMGRD_LOG=/var/lib/pgsql/9.3/data/pg_log/repmgrd.log
DAEMONIZE="-d"
# Read configuration variable file if it is present
[ -r /etc/sysconfig/$NAME ] && . /etc/sysconfig/$NAME
# pull in sysconfig settings
[ -f /etc/sysconfig/repmgrd ] && . /etc/sysconfig/repmgrd
# For SELinux we need to use 'runuser' not 'su'
if [ -x /sbin/runuser ]
then
SU=runuser
else
SU=su
fi
test -x $REPMGRD_BIN || exit 0
LOCKFILE=/var/lock/subsys/$prog
RETVAL=0
case "$REPMGRD_ENABLED" in
[Yy]*)
break
#nothing to do here
;;
*)
exit 0
exit 2
;;
esac
if [ -z "${REPMGRD_OPTS}" ]
if [ -z "$REPMGRD_OPTS" ]
then
echo "Not starting ${NAME}, REPMGRD_OPTS not set in /etc/sysconfig/${NAME}"
exit 0
echo "Not starting $prog, REPMGRD_OPTS not set in /etc/sysconfig/$prog"
exit 2
fi
start()
{
REPMGRD_START=$"Starting ${NAME} service: "
start() {
[ "$EUID" != "0" ] && exit 4
[ "$NETWORKING" = "no" ] && exit 1
# Make sure startup-time log file is valid
if [ ! -e "${REPMGRD_LOG}" -a ! -h "${REPMGRD_LOG}" ]
then
touch "${REPMGRD_LOG}" || exit 1
chown ${REPMGRD_USER}:postgres "${REPMGRD_LOG}"
chmod go-rwx "${REPMGRD_LOG}"
[ -x /sbin/restorecon ] && /sbin/restorecon "${REPMGRD_LOG}"
fi
echo -n "${REPMGRD_START}"
$SU -l $REPMGRD_USER -c "${REPMGRD_BIN} ${REPMGRD_OPTS} -p ${REPMGRD_PIDFILE} &" >> "${REPMGRD_LOG}" 2>&1 < /dev/null
sleep 2
pid=`head -n 1 "${REPMGRD_PIDFILE}" 2>/dev/null`
if [ "x${pid}" != "x" ]
then
success "${REPMGRD_START}"
touch "${REPMGRD_LOCK}"
echo $pid > "${REPMGRD_PIDFILE}"
# Start daemons.
echo -n $"Starting $prog: "
daemon --user $REPMGRD_USER $prog $DAEMONIZE $REPMGRD_OPTS
RETVAL=$?
echo
else
failure "${REPMGRD_START}"
echo
script_result=1
fi
[ $RETVAL -eq 0 ] && touch $LOCKFILE
return $RETVAL
}
stop()
{
echo -n $"Stopping ${NAME} service: "
if [ -e "${REPMGRD_LOCK}" ]
then
killproc ${NAME}
ret=$?
if [ $ret -eq 0 ]
then
echo_success
rm -f "${REPMGRD_PIDFILE}"
rm -f "${REPMGRD_LOCK}"
stop() {
[ "$EUID" != "0" ] && exit 4
echo -n $"Shutting down $prog: "
killproc $prog
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f $LOCKFILE
return $RETVAL
}
status() {
if [ -f "$LOCKFILE" ]; then
echo "$prog is running"
else
echo_failure
script_result=1
RETVAL=3
echo "$prog is stopped"
fi
else
# not running; per LSB standards this is "ok"
echo_success
fi
echo
return $RETVAL
}
# See how we were called.
case "$1" in
start)
@@ -118,16 +93,22 @@ case "$1" in
stop
;;
status)
status -p $REPMGRD_PIDFILE $NAME
script_result=$?
status $prog
;;
restart)
restart|force-reload)
stop
start
start
;;
try-restart|condrestart)
if status $prog > /dev/null; then
stop
start
fi
;;
reload)
exit 3
;;
*)
echo $"Usage: $0 {start|stop|status|restart}"
echo $"Usage: $0 {start|stop|status|restart|try-restart|force-reload}"
exit 2
esac
exit $script_result

View File

@@ -1,21 +1,4 @@
# default settings for repmgrd. This file is source by /bin/sh from
# /etc/init.d/repmgrd
#default sysconfig file for repmrgd
#custom overrides can be placed here
# disable repmgrd by default so it won't get started upon installation
# valid values: yes/no
REPMGRD_ENABLED=no
# Options for repmgrd (required)
#REPMGRD_OPTS="--verbose -d -f /var/lib/pgsql/repmgr/repmgr.conf"
# User to run repmgrd as
#REPMGRD_USER=postgres
# repmgrd binary
#REPMGRD_BIN=/usr/bin/repmgr
# pid file
#REPMGRD_PIDFILE=/var/lib/pgsql/repmgr/repmgrd.pid
# log file
#REPMGRD_LOG=/var/lib/pgsql/repmgr/repmgrd.log
REPMGRD_OPTS="-f /etc/repmgr/repmgr.conf"

View File

@@ -25,8 +25,7 @@
#include <string.h>
/* NB: postgres_fe must be included BEFORE check_dir */
#include <libpq-fe.h>
#include <postgres_fe.h>
#include "postgres_fe.h"
#include "check_dir.h"
#include "strutil.h"

View File

@@ -185,10 +185,6 @@ trim(char *s)
char *s1 = s,
*s2 = &s[strlen(s) - 1];
/* If string is empty, no action needed */
if(s2 < s1)
return s;
/* Trim and delimit right side */
while ((isspace(*s2)) && (s2 >= s1))
--s2;

View File

@@ -3,7 +3,7 @@ Version: 2.0beta2
Section: database
Priority: optional
Architecture: all
Depends: rsync, postgresql-9.0 | postgresql-9.1 | postgresql-9.2 | postgresql-9.3 | postgresql-9.4
Depends: rsync, postgresql-9.0 | postgresql-9.1 | postgresql-9.2 | postgresql-9.3
Maintainer: Jaime Casanova <jaime@2ndQuadrant.com>
Description: PostgreSQL replication setup, magament and monitoring
has two main executables

6
log.h
View File

@@ -25,15 +25,9 @@
#define REPMGR_SYSLOG 1
#define REPMGR_STDERR 2
#if (PG_VERSION_NUM >= 90100)
void
stderr_log_with_level(const char *level_name, int level, const char *fmt,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
#else
void
stderr_log_with_level(const char *level_name, int level, const char *fmt,...)
__attribute__((format(printf, 3, 4)));
#endif
/* Standard error logging */
#define stderr_log_debug(...) stderr_log_with_level("DEBUG", LOG_DEBUG, __VA_ARGS__)

253
repmgr.c
View File

@@ -100,7 +100,6 @@ main(int argc, char **argv)
{"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'},
@@ -110,15 +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'},
{"fast-checkpoint", no_argument, NULL, 'c'},
{"initdb-no-pwprompt", no_argument, NULL, 1},
{NULL, 0, NULL, 0}
};
int optindex;
int c;
int c, targ;
int action = NO_ACTION;
char *ptr = NULL;
progname = get_progname(argv[0]);
@@ -137,7 +136,7 @@ main(int argc, char **argv)
}
while ((c = getopt_long(argc, argv, "d:h:p:U:S:D:l:f:R:w:k:FWIvc", 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)
@@ -155,9 +154,6 @@ main(int argc, char **argv)
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;
@@ -190,15 +186,28 @@ 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;
case 'c':
runtime_options.fast_checkpoint = true;
break;
case 1:
runtime_options.initdb_no_pwprompt = true;
break;
default:
usage();
exit(ERR_BAD_CONFIG);
@@ -300,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);
@@ -824,7 +827,7 @@ do_standby_clone(void)
int r = 0,
retval = SUCCESS;
int i,j,
int i,
is_standby_retval;
bool flag_success = false;
bool test_mode = false;
@@ -902,30 +905,11 @@ do_standby_clone(void)
i = guc_set(conn, "wal_level", "=", "hot_standby");
if (i == 0 || i == -1)
{
PQfinish(conn);
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);
}
log_err(_("%s needs parameter 'wal_level' to be set to 'hot_standby'\n"),
progname);
exit(ERR_BAD_CONFIG);
}
i = guc_set_typed(conn, "wal_keep_segments", ">=",
@@ -1118,9 +1102,8 @@ do_standby_clone(void)
*/
sqlquery_snprintf(
sqlquery,
"SELECT pg_xlogfile_name(pg_start_backup('repmgr_standby_clone_%ld', %s))",
time(NULL),
runtime_options.fast_checkpoint ? "TRUE" : "FALSE");
"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)
@@ -1720,13 +1703,8 @@ do_witness_create(void)
*/
/* 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);
sprintf(script, "%s/pg_ctl %s -D %s init -o \"-W\"", options.pg_bindir,
options.pgctl_options, runtime_options.dest_dir);
log_info("Initialize cluster for witness: %s.\n", script);
r = system(script);
@@ -1767,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 %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 "
@@ -1847,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)",
@@ -1895,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);
@@ -1954,8 +1866,6 @@ help(const char *progname)
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"));
@@ -1964,8 +1874,8 @@ 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(_(" -c, --fast-checkpoint force fast checkpoint when cloning a standby\n"));
printf(_(" --initdb-no-pwprompt don't require superuser password when running initdb\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"));
printf(_("COMMANDS:\n"));
@@ -2017,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);
@@ -2027,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 */
if (!remote_user[0])
maxlen_snprintf(script, "ssh -o Batchmode=yes %s %s %s",
options.ssh_options, host, TRUEBIN_PATH);
else
maxlen_snprintf(script, "ssh -o Batchmode=yes %s %s -l %s %s",
options.ssh_options, host, remote_user, TRUEBIN_PATH);
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_pathes[i]);
else
maxlen_snprintf(script, "ssh -o Batchmode=yes %s %s -l %s %s",
options.ssh_options, host, remote_user,
truebin_pathes[i]);
log_debug(_("command is: %s\n"), script);
r = system(script);
}
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;
@@ -2068,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])
{
@@ -2436,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));
@@ -2452,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

@@ -20,9 +20,9 @@
#ifndef _REPMGR_H_
#define _REPMGR_H_
#include <libpq-fe.h>
#include <postgres_fe.h>
#include <getopt_long.h>
#include "postgres_fe.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "strutil.h"
#include "dbutils.h"
@@ -56,22 +56,21 @@ typedef struct
char dest_dir[MAXFILENAME];
char config_file[MAXFILENAME];
char remote_user[MAXLEN];
char superuser[MAXLEN];
char wal_keep_segments[MAXLEN];
bool verbose;
bool force;
bool wait_for_master;
bool ignore_rsync_warn;
bool initdb_no_pwprompt;
bool fast_checkpoint;
char masterport[MAXLEN];
char localport[MAXLEN];
/* 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, false, false, "", "", 0}
#define T_RUNTIME_OPTIONS_INITIALIZER { "", "", "", "", "", "", DEFAULT_WAL_KEEP_SEGMENTS, false, false, false, false, "", "", 0, "" }
#endif

View File

@@ -218,17 +218,6 @@ main(int argc, char **argv)
}
}
/*
* Read the configuration file: repmgr.conf
*/
parse_config(config_file, &local_options);
if (local_options.node == -1)
{
log_err(_("Node information is missing. "
"Check the configuration file, or provide one if you have not done so.\n"));
terminate(ERR_BAD_CONFIG);
}
if (daemonize)
{
do_daemonize();
@@ -243,6 +232,17 @@ main(int argc, char **argv)
setup_event_handlers();
#endif
/*
* Read the configuration file: repmgr.conf
*/
parse_config(config_file, &local_options);
if (local_options.node == -1)
{
log_err(_("Node information is missing. "
"Check the configuration file, or provide one if you have not done so.\n"));
terminate(ERR_BAD_CONFIG);
}
fd = freopen("/dev/null", "r", stdin);
if (fd == NULL)
{
@@ -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

@@ -25,15 +25,9 @@
#include "log.h"
#include "strutil.h"
#if (PG_VERSION_NUM >= 90100)
static int
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0)));
#else
static int
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
__attribute__((format(printf, 3, 0)));
#endif
static int
xvsnprintf(char *str, size_t size, const char *format, va_list ap)

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
@@ -31,7 +31,6 @@
#define MAXCONNINFO 1024
#if (PG_VERSION_NUM >= 90100)
extern int
xsnprintf(char *str, size_t size, const char *format,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
@@ -43,18 +42,5 @@ __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
extern int
maxlen_snprintf(char *str, const char *format,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
#else
extern int
xsnprintf(char *str, size_t size, const char *format,...)
__attribute__((format(printf, 3, 4)));
extern int
sqlquery_snprintf(char *str, const char *format,...)
__attribute__((format(printf, 2, 3)));
extern int
maxlen_snprintf(char *str, const char *format,...)
__attribute__((format(printf, 2, 3)));
#endif
#endif /* _STRUTIL_H_ */

View File

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