Compare commits

..

61 Commits

Author SHA1 Message Date
Ian Barwick
d10f1f289e Bump version in configure.in
4.0.2
2018-01-16 13:55:58 +09:00
Ian Barwick
5731ba6043 Update version and release date 2018-01-16 12:58:11 +09:00
Ian Barwick
3d6437c8f8 repmgr: assume node is actually shutting down if pingable and that's the reported status 2018-01-16 11:17:06 +09:00
Ian Barwick
54b5c8ad94 repmgrd: log execution error in "repmgrd_get_local_node_id()"
That shouldn't happen, but if it does it will make it easier to
identify the issue.
2018-01-16 11:14:04 +09:00
Ian Barwick
0eca08ffaf doc: improve switchover documentation
Emphasize need to set the "service_*_command" options when repmgr is
installed from a package.
2018-01-16 11:06:39 +09:00
Ian Barwick
05c1dc2b92 doc: add 4.0.2 release notes 2018-01-11 16:39:58 +09:00
Ian Barwick
2bd300073d doc: minor readbility fix 2018-01-11 15:49:56 +09:00
Ian Barwick
01e020df8e doc: note change of shared library name from "repmgr_funcs" to "repmgr" 2018-01-11 15:47:35 +09:00
Ian Barwick
ae7963dc64 repmgr: automatically create slot name if missing
It's possible that a node was registered with "use_replication_slots=false"
but that was later changed to "use_replication_slots=true". If the node
was not subsequently re-registered, the node record will contain an empty
slot name, which will cause any slot creation operation during
"standby follow" or "node rejoin" to fail.

To prevent this happening, check for an empty slot name and automatically
set before proceeding.

Addresses GitHub #343.
2018-01-11 11:13:41 +09:00
Ian Barwick
faffb2a6e7 repmgr: catch possible corner case when checking node shutdown status
It's conceivable that PQping is returning "no response" but the
shutdown hasn't quite completed.
2018-01-10 14:56:00 +09:00
Ian Barwick
5d57044118 repmgr: during switchover, correctly detect unclean shutdown status 2018-01-10 12:21:04 +09:00
Ian Barwick
07a88c78a5 repmgr standby switchover: add "%p" event notification parameter
This will contain the node ID of the former primary.
2018-01-10 11:01:00 +09:00
Ian Barwick
f7df8b9c80 doc: document command line options for "standby switchover" 2018-01-10 10:19:36 +09:00
Ian Barwick
20920b3da1 repmgr standby switchover: add event details 2018-01-10 09:55:24 +09:00
Ian Barwick
683f4de182 Bump version
4.0.2
2018-01-09 13:43:58 +09:00
Ian Barwick
0c62821ffb Consolidate parsing of output from executing repmgr on a remote server
This should also fix the issue reported in GitHub #349.
2018-01-09 13:33:38 +09:00
Ian Barwick
6b70e8bbe6 doc: list repmgr.conf parameters relevant during switchover 2018-01-08 11:13:39 +09:00
Ian Barwick
6b223698c9 Fix call to is_active_bdr_node() in BDR repmgrd
Following the fix to "is_active_bdr_node()" in 841f03ae, it turns out
the call in repmgrd-bdr.c was only accidentally working; explicitly
test for a false return value.
2018-01-04 21:06:45 +09:00
Ian Barwick
aee12dc2c7 "repmgr bdr register": create missing connection replication set if needed
Previously the assumption was that the "repmgr" replication set would be
set up when the nodes are created, however no checks were implemented
and this was not well-documented.

Addresses GitHub #347.
2018-01-04 17:12:52 +09:00
Ian Barwick
c5c86e1ada "repmgr bdr register": improve node name check
We'll use "bdr.bdr_get_local_node_name()" to check the local BDR node
name and the repmgr one match.
2018-01-04 16:07:06 +09:00
Ian Barwick
7476dc84f2 doc: link event notification page from relevate command reference pages 2018-01-04 14:54:14 +09:00
Ian Barwick
f6d63f5216 doc: update package documentation 2018-01-04 13:11:44 +09:00
Ian Barwick
a608b0bc18 "repmgr standby register": add --wait-start option
Implements GitHub #356.
2018-01-04 12:48:12 +09:00
Ian Barwick
469ebba656 doc: fix typos in "repmgr primary unregister" command reference 2018-01-04 12:31:29 +09:00
Ian Barwick
647c21ad0e doc: add link to event notifications page from "repmgr cluster event" 2018-01-04 10:57:54 +09:00
Ian Barwick
3d2530d6f9 Fix query in is_active_bdr_node()
Boolean column was not being checked correctly.

Also add detail output in "repmgr node role --check", where the function
is called.
2018-01-04 10:48:31 +09:00
Ian Barwick
b26e400199 "repmgr cluster event": move query to dbutils.c 2018-01-04 10:06:54 +09:00
Ian Barwick
152e9545a4 docs: document "repmgr cluster event --terse" 2018-01-04 09:53:54 +09:00
Ian Barwick
83b8f05221 "repmgr cluster events": optionally omit "Details" column with --terse
Implements GitHub #360.
2018-01-04 09:48:00 +09:00
Ian Barwick
486f8e5a2c repmgrd: document standby_[failure|recovery] event notifications
Also clean up the relevant code section.

Addresses GitHub #359.
2018-01-04 09:34:49 +09:00
Ian Barwick
e517cc74d1 repmgr node rejoin: handle missing node record correctly
If a connection was provided for a database other than the "repmgr"
database, error was logged but execution continued, resulting in
the connection being finished twice.

Addresses GitHub #358.
2018-01-03 15:20:10 +09:00
Ian Barwick
26285b470f doc: add appendix with details about packages
work-in-progress
2018-01-02 17:24:51 +09:00
Ian Barwick
1521657965 Update copyright notices to 2018 2018-01-02 10:20:09 +09:00
Ian Barwick
041604e303 doc: Fix event notification placeholder typo
Per report from Carlos.
2018-01-01 10:29:34 +09:00
Ian Barwick
0be0100a7c docs: update HISTORY 2017-12-27 10:24:56 +09:00
Ian Barwick
2133834dda doc: update documentation build instructions
Describe how to build documentation as a single file, and also note
requirement to build against 9.6 or earlier.
2017-12-27 10:24:22 +09:00
Ian Barwick
d5fd93c350 repmgr.conf.sample: fix command line argument
"repmgr node check --archive-ready" is correct, however abbreviated
versions will be accepted by getopt_long() if they don't match
or partially match any other options.

Per report by "chaintng" in GitHub #355.
2017-12-27 10:24:17 +09:00
Tony Finch
5804778b58 doc: an optional all-in-one-file manual 2017-12-27 10:24:10 +09:00
Ian Barwick
407a7ea2f4 repmgr: add missing -W option to getopt_long() invocation
Addresses GitHub #350.
2017-12-20 10:28:31 +09:00
Martín Marqués
4d2eca0978 Switch spaces for tabs in repmgr.conf sample file.
This makes comments stay aligned in most cases the conf file is
modified, and when indentation changes, it's easy to re-align
(by removing or adding a tab)

Signed-off-by: Martín Marqués <martin.marques@2ndquadrant.com>
2017-12-20 09:27:06 +09:00
Martín Marqués
9d25544ab5 Add more information to the setting up sudo without requiretty in
the documentation

Signed-off-by: Martín Marqués <martin.marques@2ndquadrant.com>
2017-12-20 09:27:02 +09:00
Daymel Bonne Solís
8506607388 Fix package name 2017-12-20 09:26:57 +09:00
Ian Barwick
e8e059c26d docs: update 4.0.1 release date 2017-12-13 15:15:13 +09:00
Abhijit Menon-Sen
38d293694d Fix typo: upstream_node_id → upstream_node 2017-12-11 09:30:37 +09:00
Ian Barwick
54a10a0c3f Add diagnostic option "repmgr node check --has-passfile"
This checks if the active libpq version (9.6 and later) has the
"passfile" option, and returns 0 if present, 1 if not.
`
2017-12-05 12:53:04 +09:00
Ian Barwick
a8016f602f Fix unpackaged upgrade SQL for PostgreSQL 9.3 2017-12-04 17:46:52 +09:00
Ian Barwick
de57ecdad1 Finalize 4.0.1 release files 2017-11-29 17:02:47 +09:00
Ian Barwick
1fde81cf3f docs: improve event notification documentation 2017-11-29 14:44:07 +09:00
Ian Barwick
146c412061 docs: minor fixes to various examples 2017-11-29 11:30:38 +09:00
Ian Barwick
e9cb61ae7a docs: add additional note about setting "wal_log_hints"
Useful to reference this when discussing PostgreSQL configuration in
general.
2017-11-29 11:25:14 +09:00
Ian Barwick
50e9460b3e Update release notes 2017-11-28 13:42:28 +09:00
Ian Barwick
47e7cbe147 Update HISTORY 2017-11-28 13:00:31 +09:00
Ian Barwick
bf0be3eb43 Bump version
4.0.1
2017-11-28 12:36:22 +09:00
Ian Barwick
270da1294c repmgr: initialise "voting_term" in "repmgr primary register"
This previously happened in the extension SQL code, which could
potentially cause replay problems if installing on a BDR cluster.

As this table is only required for streaming replication failover,
move the initialisation to "repmgr primary register".

Addresses GitHub #344 .
2017-11-28 12:26:33 +09:00
Ian Barwick
d3c47f450f docs: add 2ndQ yum repository installation instructions
These replace the HTML document at https://repmgr.org/yum-repository.html
2017-11-24 14:14:36 +09:00
Ian Barwick
c20475f94a Delete any replication slots copied by pg_rewind
If --force-rewind is used in conjunction with "repmgr node rejoin",
any replication slots present on the source node will be copied too;
it's essential to remove these to prevent stale slots being extant
when the node starts up.

We do this at file system level *before* the server starts to minimize
the risk of any problems.

Addresses GitHub #334
2017-11-24 11:15:14 +09:00
Ian Barwick
e0560c3e70 docs: fix configuration file example
Per report from Carlos Chapi.
2017-11-24 09:27:39 +09:00
Ian Barwick
3fa2bef6f4 repmgr: fix configuration file sanity check
The check was being carried out regardless of whether --copy-external-config-files
was specified, which means cloning will fail if no SSH connection is available.

Addresses GitHub #342
2017-11-23 22:50:28 +09:00
Ian Barwick
f8a0b051c8 repmgr: fix return code output for repmgr node check --action=...
Addresses GitHub #340
2017-11-23 10:35:41 +09:00
Martín Marqués
3e4a5e6ff5 Fix missing FQN for the nodes table.
This bug was not detected before because most users work with the repmgr
user. For that reason, the repmgr schema is already in the search_path
by default.

Add the repmgr schema to the nodes table in the LEFT JOIN used for
cluster show (and in other places)

Signed-off-by: Martín Marqués <martin.marques@2ndquadrant.com>
2017-11-23 10:35:38 +09:00
Ian Barwick
020b5b6982 docs: update 4.0.0 release notes 2017-11-21 16:27:18 +09:00
75 changed files with 1991 additions and 632 deletions

View File

@@ -2,7 +2,7 @@ License and Contributions
=========================
`repmgr` is licensed under the GPL v3. All of its code and documentation is
Copyright 2010-2017, 2ndQuadrant Limited. See the files COPYRIGHT and LICENSE for
Copyright 2010-2018, 2ndQuadrant Limited. See the files COPYRIGHT and LICENSE for
details.
The development of repmgr has primarily been sponsored by 2ndQuadrant customers.

View File

@@ -1,4 +1,4 @@
Copyright (c) 2010-2017, 2ndQuadrant Limited
Copyright (c) 2010-2018, 2ndQuadrant Limited
All rights reserved.
This program is free software: you can redistribute it and/or modify

29
HISTORY
View File

@@ -1,6 +1,31 @@
4.0.2 2018-01-18
repmgr: add missing -W option to getopt_long() invocation; GitHub #350 (Ian)
repmgr: automatically create slot name if missing; GitHub #343 (Ian)
repmgr: fixes to parsing output of remote repmgr invocations; GitHub #349 (Ian)
repmgr: BDR support - create missing connection replication set
if required; GitHub #347 (Ian)
repmgr: handle missing node record in "repmgr node rejoin"; GitHub #358 (Ian)
repmgr: enable documentation to be build as single HTML file; GitHub #353 (fanf2)
repmgr: recognize "--terse" option for "repmgr cluster event"; GitHub #360 (Ian)
repmgr: add "--wait-start" option for "repmgr standby register"; GitHub #356 (Ian)
repmgr: add "%p" event notification parameter for "repmgr standby switchover"
containing the node ID of the demoted primary (Ian)
docs: various fixes and updates (Ian, Daymel, Martín, ams)
4.0.1 2017-12-13
repmgr: ensure "repmgr node check --action=" returns appropriate return
code; GitHub #340 (Ian)
repmgr: add missing schema qualification in get_all_node_records_with_upstream()
query GitHub #341 (Martín)
repmgr: initialise "voting_term" table in application, not extension SQL;
GitHub #344 (Ian)
repmgr: delete any replication slots copied by pg_rewind; GitHub #334 (Ian)
repmgr: fix configuration file sanity check; GitHub #342 (Ian)
Improve event notification documentation (Ian)
4.0.0 2017-11-21
Complete rewrite with many changes; for details see the repmgr 4.0.0 release
notes at: https://repmgr.org/docs/4.0/release-4.0.html
notes at: https://repmgr.org/docs/4.0/release-4.0.0.html
3.3.2 2017-06-01
Add support for PostgreSQL 10 (Ian)
@@ -223,7 +248,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)

View File

@@ -6,7 +6,7 @@
* supported PostgreSQL versions. They're unlikely to change but
* it would be worth keeping an eye on them for any fixes/improvements.
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California

View File

@@ -1,6 +1,6 @@
/*
* compat.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California

View File

@@ -1,7 +1,7 @@
/*
* config.c - parse repmgr.conf and other configuration-related functionality
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -1,7 +1,7 @@
/*
* configfile.h
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
*
* This program is free software: you can redistribute it and/or modify

22
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for repmgr 4.0.0.
# Generated by GNU Autoconf 2.69 for repmgr 4.0.2.
#
# Report bugs to <pgsql-bugs@postgresql.org>.
#
@@ -11,7 +11,7 @@
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
#
# Copyright (c) 2010-2017, 2ndQuadrant Ltd.
# Copyright (c) 2010-2018, 2ndQuadrant Ltd.
## -------------------- ##
## M4sh Initialization. ##
## -------------------- ##
@@ -582,8 +582,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='repmgr'
PACKAGE_TARNAME='repmgr'
PACKAGE_VERSION='4.0.0'
PACKAGE_STRING='repmgr 4.0.0'
PACKAGE_VERSION='4.0.2'
PACKAGE_STRING='repmgr 4.0.2'
PACKAGE_BUGREPORT='pgsql-bugs@postgresql.org'
PACKAGE_URL='https://2ndquadrant.com/en/resources/repmgr/'
@@ -1179,7 +1179,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures repmgr 4.0.0 to adapt to many kinds of systems.
\`configure' configures repmgr 4.0.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1240,7 +1240,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of repmgr 4.0.0:";;
short | recursive ) echo "Configuration of repmgr 4.0.2:";;
esac
cat <<\_ACEOF
@@ -1319,14 +1319,14 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
repmgr configure 4.0.0
repmgr configure 4.0.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
Copyright (c) 2010-2017, 2ndQuadrant Ltd.
Copyright (c) 2010-2018, 2ndQuadrant Ltd.
_ACEOF
exit
fi
@@ -1338,7 +1338,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by repmgr $as_me 4.0.0, which was
It was created by repmgr $as_me 4.0.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2379,7 +2379,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by repmgr $as_me 4.0.0, which was
This file was extended by repmgr $as_me 4.0.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -2442,7 +2442,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
repmgr config.status 4.0.0
repmgr config.status 4.0.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@@ -1,6 +1,6 @@
AC_INIT([repmgr], [4.0.0], [pgsql-bugs@postgresql.org], [repmgr], [https://2ndquadrant.com/en/resources/repmgr/])
AC_INIT([repmgr], [4.0.2], [pgsql-bugs@postgresql.org], [repmgr], [https://2ndquadrant.com/en/resources/repmgr/])
AC_COPYRIGHT([Copyright (c) 2010-2017, 2ndQuadrant Ltd.])
AC_COPYRIGHT([Copyright (c) 2010-2018, 2ndQuadrant Ltd.])
AC_CONFIG_HEADER(config.h)

View File

@@ -1,6 +1,6 @@
/*
* controldata.c
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California

View File

@@ -1,6 +1,6 @@
/*
* controldata.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California

322
dbutils.c
View File

@@ -1,7 +1,7 @@
/*
* dbutils.c - Database connection/management functions
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
*
* This program is free software: you can redistribute it and/or modify
@@ -700,7 +700,7 @@ has_passfile(void)
PQconninfoFree(defs);
return has_passfile;
return has_passfile;
}
@@ -1608,7 +1608,12 @@ repmgrd_get_local_node_id(PGconn *conn)
res = PQexec(conn, "SELECT repmgr.get_local_node_id()");
if (!PQgetisnull(res, 0, 0))
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_error(_("unable to execute \"SELECT repmgr.get_local_node_id()\""));
log_detail("%s", PQerrorMessage(conn));
}
else if (!PQgetisnull(res, 0, 0))
{
local_node_id = atoi(PQgetvalue(res, 0, 0));
}
@@ -2130,7 +2135,7 @@ get_all_node_records_with_upstream(PGconn *conn, NodeInfoList *node_list)
" SELECT n.node_id, n.type, n.upstream_node_id, n.node_name, n.conninfo, n.repluser, "
" n.slot_name, n.location, n.priority, n.active, un.node_name AS upstream_node_name "
" FROM repmgr.nodes n "
" LEFT JOIN nodes un "
" LEFT JOIN repmgr.nodes un "
" ON un.node_id = n.upstream_node_id"
" ORDER BY n.node_id ");
@@ -2592,6 +2597,36 @@ truncate_node_records(PGconn *conn)
return true;
}
bool
update_node_record_slot_name(PGconn *primary_conn, int node_id, char *slot_name)
{
PQExpBufferData query;
PGresult *res = NULL;
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
" UPDATE repmgr.nodes "
" SET slot_name = '%s' "
" WHERE node_id = %i ",
slot_name,
node_id);
res = PQexec(primary_conn, query.data);
termPQExpBuffer(&query);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
log_error(_("unable to set node record slot name:\n %s"),
PQerrorMessage(primary_conn));
PQclear(res);
return false;
}
PQclear(res);
return true;
}
void
get_node_replication_stats(PGconn *conn, int server_version_num, t_node_info *node_info)
{
@@ -2962,7 +2997,6 @@ create_event_record(PGconn *conn, t_configuration_options *options, int node_id,
}
/*
* create_event_notification()
*
@@ -3063,7 +3097,7 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
/* we don't treat this as an error */
/* we don't treat this as a fatal error */
log_warning(_("unable to create event record:\n %s"),
PQerrorMessage(conn));
@@ -3216,6 +3250,20 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
dst_ptr += strlen(dst_ptr);
}
break;
case 'p':
/* %p: former primary id ("repmgr standby switchover") */
src_ptr++;
if (event_info->former_primary_id != UNKNOWN_NODE_ID)
{
PQExpBufferData node_id;
initPQExpBuffer(&node_id);
appendPQExpBuffer(&node_id,
"%i", event_info->former_primary_id);
strlcpy(dst_ptr, node_id.data, end_ptr - dst_ptr);
dst_ptr += strlen(dst_ptr);
termPQExpBuffer(&node_id);
}
break;
default:
/* otherwise treat the % as not special */
if (dst_ptr < end_ptr)
@@ -3249,10 +3297,102 @@ _create_event(PGconn *conn, t_configuration_options *options, int node_id, char
}
PGresult *
get_event_records(PGconn *conn, int node_id, const char *node_name, const char *event, bool all, int limit)
{
PGresult *res;
PQExpBufferData query;
PQExpBufferData where_clause;
initPQExpBuffer(&query);
initPQExpBuffer(&where_clause);
/* LEFT JOIN used here as a node record may have been removed */
appendPQExpBuffer(&query,
" SELECT e.node_id, n.node_name, e.event, e.successful, "
" TO_CHAR(e.event_timestamp, 'YYYY-MM-DD HH24:MI:SS') AS timestamp, "
" e.details "
" FROM repmgr.events e "
"LEFT JOIN repmgr.nodes n ON e.node_id = n.node_id ");
if (node_id != UNKNOWN_NODE_ID)
{
append_where_clause(&where_clause,
"n.node_id=%i", node_id);
}
else if (node_name[0] != '\0')
{
char *escaped = escape_string(conn, node_name);
if (escaped == NULL)
{
log_error(_("unable to escape value provided for node name"));
log_detail(_("node name is: \"%s\""), node_name);
}
else
{
append_where_clause(&where_clause,
"n.node_name='%s'",
escaped);
pfree(escaped);
}
}
if (event[0] != '\0')
{
char *escaped = escape_string(conn, event);
if (escaped == NULL)
{
log_error(_("unable to escape value provided for event"));
log_detail(_("event is: \"%s\""), event);
}
else
{
append_where_clause(&where_clause,
"e.event='%s'",
escaped);
pfree(escaped);
}
}
appendPQExpBuffer(&query, "\n%s\n",
where_clause.data);
appendPQExpBuffer(&query,
" ORDER BY e.event_timestamp DESC");
if (all == false && limit > 0)
{
appendPQExpBuffer(&query, " LIMIT %i",
limit);
}
log_debug("do_cluster_event():\n%s", query.data);
res = PQexec(conn, query.data);
termPQExpBuffer(&query);
termPQExpBuffer(&where_clause);
return res;
}
/* ========================== */
/* replication slot functions */
/* ========================== */
void
create_slot_name(char *slot_name, int node_id)
{
maxlen_snprintf(slot_name, "repmgr_slot_%i", node_id);
}
bool
create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, PQExpBufferData *error_msg)
{
@@ -3735,7 +3875,7 @@ int
get_current_term(PGconn *conn)
{
PGresult *res = NULL;
int term = -1;
int term = VOTING_TERM_NOT_SET;
res = PQexec(conn, "SELECT term FROM repmgr.voting_term");
@@ -3747,13 +3887,43 @@ get_current_term(PGconn *conn)
return -1;
}
term = atoi(PQgetvalue(res, 0, 0));
if (PQntuples(res) > 0)
{
term = atoi(PQgetvalue(res, 0, 0));
}
PQclear(res);
return term;
}
void
initialize_voting_term(PGconn *conn)
{
PGresult *res = NULL;
int current_term = get_current_term(conn);
if (current_term == VOTING_TERM_NOT_SET)
{
res = PQexec(conn, "INSERT INTO repmgr.voting_term (term) VALUES (1)");
}
else
{
res = PQexec(conn, "UPDATE repmgr.voting_term SET term = 1");
}
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
log_error(_("unable to initialize repmgr.voting_term:\n %s"),
PQerrorMessage(conn));
}
PQclear(res);
return;
}
void
increment_current_term(PGconn *conn)
{
@@ -3765,8 +3935,6 @@ increment_current_term(PGconn *conn)
{
log_error(_("unable to increment repmgr.voting_term:\n %s"),
PQerrorMessage(conn));
PQclear(res);
return;
}
PQclear(res);
@@ -4050,21 +4218,24 @@ is_active_bdr_node(PGconn *conn, const char *node_name)
appendPQExpBuffer(&query,
" SELECT COALESCE(s.active, TRUE) AS active"
" FROM bdr.bdr_nodes n "
" LEFT JOIN pg_replication_slots s "
" ON slot_name=bdr.bdr_format_slot_name(n.node_sysid, n.node_timeline, n.node_dboid, (SELECT oid FROM pg_database WHERE datname = current_database())) "
" WHERE node_name='%s' ",
" LEFT JOIN pg_catalog.pg_replication_slots s "
" ON s.slot_name=bdr.bdr_format_slot_name(n.node_sysid, n.node_timeline, n.node_dboid, (SELECT oid FROM pg_catalog.pg_database WHERE datname = pg_catalog.current_database())) "
" WHERE n.node_name='%s' ",
node_name);
log_verbose(LOG_DEBUG, "is_active_bdr_node():\n %s", query.data);
res = PQexec(conn, query.data);
termPQExpBuffer(&query);
/* we don't care if the query fails */
if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) == 0)
{
is_active_bdr_node = false;
}
else
{
is_active_bdr_node = atoi(PQgetvalue(res, 0, 0)) == 1 ? true : false;
is_active_bdr_node = atobool(PQgetvalue(res, 0, 0));
}
PQclear(res);
@@ -4174,7 +4345,7 @@ add_table_to_bdr_replication_set(PGconn *conn, const char *tablename, const char
bool
bdr_node_exists(PGconn *conn, const char *node_name)
bdr_node_name_matches(PGconn *conn, const char *node_name, PQExpBufferData *bdr_local_node_name)
{
PQExpBufferData query;
PGresult *res = NULL;
@@ -4183,10 +4354,7 @@ bdr_node_exists(PGconn *conn, const char *node_name)
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
"SELECT COUNT(*)"
" FROM bdr.bdr_nodes"
" WHERE node_name = '%s'",
node_name);
"SELECT bdr.bdr_get_local_node_name() AS node_name");
res = PQexec(conn, query.data);
termPQExpBuffer(&query);
@@ -4197,7 +4365,9 @@ bdr_node_exists(PGconn *conn, const char *node_name)
}
else
{
node_exists = atoi(PQgetvalue(res, 0, 0)) == 1 ? true : false;
node_exists = true;
appendPQExpBuffer(bdr_local_node_name,
"%s", PQgetvalue(res, 0, 0));
}
PQclear(res);
@@ -4482,3 +4652,115 @@ unset_bdr_failover_handler(PGconn *conn)
PQclear(res);
return;
}
bool
bdr_node_has_repmgr_set(PGconn *conn, const char *node_name)
{
PQExpBufferData query;
PGresult *res = NULL;
bool has_repmgr_set = false;
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
" SELECT COUNT(*) "
" FROM UNNEST(bdr.connection_get_replication_sets('%s') AS repset "
" WHERE repset = 'repmgr'",
node_name);
res = PQexec(conn, query.data);
termPQExpBuffer(&query);
if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) == 0)
{
has_repmgr_set = false;
}
else
{
has_repmgr_set = atoi(PQgetvalue(res, 0, 0)) == 1 ? true : false;
}
PQclear(res);
return has_repmgr_set;
}
bool
bdr_node_set_repmgr_set(PGconn *conn, const char *node_name)
{
PQExpBufferData query;
PGresult *res = NULL;
bool success = true;
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
" SELECT bdr.connection_set_replication_sets( "
" ARRAY( "
" SELECT repset::TEXT "
" FROM UNNEST(bdr.connection_get_replication_sets('%s')) AS repset "
" UNION "
" SELECT 'repmgr'::TEXT "
" ), "
" '%s' "
" ) ",
node_name,
node_name);
res = PQexec(conn, query.data);
termPQExpBuffer(&query);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
success = false;
}
PQclear(res);
return success;
}
/* miscellaneous debugging functions */
const char *
print_node_status(NodeStatus node_status)
{
switch (node_status)
{
case NODE_STATUS_UNKNOWN:
return "UNKNOWN";
case NODE_STATUS_UP:
return "UP";
case NODE_STATUS_SHUTTING_DOWN:
return "SHUTTING_DOWN";
case NODE_STATUS_DOWN:
return "DOWN";
case NODE_STATUS_UNCLEAN_SHUTDOWN:
return "UNCLEAN_SHUTDOWN";
}
return "UNIDENTIFIED_STATUS";
}
const char *
print_pqping_status(PGPing ping_status)
{
switch (ping_status)
{
case PQPING_OK:
return "PQPING_OK";
case PQPING_REJECT:
return "PQPING_REJECT";
case PQPING_NO_RESPONSE:
return "PQPING_NO_RESPONSE";
case PQPING_NO_ATTEMPT:
return "PQPING_NO_ATTEMPT";
}
return "PQPING_UNKNOWN_STATUS";
}

View File

@@ -1,7 +1,7 @@
/*
* dbutils.h
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -74,6 +74,7 @@ typedef enum
{
NODE_STATUS_UNKNOWN = -1,
NODE_STATUS_UP,
NODE_STATUS_SHUTTING_DOWN,
NODE_STATUS_DOWN,
NODE_STATUS_UNCLEAN_SHUTDOWN
} NodeStatus;
@@ -174,11 +175,13 @@ typedef struct s_event_info
{
char *node_name;
char *conninfo_str;
int former_primary_id;
} t_event_info;
#define T_EVENT_INFO_INITIALIZER { \
NULL, \
NULL \
NULL, \
UNKNOWN_NODE_ID \
}
@@ -369,10 +372,8 @@ bool check_cluster_schema(PGconn *conn);
/* GUC manipulation functions */
bool set_config(PGconn *conn, const char *config_param, const char *config_value);
bool set_config_bool(PGconn *conn, const char *config_param, bool state);
int guc_set(PGconn *conn, const char *parameter, const char *op,
const char *value);
int guc_set_typed(PGconn *conn, const char *parameter, const char *op,
const char *value, const char *datatype);
int guc_set(PGconn *conn, const char *parameter, const char *op, const char *value);
int guc_set_typed(PGconn *conn, const char *parameter, const char *op, const char *value, const char *datatype);
bool get_pg_setting(PGconn *conn, const char *setting, char *output);
/* server information functions */
@@ -421,10 +422,10 @@ bool update_node_record_set_primary(PGconn *conn, int this_node_id);
bool update_node_record_set_upstream(PGconn *conn, int this_node_id, int new_upstream_node_id);
bool update_node_record_status(PGconn *conn, int this_node_id, char *type, int upstream_node_id, bool active);
bool update_node_record_conn_priority(PGconn *conn, t_configuration_options *options);
bool update_node_record_slot_name(PGconn *primary_conn, int node_id, char *slot_name);
bool witness_copy_node_records(PGconn *primary_conn, PGconn *witness_conn);
void clear_node_info_list(NodeInfoList *nodes);
/* PostgreSQL configuration file location functions */
@@ -437,8 +438,10 @@ void config_file_list_add(t_configfile_list *list, const char *file, const char
bool create_event_record(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details);
bool create_event_notification(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details);
bool create_event_notification_extended(PGconn *conn, t_configuration_options *options, int node_id, char *event, bool successful, char *details, t_event_info *event_info);
PGresult *get_event_records(PGconn *conn, int node_id, const char *node_name, const char *event, bool all, int limit);
/* replication slot functions */
void create_slot_name(char *slot_name, int node_id);
bool create_replication_slot(PGconn *conn, char *slot_name, int server_version_num, PQExpBufferData *error_msg);
bool drop_replication_slot(PGconn *conn, char *slot_name);
RecordStatus get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record);
@@ -473,6 +476,7 @@ bool delete_monitoring_records(PGconn *primary_conn, int keep_history);
/* node voting functions */
void initialize_voting_term(PGconn *conn);
int get_current_term(PGconn *conn);
void increment_current_term(PGconn *conn);
bool announce_candidature(PGconn *conn, t_node_info *this_node, t_node_info *other_node, int electoral_term);
@@ -498,12 +502,17 @@ bool is_bdr_repmgr(PGconn *conn);
bool is_table_in_bdr_replication_set(PGconn *conn, const char *tablename, const char *set);
bool add_table_to_bdr_replication_set(PGconn *conn, const char *tablename, const char *set);
void add_extension_tables_to_bdr_replication_set(PGconn *conn);
bool bdr_node_exists(PGconn *conn, const char *node_name);
bool bdr_node_name_matches(PGconn *conn, const char *node_name, PQExpBufferData *bdr_local_node_name);
ReplSlotStatus get_bdr_node_replication_slot_status(PGconn *conn, const char *node_name);
void get_bdr_other_node_name(PGconn *conn, int node_id, char *name_buf);
bool am_bdr_failover_handler(PGconn *conn, int node_id);
void unset_bdr_failover_handler(PGconn *conn);
bool bdr_node_has_repmgr_set(PGconn *conn, const char *node_name);
bool bdr_node_set_repmgr_set(PGconn *conn, const char *node_name);
/* miscellaneous debugging functions */
const char *print_node_status(NodeStatus node_status);
const char *print_pqping_status(PGPing ping_status);
#endif /* _REPMGR_DBUTILS_H_ */

View File

@@ -3,7 +3,7 @@
* dirmod.c
* directory handling functions
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -311,6 +311,14 @@ create_pg_dir(char *path, bool force)
return true;
}
int
rmdir_recursive(char *path)
{
return nftw(path, unlink_dir_callback, 64, FTW_DEPTH | FTW_PHYS);
}
static int
unlink_dir_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
{

View File

@@ -1,6 +1,6 @@
/*
* dirutil.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -26,5 +26,5 @@ extern int check_dir(char *path);
extern bool create_dir(char *path);
extern bool is_pg_dir(char *path);
extern bool create_pg_dir(char *path, bool force);
extern int rmdir_recursive(char *path);
#endif

2
doc/.gitignore vendored
View File

@@ -2,4 +2,6 @@ HTML.index
bookindex.sgml
html-stamp
html/
nochunks.dsl
repmgr.html
version.sgml

View File

@@ -10,7 +10,7 @@ SGMLINCLUDE = -D . -D ${srcdir}
SPFLAGS += -wall -wno-unused-param -wno-empty -wfully-tagged
JADE.html.call = $(JADE) $(JADEFLAGS) $(SPFLAGS) $(SGMLINCLUDE) $(CATALOG) -d stylesheet.dsl -t sgml -i output-html
JADE.html.call = $(JADE) $(JADEFLAGS) $(SPFLAGS) $(SGMLINCLUDE) $(CATALOG) -t sgml -i output-html
ALLSGML := $(wildcard $(srcdir)/*.sgml)
# to build bookindex
@@ -26,10 +26,15 @@ html: html-stamp
html-stamp: repmgr.sgml $(ALLSGML) $(GENERATED_SGML) stylesheet.dsl website-docs.css
$(MKDIR_P) html
$(JADE.html.call) -i include-index $<
$(JADE.html.call) -d stylesheet.dsl -i include-index $<
cp $(srcdir)/stylesheet.css $(srcdir)/website-docs.css html/
touch $@
repmgr.html: repmgr.sgml $(ALLSGML) $(GENERATED_SGML) stylesheet.dsl website-docs.css
sed '/html-index-filename/a\
(define nochunks #t)' <stylesheet.dsl >nochunks.dsl
$(JADE.html.call) -d nochunks.dsl -i include-index $< >repmgr.html
version.sgml: ${repmgr_top_builddir}/repmgr_version.h
{ \
echo "<!ENTITY repmgrversion \"$(REPMGR_VERSION)\">"; \
@@ -37,7 +42,7 @@ version.sgml: ${repmgr_top_builddir}/repmgr_version.h
HTML.index: repmgr.sgml $(ALMOSTALLSGML) stylesheet.dsl
@$(MKDIR_P) html
$(JADE.html.call) -V html-index $<
$(JADE.html.call) -d stylesheet.dsl -V html-index $<
website-docs.css:
@$(MKDIR_P) html

View File

@@ -1,5 +1,5 @@
<appendix id="appendix-faq" xreflabel="FAQ">
<indexterm>
<indexterm>
<primary>FAQ (Frequently Asked Questions)</primary>
</indexterm>

158
doc/appendix-packages.sgml Normal file
View File

@@ -0,0 +1,158 @@
<appendix id="appendix-packages" xreflabel="Package details">
<indexterm>
<primary>packages</primary>
</indexterm>
<title>&repmgr; package details</title>
<para>
This section provides technical details about various &repmgr; binary
packages, such as location of the installed binaries and
configuration files.
</para>
<sect1 id="packages-centos" xreflabel="CentOS packages">
<title>CentOS, RHEL, Scientific Linux etc.</title>
<para>
Currently packages are provided for versions 6.x and 7.x of CentOS et al.
</para>
<note>
<para>
For PostgreSQL 9.6 and lower, the CentOS packages use a mixture of <literal>9.6</literal>
and <literal>96</literal> in various places to designate the major version;
from PostgreSQL 10, the first part of the version number (e.g. <literal>10</literal>) is
the major version, so there is more consistency in file/path/package naming.
</para>
</note>
<table id="centos-7-packages">
<title>CentOS 7 packages</title>
<tgroup cols="2">
<tbody>
<row>
<entry>Repository URL:</entry>
<entry><ulink url="https://yum.postgresql.org/repopackages.php">https://yum.postgresql.org/repopackages.php</ulink></entry>
</row>
<row>
<entry>Repository documentation:</entry>
<entry><ulink url="https://yum.postgresql.org/">https://yum.postgresql.org/</ulink></entry>
</row>
<row>
<entry>Package name example:</entry>
<entry><filename>repmgr10-4.0.0-1.rhel7.x86_64</filename></entry>
</row>
<row>
<entry>Metapackage:</entry>
<entry>(none)</entry>
</row>
<row>
<entry>Installation command:</entry>
<entry><literal>yum install -y repmgr10</literal></entry>
</row>
<row>
<entry>Binary location:</entry>
<entry><filename>/usr/pgsql-10/bin</filename></entry>
</row>
<row>
<entry>In default path:</entry>
<entry>NO</entry>
</row>
<row>
<entry>Configuration file location:</entry>
<entry><filename>/etc/repmgr/10/repmgr.conf</filename></entry>
</row>
<row>
<entry>repmgrd service command:</entry>
<entry><literal>service repmgr10</literal></entry>
</row>
<row>
<entry>repmgrd service file location:</entry>
<entry><filename>/usr/lib/systemd/system/repmgr10.service</filename></entry>
</row>
<row>
<entry>repmgrd log file location:</entry>
<entry>(not specified)</entry>
</row>
</tbody>
</tgroup>
</table>
<table id="centos-6-packages">
<title>CentOS 6 packages</title>
<tgroup cols="2">
<tbody>
<row>
<entry>Repository URL:</entry>
<entry><ulink url="https://yum.postgresql.org/repopackages.php">https://yum.postgresql.org/repopackages.php</ulink></entry>
</row>
<row>
<entry>Repository documentation:</entry>
<entry><ulink url="https://yum.postgresql.org/">https://yum.postgresql.org/</ulink></entry>
</row>
<row>
<entry>Package name example:</entry>
<entry><filename>repmgr96-4.0.0-1.rhel6.x86_64</filename></entry>
</row>
<row>
<entry>Metapackage:</entry>
<entry>NO</entry>
</row>
<row>
<entry>Installation command:</entry>
<entry><literal>yum install -y repmgr96</literal></entry>
</row>
<row>
<entry>Binary location:</entry>
<entry><filename>/usr/pgsql-9.6/bin</filename></entry>
</row>
<row>
<entry>In default path:</entry>
<entry>NO</entry>
</row>
<row>
<entry>Configuration file location:</entry>
<entry><filename>/etc/repmgr/9.6/repmgr.conf</filename></entry>
</row>
<row>
<entry>repmgrd service command:</entry>
<entry>service repmgr-9.6</entry>
</row>
<row>
<entry>repmgrd service file location:</entry>
<entry><literal>/etc/init.d/repmgr-9.6</literal></entry>
</row>
<row>
<entry>repmgrd log file location:</entry>
<entry><filename>/var/log/repmgr/repmgrd-9.6.log</filename></entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
</appendix>

View File

@@ -1,45 +1,324 @@
<appendix id="appendix-release-notes" xreflabel="Release notes">
<title>Release notes</title>
<indexterm>
<primary>Release notes</primary>
</indexterm>
<para>
Changes to each &repmgr; release are documented in the release notes.
Please read the release notes for all versions between
your current version and the version you are plan to upgrade to
before performing an upgrade, as there may be version-specific upgrade steps.
</para>
<para>
See also: <xref linkend="upgrading-repmgr">
</para>
<sect1 id="release-4.0">
<title>Release 4.0beta1</title>
<para><emphasis>Thu Oct 5, 2017</emphasis></para>
<appendix id="appendix-release-notes">
<title>Release notes</title>
<indexterm>
<primary>Release notes</primary>
</indexterm>
<para>
repmgr 4.0 is an entirely new version of &repmgr;, providing many
improvements together with some changes in the way it works.
In particular changes have been made to some configuration file
settings and command line options for consistency and clarity.
</para>
<para>
For detailed instructions on upgrading from repmgr 3.x, see
<xref linkend="upgrading-from-repmgr-3">.
Changes to each &repmgr; release are documented in the release notes.
Please read the release notes for all versions between
your current version and the version you are plan to upgrade to
before performing an upgrade, as there may be version-specific upgrade steps.
</para>
<note>
<para>
See also: <xref linkend="upgrading-repmgr">
</para>
<sect1 id="release-4.0.2">
<title>Release 4.0.2</title>
<para><emphasis>Thu Jan 18, 2018</emphasis></para>
<para>
repmgr 4.0.2 contains some bug fixes and minor usability enhancements.
</para>
<sect2>
<title>Usability enhancements</title>
<para>
<itemizedlist>
<listitem>
<para>
Recognize the <option>-t</option>/<option>--terse</option> option for
<command><link linkend="repmgr-cluster-event">repmgr cluster event</link></command> to hide
the <literal>Details</literal> column (GitHub #360)
</para>
</listitem>
<listitem>
<para>
Add "--wait-start" option for
<command><link linkend="repmgr-standby-register">repmgr standby register</link></command>
(GitHub #356)
</para>
</listitem>
<listitem>
<para>
Add <literal>%p</literal> <link linkend="event-notifications">event notification parameter</link>
for <command><link linkend="repmgr-standby-switchover">repmgr standby switchover</link></command>
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
<sect2>
<title>Bug fixes</title>
<para>
<itemizedlist>
<listitem>
<para>
Add missing -W option to <literal>getopt_long()</literal> invocation (GitHub #350)
</para>
</listitem>
<listitem>
<para>
Automatically create slot name if missing (GitHub #343)
</para>
</listitem>
<listitem>
<para>
Fixes to parsing output of remote repmgr invocations (GitHub #349)
</para>
</listitem>
<listitem>
<para>
When registering BDR nodes, automatically create missing connection replication set (GitHub #347)
</para>
</listitem>
<listitem>
<para>
Handle missing node record in <command><link linkend="repmgr-node-rejoin">repmgr node rejoin</link></command>
(GitHub #358)
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
<sect2>
<title>Documentation</title>
<para>
<itemizedlist>
<listitem>
<para>
The documentation can now be built as a single HTML file (GitHub pull request #353)
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="release-4.0.1">
<title>Release 4.0.1</title>
<para><emphasis>Wed Dec 13, 2017</emphasis></para>
<para>
repmgr 4.0.1 is a bugfix release.
</para>
<sect2>
<title>Bug fixes</title>
<para>
<itemizedlist>
<listitem>
<para>
ensure correct return codes are returned for
<command><link linkend="repmgr-node-check">repmgr node check --action=</link></command> operations
(GitHub #340)
</para>
</listitem>
<listitem>
<para>
Fix <xref linkend="repmgr-cluster-show"> when <literal>repmgr</literal> schema not set in search path
(GitHub #341)
</para>
</listitem>
<listitem>
<para>
When using <literal>--force-rewind</literal> with <xref linkend="repmgr-node-rejoin">
delete any replication slots copied by <application>pg_rewind</application>
(GitHub #334)
</para>
</listitem>
<listitem>
<para>
Only perform sanity check on accessibility of configuration files outside
the data directory when <literal>--copy-external-config-files</literal>
provided (GitHub #342)
</para>
</listitem>
<listitem>
<para>
Initialise "voting_term" table in application, not extension SQL
(GitHub #344)
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="release-4.0.0">
<title>Release 4.0.0</title>
<para><emphasis>Tue Nov 21, 2017</emphasis></para>
<para>
repmgr 4.0 is an entirely new version of &repmgr;, implementing &repmgr;
as a native PostgreSQL extension, adding new and improving existing features,
and making &repmgr; more user-friendly and intuitive to use. The new code base
will make it easier to add additional functionality for future releases.
</para>
<note>
<simpara>
With the new version, the opportunity has been taken to
make some changes in the way &repmgr; is set up and
configured. In particular changes have been made to some
configuration file settings consistency for and clarity.
Changes are covered in detail below
</simpara>
<simpara>
To standardise terminology, from this release <literal>primary</literal> is used to
denote the read/write node in a streaming replication cluster. <literal>master</literal>
is still accepted as an alias for &repmgr; commands
(e.g. <link linkend="repmgr-primary-register"><command>repmgr master register</command></link>).
</para>
</simpara>
</note>
<para>
For detailed instructions on upgrading from repmgr 3.x, see <xref linkend="upgrading-from-repmgr-3">.
</para>
<sect2>
<title>Features and improvements</title>
<para>
<itemizedlist>
<listitem>
<para>
<emphasis>improved switchover</emphasis>:
the <command>switchover</command> process has been improved and streamlined,
speeding up the switchover process and can also instruct other standbys
to follow the new primary once the switchover has completed. See
<xref linkend="performing-switchover"> for more details.
</para>
</listitem>
<listitem>
<para>
<emphasis>"--dry-run" option</emphasis>: many &repmgr; commands now provide
a <literal>--dry-run</literal> option which will execute the command as far
as possible without making any changes, which will enable possible issues
to be identified before the intended operation is actually carried out.
</para>
</listitem>
<listitem>
<para>
<emphasis>easier upgrades</emphasis>: &repmgr; is now implemented as a native
PostgreSQL extension, which means future upgrades can be carried out by
installing the upgraded package and issuing
<ulink url="https://www.postgresql.org/docs/current/static/sql-alterextension.html">ALTER EXTENSION repmgr UPDATE</ulink>.
</para>
</listitem>
<listitem>
<para>
<emphasis>improved logging output</emphasis>:
&repmgr; (and <application>repmgrd</application>) now provide more explicit
logging output giving a better picture of what is going on. Where appropriate,
<literal>DETAIL</literal> and <literal>HINT</literal> log lines provide additional
detail and suggestions for resolving problems. Additionally, <application>repmgrd</application>
now emits informational log lines at regular, configurable intervals
to confirm that it's running correctly and which node(s) it's monitoring.
</para>
</listitem>
<listitem>
<para>
<emphasis>automatic configuration file location in packages</emphasis>:
Many operating system packages place the &repmgr; configuration files
in a version-specific subdirectory, e.g. <filename>/etc/repmgr/9.6/repmgr.conf</filename>;
&repmgr; now makes it easy for package maintainers to provide a patch
with the actual file location, meaning <filename>repmgr.conf</filename>
does not need to be provided explicitly. This is currently the case
for 2ndQuadrant-provided <literal>.deb</literal> and <literal>.rpm</literal> packages.
</para>
</listitem>
<listitem>
<para>
<emphasis>monitoring and status checks</emphasis>:
New commands <xref linkend="repmgr-node-check"> and
<xref linkend="repmgr-node-status"> providing information
about a node's status and replication-related monitoring
output.
</para>
</listitem>
<listitem>
<para>
<emphasis>node rejoin</emphasis>:
New commands <xref linkend="repmgr-node-rejoin"> enables a failed
primary to be rejoined to a replication cluster, optionally using
<application>pg_rewind</application> to synchronise its data,
(note that <application>pg_rewind</application> may not be useable
in some circumstances).
</para>
</listitem>
<listitem>
<para>
<emphasis>automatic failover</emphasis>:
improved detection of node status; promotion decision based on a consensual
model, with the promoted primary explicitly informing other standbys to
follow it. The <application>repmgrd</application> daemon will continue
functioning even if the monitored PostgreSQL instance is down, and resume
monitoring if it reappears. Additionally, if the instance's role has changed
(typically from a primary to a standby, e.g. following reintegration of a
failed primary using <xref linkend="repmgr-node-rejoin">) <application>repmgrd</application>
will automatically resume monitoring it as a standby.
</para>
</listitem>
<listitem>
<para>
<emphasis>new documentation</emphasis>:
the existing documentation spread over multiple text files
has been consolidated into DocBook format (as used by the
main PostgreSQL project) and is now available online in
HTML format.
</para>
<para>
The DocBook files can easily be used to create versions
of the documentation in other formats such as PDF.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
<sect2>
<title>New command line options</title>
<para>
@@ -236,7 +515,7 @@
<sect2>
<title>repmgrd</title>
<para>
The `repmgr` shared library has been renamed from <literal>repmgr_funcs</literal> to
The shared library has been renamed from <literal>repmgr_funcs</literal> to
<literal>repmgr</literal>, meaning <varname>shared_preload_libraries</varname>
in <filename>postgresql.conf</filename> needs to be updated to the new name:
<programlisting>

View File

@@ -60,10 +60,10 @@
</varlistentry>
<varlistentry>
<term><option>%t</option></term>
<term><option>%s</option></term>
<listitem>
<para>
success (1 or 0)
success (1) or failure (0)
</para>
</listitem>
</varlistentry>
@@ -84,6 +84,17 @@
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>%p</option></term>
<listitem>
<para>
node ID of the demoted standby (<xref linkend="repmgr-standby-switchover"> only)
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
The values provided for <literal>%t</literal> and <literal>%d</literal>
@@ -121,11 +132,15 @@
<para>
By default, all notification types will be passed to the designated script;
the notification types can be filtered to explicitly named ones:
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara><literal>primary_register</literal></simpara>
</listitem>
<listitem>
<simpara><literal>primary_unregister</literal></simpara>
</listitem>
<listitem>
<simpara><literal>standby_register</literal></simpara>
</listitem>
@@ -144,6 +159,21 @@
<listitem>
<simpara><literal>standby_disconnect_manual</literal></simpara>
</listitem>
<listitem>
<simpara><literal>standby_failure</literal></simpara>
</listitem>
<listitem>
<simpara><literal>standby_recovery</literal></simpara>
</listitem>
<listitem>
<simpara><literal>witness_register</literal></simpara>
</listitem>
<listitem>
<simpara><literal>witness_unregister</literal></simpara>
</listitem>
<listitem>
<simpara><literal>node_rejoin</literal></simpara>
</listitem>
<listitem>
<simpara><literal>repmgrd_start</literal></simpara>
</listitem>

View File

@@ -80,6 +80,7 @@
<!ENTITY appendix-release-notes SYSTEM "appendix-release-notes.sgml">
<!ENTITY appendix-faq SYSTEM "appendix-faq.sgml">
<!ENTITY appendix-signatures SYSTEM "appendix-signatures.sgml">
<!ENTITY appendix-packages SYSTEM "appendix-packages.sgml">
<!ENTITY bookindex SYSTEM "bookindex.sgml">

View File

@@ -16,7 +16,7 @@
<para>
RPM packages for &repmgr; are available via Yum through
the PostgreSQL Global Development Group RPM repository
(<ulink url="https://yum.postgresql.org/">http://yum.postgresql.org/</>).
(<ulink url="https://yum.postgresql.org/">http://yum.postgresql.org/</ulink>).
Follow the instructions for your distribution (RedHat, CentOS,
Fedora, etc.) and architecture as detailed there.
</para>
@@ -24,11 +24,117 @@
<ulink url="https://2ndquadrant.com">2ndQuadrant</ulink> also provides its
own RPM packages which are made available
at the same time as each &repmgr; release, as it can take some days for
them to become available via the main PGDG repository. See here for details:
<ulink url="http://repmgr.org/yum-repository.html">http://repmgr.org/yum-repository.html</>
them to become available via the main PGDG repository. See following section for details:
</para>
<sect3 id="installation-packages-redhat-2ndq">
<title>2ndQuadrant repmgr yum repository</title>
<para>
Beginning with <ulink url="http://repmgr.org/release-notes-3.1.3.html">repmgr 3.1.3</ulink>,
<ulink url="https://2ndquadrant.com/">2ndQuadrant</ulink> provides a dedicated <literal>yum</literal>
repository for &repmgr; releases. This repository complements the main
<ulink url="https://yum.postgresql.org/repopackages.php">PGDG community repository</ulink>,
but enables repmgr users to access the latest &repmgr; packages before they are
available via the PGDG repository, which can take several days to be updated following
a fresh &repmgr; release.
</para>
<para>
<emphasis>Installation</emphasis>
<itemizedlist>
<listitem>
<para>
Import the repository public key (optional but recommended):
<programlisting>
rpm --import http://packages.2ndquadrant.com/repmgr/RPM-GPG-KEY-repmgr</programlisting>
</para>
</listitem>
<listitem>
<para>
Install the repository RPM for your distribution (this enables the 2ndQuadrant
repository as a source of repmgr packages):
<itemizedlist>
<listitem>
<simpara>
<emphasis>Fedora:</emphasis>
<ulink url="http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-fedora-1.0-1.noarch.rpm">http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-fedora-1.0-1.noarch.rpm</ulink>
</simpara>
</listitem>
<listitem>
<simpara>
<emphasis>RHEL, CentOS etc:</emphasis>
<ulink url="http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-rhel-1.0-1.noarch.rpm">http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-rhel-1.0-1.noarch.rpm</ulink>
</simpara>
</listitem>
</itemizedlist>
</para>
<para>
e.g.:
<programlisting>
$ yum install http://packages.2ndquadrant.com/repmgr/yum-repo-rpms/repmgr-rhel-1.0-1.noarch.rpm</programlisting>
</para>
</listitem>
<listitem>
<para>
Install the repmgr version appropriate for your PostgreSQL version (e.g. <literal>repmgr96</literal>), e.g.:
<programlisting>
$ yum install repmgr96</programlisting>
</para>
</listitem>
</itemizedlist>
</para>
<para>
<emphasis>Compatibility with PGDG Repositories</emphasis>
</para>
<para>
The 2ndQuadrant &repmgr; yum repository uses exactly the same package definitions as the
main PGDG repository and is effectively a selective mirror for &repmgr; packages only.
</para>
<para>
Normally yum should prioritize the repository with the most recent &repmgr; version.
Once the PGDG repository has been updated, it doesn't matter which repository
the packages are installed from.
</para>
<para>
To ensure the 2ndQuadrant repository is always prioritised, install <literal>yum-plugin-priorities</literal>
and set the repository priorities accordingly.
</para>
<para>
<emphasis>Installing a specific package version</emphasis>
</para>
<para>
To install a specific package version, execute <command>yum --showduplicates list</command>
for the package in question:
<programlisting>
[root@localhost ~]# yum --showduplicates list repmgr96
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* base: ftp.iij.ad.jp
* extras: ftp.iij.ad.jp
* updates: ftp.iij.ad.jp
Available Packages
repmgr96.x86_64 3.2-1.el6 2ndquadrant-repmgr
repmgr96.x86_64 3.2.1-1.el6 2ndquadrant-repmgr
repmgr96.x86_64 3.3-1.el6 2ndquadrant-repmgr
repmgr96.x86_64 3.3.1-1.el6 2ndquadrant-repmgr
repmgr96.x86_64 3.3.2-1.el6 2ndquadrant-repmgr
repmgr96.x86_64 3.3.2-1.rhel6 pgdg96
repmgr96.x86_64 4.0.0-1.el6 2ndquadrant-repmgr
repmgr96.x86_64 4.0.0-1.rhel6 pgdg96</programlisting>
then append the appropriate version number to the package name with a hyphen, e.g.:
<programlisting>
[root@localhost ~]# yum install repmgr96-3.3.2-1.el6</programlisting>
</para>
</sect3>
</sect2>
<sect2 id="installation-packages-debian" xreflabel="Installing from packages on Debian or Ubuntu">
<indexterm>
@@ -38,9 +144,9 @@
<title>Debian/Ubuntu</title>
<para>.deb packages for &repmgr; are available from the
PostgreSQL Community APT repository (<ulink url="http://apt.postgresql.org/">http://apt.postgresql.org/</>).
PostgreSQL Community APT repository (<ulink url="http://apt.postgresql.org/">http://apt.postgresql.org/</ulink>).
Instructions can be found in the APT section of the PostgreSQL Wiki
(<ulink url="https://wiki.postgresql.org/wiki/Apt">https://wiki.postgresql.org/wiki/Apt</>).
(<ulink url="https://wiki.postgresql.org/wiki/Apt">https://wiki.postgresql.org/wiki/Apt</ulink>).
</para>
</sect2>

View File

@@ -155,6 +155,20 @@
The generated HTML files will be placed in the <filename>doc/html</filename>
subdirectory of your source tree.
</para>
<para>
To build the documentation as a single HTML file, execute:
<programlisting>
cd doc/ && make repmgr.html</programlisting>
</para>
<note>
<simpara>
Due to changes in PostgreSQL's documentation build system from PostgreSQL 10,
the documentation can currently only be built agains PostgreSQL 9.6 or earlier.
This limitation will be fixed when time and resources permit.
</simpara>
</note>
</sect2>

View File

@@ -3,7 +3,7 @@
<date>2017</date>
<copyright>
<year>2010-2017</year>
<year>2010-2018</year>
<holder>2ndQuadrant, Ltd.</holder>
</copyright>
@@ -11,7 +11,7 @@
<title>Legal Notice</title>
<para>
<productname>repmgr</productname> is Copyright &copy; 2010-2017
<productname>repmgr</productname> is Copyright &copy; 2010-2018
by 2ndQuadrant, Ltd. All rights reserved.
</para>

View File

@@ -103,11 +103,11 @@
# ignores archiving. Use something more sensible.
archive_command = '/bin/true'
# If you have configured `pg_basebackup_options`
# in `repmgr.conf` to include the setting `--xlog-method=fetch` (from
# PostgreSQL 10 `--wal-method=fetch`), *and* you have not set
# `restore_command` in `repmgr.conf`to fetch WAL files from another
# source such as Barman, you'll need to set `wal_keep_segments` to a
# If you have configured "pg_basebackup_options"
# in "repmgr.conf" to include the setting "--xlog-method=fetch" (from
# PostgreSQL 10 "--wal-method=fetch"), *and* you have not set
# "restore_command" in "repmgr.conf"to fetch WAL files from another
# source such as Barman, you'll need to set "wal_keep_segments" to a
# high enough value to ensure that all WAL files generated while
# the standby is being cloned are retained until the standby starts up.
#
@@ -121,6 +121,11 @@
<command>include 'postgresql.replication.conf</command>.
</simpara>
</tip>
<para>
Additionally, if you are intending to use <application>pg_rewind</application>,
and the cluster was not initialised using data checksums, you may want to consider enabling
<varname>wal_log_hints</varname>; for more details see <xref linkend="repmgr-node-rejoin-pg-rewind">.
</para>
</sect1>
<sect1 id="quickstart-repmgr-user-database">
@@ -306,11 +311,10 @@
(and possibly <literal>data_directory</literal>) adjusted accordingly, e.g.:
</para>
<programlisting>
node=2
node_id=2
node_name=node2
conninfo='host=node2 user=repmgr dbname=repmgr connect_timeout=2'
data_directory='/var/lib/postgresql/data'
</programlisting>
data_directory='/var/lib/postgresql/data'</programlisting>
<para>
Use the <command>--dry-run</command> option to check the standby can be cloned:
</para>

View File

@@ -40,10 +40,13 @@
<simpara><literal>--node-name</literal>: restrict entries to node with this name</simpara>
</listitem>
<listitem>
<simpara><literal>--event</literal>: filter specific event</simpara>
<simpara><literal>--event</literal>: filter specific event (see <xref linkend="event-notifications"> for a full list)</simpara>
</listitem>
</itemizedlist>
</para>
<para>
The "Details" column can be omitted by providing <literal>--terse</literal>.
</para>
</refsect1>
<refsect1>

View File

@@ -45,6 +45,13 @@
</para>
</refsect1>
<refsect1>
<title>Event notifications</title>
<para>
A <literal>node_rejoin</literal> <link linkend="event-notifications">event notification</link> will be generated.
</para>
</refsect1>
<refsect1>
<title>Notes</title>
<para>
@@ -69,7 +76,7 @@
</tip>
</refsect1>
<refsect1 id="repmgr-node-rejoin-pg-rewind">
<refsect1 id="repmgr-node-rejoin-pg-rewind" xreflabel="Using pg_rewind">
<title>Using <command>pg_rewind</command></title>
<para>
<command>repmgr node rejoin</command> can optionally use <command>pg_rewind</command> to re-integrate a
@@ -78,7 +85,8 @@
</para>
<note>
<para>
<command>pg_rewind</command> *requires* that either <varname>wal_log_hints</varname> is enabled, or that
<command>pg_rewind</command> <emphasis>requires</emphasis> that either
<varname>wal_log_hints</varname> is enabled, or that
data checksums were enabled when the cluster was initialized. See the
<ulink url="https://www.postgresql.org/docs/current/static/app-pgrewind.html"><command>pg_rewind</command> documentation</ulink> for details.
</para>

View File

@@ -48,4 +48,11 @@
</note>
</refsect1>
<refsect1>
<title>Event notifications</title>
<para>
A <literal>primary_register</literal> <link linkend="event-notifications">event notification</link> will be generated.
</para>
</refsect1>
</refentry>

View File

@@ -13,7 +13,7 @@
<refsect1>
<title>Description</title>
<para>
<command>repmgr primary register</command> unregisters an inactive primary node
<command>repmgr primary unregister</command> unregisters an inactive primary node
from the &repmgr; metadata. This is typically when the primary has failed and is
being removed from the cluster after a new primary has been promoted.
</para>
@@ -28,7 +28,15 @@
<para>
<command>repmgr master unregister</command> can be used as an alias for
<command>repmgr primary unregister</command>/
<command>repmgr primary unregister</command>.
</para>
</refsect1>
<refsect1>
<title>Event notifications</title>
<para>
A <literal>primary_unregister</literal> <link linkend="event-notifications">event notification</link> will be generated.
</para>
</refsect1>
</refentry>

View File

@@ -99,5 +99,13 @@
</simpara>
</note>
</refsect1>
<refsect1>
<title>Event notifications</title>
<para>
A <literal>standby_clone</literal> <link linkend="event-notifications">event notification</link> will be generated.
</para>
</refsect1>
</refentry>

View File

@@ -48,6 +48,13 @@
</para>
</refsect1>
<refsect1>
<title>Event notifications</title>
<para>
A <literal>standby_follow</literal> <link linkend="event-notifications">event notification</link> will be generated.
</para>
</refsect1>
<refsect1>
<title>See also</title>
<para>

View File

@@ -41,4 +41,12 @@
DETAIL: server "node2" (ID: 2) was successfully promoted to primary</programlisting>
</para>
</refsect1>
<refsect1>
<title>Event notifications</title>
<para>
A <literal>standby_promote</literal> <link linkend="event-notifications">event notification</link> will be generated.
</para>
</refsect1>
</refentry>

View File

@@ -37,7 +37,24 @@
</note>
</refsect1>
<refsect1 id="repmgr-standby-register-wait" xreflabel="repmgr standby register --wait">
<refsect1 id="repmgr-standby-register-wait-start" xreflabel="repmgr standby register --wait-start">
<title>Waiting for the the standby to start</title>
<para>
By default, &repmgr; will wait 30 seconds for the standby to become available before
aborting with a connection error. This is useful when setting up a standby from a script,
as the standby may not have fully started up by the time <command>repmgr standby register</command>
is executed.
</para>
<para>
To change the timeout, pass the desired value with the <literal>--wait-start</literal> option.
A value of <literal>0</literal> will disable the timeout.
</para>
<para>
The timeout will be ignored if <literal>-F/--force</literal> was provided.
</para>
</refsect1>
<refsect1 id="repmgr-standby-register-wait-sync" xreflabel="repmgr standby register --wait-sync">
<title>Waiting for the registration to propagate to the standby</title>
<para>
Depending on your environment and workload, it may take some time for
@@ -74,4 +91,13 @@
<literal>-F/--force</literal> option does not result in an incorrectly configured cluster.
</para>
</refsect1>
<refsect1>
<title>Event notifications</title>
<para>
A <literal>standby_register</literal> <link linkend="event-notifications">event notification</link>
will be generated.
</para>
</refsect1>
</refentry>

View File

@@ -27,6 +27,71 @@
</para>
</refsect1>
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term><option>--always-promote</option></term>
<listitem>
<para>
Promote standby to primary, even if it is behind original primary
(original primary will be shut down in any case).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--dry-run</option></term>
<listitem>
<para>
Check prerequisites but don't actually execute a switchover.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-F</option></term>
<term><option>--force</option></term>
<listitem>
<para>
Ignore warnings and continue anyway.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--force-rewind</option></term>
<listitem>
<para>
Use <application>pg_rewind</application> to reintegrate the old primary if necessary
(PostgreSQL 9.5 and later).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-R</option></term>
<term><option>--remote-user</option></term>
<listitem>
<para>
System username for remote SSH operations (defaults to local system user).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--siblings-follow</option></term>
<listitem>
<para>
Have standbys attached to the old primary follow the new primary.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Execution</title>
@@ -40,6 +105,21 @@
</para>
</refsect1>
<refsect1>
<title>Event notifications</title>
<para>
<literal>standby_switchover</literal> and <literal>standby_promote</literal>
<link linkend="event-notifications">event notifications</link> will be generated for the new primary,
and a <literal>node_rejoin</literal> event notification for the former primary (new standby).
</para>
<para>
If using an event notification script, <literal>standby_switchover</literal>
will populate the placeholder parameter <literal>%p</literal> with the node ID of
the former standby.
</para>
</refsect1>
<refsect1>
<title>See also</title>
<para>

View File

@@ -42,5 +42,13 @@
repmgr standby unregister -f /etc/repmgr.conf --node-id=3</programlisting>
</para>
</refsect1>
<refsect1>
<title>Event notifications</title>
<para>
A <literal>standby_unregister</literal> <link linkend="event-notifications">event notification</link> will be generated.
</para>
</refsect1>
</refentry>

View File

@@ -49,4 +49,12 @@
</para>
</refsect1>
<refsect1>
<title>Event notifications</title>
<para>
A <literal>witness_register</literal> <link linkend="event-notifications">event notification</link> will be generated.
</para>
</refsect1>
</refentry>

View File

@@ -41,7 +41,7 @@
<para>
Unregistering a non-running witness node:
<programlisting>
$ repmgr -f /etc/repmgr.conf witness unregister -h localhost -p 5501 -F
$ repmgr -f /etc/repmgr.conf witness unregister -h node1 -p 5501 -F
INFO: connecting to witness node "node3" (ID: 3)
NOTICE: unable to connect to witness node "node3" (ID: 3), removing node record on cluster primary only
INFO: unregistering witness node 3
@@ -61,4 +61,13 @@
<link linkend="repmgr-witness-register">repmgr witness register --force</link>.
</para>
</refsect1>
<refsect1>
<title>Event notifications</title>
<para>
A <literal>witness_unregister</literal> <link linkend="event-notifications">event notification</link> will be generated.
</para>
</refsect1>
</refentry>

View File

@@ -117,6 +117,7 @@
&appendix-release-notes;
&appendix-signatures;
&appendix-faq;
&appendix-packages;
<![%include-index;[&bookindex;]]>
<![%include-xslt-index;[<index id="bookindex"></index>]]>

View File

@@ -54,45 +54,77 @@
<secondary>preparation</secondary>
</indexterm>
<title>Preparing for switchover</title>
<para>
As mentioned above, success of the switchover operation depends on &repmgr;
being able to shut down the current primary server quickly and cleanly.
As mentioned in the previous section, success of the switchover operation depends on
&repmgr; being able to shut down the current primary server quickly and cleanly.
</para>
<para>
Double-check which commands will be used to stop/start/restart the current
primary; on the primary execute:
<programlisting>
repmgr -f /etc/repmgr.conf node service --list --action=stop
repmgr -f /etc/repmgr.conf node service --list --action=start
repmgr -f /etc/repmgr.conf node service --list --action=restart
</programlisting>
repmgr -f /etc/repmgr.conf node service --list --action=restart</programlisting>
</para>
<para>
These commands can be defined in <filename>repmgr.conf</filename> with
<option>service_start_command</option>, <option>service_stop_command</option>
and <option>service_restart_command</option>.
</para>
<important>
<para>
If &repmgr; is installed from a package. you should set these commands
to use the appropriate service commands defined by the package/operating
system as these will ensure PostgreSQL is stopped/started properly
taking into account configuration and log file locations etc.
</para>
<para>
If the <option>service_*_command</option> options aren't defined, &repmgr; will
fall back to using <application>pg_ctl</application> to stop/start/restart
PostgreSQL, which may not work properly.
</para>
</important>
<note>
<simpara>
On <literal>systemd</literal> systems we strongly recommend using the appropriate
<command>systemctl</command> commands (typically run via <command>sudo</command>) to ensure
<literal>systemd</literal> informed about the status of the PostgreSQL service.
<literal>systemd</literal> is informed about the status of the PostgreSQL service.
</simpara>
<simpara>
If using <command>sudo</command> for the <command>systemctl</command> calls, make sure the
<command>sudo</command> specification doesn't require a real tty for the user. If not set
this way, <command>repmgr</command> will fail to stop the primary.
</simpara>
</note>
<para>
Check that access from applications is minimalized or preferably blocked
completely, so applications are not unexpectedly interrupted.
</para>
<para>
Check there is no significant replication lag on standbys attached to the
current primary.
</para>
<para>
If WAL file archiving is set up, check that there is no backlog of files waiting
to be archived, as PostgreSQL will not finally shut down until all these have been
to be archived, as PostgreSQL will not finally shut down until all of these have been
archived. If there is a backlog exceeding <varname>archive_ready_warning</varname> WAL files,
&repmgr; will emit a warning before attempting to perform a switchover; you can also check
manually with <command>repmgr node check --archive-ready</command>.
</para>
<para>
Ensure that <application>repmgrd</application> is *not* running anywhere to prevent it unintentionally
promoting a node.
</para>
<para>
Finally, consider executing <command>repmgr standby switchover</command> with the
<literal>--dry-run</literal> option; this will perform any necessary checks and inform you about
@@ -101,7 +133,7 @@
<programlisting>
$ repmgr standby switchover -f /etc/repmgr.conf --siblings-follow --dry-run
NOTICE: checking switchover on node "node2" (ID: 2) in --dry-run mode
INFO: SSH connection to host "localhost" succeeded
INFO: SSH connection to host "node1" succeeded
INFO: archive mode is "off"
INFO: replication lag on this standby is 0 seconds
INFO: all sibling nodes are reachable via SSH
@@ -110,6 +142,48 @@
"pg_ctl -l /var/log/postgresql/startup.log -D '/var/lib/postgresql/data' -m fast -W stop"
</programlisting>
</para>
<important>
<para>
Be aware that <option>--dry-run</option> checks the prerequisites
for performing the switchover and some basic sanity checks on the
state of the database which might effect the switchover operation
(e.g. replication lag); it cannot however guarantee the switchover
operation will succeed. In particular, if the current primary
does not shut down cleanly, &repmgr; will not be able to reliably
execute the switchover (as there would be a danger of divergence
between the former and new primary nodes).
</para>
</important>
<para>
Note that following parameters in <filename>repmgr.conf</filename> are relevant to the
switchover operation:
<itemizedlist spacing="compact" mark="bullet">
<listitem>
<simpara>
<literal>reconnect_attempts</literal>: number of times to check the original primary
for a clean shutdown after executing the shutdown command, before aborting
</simpara>
</listitem>
<listitem>
<simpara>
<literal>reconnect_interval</literal>: interval (in seconds) to check the original
primary for a clean shutdown after executing the shutdown command (up to a maximum
of <literal>reconnect_attempts</literal> tries)
</simpara>
</listitem>
<listitem>
<simpara>
<literal>replication_lag_critical</literal>:
if replication lag (in seconds) on the standby exceeds this value, the
switchover will be aborted (unless the <literal>-F/--force</literal> option
is provided)
</simpara>
</listitem>
</itemizedlist>
</para>
</sect1>
<sect1 id="switchover-execution" xreflabel="Executing the switchover command">
@@ -133,7 +207,7 @@
INFO: searching for primary node
INFO: checking if node 1 is primary
INFO: current primary node is 1
INFO: SSH connection to host "localhost" succeeded
INFO: SSH connection to host "node1" succeeded
INFO: archive mode is "off"
INFO: replication lag on this standby is 0 seconds
NOTICE: local node "node2" (ID: 2) will be promoted to primary; current primary "node1" (ID: 1) will be demoted to standby

View File

@@ -45,7 +45,7 @@
</listitem>
<listitem>
<simpara>
upgrading the repmgr schema
upgrading the repmgr schema using <command>CREATE EXTENSION</command>
</simpara>
</listitem>
</orderedlist>
@@ -58,11 +58,19 @@
a packaged PostgreSQL extension) is normally carried out
automatically when the &repmgr; extension is created.
</para>
<para>
The shared library has been renamed from <literal>repmgr_funcs</literal> to
<literal>repmgr</literal> - if it's set in <varname>shared_preload_libraries</varname>
in <filename>postgresql.conf</filename> it will need to be updated to the new name:
<programlisting>
shared_preload_libraries = 'repmgr'</programlisting>
</para>
<sect2 id="converting-repmgr-conf">
<title>Converting repmgr.conf configuration files</title>
<para>
With a completely new repmgr version, we've taken the opportunity
to rename some configuration items have had their names changed for
to rename some configuration items for
clarity and consistency, both between the configuration file and
the column names in <structname>repmgr.nodes</structname>
(e.g. <varname>node</varname> to <varname>node_id</varname>), and
@@ -151,7 +159,7 @@
be ignored.</simpara>
</listitem>
<listitem>
<simpara><varname>upstream_node_id</varname>: is replaced by the
<simpara><varname>upstream_node</varname>: is replaced by the
command-line parameter <literal>--upstream-node-id</literal></simpara>
</listitem>
</itemizedlist>
@@ -167,7 +175,7 @@
$ ./convert-config.pl /etc/repmgr.conf
node_id=2
node_name=node2
conninfo=host=localhost dbname=repmgr user=repmgr connect_timeout=2
conninfo=host=node2 dbname=repmgr user=repmgr connect_timeout=2
pg_ctl_options='-l /var/log/postgres/startup.log'
rsync_options=--exclude=postgresql.local.conf --archive
log_level=INFO

View File

@@ -1 +1 @@
<!ENTITY repmgrversion "4.0.0">
<!ENTITY repmgrversion "4.0.2">

View File

@@ -1,6 +1,6 @@
/*
* errcode.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

2
log.c
View File

@@ -1,6 +1,6 @@
/*
* log.c - Logging methods
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

2
log.h
View File

@@ -1,6 +1,6 @@
/*
* log.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -91,9 +91,6 @@ CREATE RULE voting_term_delete AS
ON DELETE TO repmgr.voting_term
DO INSTEAD NOTHING;
/* XXX do this in "repmgr primary register" */
INSERT INTO repmgr.voting_term (term) VALUES (1);
/* ================= */
/* repmgrd functions */

View File

@@ -71,6 +71,17 @@ INSERT INTO repmgr.voting_term (term) VALUES (1);
-- convert "repmgr_$cluster.repl_monitor" to "monitoring_history"
DO $repmgr$
DECLARE
DECLARE server_version_num INT;
BEGIN
SELECT setting
FROM pg_catalog.pg_settings
WHERE name = 'server_version_num'
INTO server_version_num;
IF server_version_num >= 90400 THEN
EXECUTE $repmgr_func$
CREATE TABLE repmgr.monitoring_history (
primary_node_id INTEGER NOT NULL,
standby_node_id INTEGER NOT NULL,
@@ -80,12 +91,32 @@ CREATE TABLE repmgr.monitoring_history (
last_wal_standby_location PG_LSN,
replication_lag BIGINT NOT NULL,
apply_lag BIGINT NOT NULL
);
)
$repmgr_func$;
INSERT INTO repmgr.monitoring_history
(primary_node_id, standby_node_id, last_monitor_time, last_apply_time, last_wal_primary_location, last_wal_standby_location, replication_lag, apply_lag)
SELECT primary_node, standby_node, last_monitor_time, last_apply_time, last_wal_primary_location::pg_lsn, last_wal_standby_location::pg_lsn, replication_lag, apply_lag
FROM repmgr.repl_monitor;
ELSE
EXECUTE $repmgr_func$
CREATE TABLE repmgr.monitoring_history (
primary_node_id INTEGER NOT NULL,
standby_node_id 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_func$;
INSERT INTO repmgr.monitoring_history
(primary_node_id, standby_node_id, last_monitor_time, last_apply_time, last_wal_primary_location, last_wal_standby_location, replication_lag, apply_lag)
SELECT primary_node, standby_node, last_monitor_time, last_apply_time, last_wal_primary_location, last_wal_standby_location, replication_lag, apply_lag
FROM repmgr.repl_monitor;
INSERT INTO repmgr.monitoring_history
(primary_node_id, standby_node_id, last_monitor_time, last_apply_time, last_wal_primary_location, last_wal_standby_location, replication_lag, apply_lag)
SELECT primary_node, standby_node, last_monitor_time, last_apply_time, last_wal_primary_location::pg_lsn, last_wal_standby_location::pg_lsn, replication_lag, apply_lag
FROM repmgr.repl_monitor;
END IF;
END$repmgr$;
CREATE INDEX idx_monitoring_history_time
ON repmgr.monitoring_history (last_monitor_time, standby_node_id);

View File

@@ -1,9 +1,9 @@
/*
* repmgr-action-standby.c
* repmgr-action-bdr.c
*
* Implements BDR-related actions for the repmgr command line utility
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -92,7 +92,39 @@ do_bdr_register(void)
exit(ERR_BAD_CONFIG);
}
/* check whether repmgr extension exists, and that any other nodes are BDR */
/* check for a matching BDR node */
{
PQExpBufferData bdr_local_node_name;
bool node_match = false;
initPQExpBuffer(&bdr_local_node_name);
node_match = bdr_node_name_matches(conn, config_file_options.node_name, &bdr_local_node_name);
if (node_match == false)
{
if (strlen(bdr_local_node_name.data))
{
log_error(_("local node BDR node name is \"%s\", expected: \"%s\""),
bdr_local_node_name.data,
config_file_options.node_name);
log_hint(_("\"node_name\" in repmgr.conf must match \"node_name\" in bdr.bdr_nodes"));
}
else
{
log_error(_("local node does not report BDR node name"));
log_hint(_("ensure this is an active BDR node"));
}
PQfinish(conn);
pfree(dbname);
termPQExpBuffer(&bdr_local_node_name);
exit(ERR_BAD_CONFIG);
}
termPQExpBuffer(&bdr_local_node_name);
}
/* check whether repmgr extension exists, and there are no non-BDR nodes registered */
extension_status = get_repmgr_extension_status(conn);
if (extension_status == REPMGR_UNKNOWN)
@@ -142,17 +174,9 @@ do_bdr_register(void)
pfree(dbname);
/* check for a matching BDR node */
if (bdr_node_has_repmgr_set(conn, config_file_options.node_name) == false)
{
bool node_exists = bdr_node_exists(conn, config_file_options.node_name);
if (node_exists == false)
{
log_error(_("no BDR node with node_name \"%s\" found"), config_file_options.node_name);
log_hint(_("\"node_name\" in repmgr.conf must match \"node_name\" in bdr.bdr_nodes"));
PQfinish(conn);
exit(ERR_BAD_CONFIG);
}
bdr_node_set_repmgr_set(conn, config_file_options.node_name);
}
/*

View File

@@ -1,6 +1,6 @@
/*
* repmgr-action-bdr.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -3,7 +3,7 @@
*
* Implements cluster information actions for the repmgr command line utility
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -436,82 +436,18 @@ void
do_cluster_event(void)
{
PGconn *conn = NULL;
PQExpBufferData query;
PQExpBufferData where_clause;
PGresult *res;
int i = 0;
int column_count = EVENT_HEADER_COUNT;
conn = establish_db_connection(config_file_options.conninfo, true);
initPQExpBuffer(&query);
initPQExpBuffer(&where_clause);
/* LEFT JOIN used here as a node record may have been removed */
appendPQExpBuffer(
&query,
" SELECT e.node_id, n.node_name, e.event, e.successful, \n"
" TO_CHAR(e.event_timestamp, 'YYYY-MM-DD HH24:MI:SS') AS timestamp, \n"
" e.details \n"
" FROM repmgr.events e \n"
"LEFT JOIN repmgr.nodes n ON e.node_id = n.node_id ");
if (runtime_options.node_id != UNKNOWN_NODE_ID)
{
append_where_clause(&where_clause,
"n.node_id=%i", runtime_options.node_id);
}
else if (runtime_options.node_name[0] != '\0')
{
char *escaped = escape_string(conn, runtime_options.node_name);
if (escaped == NULL)
{
log_error(_("unable to escape value provided for node name"));
}
else
{
append_where_clause(&where_clause,
"n.node_name='%s'",
escaped);
pfree(escaped);
}
}
if (runtime_options.event[0] != '\0')
{
char *escaped = escape_string(conn, runtime_options.event);
if (escaped == NULL)
{
log_error(_("unable to escape value provided for event"));
}
else
{
append_where_clause(&where_clause,
"e.event='%s'",
escaped);
pfree(escaped);
}
}
appendPQExpBuffer(&query, "\n%s\n",
where_clause.data);
appendPQExpBuffer(&query,
" ORDER BY e.event_timestamp DESC");
if (runtime_options.all == false && runtime_options.limit > 0)
{
appendPQExpBuffer(&query, " LIMIT %i",
runtime_options.limit);
}
log_debug("do_cluster_event():\n%s", query.data);
res = PQexec(conn, query.data);
termPQExpBuffer(&query);
termPQExpBuffer(&where_clause);
res = get_event_records(conn,
runtime_options.node_id,
runtime_options.node_name,
runtime_options.event,
runtime_options.all,
runtime_options.limit);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
@@ -538,7 +474,11 @@ do_cluster_event(void)
strncpy(headers_event[EV_TIMESTAMP].title, _("Timestamp"), MAXLEN);
strncpy(headers_event[EV_DETAILS].title, _("Details"), MAXLEN);
for (i = 0; i < EVENT_HEADER_COUNT; i++)
/* if --terse provided, simply omit the "Details" column */
if (runtime_options.terse == true)
column_count --;
for (i = 0; i < column_count; i++)
{
headers_event[i].max_length = strlen(headers_event[i].title);
}
@@ -547,7 +487,7 @@ do_cluster_event(void)
{
int j;
for (j = 0; j < EVENT_HEADER_COUNT; j++)
for (j = 0; j < column_count; j++)
{
headers_event[j].cur_length = strlen(PQgetvalue(res, i, j));
if (headers_event[j].cur_length > headers_event[j].max_length)
@@ -558,7 +498,7 @@ do_cluster_event(void)
}
for (i = 0; i < EVENT_HEADER_COUNT; i++)
for (i = 0; i < column_count; i++)
{
if (i == 0)
printf(" ");
@@ -571,14 +511,14 @@ do_cluster_event(void)
}
printf("\n");
printf("-");
for (i = 0; i < EVENT_HEADER_COUNT; i++)
for (i = 0; i < column_count; i++)
{
int j;
for (j = 0; j < headers_event[i].max_length; j++)
printf("-");
if (i < (EVENT_HEADER_COUNT - 1))
if (i < (column_count - 1))
printf("-+-");
else
printf("-");
@@ -591,13 +531,13 @@ do_cluster_event(void)
int j;
printf(" ");
for (j = 0; j < EVENT_HEADER_COUNT; j++)
for (j = 0; j < column_count; j++)
{
printf("%-*s",
headers_event[j].max_length,
PQgetvalue(res, i, j));
if (j < (EVENT_HEADER_COUNT - 1))
if (j < (column_count - 1))
printf(" | ");
}

View File

@@ -1,6 +1,6 @@
/*
* repmgr-action-cluster.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -3,7 +3,7 @@
*
* Implements actions available for any kind of node
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -496,16 +496,19 @@ _do_node_status_is_shutdown_cleanly(void)
db_state = get_db_state(config_file_options.data_directory);
log_verbose(LOG_DEBUG, "db state now: %s", describe_db_state(db_state));
if (db_state != DB_SHUTDOWNED && db_state != DB_SHUTDOWNED_IN_RECOVERY)
{
/*
* node is not running, but pg_controldata says it is - unclean
* shutdown
*/
if (node_status != NODE_STATUS_UP)
{
node_status = NODE_STATUS_UNCLEAN_SHUTDOWN;
}
/* server is still responding but shutting down */
else if (db_state == DB_SHUTDOWNING)
{
node_status = NODE_STATUS_SHUTTING_DOWN;
}
}
checkPoint = get_latest_checkpoint_location(config_file_options.data_directory);
@@ -525,19 +528,24 @@ _do_node_status_is_shutdown_cleanly(void)
node_status = NODE_STATUS_DOWN;
}
log_verbose(LOG_DEBUG, "node status determined as: %s", print_node_status(node_status));
switch (node_status)
{
case NODE_STATUS_UP:
appendPQExpBuffer(&output, "RUNNING");
break;
case NODE_STATUS_UNCLEAN_SHUTDOWN:
appendPQExpBuffer(&output, "UNCLEAN_SHUTDOWN");
case NODE_STATUS_SHUTTING_DOWN:
appendPQExpBuffer(&output, "SHUTTING_DOWN");
break;
case NODE_STATUS_DOWN:
appendPQExpBuffer(&output,
"SHUTDOWN --last-checkpoint-lsn=%X/%X",
format_lsn(checkPoint));
break;
case NODE_STATUS_UNCLEAN_SHUTDOWN:
appendPQExpBuffer(&output, "UNCLEAN_SHUTDOWN");
break;
case NODE_STATUS_UNKNOWN:
appendPQExpBuffer(&output, "UNKNOWN");
break;
@@ -559,10 +567,20 @@ do_node_check(void)
t_node_info node_info = T_NODE_INFO_INITIALIZER;
CheckStatus return_code;
CheckStatusList status_list = {NULL, NULL};
CheckStatusListCell *cell = NULL;
/* internal */
if (runtime_options.has_passfile == true)
{
return_code = has_passfile() ? 0 : 1;
exit(return_code);
}
if (strlen(config_file_options.conninfo))
conn = establish_db_connection(config_file_options.conninfo, true);
else
@@ -585,38 +603,51 @@ do_node_check(void)
*/
if (runtime_options.archive_ready == true)
{
(void) do_node_check_archive_ready(conn, runtime_options.output_mode, NULL);
return_code = do_node_check_archive_ready(conn,
runtime_options.output_mode,
NULL);
PQfinish(conn);
return;
exit(return_code);
}
if (runtime_options.downstream == true)
{
(void) do_node_check_downstream(conn, runtime_options.output_mode, NULL);
return_code = do_node_check_downstream(conn,
runtime_options.output_mode,
NULL);
PQfinish(conn);
return;
exit(return_code);
}
if (runtime_options.replication_lag == true)
{
(void) do_node_check_replication_lag(conn, runtime_options.output_mode, &node_info, NULL);
return_code = do_node_check_replication_lag(conn,
runtime_options.output_mode,
&node_info,
NULL);
PQfinish(conn);
return;
exit(return_code);
}
if (runtime_options.role == true)
{
(void) do_node_check_role(conn, runtime_options.output_mode, &node_info, NULL);
return_code = do_node_check_role(conn,
runtime_options.output_mode,
&node_info,
NULL);
PQfinish(conn);
return;
exit(return_code);
}
if (runtime_options.slots == true)
{
(void) do_node_check_slots(conn, runtime_options.output_mode, &node_info, NULL);
return_code = do_node_check_slots(conn,
runtime_options.output_mode,
&node_info,
NULL);
PQfinish(conn);
return;
exit(return_code);
}
if (runtime_options.output_mode == OM_NAGIOS)
@@ -705,8 +736,7 @@ do_node_check_role(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckS
}
else
{
appendPQExpBuffer(
&details,
appendPQExpBuffer(&details,
_("node is primary"));
}
break;
@@ -731,8 +761,7 @@ do_node_check_role(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckS
if (is_bdr_db(conn, &output) == false)
{
status = CHECK_STATUS_CRITICAL;
appendPQExpBuffer(
&details,
appendPQExpBuffer(&details,
"%s", output.data);
}
termPQExpBuffer(&output);
@@ -745,6 +774,11 @@ do_node_check_role(PGconn *conn, OutputMode mode, t_node_info *node_info, CheckS
appendPQExpBuffer(&details,
_("node is not an active BDR node"));
}
else
{
appendPQExpBuffer(&details,
_("node is an active BDR node"));
}
}
}
default:
@@ -1533,13 +1567,11 @@ parse_server_action(const char *action_name)
/*
* Intended mainly for "internal" use by "standby switchover", which
* calls this on the target server to excute pg_rewind on a demoted
* primary with a forked (sic) timeline. This function does not
* currently check whether this is a useful thing to do (however
* "standby switchover" will perform a check before calling it).
* Rejoin a dormant (shut down) node to the replication cluster; this
* is typically a former primary which needs to be demoted to a standby.
*
* TODO: make this into a more generally useful function.
* Note that "repmgr node rejoin" is also executed by
* "repmgr standby switchover" after promoting the new primary.
*/
void
do_node_rejoin(void)
@@ -1592,21 +1624,28 @@ do_node_rejoin(void)
/* check if cleanly shut down */
if (db_state != DB_SHUTDOWNED && db_state != DB_SHUTDOWNED_IN_RECOVERY)
{
log_error(_("database is not shut down cleanly"));
if (runtime_options.force_rewind == true)
if (db_state == DB_SHUTDOWNING)
{
log_detail(_("pg_rewind will not be able to run"));
log_error(_("database is still shutting down"));
}
else
{
log_error(_("database is not shut down cleanly"));
if (runtime_options.force_rewind == true)
{
log_detail(_("pg_rewind will not be able to run"));
}
log_hint(_("database should be restarted then shut down cleanly after crash recovery completes"));
exit(ERR_BAD_CONFIG);
}
log_hint(_("database should be restarted and shut down cleanly after crash recovery completes"));
exit(ERR_BAD_CONFIG);
}
/* check provided upstream connection */
upstream_conn = establish_db_connection_by_params(&source_conninfo, true);
/* sanity-checks for 9.3 */
/* sanity checks for 9.3 */
server_version_num = get_server_version(upstream_conn, NULL);
if (server_version_num < 90400)
@@ -1615,7 +1654,9 @@ do_node_rejoin(void)
if (get_primary_node_record(upstream_conn, &primary_node_record) == false)
{
log_error(_("unable to retrieve primary node record"));
log_hint(_("check the provided database connection string is for a \"repmgr\" database"));
PQfinish(upstream_conn);
exit(ERR_BAD_CONFIG);
}
PQfinish(upstream_conn);
@@ -1755,19 +1796,72 @@ do_node_rejoin(void)
log_detail("%s", strerror(errno));
}
}
termPQExpBuffer(&filebuf);
/* delete any replication slots copied in by pg_rewind */
{
PQExpBufferData slotdir_path;
DIR *slotdir;
struct dirent *slotdir_ent;
initPQExpBuffer(&slotdir_path);
appendPQExpBuffer(&slotdir_path,
"%s/pg_replslot",
config_file_options.data_directory);
slotdir = opendir(slotdir_path.data);
if (slotdir == NULL)
{
log_warning(_("unable to open replication slot directory \"%s\""),
slotdir_path.data);
log_detail("%s", strerror(errno));
}
else
{
while ((slotdir_ent = readdir(slotdir)) != NULL) {
struct stat statbuf;
PQExpBufferData slotdir_ent_path;
if(strcmp(slotdir_ent->d_name, ".") == 0 || strcmp(slotdir_ent->d_name, "..") == 0)
continue;
initPQExpBuffer(&slotdir_ent_path);
appendPQExpBuffer(&slotdir_ent_path,
"%s/%s",
slotdir_path.data,
slotdir_ent->d_name);
if (stat(slotdir_ent_path.data, &statbuf) == 0 && !S_ISDIR(statbuf.st_mode))
{
termPQExpBuffer(&slotdir_ent_path);
continue;
}
log_debug("deleting slot directory \"%s\"", slotdir_ent_path.data);
if (rmdir_recursive(slotdir_ent_path.data) != 0 && errno != EEXIST)
{
log_warning(_("unable to delete replication slot directory \"%s\""), slotdir_ent_path.data);
log_detail("%s", strerror(errno));
log_hint(_("directory may need to be manually removed"));
}
termPQExpBuffer(&slotdir_ent_path);
}
}
termPQExpBuffer(&slotdir_path);
}
}
initPQExpBuffer(&follow_output);
success = do_standby_follow_internal(
upstream_conn,
success = do_standby_follow_internal(upstream_conn,
&primary_node_record,
&follow_output);
create_event_notification(
upstream_conn,
create_event_notification(upstream_conn,
&config_file_options,
config_file_options.node_id,
"node_rejoin",

View File

@@ -1,6 +1,6 @@
/*
* repmgr-action-node.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -22,7 +22,6 @@
extern void do_node_status(void);
extern void do_node_check(void);
extern void do_node_rejoin(void);
extern void do_node_service(void);

View File

@@ -3,7 +3,7 @@
*
* Implements primary actions for the repmgr command line utility
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -74,7 +74,11 @@ do_primary_register(void)
log_verbose(LOG_INFO, _("server is not in recovery"));
/* create the repmgr extension if it doesn't already exist */
/*
* create the repmgr extension if it doesn't already exist;
* note that create_repmgr_extension() will take into account
* the --dry-run option
*/
if (!create_repmgr_extension(conn))
{
PQfinish(conn);
@@ -92,6 +96,7 @@ do_primary_register(void)
return;
}
initialize_voting_term(conn);
/* Ensure there isn't another registered node which is primary */
primary_conn = get_primary_connection(conn, &current_primary_id, NULL);

View File

@@ -1,6 +1,6 @@
/*
* repmgr-action-primary.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -3,7 +3,7 @@
*
* Implements standby actions for the repmgr command line utility
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -99,7 +99,8 @@ static bool create_recovery_file(t_node_info *node_record, t_conninfo_param_list
static void write_primary_conninfo(char *line, t_conninfo_param_list *param_list);
static bool write_recovery_file_line(FILE *recovery_file, char *recovery_file_path, char *line);
static int parse_output_to_argv(const char *string, char ***argv_array);
static void free_parsed_argv(char ***argv_array);
static NodeStatus parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr *checkPoint);
static CheckStatus parse_node_check_archiver(const char *node_check_output, int *files, int *threshold);
@@ -359,7 +360,7 @@ do_standby_clone(void)
* If copying of external configuration files requested, and any are
* detected, perform sanity checks
*/
if (PQstatus(source_conn) == CONNECTION_OK)
if (PQstatus(source_conn) == CONNECTION_OK && runtime_options.copy_external_config_files == true)
{
PGconn *superuser_conn = NULL;
PGconn *privileged_conn = NULL;
@@ -549,7 +550,7 @@ do_standby_clone(void)
* This won't run in Barman mode as "config_files" is only populated in
* "initialise_direct_clone()", which isn't called in Barman mode.
*/
if (runtime_options.copy_external_config_files && config_files.entries)
if (runtime_options.copy_external_config_files == true && config_files.entries > 0)
{
copy_configuration_files();
}
@@ -783,9 +784,52 @@ do_standby_register(void)
conn = establish_db_connection_quiet(config_file_options.conninfo);
/*
* if --force provided, don't wait for the node to start, as the
* normal use case will be re-registering an existing node, or
* registering an inactive/not-yet-extant one; we'll do the
* error handling for those cases in the next code block
*/
if (PQstatus(conn) != CONNECTION_OK && runtime_options.force == false)
{
bool conn_ok = false;
int timer = 0;
for (;;)
{
if (timer == runtime_options.wait_start)
break;
sleep(1);
log_verbose(LOG_INFO, _("%i of %i connection attempts"),
timer + 1,
runtime_options.wait_start);
conn = establish_db_connection_quiet(config_file_options.conninfo);
if (PQstatus(conn) == CONNECTION_OK)
{
conn_ok = true;
break;
}
timer++;
}
if (conn_ok == true)
{
log_info(_("connected to local node \"%s\" (ID: %i) after %i seconds"),
config_file_options.node_name,
config_file_options.node_id,
timer);
}
}
if (PQstatus(conn) != CONNECTION_OK)
{
if (!runtime_options.force)
if (runtime_options.force == false)
{
log_error(_("unable to connect to local node \"%s\" (ID: %i)"),
config_file_options.node_name,
@@ -797,7 +841,7 @@ do_standby_register(void)
exit(ERR_BAD_CONFIG);
}
if (!runtime_options.connection_param_provided)
if (runtime_options.connection_param_provided == false)
{
log_error(_("unable to connect to local node \"%s\" (ID: %i) and no primary connection parameters provided"),
config_file_options.node_name,
@@ -821,8 +865,8 @@ do_standby_register(void)
}
/*
* User is forcing a registration and must have supplied primary
* connection info
* otherwise user is forcing a registration of a (potentially) inactive (or
* not-yet-extant) node and must have supplied primary connection info
*/
else
{
@@ -1731,6 +1775,26 @@ do_standby_follow_internal(PGconn *primary_conn, t_node_info *primary_node_recor
{
int primary_server_version_num = get_server_version(primary_conn, NULL);
/*
* Here we add a sanity check for the "slot_name" field - it's possible
* the node was initially registered with "use_replication_slots=false"
* but the configuration was subsequently changed, leaving the field NULL.
*
* To avoid annoying failures we can just update the node record and proceed.
*/
if (!strlen(local_node_record.slot_name))
{
create_slot_name(local_node_record.slot_name, config_file_options.node_id);
log_notice(_("setting node %i's slot name to \"%s\""),
config_file_options.node_id,
local_node_record.slot_name);
update_node_record_slot_name(primary_conn, config_file_options.node_id, local_node_record.slot_name);
}
if (create_replication_slot(primary_conn,
local_node_record.slot_name,
primary_server_version_num,
@@ -1823,8 +1887,8 @@ do_standby_follow_internal(PGconn *primary_conn, t_node_info *primary_node_recor
/* Set the replication user from the primary node record */
param_set(&recovery_conninfo, "user", primary_node_record->repluser);
log_info(_("setting node %i's primary to node %i"),
config_file_options.node_id, primary_node_record->node_id);
log_notice(_("setting node %i's primary to node %i"),
config_file_options.node_id, primary_node_record->node_id);
if (!create_recovery_file(&local_node_record, &recovery_conninfo, config_file_options.data_directory))
{
@@ -1927,14 +1991,11 @@ do_standby_follow_internal(PGconn *primary_conn, t_node_info *primary_node_recor
* - promoting this standby node to primary
* - forcing previous primary node to follow this node
*
* Caveats:
* Caveat:
* - repmgrd must not be running, otherwise it may
* attempt a failover
* (TODO: find some way of notifying repmgrd of planned
* activity like this)
* - currently only set up for two-node operation; any other
* standbys will probably become downstream cascaded standbys
* of the old primary once it's restarted
*
* TODO:
* - make connection test timeouts/intervals configurable (see below)
@@ -1975,6 +2036,8 @@ do_standby_switchover(void)
NodeInfoList sibling_nodes = T_NODE_INFO_LIST_INITIALIZER;
int unreachable_sibling_node_count = 0;
t_event_info event_info = T_EVENT_INFO_INITIALIZER;
/*
* SANITY CHECKS
*
@@ -2073,6 +2136,8 @@ do_standby_switchover(void)
log_verbose(LOG_DEBUG, "remote node name is \"%s\"", remote_node_record.node_name);
/* this will fill the %p event notification parameter */
event_info.former_primary_id = remote_node_record.node_id;
/*
* If --force-rewind specified, check pg_rewind can be used, and
@@ -2603,6 +2668,7 @@ do_standby_switchover(void)
i + 1, config_file_options.reconnect_attempts);
ping_res = PQping(remote_conninfo);
log_debug("ping status is: %s", print_pqping_status(ping_res));
/* database server could not be contacted */
if (ping_res == PQPING_NO_RESPONSE || ping_res == PQPING_NO_ATTEMPT)
@@ -2623,8 +2689,7 @@ do_standby_switchover(void)
initPQExpBuffer(&command_output);
command_success = remote_command(
remote_host,
command_success = remote_command(remote_host,
runtime_options.remote_user,
remote_command_str.data,
&command_output);
@@ -2635,6 +2700,8 @@ do_standby_switchover(void)
{
NodeStatus status = parse_node_status_is_shutdown_cleanly(command_output.data, &remote_last_checkpoint_lsn);
log_verbose(LOG_DEBUG, "remote node status is: %s", print_node_status(status));
if (status == NODE_STATUS_DOWN && remote_last_checkpoint_lsn != InvalidXLogRecPtr)
{
shutdown_success = true;
@@ -2644,11 +2711,30 @@ do_standby_switchover(void)
break;
}
/* remote node did not shut down cleanly */
else if (status == NODE_STATUS_UNCLEAN_SHUTDOWN)
{
if (!runtime_options.force)
{
log_error(_("current primary did not shut down cleanly, aborting"));
log_hint(_("use -F/--force to promote current standby"));
termPQExpBuffer(&command_output);
exit(ERR_SWITCHOVER_FAIL);
}
log_error(_("current primary did not shut down cleanly, continuing anyway"));
shutdown_success = true;
break;
}
else if (status == NODE_STATUS_SHUTTING_DOWN)
{
log_info(_("remote node is still shutting down"));
}
}
termPQExpBuffer(&command_output);
}
log_debug("sleeping %i seconds until next check", config_file_options.reconnect_interval);
sleep(config_file_options.reconnect_interval);
}
@@ -2662,7 +2748,7 @@ do_standby_switchover(void)
/* this is unlikely to happen, but check and handle gracefully anyway */
if (PQstatus(local_conn) != CONNECTION_OK)
{
log_warning(_("connection to local node lost, reconnecting.."));
log_warning(_("connection to local node lost, reconnecting..."));
local_conn = establish_db_connection(config_file_options.conninfo, false);
if (PQstatus(local_conn) != CONNECTION_OK)
@@ -2749,8 +2835,7 @@ do_standby_switchover(void)
log_debug("executing:\n %s", remote_command_str.data);
initPQExpBuffer(&command_output);
command_success = remote_command(
remote_host,
command_success = remote_command(remote_host,
runtime_options.remote_user,
remote_command_str.data,
&command_output);
@@ -2766,21 +2851,33 @@ do_standby_switchover(void)
if (strlen(command_output.data) > 2)
log_detail("%s", command_output.data);
create_event_record(local_conn,
&config_file_options,
config_file_options.node_id,
"standby_switchover",
false,
command_output.data);
create_event_notification_extended(local_conn,
&config_file_options,
config_file_options.node_id,
"standby_switchover",
false,
command_output.data,
&event_info);
}
else
{
create_event_record(local_conn,
&config_file_options,
config_file_options.node_id,
"standby_switchover",
true,
NULL);
PQExpBufferData event_details;
initPQExpBuffer(&event_details);
appendPQExpBuffer(&event_details,
"node %i promoted to primary, node %i demoted to standby",
config_file_options.node_id,
remote_node_record.node_id);
create_event_notification_extended(local_conn,
&config_file_options,
config_file_options.node_id,
"standby_switchover",
true,
event_details.data,
&event_info);
termPQExpBuffer(&event_details);
}
termPQExpBuffer(&command_output);
@@ -2850,8 +2947,7 @@ do_standby_switchover(void)
initPQExpBuffer(&command_output);
success = remote_command(
host,
success = remote_command(host,
runtime_options.remote_user,
remote_command_str.data,
&command_output);
@@ -3680,8 +3776,7 @@ initialise_direct_clone(t_node_info *node_record)
{
log_error("%s", event_details.data);
create_event_notification(
primary_conn,
create_event_notification(primary_conn,
&config_file_options,
config_file_options.node_id,
"standby_clone",
@@ -4989,32 +5084,18 @@ write_primary_conninfo(char *line, t_conninfo_param_list *param_list)
}
/* TODO: consolidate code in below functions */
static NodeStatus
parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr *checkPoint)
{
int options_len = 0;
char *options_string = NULL;
char *options_string_ptr = NULL;
NodeStatus node_status = NODE_STATUS_UNKNOWN;
/*
* Add parsed options to this list, then copy to an array to pass to
* getopt
*/
static ItemList option_argv = {NULL, NULL};
char *argv_item;
int c,
argc_item = 1;
char **argv_array;
ItemListCell *cell;
int c = 0,
argc_item = 0;
char **argv_array = NULL;
int optindex = 0;
/* We're only interested in these options */
static struct option long_options[] =
struct option node_status_options[] =
{
{"last-checkpoint-lsn", required_argument, NULL, 'L'},
{"state", required_argument, NULL, 'S'},
@@ -5028,51 +5109,7 @@ parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr
return node_status;
}
options_len = strlen(node_status_output) + 1;
options_string = pg_malloc(options_len);
options_string_ptr = options_string;
/* Copy the string before operating on it with strtok() */
strncpy(options_string, node_status_output, options_len);
/* Extract arguments into a list and keep a count of the total */
while ((argv_item = strtok(options_string_ptr, " ")) != NULL)
{
item_list_append(&option_argv, argv_item);
argc_item++;
if (options_string_ptr != NULL)
options_string_ptr = NULL;
}
/*
* Array of argument values to pass to getopt_long - this will need to
* include an empty string as the first value (normally this would be the
* program name)
*/
argv_array = pg_malloc0(sizeof(char *) * (argc_item + 2));
/* Insert a blank dummy program name at the start of the array */
argv_array[0] = pg_malloc0(1);
c = 1;
/*
* Copy the previously extracted arguments from our list to the array
*/
for (cell = option_argv.head; cell; cell = cell->next)
{
int argv_len = strlen(cell->string) + 1;
argv_array[c] = pg_malloc0(argv_len);
strncpy(argv_array[c], cell->string, argv_len);
c++;
}
argv_array[c] = NULL;
argc_item = parse_output_to_argv(node_status_output, &argv_array);
/* Reset getopt's optind variable */
optind = 0;
@@ -5080,7 +5117,7 @@ parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr
/* Prevent getopt from emitting errors */
opterr = 0;
while ((c = getopt_long(argc_item, argv_array, "L:S:", long_options,
while ((c = getopt_long(argc_item, argv_array, "L:S:", node_status_options,
&optindex)) != -1)
{
switch (c)
@@ -5113,16 +5150,7 @@ parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr
}
}
pfree(options_string);
{
int i;
for (i = 0; i < argc_item + 2; i++)
pfree(argv_array[i]);
}
pfree(argv_array);
free_parsed_argv(&argv_array);
return node_status;
}
@@ -5131,30 +5159,15 @@ parse_node_status_is_shutdown_cleanly(const char *node_status_output, XLogRecPtr
static CheckStatus
parse_node_check_archiver(const char *node_check_output, int *files, int *threshold)
{
int options_len = 0;
char *options_string = NULL;
char *options_string_ptr = NULL;
CheckStatus status = CHECK_STATUS_UNKNOWN;
/*
* Add parsed options to this list, then copy to an array to pass to
* getopt
*/
static ItemList option_argv = {NULL, NULL};
char *argv_item;
int c,
argc_item = 1;
char **argv_array;
ItemListCell *cell;
int c = 0,
argc_item = 0;
char **argv_array = NULL;
int optindex = 0;
/* We're only interested in these options */
static struct option long_options[] =
struct option node_check_options[] =
{
{"status", required_argument, NULL, 'S'},
{"files", required_argument, NULL, 'f'},
@@ -5171,51 +5184,8 @@ parse_node_check_archiver(const char *node_check_output, int *files, int *thresh
return status;
}
options_len = strlen(node_check_output) + 1;
options_string = pg_malloc(options_len);
options_string_ptr = options_string;
argc_item = parse_output_to_argv(node_check_output, &argv_array);
/* Copy the string before operating on it with strtok() */
strncpy(options_string, node_check_output, options_len);
/* Extract arguments into a list and keep a count of the total */
while ((argv_item = strtok(options_string_ptr, " ")) != NULL)
{
item_list_append(&option_argv, argv_item);
argc_item++;
if (options_string_ptr != NULL)
options_string_ptr = NULL;
}
/*
* Array of argument values to pass to getopt_long - this will need to
* include an empty string as the first value (normally this would be the
* program name)
*/
argv_array = pg_malloc0(sizeof(char *) * (argc_item + 2));
/* Insert a blank dummy program name at the start of the array */
argv_array[0] = pg_malloc0(1);
c = 1;
/*
* Copy the previously extracted arguments from our list to the array
*/
for (cell = option_argv.head; cell; cell = cell->next)
{
int argv_len = strlen(cell->string) + 1;
argv_array[c] = pg_malloc0(argv_len);
strncpy(argv_array[c], cell->string, argv_len);
c++;
}
argv_array[c] = NULL;
/* Reset getopt's optind variable */
optind = 0;
@@ -5223,7 +5193,7 @@ parse_node_check_archiver(const char *node_check_output, int *files, int *thresh
/* Prevent getopt from emitting errors */
opterr = 0;
while ((c = getopt_long(argc_item, argv_array, "f:S:t:", long_options,
while ((c = getopt_long(argc_item, argv_array, "f:S:t:", node_check_options,
&optindex)) != -1)
{
switch (c)
@@ -5265,11 +5235,99 @@ parse_node_check_archiver(const char *node_check_output, int *files, int *thresh
}
}
free_parsed_argv(&argv_array);
return status;
}
static int
parse_output_to_argv(const char *string, char ***argv_array)
{
int options_len = 0;
char *options_string = NULL;
char *options_string_ptr = NULL;
int c = 1,
argc_item = 1;
char *argv_item = NULL;
char **local_argv_array = NULL;
ItemListCell *cell;
/*
* Add parsed options to this list, then copy to an array to pass to
* getopt
*/
ItemList option_argv = {NULL, NULL};
options_len = strlen(string) + 1;
options_string = pg_malloc(options_len);
options_string_ptr = options_string;
/* Copy the string before operating on it with strtok() */
strncpy(options_string, string, options_len);
/* Extract arguments into a list and keep a count of the total */
while ((argv_item = strtok(options_string_ptr, " ")) != NULL)
{
item_list_append(&option_argv, trim(argv_item));
argc_item++;
if (options_string_ptr != NULL)
options_string_ptr = NULL;
}
pfree(options_string);
/*
* Array of argument values to pass to getopt_long - this will need to
* include an empty string as the first value (normally this would be the
* program name)
*/
local_argv_array = pg_malloc0(sizeof(char *) * (argc_item + 2));
/* Insert a blank dummy program name at the start of the array */
local_argv_array[0] = pg_malloc0(1);
/*
* Copy the previously extracted arguments from our list to the array
*/
for (cell = option_argv.head; cell; cell = cell->next)
{
int argv_len = strlen(cell->string) + 1;
local_argv_array[c] = (char *)pg_malloc0(argv_len);
strncpy(local_argv_array[c], cell->string, argv_len);
c++;
}
local_argv_array[c] = NULL;
item_list_free(&option_argv);
*argv_array = local_argv_array;
return argc_item;
}
static void
free_parsed_argv(char ***argv_array)
{
char **local_argv_array = *argv_array;
int i = 0;
while (local_argv_array[i] != NULL)
{
pfree((char *)local_argv_array[i]);
i++;
}
pfree((char **)local_argv_array);
*argv_array = NULL;
}
void
@@ -5313,6 +5371,8 @@ do_standby_help(void)
printf(_(" -F, --force overwrite an existing node record, or if primary connection\n" \
" parameters supplied, create record even if standby offline\n"));
printf(_(" --upstream-node-id ID of the upstream node to replicate from (optional)\n"));
printf(_(" --wait-start=VALUE wait for the standby to start (timeout in seconds, default %i)\n"), DEFAULT_WAIT_START);
printf(_(" --wait-sync[=VALUE] wait for the node record to synchronise to the standby\n" \
" (optional timeout in seconds)\n"));

View File

@@ -1,6 +1,6 @@
/*
* repmgr-action-standby.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -3,7 +3,7 @@
*
* Implements witness actions for the repmgr command line utility
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -1,6 +1,6 @@
/*
* repmgr-action-witness.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -1,6 +1,6 @@
/*
* repmgr-client-global.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -86,6 +86,7 @@ typedef struct
/* "standby register" options */
bool wait_register_sync;
int wait_register_sync_seconds;
int wait_start;
/* "standby switchover" options */
bool always_promote;
@@ -101,6 +102,7 @@ typedef struct
bool replication_lag;
bool role;
bool slots;
bool has_passfile;
/* "node join" options */
char config_files[MAXLEN];
@@ -145,13 +147,13 @@ typedef struct
/* "standby clone"/"standby follow" options */ \
NO_UPSTREAM_NODE, \
/* "standby register" options */ \
false, 0, \
false, 0, DEFAULT_WAIT_START, \
/* "standby switchover" options */ \
false, false, false, \
/* "node status" options */ \
false, \
/* "node check" options */ \
false, false, false, false, false, \
false, false, false, false, false, false, \
/* "node join" options */ \
"", \
/* "node service" options */ \

View File

@@ -1,7 +1,7 @@
/*
* repmgr-client.c - Command interpreter for the repmgr package
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* This module is a command-line utility to easily setup a cluster of
* hot standby servers for an HA environment
@@ -177,7 +177,7 @@ main(int argc, char **argv)
strncpy(runtime_options.username, pw->pw_name, MAXLEN);
}
while ((c = getopt_long(argc, argv, "?Vb:f:Fd:h:p:U:R:S:L:vtD:crC:", long_options,
while ((c = getopt_long(argc, argv, "?Vb:f:FWd:h:p:U:R:S:D:ckL:tvC:", long_options,
&optindex)) != -1)
{
/*
@@ -389,7 +389,11 @@ main(int argc, char **argv)
*---------------------------
*/
case OPT_REGISTER_WAIT:
case OPT_WAIT_START:
runtime_options.wait_start = repmgr_atoi(optarg, "--wait-start", &cli_errors, false);
break;
case OPT_WAIT_SYNC:
runtime_options.wait_register_sync = true;
if (optarg != NULL)
{
@@ -447,6 +451,10 @@ main(int argc, char **argv)
runtime_options.slots = true;
break;
case OPT_HAS_PASSFILE:
runtime_options.has_passfile = true;
break;
/*--------------------
* "node rejoin" options
*--------------------
@@ -1316,7 +1324,7 @@ check_cli_parameters(const int action)
/*
* XXX if -D/--pgdata provided, and also
* config_file_options.pgdaga, warn -D/--pgdata will be
* config_file_options.pgdata, warn -D/--pgdata will be
* ignored
*/
@@ -1356,6 +1364,12 @@ check_cli_parameters(const int action)
}
}
break;
case NODE_CHECK:
if (runtime_options.has_passfile == true)
{
config_file_required = false;
}
break;
case NODE_STATUS:
if (runtime_options.node_id != UNKNOWN_NODE_ID)
{
@@ -2715,6 +2729,6 @@ init_node_record(t_node_info *node_record)
if (config_file_options.use_replication_slots == true)
{
maxlen_snprintf(node_record->slot_name, "repmgr_slot_%i", config_file_options.node_id);
create_slot_name(node_record->slot_name, config_file_options.node_id);
}
}

View File

@@ -1,6 +1,6 @@
/*
* repmgr-client.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -56,7 +56,7 @@
#define OPT_NODE_NAME 1007
#define OPT_WITHOUT_BARMAN 1008
#define OPT_NO_UPSTREAM_CONNECTION 1009
#define OPT_REGISTER_WAIT 1010
#define OPT_WAIT_SYNC 1010
#define OPT_LOG_TO_FILE 1011
#define OPT_UPSTREAM_CONNINFO 1012
#define OPT_REPLICATION_USER 1013
@@ -81,6 +81,9 @@
#define OPT_DOWNSTREAM 1032
#define OPT_SLOTS 1033
#define OPT_CONFIG_ARCHIVE_DIR 1034
#define OPT_HAS_PASSFILE 1035
#define OPT_WAIT_START 1036
/* deprecated since 3.3 */
#define OPT_DATA_DIR 999
#define OPT_NO_CONNINFO_PASSWORD 998
@@ -135,7 +138,8 @@ static struct option long_options[] =
{"without-barman", no_argument, NULL, OPT_WITHOUT_BARMAN},
/* "standby register" options */
{"wait-sync", optional_argument, NULL, OPT_REGISTER_WAIT},
{"wait-start", required_argument, NULL, OPT_WAIT_START},
{"wait-sync", optional_argument, NULL, OPT_WAIT_SYNC},
/* "standby switchover" options
*
@@ -153,6 +157,7 @@ static struct option long_options[] =
{"replication-lag", no_argument, NULL, OPT_REPLICATION_LAG},
{"role", no_argument, NULL, OPT_ROLE},
{"slots", no_argument, NULL, OPT_SLOTS},
{"has-passfile", no_argument, NULL, OPT_HAS_PASSFILE},
/* "node rejoin" options */
{"config-files", required_argument, NULL, OPT_CONFIG_FILES},

View File

@@ -1,7 +1,7 @@
/*
* repmgr.c - repmgr extension
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* This is the actual extension code; see repmgr-client.c for the code which
* generates the repmgr binary

View File

@@ -13,35 +13,35 @@
# repmgr and repmgrd require the following items to be explicitly configured.
#node_id= # A unique integer greater than zero
#node_name='' # An arbitrary (but unique) string; we recommend
# using the server's hostname or another identifier
# unambiguously associated with the server to avoid
# confusion. Avoid choosing names which reflect the
# node's current role, e.g. "primary" or "standby1",
# as roles can change and it will be confusing if
# the current primary is called "standby1".
#node_id= # A unique integer greater than zero
#node_name='' # An arbitrary (but unique) string; we recommend
# using the server's hostname or another identifier
# unambiguously associated with the server to avoid
# confusion. Avoid choosing names which reflect the
# node's current role, e.g. "primary" or "standby1",
# as roles can change and it will be confusing if
# the current primary is called "standby1".
#conninfo='' # Database connection information as a conninfo string.
# All servers in the cluster must be able to connect to
# the local node using this string.
#
# For details on conninfo strings, see:
# https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
#
# If repmgrd is in use, consider explicitly setting
# "connect_timeout" in the conninfo string to determine
# the length of time which elapses before a network
# connection attempt is abandoned; for details see:
# https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNECT-CONNECT-TIMEOUT
#conninfo='' # Database connection information as a conninfo string.
# All servers in the cluster must be able to connect to
# the local node using this string.
#
# For details on conninfo strings, see:
# https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
#
# If repmgrd is in use, consider explicitly setting
# "connect_timeout" in the conninfo string to determine
# the length of time which elapses before a network
# connection attempt is abandoned; for details see:
# https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNECT-CONNECT-TIMEOUT
#data_directory # The node's data directory. This is needed by repmgr
# when performing operations when the PostgreSQL instance
# is not running and there's no other way of determining
# the data directory.
#data_directory='' # The node's data directory. This is needed by repmgr
# when performing operations when the PostgreSQL instance
# is not running and there's no other way of determining
# the data directory.
#replication_user # User to make replication connections with, if not set defaults
# to the user defined in "conninfo".
#replication_user='repmgr' # User to make replication connections with, if not set defaults
# to the user defined in "conninfo".
# =============================================================================
@@ -52,28 +52,28 @@
# Replication settings
#------------------------------------------------------------------------------
#replication_type=physical # Must be one of 'physical' or 'bdr'.
#replication_type=physical # Must be one of 'physical' or 'bdr'.
#location=default # arbitrary string defining the location of the node; this
# is used during failover to check visibilty of the
# current primary node. See the 'repmgrd' documentation
# in README.md for further details.
#location=default # arbitrary string defining the location of the node; this
# is used during failover to check visibilty of the
# current primary node. See the 'repmgrd' documentation
# in README.md for further details.
#use_replication_slots=no # whether to use physical replication slots
# NOTE: when using replication slots,
# 'max_replication_slots' should be configured for
# at least the number of standbys which will connect
# to the primary.
#use_replication_slots=no # whether to use physical replication slots
# NOTE: when using replication slots,
# 'max_replication_slots' should be configured for
# at least the number of standbys which will connect
# to the primary.
#recovery_min_apply_delay= # If provided, "recovery_min_apply_delay" in recovery.conf
# will be set to this value.
#recovery_min_apply_delay= # If provided, "recovery_min_apply_delay" in recovery.conf
# will be set to this value.
#------------------------------------------------------------------------------
# Witness server settings
#------------------------------------------------------------------------------
#witness_sync_interval=15 # interval (in seconds) to synchronise node records
# to the witness server
#witness_sync_interval=15 # interval (in seconds) to synchronise node records
# to the witness server
#------------------------------------------------------------------------------
# Logging settings
@@ -85,14 +85,14 @@
# This is mainly intended for those cases when `repmgr` is executed directly
# by `repmgrd`.
#log_level=INFO # Log level: possible values are DEBUG, INFO, NOTICE,
# WARNING, ERROR, ALERT, CRIT or EMERG
#log_level=INFO # Log level: possible values are DEBUG, INFO, NOTICE,
# WARNING, ERROR, ALERT, CRIT or EMERG
#log_facility=STDERR # Logging facility: possible values are STDERR, or for
# syslog integration, one of LOCAL0, LOCAL1, ..., LOCAL7, USER
#log_facility=STDERR # Logging facility: possible values are STDERR, or for
# syslog integration, one of LOCAL0, LOCAL1, ..., LOCAL7, USER
#log_file='' # stderr can be redirected to an arbitrary file:
#log_status_interval=300 # interval (in seconds) for repmgrd to log a status message
#log_file='' # stderr can be redirected to an arbitrary file:
#log_status_interval=300 # interval (in seconds) for repmgrd to log a status message
#------------------------------------------------------------------------------
@@ -118,28 +118,28 @@
#
# event_notifications=primary_register,standby_register
#event_notification_command='' # An external program or script which
# can be executed by the user under which
# repmgr/repmgrd are run.
#event_notification_command='' # An external program or script which
# can be executed by the user under which
# repmgr/repmgrd are run.
#event_notifications='' # A commas-separated list of notification
# types
#event_notifications='' # A commas-separated list of notification
# types
#------------------------------------------------------------------------------
# Environment/command settings
#------------------------------------------------------------------------------
#pg_bindir='' # Path to PostgreSQL binary directory (location
# of pg_ctl, pg_basebackup etc.). Only needed
# if these files are not in the system $PATH.
#
# Debian/Ubuntu users: you will probably need to
# set this to the directory where `pg_ctl` is located,
# e.g. /usr/lib/postgresql/9.6/bin/
#use_primary_conninfo_password=false # explicitly set "password" in recovery.conf's
# "primary_conninfo" parameter using the value contained
# in the environment variable PGPASSWORD
#passfile='' # path to .pgpass file to include in "primary_conninfo"
#pg_bindir='' # Path to PostgreSQL binary directory (location
# of pg_ctl, pg_basebackup etc.). Only needed
# if these files are not in the system $PATH.
#
# Debian/Ubuntu users: you will probably need to
# set this to the directory where `pg_ctl` is located,
# e.g. /usr/lib/postgresql/9.6/bin/
#use_primary_conninfo_password=false # explicitly set "password" in recovery.conf's
# "primary_conninfo" parameter using the value contained
# in the environment variable PGPASSWORD
#passfile='' # path to .pgpass file to include in "primary_conninfo"
#------------------------------------------------------------------------------
# external command options
#------------------------------------------------------------------------------
@@ -153,11 +153,10 @@
# rsync_options=--archive --checksum --compress --progress --rsh="ssh -o \"StrictHostKeyChecking no\""
# ssh_options=-o "StrictHostKeyChecking no"
#pg_ctl_options='' # Options to append to "pg_ctl"
#pg_basebackup_options='' # Options to append to "pg_basebackup"
#rsync_options='' # Options to append to "rsync"
ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
#pg_ctl_options='' # Options to append to "pg_ctl"
#pg_basebackup_options='' # Options to append to "pg_basebackup"
#rsync_options='' # Options to append to "rsync"
ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
@@ -172,12 +171,12 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
# tablespace_mapping=/path/to/original/tablespace=/path/to/new/tablespace
# restore_command = 'cp /path/to/archived/wals/%f %p'
#tablespace_mapping='' # Tablespaces can be remapped from one
# file system location to another. This
# parameter can be provided multiple times.
#tablespace_mapping='' # Tablespaces can be remapped from one
# file system location to another. This
# parameter can be provided multiple times.
#restore_command='' # This will be placed in the recovery.conf
# file generated by repmgr
#restore_command='' # This will be placed in the recovery.conf
# file generated by repmgr
#------------------------------------------------------------------------------
# Standby follow settings
@@ -186,19 +185,19 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
# These settings apply when instructing a standby to follow the new primary
# ("repmgr standby follow").
#primary_follow_timeout=60 # The length of time (in seconds) to wait
# for the new primary to become available
#primary_follow_timeout=60 # The length of time (in seconds) to wait
# for the new primary to become available
#------------------------------------------------------------------------------
# Barman options
#------------------------------------------------------------------------------
#barman_server='' # The barman configuration section
#barman_host='' # The host name of the barman server
#barman_config='' # The Barman configuration file on the
# Barman server (needed if the file is
# in a non-standard location)
#barman_server='' # The barman configuration section
#barman_host='' # The host name of the barman server
#barman_config='' # The Barman configuration file on the
# Barman server (needed if the file is
# in a non-standard location)
#------------------------------------------------------------------------------
# Failover and monitoring settings (repmgrd)
@@ -207,42 +206,42 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
# These settings are only applied when repmgrd is running. Values shown
# are defaults.
#failover=manual # one of 'automatic', 'manual'.
# determines what action to take in the event of upstream failure
#
# 'automatic': repmgrd will automatically attempt to promote the
# node or follow the new upstream node
# 'manual': repmgrd will take no action and the node will require
# manual attention to reattach it to replication
# (does not apply to BDR mode)
#failover=manual # one of 'automatic', 'manual'.
# determines what action to take in the event of upstream failure
#
# 'automatic': repmgrd will automatically attempt to promote the
# node or follow the new upstream node
# 'manual': repmgrd will take no action and the node will require
# manual attention to reattach it to replication
# (does not apply to BDR mode)
#priority=100 # indicate a preferred priorty for promoting nodes;
# a value of zero prevents the node being promoted to primary
# (default: 100)
#priority=100 # indicate a preferred priorty for promoting nodes;
# a value of zero prevents the node being promoted to primary
# (default: 100)
#reconnect_attempts=6 # Number attempts which will be made to reconnect to an unreachable
# primary (or other upstream node)
#reconnect_interval=10 # Interval between attempts to reconnect to an unreachable
# primary (or other upstream node)
#promote_command= # command to execute when promoting a new primary; use something like:
#
# repmgr standby promote -f /etc/repmgr.conf
#
#follow_command= # command to execute when instructing a standby to follow a new primary;
# use something like:
#
# repmgr standby follow -f /etc/repmgr.conf -W --upstream-node-id=%n
#
#primary_notification_timeout=60 # Interval (in seconds) which repmgrd on a standby
# will wait for a notification from the new primary,
# before falling back to degraded monitoring
#reconnect_attempts=6 # Number attempts which will be made to reconnect to an unreachable
# primary (or other upstream node)
#reconnect_interval=10 # Interval between attempts to reconnect to an unreachable
# primary (or other upstream node)
#promote_command= # command to execute when promoting a new primary; use something like:
#
# repmgr standby promote -f /etc/repmgr.conf
#
#follow_command= # command to execute when instructing a standby to follow a new primary;
# use something like:
#
# repmgr standby follow -f /etc/repmgr.conf -W --upstream-node-id=%n
#
#primary_notification_timeout=60 # Interval (in seconds) which repmgrd on a standby
# will wait for a notification from the new primary,
# before falling back to degraded monitoring
#monitoring_history=no
#degraded_monitoring_timeout=-1 # Interval (in seconds) after which repmgrd will terminate if the
# server being monitored is no longer available. -1 (default)
# disables the timeout completely.
#async_query_timeout=60 # Interval (in seconds) which repmgrd will wait before
# cancelling an asynchronous query.
#degraded_monitoring_timeout=-1 # Interval (in seconds) after which repmgrd will terminate if the
# server being monitored is no longer available. -1 (default)
# disables the timeout completely.
#async_query_timeout=60 # Interval (in seconds) which repmgrd will wait before
# cancelling an asynchronous query.
#------------------------------------------------------------------------------
# service control commands
@@ -275,10 +274,10 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
#service_stop_command = ''
#service_restart_command = ''
#service_reload_command = ''
#service_promote_command = '' # Note: this overrides any value contained in the setting
# "promote_command". This is intended for systems which
# provide a package-level promote command, such as Debian's
# "pg_ctlcluster"
#service_promote_command = '' # Note: this overrides any value contained in the setting
# "promote_command". This is intended for systems which
# provide a package-level promote command, such as Debian's
# "pg_ctlcluster"
#------------------------------------------------------------------------------
@@ -287,25 +286,25 @@ ssh_options='-q -o ConnectTimeout=10' # Options to append to "ssh"
# Various warning/critical thresholds used by "repmgr node check".
#archive_ready_warning=16 # repmgr node check --archiver
#archive_ready_critical=128 #
# Numbers of files pending archiving via PostgreSQL's
# "archive_command" configuration parameter. If
# files can't be archived fast enough, or the archive
# command is failing, the buildup of files can
# cause various issues, such as server shutdown being
# delayed until all files are archived, or excessive
# space being occupied by unarchived files.
#
# Note that these values will be checked when executing
# "repmgr standby switchover" to warn about potential
# issues with shutting down the demotion candidate.
#archive_ready_warning=16 # repmgr node check --archive-ready
#archive_ready_critical=128 #
# Numbers of files pending archiving via PostgreSQL's
# "archive_command" configuration parameter. If
# files can't be archived fast enough, or the archive
# command is failing, the buildup of files can
# cause various issues, such as server shutdown being
# delayed until all files are archived, or excessive
# space being occupied by unarchived files.
#
# Note that these values will be checked when executing
# "repmgr standby switchover" to warn about potential
# issues with shutting down the demotion candidate.
#replication_lag_warning=300 # repmgr node check --replication-lag
#replication_lag_critical=600 #
# Note that these values will be checked when executing
# "repmgr standby switchover" to warn about potential
# issues with shutting down the demotion candidate.
#replication_lag_warning=300 # repmgr node check --replication-lag
#replication_lag_critical=600 #
# Note that these values will be checked when executing
# "repmgr standby switchover" to warn about potential
# issues with shutting down the demotion candidate.
#------------------------------------------------------------------------------

View File

@@ -1,6 +1,6 @@
/*
* repmgr.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -56,6 +56,7 @@
#define NO_UPSTREAM_NODE -1
#define UNKNOWN_NODE_ID -1
#define VOTING_TERM_NOT_SET -1
/*
* various default values - ensure repmgr.conf.sample is update
@@ -75,6 +76,7 @@
#define DEFAULT_REPLICATION_LAG_WARNING 300 /* seconds */
#define DEFAULT_REPLICATION_LAG_CRITICAL 600 /* seconds */
#define DEFAULT_WITNESS_SYNC_INTERVAL 15 /* seconds */
#define DEFAULT_WAIT_START 30 /* seconds */
#ifndef RECOVERY_COMMAND_FILE
#define RECOVERY_COMMAND_FILE "recovery.conf"

View File

@@ -1,3 +1,3 @@
#define REPMGR_VERSION_DATE ""
#define REPMGR_VERSION "4.0.0"
#define REPMGR_VERSION "4.0.2"

View File

@@ -1,7 +1,7 @@
/*
* repmgrd-bdr.c - BDR functionality for repmgrd
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -124,9 +124,9 @@ monitor_bdr(void)
exit(ERR_BAD_CONFIG);
}
if (is_active_bdr_node(local_conn, local_node_info.node_name))
if (is_active_bdr_node(local_conn, local_node_info.node_name) == false)
{
log_error(_("BDR node %s is not active, terminating"),
log_error(_("BDR node \"%s\" is not active, terminating"),
local_node_info.node_name);
PQfinish(local_conn);
exit(ERR_BAD_CONFIG);

View File

@@ -1,6 +1,6 @@
/*
* repmgrd-bdr.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -1,7 +1,7 @@
/*
* repmgrd-physical.c - physical replication functionality for repmgrd
* repmgrd-physical.c - physical (streaming) replication functionality for repmgrd
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -107,11 +107,11 @@ do_physical_node_check(void)
if (local_node_info.active == false)
{
char *hint = "Check that 'repmgr (primary|standby) register' was executed for this node";
char *hint = "Check that \"repmgr (primary|standby) register\" was executed for this node";
switch (config_file_options.failover)
{
/* "failover" is an enum, all values should be covered here */
/* "failover" is an enum, all values should be covered here */
case FAILOVER_AUTOMATIC:
log_error(_("this node is marked as inactive and cannot be used as a failover target"));
@@ -935,22 +935,19 @@ loop:
local_node_info.active = false;
appendPQExpBuffer(
&event_details,
appendPQExpBuffer(&event_details,
_("unable to connect to local node \"%s\" (ID: %i), marking inactive"),
local_node_info.node_name,
local_node_info.node_id);
log_warning("%s", event_details.data)
log_warning("%s", event_details.data);
create_event_notification(
primary_conn,
&config_file_options,
local_node_info.node_id,
"standby_failure",
false,
event_details.data);
create_event_notification(primary_conn,
&config_file_options,
local_node_info.node_id,
"standby_failure",
false,
event_details.data);
termPQExpBuffer(&event_details);
}
@@ -971,8 +968,7 @@ loop:
local_node_info.active = true;
appendPQExpBuffer(
&event_details,
appendPQExpBuffer(&event_details,
_("reconnected to local node \"%s\" (ID: %i), marking active"),
local_node_info.node_name,
local_node_info.node_id);

View File

@@ -1,6 +1,6 @@
/*
* repmgrd-physical.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -1,7 +1,7 @@
/*
* repmgrd.c - Replication manager daemon
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -1,6 +1,6 @@
/*
* repmgrd.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*/

View File

@@ -1,7 +1,7 @@
/*
* strutil.c
*
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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

View File

@@ -1,6 +1,6 @@
/*
* strutil.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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
@@ -33,12 +33,17 @@
#define MAXLEN_STR STR(MAXLEN)
/*
* These values must match the Nagios return codes defined here:
*
* https://assets.nagios.com/downloads/nagioscore/docs/nagioscore/3/en/pluginapi.html
*/
typedef enum
{
CHECK_STATUS_OK = 0,
CHECK_STATUS_WARNING,
CHECK_STATUS_CRITICAL,
CHECK_STATUS_UNKNOWN
CHECK_STATUS_OK = 0,
CHECK_STATUS_WARNING = 1,
CHECK_STATUS_CRITICAL = 2,
CHECK_STATUS_UNKNOWN = 3
} CheckStatus;
typedef enum

View File

@@ -1,6 +1,6 @@
/*
* voting.h
* Copyright (c) 2ndQuadrant, 2010-2017
* Copyright (c) 2ndQuadrant, 2010-2018
*
* 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